github.com/google/syzkaller@v0.0.0-20240517125934-c0f1611a36d6/pkg/compiler/check.go (about)

     1  // Copyright 2017 syzkaller project authors. All rights reserved.
     2  // Use of this source code is governed by Apache 2 LICENSE that can be found in the LICENSE file.
     3  
     4  // Package compiler generates sys descriptions of syscalls, types and resources
     5  // from textual descriptions.
     6  package compiler
     7  
     8  import (
     9  	"errors"
    10  	"fmt"
    11  	"regexp"
    12  	"strings"
    13  
    14  	"github.com/google/syzkaller/pkg/ast"
    15  	"github.com/google/syzkaller/prog"
    16  	"github.com/google/syzkaller/sys/targets"
    17  )
    18  
    19  func (comp *compiler) typecheck() {
    20  	comp.checkComments()
    21  	comp.checkDirectives()
    22  	comp.checkNames()
    23  	comp.checkFlags()
    24  	comp.checkFields()
    25  	comp.checkTypedefs()
    26  	comp.checkTypes()
    27  }
    28  
    29  func (comp *compiler) check(consts map[string]uint64) {
    30  	comp.checkTypeValues()
    31  	comp.checkAttributeValues()
    32  	comp.checkUnused()
    33  	comp.checkRecursion()
    34  	comp.checkFieldPaths()
    35  	comp.checkConstructors()
    36  	comp.checkVarlens()
    37  	comp.checkDupConsts()
    38  	comp.checkConstsFlags(consts)
    39  }
    40  
    41  func (comp *compiler) checkComments() {
    42  	confusingComment := regexp.MustCompile(`^\s*(include|incdir|define)`)
    43  	for _, decl := range comp.desc.Nodes {
    44  		switch n := decl.(type) {
    45  		case *ast.Comment:
    46  			if confusingComment.MatchString(n.Text) {
    47  				comp.error(n.Pos, "confusing comment faking a directive (rephrase if it's intentional)")
    48  			}
    49  		}
    50  	}
    51  }
    52  
    53  func (comp *compiler) checkDirectives() {
    54  	includes := make(map[string]bool)
    55  	incdirs := make(map[string]bool)
    56  	defines := make(map[string]bool)
    57  	for _, decl := range comp.desc.Nodes {
    58  		switch n := decl.(type) {
    59  		case *ast.Include:
    60  			name := n.File.Value
    61  			path := n.Pos.File + "/" + name
    62  			if includes[path] {
    63  				comp.error(n.Pos, "duplicate include %q", name)
    64  			}
    65  			includes[path] = true
    66  		case *ast.Incdir:
    67  			name := n.Dir.Value
    68  			path := n.Pos.File + "/" + name
    69  			if incdirs[path] {
    70  				comp.error(n.Pos, "duplicate incdir %q", name)
    71  			}
    72  			incdirs[path] = true
    73  		case *ast.Define:
    74  			name := n.Name.Name
    75  			path := n.Pos.File + "/" + name
    76  			if defines[path] {
    77  				comp.error(n.Pos, "duplicate define %v", name)
    78  			}
    79  			defines[path] = true
    80  		}
    81  	}
    82  }
    83  
    84  func (comp *compiler) checkNames() {
    85  	calls := make(map[string]*ast.Call)
    86  	for _, decl := range comp.desc.Nodes {
    87  		switch n := decl.(type) {
    88  		case *ast.Resource, *ast.Struct, *ast.TypeDef:
    89  			pos, typ, name := decl.Info()
    90  			if reservedName[name] {
    91  				comp.error(pos, "%v uses reserved name %v", typ, name)
    92  				continue
    93  			}
    94  			if builtinTypes[name] != nil {
    95  				comp.error(pos, "%v name %v conflicts with builtin type", typ, name)
    96  				continue
    97  			}
    98  			if prev := comp.resources[name]; prev != nil {
    99  				comp.error(pos, "type %v redeclared, previously declared as resource at %v",
   100  					name, prev.Pos)
   101  				continue
   102  			}
   103  			if prev := comp.typedefs[name]; prev != nil {
   104  				comp.error(pos, "type %v redeclared, previously declared as type alias at %v",
   105  					name, prev.Pos)
   106  				continue
   107  			}
   108  			if prev := comp.structs[name]; prev != nil {
   109  				_, typ, _ := prev.Info()
   110  				comp.error(pos, "type %v redeclared, previously declared as %v at %v",
   111  					name, typ, prev.Pos)
   112  				continue
   113  			}
   114  			switch n := decl.(type) {
   115  			case *ast.Resource:
   116  				comp.resources[name] = n
   117  			case *ast.TypeDef:
   118  				comp.typedefs[name] = n
   119  			case *ast.Struct:
   120  				comp.structs[name] = n
   121  			}
   122  		case *ast.IntFlags:
   123  			name := n.Name.Name
   124  			if name == "_" {
   125  				continue
   126  			}
   127  			if reservedName[name] {
   128  				comp.error(n.Pos, "flags uses reserved name %v", name)
   129  				continue
   130  			}
   131  			if prev := comp.intFlags[name]; prev != nil {
   132  				comp.error(n.Pos, "flags %v redeclared, previously declared at %v",
   133  					name, prev.Pos)
   134  				continue
   135  			}
   136  			comp.intFlags[name] = n
   137  		case *ast.StrFlags:
   138  			name := n.Name.Name
   139  			if reservedName[name] {
   140  				comp.error(n.Pos, "string flags uses reserved name %v", name)
   141  				continue
   142  			}
   143  			if prev := comp.strFlags[name]; prev != nil {
   144  				comp.error(n.Pos, "string flags %v redeclared, previously declared at %v",
   145  					name, prev.Pos)
   146  				continue
   147  			}
   148  			comp.strFlags[name] = n
   149  		case *ast.Call:
   150  			name := n.Name.Name
   151  			if prev := calls[name]; prev != nil {
   152  				comp.error(n.Pos, "syscall %v redeclared, previously declared at %v",
   153  					name, prev.Pos)
   154  			}
   155  			calls[name] = n
   156  		}
   157  	}
   158  }
   159  
   160  func (comp *compiler) checkFlags() {
   161  	checkFlagsGeneric[*ast.IntFlags, *ast.Int](comp, comp.intFlags)
   162  	checkFlagsGeneric[*ast.StrFlags, *ast.String](comp, comp.strFlags)
   163  }
   164  
   165  func checkFlagsGeneric[F ast.Flags[V], V ast.FlagValue](comp *compiler, allFlags map[string]F) {
   166  	for name, flags := range allFlags {
   167  		inConstIdent := true
   168  		for _, val := range flags.GetValues() {
   169  			if _, ok := allFlags[val.GetName()]; ok {
   170  				inConstIdent = false
   171  			} else {
   172  				if !inConstIdent {
   173  					comp.error(flags.GetPos(), "flags identifier not at the end in %v definition", name)
   174  					break
   175  				}
   176  			}
   177  		}
   178  	}
   179  }
   180  
   181  func (comp *compiler) checkFields() {
   182  	for _, decl := range comp.desc.Nodes {
   183  		switch n := decl.(type) {
   184  		case *ast.Struct:
   185  			_, typ, name := n.Info()
   186  			comp.checkStructFields(n, typ, name)
   187  		case *ast.TypeDef:
   188  			if n.Struct != nil {
   189  				_, typ, _ := n.Struct.Info()
   190  				comp.checkStructFields(n.Struct, "template "+typ, n.Name.Name)
   191  			}
   192  		case *ast.Call:
   193  			name := n.Name.Name
   194  			comp.checkFieldGroup(n.Args, "argument", "syscall "+name)
   195  			if len(n.Args) > prog.MaxArgs {
   196  				comp.error(n.Pos, "syscall %v has %v arguments, allowed maximum is %v",
   197  					name, len(n.Args), prog.MaxArgs)
   198  			}
   199  		}
   200  	}
   201  }
   202  
   203  func (comp *compiler) checkStructFields(n *ast.Struct, typ, name string) {
   204  	comp.checkFieldGroup(n.Fields, "field", typ+" "+name)
   205  	if len(n.Fields) < 1 {
   206  		comp.error(n.Pos, "%v %v has no fields, need at least 1 field", typ, name)
   207  	}
   208  	hasDirections, hasOutOverlay := false, false
   209  	prevFieldHadIf := false
   210  	for fieldIdx, f := range n.Fields {
   211  		if n.IsUnion {
   212  			_, exprs := comp.parseAttrs(unionFieldAttrs, f, f.Attrs)
   213  			if fieldIdx > 0 && fieldIdx+1 < len(n.Fields) &&
   214  				prevFieldHadIf && exprs[attrIf] == nil {
   215  				comp.error(f.Pos, "either no fields have conditions or all except the last")
   216  			}
   217  			prevFieldHadIf = exprs[attrIf] != nil
   218  			if fieldIdx+1 == len(n.Fields) && exprs[attrIf] != nil {
   219  				comp.error(f.Pos, "unions must not have if conditions on the last field")
   220  			}
   221  			continue
   222  		}
   223  		attrs, _ := comp.parseAttrs(structFieldAttrs, f, f.Attrs)
   224  		dirCount := attrs[attrIn] + attrs[attrOut] + attrs[attrInOut]
   225  		if dirCount != 0 {
   226  			hasDirections = true
   227  		}
   228  		if dirCount > 1 {
   229  			_, typ, _ := f.Info()
   230  			comp.error(f.Pos, "%v has multiple direction attributes", typ)
   231  		}
   232  		if attrs[attrOutOverlay] > 0 {
   233  			if fieldIdx == 0 {
   234  				comp.error(f.Pos, "%v attribute must not be specified on the first field", attrOutOverlay.Name)
   235  			}
   236  			if hasOutOverlay || attrs[attrOutOverlay] > 1 {
   237  				comp.error(f.Pos, "multiple %v attributes", attrOutOverlay.Name)
   238  			}
   239  			hasOutOverlay = true
   240  		}
   241  		if hasDirections && hasOutOverlay {
   242  			comp.error(f.Pos, "mix of direction and %v attributes is not supported", attrOutOverlay.Name)
   243  		}
   244  	}
   245  }
   246  
   247  func (comp *compiler) checkFieldGroup(fields []*ast.Field, what, ctx string) {
   248  	existing := make(map[string]bool)
   249  	for _, f := range fields {
   250  		fn := f.Name.Name
   251  		if fn == prog.ParentRef || fn == prog.SyscallRef {
   252  			comp.error(f.Pos, "reserved %v name %v in %v", what, fn, ctx)
   253  		}
   254  		if existing[fn] {
   255  			comp.error(f.Pos, "duplicate %v %v in %v", what, fn, ctx)
   256  		}
   257  		existing[fn] = true
   258  	}
   259  }
   260  
   261  const argBase = "BASE"
   262  
   263  func (comp *compiler) checkTypedefs() {
   264  	for _, decl := range comp.desc.Nodes {
   265  		switch n := decl.(type) {
   266  		case *ast.TypeDef:
   267  			if len(n.Args) == 0 {
   268  				// Non-template types are fully typed, so we check them ahead of time.
   269  				err0 := comp.errors
   270  				comp.checkType(checkCtx{}, n.Type, checkIsTypedef)
   271  				if err0 != comp.errors {
   272  					// To not produce confusing errors on broken type usage.
   273  					delete(comp.typedefs, n.Name.Name)
   274  				}
   275  			} else {
   276  				// For templates we only do basic checks of arguments.
   277  				names := make(map[string]bool)
   278  				for i, arg := range n.Args {
   279  					if arg.Name == argBase && i != len(n.Args)-1 {
   280  						comp.error(arg.Pos, "type argument BASE must be the last argument")
   281  					}
   282  					if names[arg.Name] {
   283  						comp.error(arg.Pos, "duplicate type argument %v", arg.Name)
   284  					}
   285  					names[arg.Name] = true
   286  					for _, c := range arg.Name {
   287  						if c >= 'A' && c <= 'Z' ||
   288  							c >= '0' && c <= '9' ||
   289  							c == '_' {
   290  							continue
   291  						}
   292  						comp.error(arg.Pos, "type argument %v must be ALL_CAPS",
   293  							arg.Name)
   294  						break
   295  					}
   296  				}
   297  			}
   298  		}
   299  	}
   300  }
   301  
   302  func (comp *compiler) checkTypes() {
   303  	for _, decl := range comp.desc.Nodes {
   304  		switch n := decl.(type) {
   305  		case *ast.Resource:
   306  			comp.checkType(checkCtx{}, n.Base, checkIsResourceBase)
   307  		case *ast.Struct:
   308  			comp.checkStruct(checkCtx{}, n)
   309  		case *ast.Call:
   310  			comp.checkCall(n)
   311  		}
   312  	}
   313  }
   314  
   315  func (comp *compiler) checkTypeValues() {
   316  	for _, decl := range comp.desc.Nodes {
   317  		switch n := decl.(type) {
   318  		case *ast.Call, *ast.Struct, *ast.Resource, *ast.TypeDef:
   319  			comp.foreachType(decl, func(t *ast.Type, desc *typeDesc,
   320  				args []*ast.Type, base prog.IntTypeCommon) {
   321  				if desc.CheckConsts != nil {
   322  					desc.CheckConsts(comp, t, args, base)
   323  				}
   324  				for i, arg := range args {
   325  					if check := desc.Args[i].Type.CheckConsts; check != nil {
   326  						check(comp, arg)
   327  					}
   328  				}
   329  			})
   330  		case *ast.IntFlags:
   331  			allEqual := len(n.Values) >= 2
   332  			for _, val := range n.Values {
   333  				if val.Value != n.Values[0].Value {
   334  					allEqual = false
   335  				}
   336  			}
   337  			if allEqual {
   338  				comp.error(n.Pos, "all %v values are equal %v", n.Name.Name, n.Values[0].Value)
   339  			}
   340  		}
   341  	}
   342  }
   343  
   344  func (comp *compiler) checkAttributeValues() {
   345  	for _, decl := range comp.desc.Nodes {
   346  		switch n := decl.(type) {
   347  		case *ast.Struct:
   348  			for _, attr := range n.Attrs {
   349  				desc := structOrUnionAttrs(n)[attr.Ident]
   350  				if desc.CheckConsts != nil {
   351  					desc.CheckConsts(comp, n, attr)
   352  				}
   353  			}
   354  			// Check each field's attributes.
   355  			st := decl.(*ast.Struct)
   356  			hasOutOverlay := false
   357  			for _, f := range st.Fields {
   358  				isOut := hasOutOverlay
   359  				for _, attr := range f.Attrs {
   360  					switch attr.Ident {
   361  					case attrOutOverlay.Name:
   362  						hasOutOverlay = true
   363  						fallthrough
   364  					case attrOut.Name, attrInOut.Name:
   365  						isOut = true
   366  					}
   367  				}
   368  				if isOut && comp.getTypeDesc(f.Type).CantBeOut {
   369  					comp.error(f.Pos, "%v type must not be used as output", f.Type.Ident)
   370  				}
   371  			}
   372  		case *ast.Call:
   373  			attrNames := make(map[string]bool)
   374  			descAttrs := comp.parseIntAttrs(callAttrs, n, n.Attrs)
   375  			for desc := range descAttrs {
   376  				attrNames[prog.CppName(desc.Name)] = true
   377  			}
   378  
   379  			checked := make(map[string]bool)
   380  			for _, a := range n.Args {
   381  				comp.checkRequiredCallAttrs(n, attrNames, a.Type, checked)
   382  			}
   383  		}
   384  	}
   385  }
   386  
   387  func (comp *compiler) checkRequiredCallAttrs(call *ast.Call, callAttrNames map[string]bool,
   388  	t *ast.Type, checked map[string]bool) {
   389  	desc := comp.getTypeDesc(t)
   390  	for attr := range desc.RequiresCallAttrs {
   391  		if !callAttrNames[attr] {
   392  			comp.error(call.Pos, "call %v refers to type %v and so must be marked %s", call.Name.Name, t.Ident, attr)
   393  		}
   394  	}
   395  
   396  	if desc == typeStruct {
   397  		s := comp.structs[t.Ident]
   398  		// Prune recursion, can happen even on correct tree via opt pointers.
   399  		if checked[s.Name.Name] {
   400  			return
   401  		}
   402  		checked[s.Name.Name] = true
   403  		fields := s.Fields
   404  		for _, fld := range fields {
   405  			comp.checkRequiredCallAttrs(call, callAttrNames, fld.Type, checked)
   406  		}
   407  	} else if desc == typeArray {
   408  		typ := t.Args[0]
   409  		comp.checkRequiredCallAttrs(call, callAttrNames, typ, checked)
   410  	} else if desc == typePtr {
   411  		typ := t.Args[1]
   412  		comp.checkRequiredCallAttrs(call, callAttrNames, typ, checked)
   413  	}
   414  }
   415  
   416  func (comp *compiler) checkFieldPaths() {
   417  	warned := make(map[string]bool)
   418  	for _, decl := range comp.desc.Nodes {
   419  		switch n := decl.(type) {
   420  		case *ast.Call:
   421  			for _, arg := range n.Args {
   422  				checked := make(map[string]bool)
   423  
   424  				parents := []parentDesc{{fields: n.Args, call: n.Name.Name}}
   425  				comp.checkFieldPathsRec(arg.Type, arg.Type, parents, checked, warned, true)
   426  			}
   427  		}
   428  	}
   429  }
   430  
   431  type parentDesc struct {
   432  	call   string
   433  	name   string
   434  	fields []*ast.Field
   435  }
   436  
   437  func (pd *parentDesc) String() string {
   438  	if pd.call != "" {
   439  		return fmt.Sprintf("<%s>", pd.call)
   440  	}
   441  	return pd.name
   442  }
   443  
   444  // templateBase return the part before '[' for full template names.
   445  func templateBase(name string) string {
   446  	if pos := strings.IndexByte(name, '['); pos != -1 {
   447  		return name[:pos]
   448  	}
   449  	return name
   450  }
   451  
   452  func parentTargetName(s *ast.Struct) string {
   453  	// For template parents name is "struct_name[ARG1, ARG2]", strip the part after '['.
   454  	return templateBase(s.Name.Name)
   455  }
   456  
   457  func (comp *compiler) checkFieldPathsRec(t0, t *ast.Type, parents []parentDesc,
   458  	checked, warned map[string]bool, isArg bool) {
   459  	desc := comp.getTypeDesc(t)
   460  	if desc == typeStruct {
   461  		s := comp.structs[t.Ident]
   462  		// Prune recursion, can happen even on correct tree via opt pointers.
   463  		// There may be several paths to the same type, let's at least look
   464  		// at the nearest parent.
   465  		checkName := s.Name.Name
   466  		if len(parents) > 1 {
   467  			checkName = parents[len(parents)-2].name + " " + checkName
   468  		}
   469  		if checked[checkName] {
   470  			return
   471  		}
   472  		checked[checkName] = true
   473  		fields := s.Fields
   474  		if s.IsUnion {
   475  			fields = nil
   476  		}
   477  		parentName := parentTargetName(s)
   478  		parents = append([]parentDesc{}, parents...)
   479  		parents = append(parents, parentDesc{name: parentName, fields: fields})
   480  		for _, fld := range s.Fields {
   481  			comp.checkFieldPathsRec(fld.Type, fld.Type, parents, checked, warned, false)
   482  			for _, attr := range fld.Attrs {
   483  				attrDesc := structFieldAttrs[attr.Ident]
   484  				if attrDesc == nil || attrDesc.Type != exprAttr {
   485  					continue
   486  				}
   487  				if attrDesc == attrIf {
   488  					comp.checkExprFieldType(fld.Type)
   489  				}
   490  				ast.Recursive(func(n ast.Node) bool {
   491  					exprType, ok := n.(*ast.Type)
   492  					if !ok || exprType.Ident != valueIdent {
   493  						return true
   494  					}
   495  					comp.validateFieldPath(exprType.Args[0], t0, exprType, parents, warned)
   496  					return false
   497  				})(attr.Args[0])
   498  			}
   499  		}
   500  		return
   501  	}
   502  	_, args, _ := comp.getArgsBase(t, isArg)
   503  	for i, arg := range args {
   504  		argDesc := desc.Args[i]
   505  		if argDesc.Type == typeArgLenTarget {
   506  			comp.validateFieldPath(arg, t0, t, parents, warned)
   507  		} else if argDesc.Type == typeArgType {
   508  			comp.checkFieldPathsRec(t0, arg, parents, checked, warned, argDesc.IsArg)
   509  		}
   510  	}
   511  }
   512  
   513  func (comp *compiler) validateFieldPath(arg, fieldType, t *ast.Type, parents []parentDesc,
   514  	warned map[string]bool) {
   515  	targets := append([]*ast.Type{arg}, arg.Colon...)
   516  	const maxParents = 2
   517  	for i, target := range targets {
   518  		if target.Ident == prog.ParentRef &&
   519  			(i >= maxParents || targets[0].Ident != prog.ParentRef) {
   520  			// It's not a fundamental limitation, but it helps prune recursion in checkLenType().
   521  			// If we need more, we need to adjust the key of the "checked" map.
   522  			if !warned[parents[len(parents)-1].name] {
   523  				comp.error(target.Pos, "%v may only stay at the beginning (max %d times)",
   524  					prog.ParentRef, maxParents)
   525  			}
   526  			warned[parents[len(parents)-1].name] = true
   527  			return
   528  		}
   529  		if target.Ident == prog.SyscallRef {
   530  			if i != 0 {
   531  				comp.error(target.Pos, "syscall can't be in the middle of path expressions")
   532  				return
   533  			}
   534  			if len(targets) == 1 {
   535  				comp.error(targets[0].Pos, "no argument name after syscall reference")
   536  				return
   537  			}
   538  		}
   539  	}
   540  	// Drop parents from the prefix (it will simplify further code).
   541  	droppedParents := 0
   542  	for len(targets) > 0 && targets[0].Ident == prog.ParentRef {
   543  		target := targets[0]
   544  		if parents[len(parents)-1].call != "" {
   545  			comp.error(target.Pos, "%v reached the call (%v)",
   546  				prog.ParentRef, parents[0].call)
   547  			return
   548  		}
   549  		droppedParents++
   550  		targets = targets[1:]
   551  		// Ignore the first "parent" item.
   552  		if droppedParents > 1 {
   553  			if len(parents) < 2 {
   554  				comp.error(target.Pos, "too many %v elements", prog.ParentRef)
   555  				return
   556  			}
   557  			parents = parents[:len(parents)-1]
   558  		}
   559  	}
   560  	comp.validateFieldPathRec(fieldType, t, targets, parents, warned)
   561  }
   562  
   563  func (comp *compiler) validateFieldPathRec(t0, t *ast.Type, targets []*ast.Type,
   564  	parents []parentDesc, warned map[string]bool) {
   565  	if len(targets) == 0 {
   566  		if t.Ident == "offsetof" {
   567  			comp.error(t.Pos, "%v must refer to fields", t.Ident)
   568  			return
   569  		}
   570  		return
   571  	}
   572  	isValuePath := t.Ident == valueIdent
   573  	target := targets[0]
   574  	targets = targets[1:]
   575  	fields := parents[len(parents)-1].fields
   576  	for _, fld := range fields {
   577  		if target.Ident != fld.Name.Name {
   578  			continue
   579  		}
   580  		if fld.Type == t0 {
   581  			comp.error(target.Pos, "%v target %v refers to itself", t.Ident, target.Ident)
   582  			return
   583  		}
   584  		if !comp.checkPathField(target, t, fld) {
   585  			return
   586  		}
   587  		if len(targets) == 0 {
   588  			if t.Ident == "len" {
   589  				typ, desc := comp.derefPointers(fld.Type)
   590  				if desc == typeArray && comp.isVarlen(typ.Args[0]) {
   591  					// We can reach the same struct multiple times starting from different
   592  					// syscall arguments. Warn only once.
   593  					if !warned[parents[len(parents)-1].name] {
   594  						warned[parents[len(parents)-1].name] = true
   595  						comp.warning(target.Pos, "len target %v refer to an array with"+
   596  							" variable-size elements (do you mean bytesize?)",
   597  							target.Ident)
   598  					}
   599  				}
   600  			}
   601  			if isValuePath {
   602  				comp.checkExprLastField(target, fld)
   603  			}
   604  			return
   605  		}
   606  		typ, desc := comp.derefPointers(fld.Type)
   607  		if desc != typeStruct {
   608  			comp.error(target.Pos, "%v path %v does not refer to a struct", t.Ident, target.Ident)
   609  			return
   610  		}
   611  		s := comp.structs[typ.Ident]
   612  		if s.IsUnion {
   613  			comp.error(target.Pos, "%v path %v does not refer to a struct", t.Ident, target.Ident)
   614  			return
   615  		}
   616  		parents = append(parents, parentDesc{name: parentTargetName(s), fields: s.Fields})
   617  		comp.validateFieldPathRec(t0, t, targets, parents, warned)
   618  		return
   619  	}
   620  	for pi := len(parents) - 1; pi >= 0; pi-- {
   621  		parent := parents[pi]
   622  		if parent.name != "" && parent.name == target.Ident ||
   623  			parent.name == "" && target.Ident == prog.SyscallRef {
   624  			parents1 := make([]parentDesc, pi+1)
   625  			copy(parents1, parents[:pi+1])
   626  			comp.validateFieldPathRec(t0, t, targets, parents1, warned)
   627  			return
   628  		}
   629  	}
   630  	warnKey := parents[len(parents)-1].name + " " + target.Pos.String()
   631  	if !warned[warnKey] {
   632  		comp.error(target.Pos, "%v target %v does not exist in %s",
   633  			t.Ident, target.Ident, parents[len(parents)-1].String())
   634  	}
   635  	warned[warnKey] = true
   636  }
   637  
   638  func (comp *compiler) checkPathField(target, t *ast.Type, field *ast.Field) bool {
   639  	for _, attr := range field.Attrs {
   640  		desc := structFieldAttrs[attr.Ident]
   641  		if desc == attrIf {
   642  			comp.error(target.Pos, "%s has conditions, so %s path cannot reference it",
   643  				field.Name.Name, t.Ident)
   644  			return false
   645  		}
   646  	}
   647  
   648  	return true
   649  }
   650  
   651  func (comp *compiler) checkExprLastField(target *ast.Type, field *ast.Field) {
   652  	_, desc := comp.derefPointers(field.Type)
   653  	if desc != typeInt && desc != typeFlags {
   654  		comp.error(target.Pos, "%v does not refer to an integer or a flag", field.Name.Name)
   655  	}
   656  }
   657  
   658  func (comp *compiler) checkExprFieldType(t *ast.Type) {
   659  	desc := comp.getTypeDesc(t)
   660  	if desc == typeInt && len(t.Colon) != 0 {
   661  		comp.error(t.Pos, "bitfields may not have conditions")
   662  	}
   663  }
   664  
   665  func CollectUnused(desc *ast.Description, target *targets.Target, eh ast.ErrorHandler) ([]ast.Node, error) {
   666  	comp := createCompiler(desc, target, eh)
   667  	comp.typecheck()
   668  	if comp.errors > 0 {
   669  		return nil, errors.New("typecheck failed")
   670  	}
   671  
   672  	nodes := comp.collectUnused()
   673  	if comp.errors > 0 {
   674  		return nil, errors.New("collectUnused failed")
   675  	}
   676  	return nodes, nil
   677  }
   678  
   679  func (comp *compiler) collectUnused() []ast.Node {
   680  	var unused []ast.Node
   681  
   682  	comp.used, _, _ = comp.collectUsed(false)
   683  	structs, flags, strflags := comp.collectUsed(true)
   684  
   685  	note := func(n ast.Node) {
   686  		if pos, _, _ := n.Info(); pos.Builtin() {
   687  			return
   688  		}
   689  		unused = append(unused, n)
   690  	}
   691  
   692  	for name, n := range comp.intFlags {
   693  		if !flags[name] {
   694  			note(n)
   695  		}
   696  	}
   697  	for name, n := range comp.strFlags {
   698  		if !strflags[name] {
   699  			note(n)
   700  		}
   701  	}
   702  	for name, n := range comp.resources {
   703  		if !structs[name] {
   704  			note(n)
   705  		}
   706  	}
   707  	for name, n := range comp.structs {
   708  		if !structs[name] {
   709  			note(n)
   710  		}
   711  	}
   712  	for name, n := range comp.typedefs {
   713  		if !comp.usedTypedefs[name] {
   714  			note(n)
   715  		}
   716  	}
   717  
   718  	return unused
   719  }
   720  
   721  func (comp *compiler) collectUsed(all bool) (structs, flags, strflags map[string]bool) {
   722  	structs = make(map[string]bool)
   723  	flags = make(map[string]bool)
   724  	strflags = make(map[string]bool)
   725  	for _, decl := range comp.desc.Nodes {
   726  		switch n := decl.(type) {
   727  		case *ast.Call:
   728  			if !all && n.NR == ^uint64(0) {
   729  				break
   730  			}
   731  			for _, arg := range n.Args {
   732  				comp.collectUsedType(structs, flags, strflags, arg.Type, true)
   733  			}
   734  			if n.Ret != nil {
   735  				comp.collectUsedType(structs, flags, strflags, n.Ret, true)
   736  			}
   737  		}
   738  	}
   739  	return
   740  }
   741  
   742  func (comp *compiler) collectUsedType(structs, flags, strflags map[string]bool, t *ast.Type, isArg bool) {
   743  	desc := comp.getTypeDesc(t)
   744  	if desc == typeResource {
   745  		r := comp.resources[t.Ident]
   746  		for r != nil && !structs[r.Name.Name] {
   747  			structs[r.Name.Name] = true
   748  			r = comp.resources[r.Base.Ident]
   749  		}
   750  		return
   751  	}
   752  	if desc == typeStruct {
   753  		if structs[t.Ident] {
   754  			return
   755  		}
   756  		structs[t.Ident] = true
   757  		s := comp.structs[t.Ident]
   758  		for _, fld := range s.Fields {
   759  			comp.collectUsedType(structs, flags, strflags, fld.Type, false)
   760  		}
   761  		return
   762  	}
   763  	if desc == typeFlags ||
   764  		(desc == typeInt && len(t.Args) > 0 && t.Args[0].Ident != "") {
   765  		flags[t.Args[0].Ident] = true
   766  		return
   767  	}
   768  	if desc == typeString {
   769  		if len(t.Args) != 0 && t.Args[0].Ident != "" {
   770  			strflags[t.Args[0].Ident] = true
   771  		}
   772  		return
   773  	}
   774  	_, args, _ := comp.getArgsBase(t, isArg)
   775  	for i, arg := range args {
   776  		if desc.Args[i].Type == typeArgType {
   777  			comp.collectUsedType(structs, flags, strflags, arg, desc.Args[i].IsArg)
   778  		}
   779  	}
   780  }
   781  
   782  func (comp *compiler) checkUnused() {
   783  	for _, n := range comp.collectUnused() {
   784  		pos, typ, name := n.Info()
   785  		comp.error(pos, fmt.Sprintf("unused %v %v", typ, name))
   786  	}
   787  }
   788  
   789  func (comp *compiler) checkConstsFlags(consts map[string]uint64) {
   790  	for name := range consts {
   791  		if flags, isFlag := comp.intFlags[name]; isFlag {
   792  			pos, _, _ := flags.Info()
   793  			comp.error(pos, "const %v is already a flag", name)
   794  		}
   795  	}
   796  }
   797  
   798  type structDir struct {
   799  	Struct string
   800  	Dir    prog.Dir
   801  }
   802  
   803  func (comp *compiler) checkConstructors() {
   804  	ctors := make(map[string]bool)  // resources for which we have ctors
   805  	inputs := make(map[string]bool) // resources which are used as inputs
   806  	checked := make(map[structDir]bool)
   807  	for _, decl := range comp.desc.Nodes {
   808  		switch n := decl.(type) {
   809  		case *ast.Call:
   810  			for _, arg := range n.Args {
   811  				comp.checkTypeCtors(arg.Type, prog.DirIn, true, true, ctors, inputs, checked, nil)
   812  			}
   813  			if n.Ret != nil {
   814  				comp.checkTypeCtors(n.Ret, prog.DirOut, true, true, ctors, inputs, checked, nil)
   815  			}
   816  		}
   817  	}
   818  	for _, decl := range comp.desc.Nodes {
   819  		switch n := decl.(type) {
   820  		case *ast.Resource:
   821  			name := n.Name.Name
   822  			if !comp.used[name] {
   823  				continue
   824  			}
   825  			if !ctors[name] {
   826  				comp.error(n.Pos, "resource %v can't be created"+
   827  					" (never mentioned as a syscall return value or output argument/field)", name)
   828  			}
   829  			if !inputs[name] {
   830  				comp.error(n.Pos, "resource %v is never used as an input"+
   831  					" (such resources are not useful)", name)
   832  			}
   833  		}
   834  	}
   835  }
   836  
   837  func (comp *compiler) checkTypeCtors(t *ast.Type, dir prog.Dir, isArg, canCreate bool,
   838  	ctors, inputs map[string]bool, checked map[structDir]bool, neverOutAt *ast.Pos) {
   839  	desc, args, base := comp.getArgsBase(t, isArg)
   840  	if base.IsOptional {
   841  		canCreate = false
   842  	}
   843  	if desc.CantHaveOut {
   844  		neverOutAt = &t.Pos
   845  	}
   846  	if desc == typeResource {
   847  		// TODO(dvyukov): consider changing this to "dir == prog.DirOut".
   848  		// We have few questionable cases where resources can be created
   849  		// only by inout struct fields. These structs should be split
   850  		// into two different structs: one is in and second is out.
   851  		// But that will require attaching dir to individual fields.
   852  		if dir != prog.DirIn && neverOutAt != nil {
   853  			comp.error(*neverOutAt, "resource %s cannot be created in fmt", t.Ident)
   854  		}
   855  		if canCreate && dir != prog.DirIn {
   856  			r := comp.resources[t.Ident]
   857  			for r != nil && !ctors[r.Name.Name] {
   858  				ctors[r.Name.Name] = true
   859  				r = comp.resources[r.Base.Ident]
   860  			}
   861  		}
   862  		if dir != prog.DirOut {
   863  			r := comp.resources[t.Ident]
   864  			for r != nil && !inputs[r.Name.Name] {
   865  				inputs[r.Name.Name] = true
   866  				r = comp.resources[r.Base.Ident]
   867  			}
   868  		}
   869  		return
   870  	}
   871  	if desc == typeStruct {
   872  		s := comp.structs[t.Ident]
   873  		if s.IsUnion {
   874  			canCreate = false
   875  		}
   876  		name := s.Name.Name
   877  		key := structDir{name, dir}
   878  		if checked[key] {
   879  			return
   880  		}
   881  		checked[key] = true
   882  		for _, fld := range s.Fields {
   883  			fldDir, fldHasDir := comp.genFieldDir(comp.parseIntAttrs(structFieldAttrs, fld, fld.Attrs))
   884  			if !fldHasDir {
   885  				fldDir = dir
   886  			}
   887  			comp.checkTypeCtors(fld.Type, fldDir, false, canCreate, ctors, inputs, checked, neverOutAt)
   888  		}
   889  		return
   890  	}
   891  	if desc == typePtr {
   892  		dir = genDir(t.Args[0])
   893  	}
   894  	for i, arg := range args {
   895  		if desc.Args[i].Type == typeArgType {
   896  			comp.checkTypeCtors(arg, dir, desc.Args[i].IsArg, canCreate, ctors, inputs, checked, neverOutAt)
   897  		}
   898  	}
   899  }
   900  
   901  func (comp *compiler) checkRecursion() {
   902  	checked := make(map[string]bool)
   903  	for _, decl := range comp.desc.Nodes {
   904  		switch n := decl.(type) {
   905  		case *ast.Resource:
   906  			comp.checkResourceRecursion(n)
   907  		case *ast.Struct:
   908  			var path []pathElem
   909  			comp.checkStructRecursion(checked, n, path)
   910  		}
   911  	}
   912  }
   913  
   914  func (comp *compiler) checkResourceRecursion(n *ast.Resource) {
   915  	var seen []string
   916  	for n != nil {
   917  		if arrayContains(seen, n.Name.Name) {
   918  			chain := ""
   919  			for _, r := range seen {
   920  				chain += r + "->"
   921  			}
   922  			chain += n.Name.Name
   923  			comp.error(n.Pos, "recursive resource %v", chain)
   924  			return
   925  		}
   926  		seen = append(seen, n.Name.Name)
   927  		n = comp.resources[n.Base.Ident]
   928  	}
   929  }
   930  
   931  type pathElem struct {
   932  	Pos    ast.Pos
   933  	Struct string
   934  	Field  string
   935  }
   936  
   937  func (comp *compiler) checkStructRecursion(checked map[string]bool, n *ast.Struct, path []pathElem) {
   938  	name := n.Name.Name
   939  	if checked[name] {
   940  		return
   941  	}
   942  	for i, elem := range path {
   943  		if elem.Struct != name {
   944  			continue
   945  		}
   946  		path = path[i:]
   947  		str := ""
   948  		for _, elem := range path {
   949  			str += fmt.Sprintf("%v.%v -> ", elem.Struct, elem.Field)
   950  		}
   951  		str += name
   952  		comp.error(path[0].Pos, "recursive declaration: %v (mark some pointers as opt)", str)
   953  		checked[name] = true
   954  		return
   955  	}
   956  	for _, f := range n.Fields {
   957  		path = append(path, pathElem{
   958  			Pos:    f.Pos,
   959  			Struct: name,
   960  			Field:  f.Name.Name,
   961  		})
   962  		comp.recurseField(checked, f.Type, path)
   963  		path = path[:len(path)-1]
   964  	}
   965  	checked[name] = true
   966  }
   967  
   968  func (comp *compiler) recurseField(checked map[string]bool, t *ast.Type, path []pathElem) {
   969  	desc := comp.getTypeDesc(t)
   970  	if desc == typeStruct {
   971  		comp.checkStructRecursion(checked, comp.structs[t.Ident], path)
   972  		return
   973  	}
   974  	_, args, base := comp.getArgsBase(t, false)
   975  	if desc == typePtr && base.IsOptional {
   976  		return // optional pointers prune recursion
   977  	}
   978  	for i, arg := range args {
   979  		if desc.Args[i].Type == typeArgType {
   980  			comp.recurseField(checked, arg, path)
   981  		}
   982  	}
   983  }
   984  
   985  func (comp *compiler) checkStruct(ctx checkCtx, n *ast.Struct) {
   986  	var flags checkFlags
   987  	if !n.IsUnion {
   988  		flags |= checkIsStruct
   989  	}
   990  	for _, f := range n.Fields {
   991  		comp.checkType(ctx, f.Type, flags)
   992  	}
   993  	comp.parseAttrs(structOrUnionAttrs(n), n, n.Attrs)
   994  }
   995  
   996  func (comp *compiler) checkCall(n *ast.Call) {
   997  	for _, a := range n.Args {
   998  		comp.checkType(checkCtx{}, a.Type, checkIsArg)
   999  	}
  1000  	if n.Ret != nil {
  1001  		comp.checkType(checkCtx{}, n.Ret, checkIsArg|checkIsRet)
  1002  	}
  1003  	comp.parseAttrs(callAttrs, n, n.Attrs)
  1004  }
  1005  
  1006  type checkFlags int
  1007  
  1008  const (
  1009  	checkIsArg          checkFlags = 1 << iota // immediate syscall arg type
  1010  	checkIsRet                                 // immediate syscall ret type
  1011  	checkIsStruct                              // immediate struct field type
  1012  	checkIsResourceBase                        // immediate resource base type
  1013  	checkIsTypedef                             // immediate type alias/template type
  1014  )
  1015  
  1016  type checkCtx struct {
  1017  	instantiationStack []string
  1018  }
  1019  
  1020  func (comp *compiler) checkType(ctx checkCtx, t *ast.Type, flags checkFlags) {
  1021  	comp.checkTypeImpl(ctx, t, comp.getTypeDesc(t), flags)
  1022  }
  1023  
  1024  func (comp *compiler) checkTypeImpl(ctx checkCtx, t *ast.Type, desc *typeDesc, flags checkFlags) {
  1025  	if unexpected, _, ok := checkTypeKind(t, kindIdent); !ok {
  1026  		comp.error(t.Pos, "unexpected %v, expect type", unexpected)
  1027  		return
  1028  	}
  1029  	if desc == nil {
  1030  		comp.error(t.Pos, "unknown type %v", t.Ident)
  1031  		return
  1032  	}
  1033  	if desc == typeTypedef {
  1034  		err0 := comp.errors
  1035  		// Replace t with type alias/template target type inplace,
  1036  		// and check the replaced type recursively.
  1037  		comp.replaceTypedef(&ctx, t, flags)
  1038  		if err0 == comp.errors {
  1039  			comp.checkType(ctx, t, flags)
  1040  		}
  1041  		return
  1042  	}
  1043  	err0 := comp.errors
  1044  	comp.checkTypeBasic(t, desc, flags)
  1045  	if err0 != comp.errors {
  1046  		return
  1047  	}
  1048  	args := comp.checkTypeArgs(t, desc, flags)
  1049  	if err0 != comp.errors {
  1050  		return
  1051  	}
  1052  	for i, arg := range args {
  1053  		if desc.Args[i].Type == typeArgType {
  1054  			var innerFlags checkFlags
  1055  			if desc.Args[i].IsArg {
  1056  				innerFlags |= checkIsArg
  1057  			}
  1058  			comp.checkType(ctx, arg, innerFlags)
  1059  		} else {
  1060  			comp.checkTypeArg(t, arg, desc.Args[i])
  1061  		}
  1062  	}
  1063  	if err0 != comp.errors {
  1064  		return
  1065  	}
  1066  	if desc.Check != nil {
  1067  		_, args, base := comp.getArgsBase(t, flags&checkIsArg != 0)
  1068  		desc.Check(comp, t, args, base)
  1069  	}
  1070  }
  1071  
  1072  func (comp *compiler) checkTypeBasic(t *ast.Type, desc *typeDesc, flags checkFlags) {
  1073  	for i, col := range t.Colon {
  1074  		if i >= desc.MaxColon {
  1075  			comp.error(col.Pos, "unexpected ':'")
  1076  			return
  1077  		}
  1078  		if flags&checkIsStruct == 0 {
  1079  			comp.error(col.Pos, "unexpected ':', only struct fields can be bitfields")
  1080  			return
  1081  		}
  1082  	}
  1083  	if flags&checkIsTypedef != 0 && !desc.CanBeTypedef {
  1084  		comp.error(t.Pos, "%v can't be type alias target", t.Ident)
  1085  		return
  1086  	}
  1087  	if flags&checkIsResourceBase != 0 &&
  1088  		(desc.CanBeResourceBase == nil || !desc.CanBeResourceBase(comp, t)) {
  1089  		comp.error(t.Pos, "%v can't be resource base (int types can)", t.Ident)
  1090  		return
  1091  	}
  1092  	canBeArg, canBeRet := false, false
  1093  	if desc.CanBeArgRet != nil {
  1094  		canBeArg, canBeRet = desc.CanBeArgRet(comp, t)
  1095  	}
  1096  	if flags&checkIsRet != 0 && !canBeRet {
  1097  		comp.error(t.Pos, "%v can't be syscall return", t.Ident)
  1098  		return
  1099  	}
  1100  	if flags&checkIsArg != 0 && !canBeArg {
  1101  		comp.error(t.Pos, "%v can't be syscall argument", t.Ident)
  1102  		return
  1103  	}
  1104  }
  1105  
  1106  func (comp *compiler) checkTypeArgs(t *ast.Type, desc *typeDesc, flags checkFlags) []*ast.Type {
  1107  	args, opt := removeOpt(t)
  1108  	if opt != nil {
  1109  		if len(opt.Args) != 0 {
  1110  			comp.error(opt.Pos, "opt can't have arguments")
  1111  		}
  1112  		if flags&checkIsResourceBase != 0 || desc.CantBeOpt {
  1113  			what := "resource base"
  1114  			if desc.CantBeOpt {
  1115  				what = t.Ident
  1116  			}
  1117  			comp.error(opt.Pos, "%v can't be marked as opt", what)
  1118  			return nil
  1119  		}
  1120  	}
  1121  	addArgs := 0
  1122  	needBase := flags&checkIsArg == 0 && desc.NeedBase
  1123  	if needBase {
  1124  		addArgs++ // last arg must be base type, e.g. const[0, int32]
  1125  	}
  1126  	if len(args) > len(desc.Args)+addArgs || len(args) < len(desc.Args)-desc.OptArgs+addArgs {
  1127  		comp.error(t.Pos, "wrong number of arguments for type %v, expect %v",
  1128  			t.Ident, expectedTypeArgs(desc, needBase))
  1129  		return nil
  1130  	}
  1131  	if needBase {
  1132  		base := args[len(args)-1]
  1133  		args = args[:len(args)-1]
  1134  		comp.checkTypeArg(t, base, typeArgBase)
  1135  	}
  1136  	return args
  1137  }
  1138  
  1139  func (comp *compiler) replaceTypedef(ctx *checkCtx, t *ast.Type, flags checkFlags) {
  1140  	typedefName := t.Ident
  1141  	typedef := comp.typedefs[typedefName]
  1142  	fullTypeName := ast.SerializeNode(t)
  1143  	if comp.brokenTypedefs[fullTypeName] {
  1144  		// We've already produced some errors for this exact type instantiation.
  1145  		// Don't produce duplicates, also helps to prevent exponential
  1146  		// slowdown due to some cases of recursion. But increment the number
  1147  		// of errors so that callers can understand that we did not succeed.
  1148  		comp.errors++
  1149  		return
  1150  	}
  1151  	comp.usedTypedefs[typedefName] = true
  1152  	err0 := comp.errors
  1153  	defer func() {
  1154  		comp.brokenTypedefs[fullTypeName] = err0 != comp.errors
  1155  	}()
  1156  	if len(t.Colon) != 0 {
  1157  		comp.error(t.Pos, "type alias %v with ':'", t.Ident)
  1158  		return
  1159  	}
  1160  	// Handling optional BASE argument.
  1161  	if len(typedef.Args) > 0 && typedef.Args[len(typedef.Args)-1].Name == argBase {
  1162  		if flags&checkIsArg != 0 && len(t.Args) == len(typedef.Args)-1 {
  1163  			t.Args = append(t.Args, &ast.Type{
  1164  				Pos:   t.Pos,
  1165  				Ident: "intptr",
  1166  			})
  1167  		} else if len(t.Args) == len(typedef.Args) {
  1168  			comp.checkTypeArg(t, t.Args[len(t.Args)-1], typeArgBase)
  1169  		}
  1170  	}
  1171  	recursion := 0
  1172  	ctx.instantiationStack = append(ctx.instantiationStack, fullTypeName)
  1173  	for i, prev := range ctx.instantiationStack[:len(ctx.instantiationStack)-1] {
  1174  		if typedefName == templateBase(prev) {
  1175  			recursion++
  1176  			if recursion > 10 {
  1177  				comp.error(t.Pos, "type instantiation recursion: %v", strings.Join(ctx.instantiationStack, " -> "))
  1178  				return
  1179  			}
  1180  		}
  1181  		if prev != fullTypeName {
  1182  			continue
  1183  		}
  1184  		comp.error(t.Pos, "type instantiation loop: %v", strings.Join(ctx.instantiationStack[i:], " -> "))
  1185  		return
  1186  	}
  1187  	nargs := len(typedef.Args)
  1188  	args := t.Args
  1189  	if nargs != len(t.Args) {
  1190  		if nargs == 0 {
  1191  			comp.error(t.Pos, "type %v is not a template", typedefName)
  1192  		} else {
  1193  			if flags&checkIsArg != 0 && typedef.Args[len(typedef.Args)-1].Name == argBase {
  1194  				nargs--
  1195  			}
  1196  			comp.error(t.Pos, "template %v needs %v arguments instead of %v",
  1197  				typedefName, nargs, len(t.Args))
  1198  		}
  1199  		return
  1200  	}
  1201  	pos0 := t.Pos
  1202  	if typedef.Type != nil {
  1203  		*t = *typedef.Type.Clone().(*ast.Type)
  1204  		if !comp.instantiate(t, typedef.Args, args) {
  1205  			return
  1206  		}
  1207  	} else {
  1208  		if comp.structs[fullTypeName] == nil {
  1209  			inst := typedef.Struct.Clone().(*ast.Struct)
  1210  			inst.Name.Name = fullTypeName
  1211  			if !comp.instantiate(inst, typedef.Args, args) {
  1212  				return
  1213  			}
  1214  			comp.checkStruct(*ctx, inst)
  1215  			if err0 != comp.errors {
  1216  				return
  1217  			}
  1218  			comp.desc.Nodes = append(comp.desc.Nodes, inst)
  1219  			comp.structs[fullTypeName] = inst
  1220  		}
  1221  		*t = ast.Type{
  1222  			Ident: fullTypeName,
  1223  		}
  1224  	}
  1225  	t.Pos = pos0
  1226  	comp.maybeRemoveBase(t, flags)
  1227  }
  1228  
  1229  func (comp *compiler) maybeRemoveBase(t *ast.Type, flags checkFlags) {
  1230  	// Remove base type if it's not needed in this context.
  1231  	// If desc is nil, will return an error later when we typecheck the result.
  1232  	desc := comp.getTypeDesc(t)
  1233  	if desc != nil && flags&checkIsArg != 0 && desc.NeedBase && len(t.Args) != 0 {
  1234  		baseTypePos := len(t.Args) - 1
  1235  		if t.Args[baseTypePos].Ident == "opt" && len(t.Args) >= 2 {
  1236  			baseTypePos--
  1237  		}
  1238  		copy(t.Args[baseTypePos:], t.Args[baseTypePos+1:])
  1239  		t.Args = t.Args[:len(t.Args)-1]
  1240  	}
  1241  }
  1242  
  1243  func (comp *compiler) instantiate(templ ast.Node, params []*ast.Ident, args []*ast.Type) bool {
  1244  	if len(params) == 0 {
  1245  		return true
  1246  	}
  1247  	argMap := make(map[string]*ast.Type)
  1248  	for i, param := range params {
  1249  		argMap[param.Name] = args[i]
  1250  	}
  1251  	argUsed := make(map[string]bool)
  1252  	err0 := comp.errors
  1253  	ast.PostRecursive(func(n ast.Node) {
  1254  		templArg, ok := n.(*ast.Type)
  1255  		if !ok {
  1256  			return
  1257  		}
  1258  		if concreteArg := argMap[templArg.Ident]; concreteArg != nil {
  1259  			argUsed[templArg.Ident] = true
  1260  			origArgs := templArg.Args
  1261  			if len(origArgs) != 0 && len(concreteArg.Args) != 0 {
  1262  				comp.error(templArg.Pos, "both template parameter %v and its usage"+
  1263  					" have sub-arguments", templArg.Ident)
  1264  				return
  1265  			}
  1266  			*templArg = *concreteArg.Clone().(*ast.Type)
  1267  			if len(origArgs) != 0 {
  1268  				templArg.Args = origArgs
  1269  			}
  1270  		}
  1271  		// TODO(dvyukov): somewhat hacky, but required for int8[0:CONST_ARG]
  1272  		// Need more checks here. E.g. that CONST_ARG does not have subargs.
  1273  		// And if CONST_ARG is a value, then use concreteArg.Value.
  1274  		// Also need to error if CONST_ARG is a string.
  1275  		if len(templArg.Colon) != 0 {
  1276  			col := templArg.Colon[0]
  1277  			if concreteArg := argMap[col.Ident]; concreteArg != nil {
  1278  				argUsed[col.Ident] = true
  1279  				col.Ident = concreteArg.Ident
  1280  				col.Pos = concreteArg.Pos
  1281  			}
  1282  		}
  1283  	})(templ)
  1284  	for _, param := range params {
  1285  		if !argUsed[param.Name] {
  1286  			comp.error(argMap[param.Name].Pos,
  1287  				"template argument %v is not used", param.Name)
  1288  		}
  1289  	}
  1290  	return err0 == comp.errors
  1291  }
  1292  
  1293  func (comp *compiler) checkTypeArg(t, arg *ast.Type, argDesc namedArg) {
  1294  	desc := argDesc.Type
  1295  	if len(desc.Names) != 0 {
  1296  		if unexpected, _, ok := checkTypeKind(arg, kindIdent); !ok {
  1297  			comp.error(arg.Pos, "unexpected %v for %v argument of %v type, expect %+v",
  1298  				unexpected, argDesc.Name, t.Ident, desc.Names)
  1299  			return
  1300  		}
  1301  		if !arrayContains(desc.Names, arg.Ident) {
  1302  			comp.error(arg.Pos, "unexpected value %v for %v argument of %v type, expect %+v",
  1303  				arg.Ident, argDesc.Name, t.Ident, desc.Names)
  1304  			return
  1305  		}
  1306  	} else {
  1307  		if unexpected, expect, ok := checkTypeKind(arg, desc.Kind); !ok {
  1308  			comp.error(arg.Pos, "unexpected %v for %v argument of %v type, expect %v",
  1309  				unexpected, argDesc.Name, t.Ident, expect)
  1310  			return
  1311  		}
  1312  	}
  1313  	for i, col := range arg.Colon {
  1314  		if i >= desc.MaxColon {
  1315  			comp.error(col.Pos, "unexpected ':'")
  1316  			return
  1317  		}
  1318  		// We only want to perform this check if kindIdent is the only kind of
  1319  		// this type. Otherwise, the token after the colon could legitimately
  1320  		// be an int for example.
  1321  		if desc.Kind == kindIdent {
  1322  			if unexpected, expect, ok := checkTypeKind(col, kindIdent); !ok {
  1323  				comp.error(arg.Pos, "unexpected %v after colon, expect %v", unexpected, expect)
  1324  				return
  1325  			}
  1326  		}
  1327  	}
  1328  	if len(arg.Args) > desc.MaxArgs {
  1329  		comp.error(arg.Pos, "%v argument has subargs", argDesc.Name)
  1330  		return
  1331  	}
  1332  	if desc.Check != nil {
  1333  		desc.Check(comp, arg)
  1334  	}
  1335  }
  1336  
  1337  func expectedTypeArgs(desc *typeDesc, needBase bool) string {
  1338  	expect := ""
  1339  	for i, arg := range desc.Args {
  1340  		if expect != "" {
  1341  			expect += ", "
  1342  		}
  1343  		opt := i >= len(desc.Args)-desc.OptArgs
  1344  		if opt {
  1345  			expect += "["
  1346  		}
  1347  		expect += arg.Name
  1348  		if opt {
  1349  			expect += "]"
  1350  		}
  1351  	}
  1352  	if needBase {
  1353  		if expect != "" {
  1354  			expect += ", "
  1355  		}
  1356  		expect += typeArgBase.Name
  1357  	}
  1358  	if !desc.CantBeOpt {
  1359  		if expect != "" {
  1360  			expect += ", "
  1361  		}
  1362  		expect += "[opt]"
  1363  	}
  1364  	if expect == "" {
  1365  		expect = "no arguments"
  1366  	}
  1367  	return expect
  1368  }
  1369  
  1370  func checkTypeKind(t *ast.Type, kind int) (unexpected, expect string, ok bool) {
  1371  	switch {
  1372  	case kind == kindAny:
  1373  		ok = true
  1374  	case t.HasString:
  1375  		ok = kind&kindString != 0
  1376  		if !ok {
  1377  			unexpected = fmt.Sprintf("string %q", t.String)
  1378  		}
  1379  	case t.Ident != "":
  1380  		ok = kind&(kindIdent|kindInt) != 0
  1381  		if !ok {
  1382  			unexpected = fmt.Sprintf("identifier %v", t.Ident)
  1383  		}
  1384  	default:
  1385  		ok = kind&kindInt != 0
  1386  		if !ok {
  1387  			unexpected = fmt.Sprintf("int %v", t.Value)
  1388  		}
  1389  	}
  1390  	if !ok {
  1391  		var expected []string
  1392  		if kind&kindString != 0 {
  1393  			expected = append(expected, "string")
  1394  		}
  1395  		if kind&kindIdent != 0 {
  1396  			expected = append(expected, "identifier")
  1397  		}
  1398  		if kind&kindInt != 0 {
  1399  			expected = append(expected, "int")
  1400  		}
  1401  		expect = strings.Join(expected, " or ")
  1402  	}
  1403  	return
  1404  }
  1405  
  1406  func (comp *compiler) checkVarlens() {
  1407  	for _, decl := range comp.desc.Nodes {
  1408  		switch n := decl.(type) {
  1409  		case *ast.Struct:
  1410  			comp.checkVarlen(n)
  1411  		}
  1412  	}
  1413  }
  1414  
  1415  func (comp *compiler) isVarlen(t *ast.Type) bool {
  1416  	desc, args, _ := comp.getArgsBase(t, false)
  1417  	return desc.Varlen != nil && desc.Varlen(comp, t, args)
  1418  }
  1419  
  1420  func (comp *compiler) isZeroSize(t *ast.Type) bool {
  1421  	desc, args, _ := comp.getArgsBase(t, false)
  1422  	return desc.ZeroSize != nil && desc.ZeroSize(comp, t, args)
  1423  }
  1424  
  1425  func (comp *compiler) checkVarlen(n *ast.Struct) {
  1426  	// Non-varlen unions can't have varlen fields.
  1427  	// Non-packed structs can't have varlen fields in the middle.
  1428  	if n.IsUnion {
  1429  		attrs := comp.parseIntAttrs(unionAttrs, n, n.Attrs)
  1430  		if attrs[attrVarlen] != 0 {
  1431  			return
  1432  		}
  1433  	} else {
  1434  		attrs := comp.parseIntAttrs(structAttrs, n, n.Attrs)
  1435  		if attrs[attrPacked] != 0 {
  1436  			return
  1437  		}
  1438  	}
  1439  	for i, f := range n.Fields {
  1440  		_, exprs := comp.parseAttrs(structOrUnionFieldAttrs(n), f, f.Attrs)
  1441  		if !n.IsUnion && i == len(n.Fields)-1 {
  1442  			break
  1443  		}
  1444  		if comp.isVarlen(f.Type) || !n.IsUnion && exprs[attrIf] != nil {
  1445  			if n.IsUnion {
  1446  				comp.error(f.Pos, "variable size field %v in non-varlen union %v",
  1447  					f.Name.Name, n.Name.Name)
  1448  			} else {
  1449  				comp.error(f.Pos, "variable size field %v in the middle of non-packed struct %v",
  1450  					f.Name.Name, n.Name.Name)
  1451  			}
  1452  		}
  1453  	}
  1454  }
  1455  
  1456  func (comp *compiler) checkDupConsts() {
  1457  	// The idea is to detect copy-paste errors in const arguments, e.g.:
  1458  	//   call$FOO(fd fd, arg const[FOO])
  1459  	//   call$BAR(fd fd, arg const[FOO])
  1460  	// The second one is meant to be const[BAR],
  1461  	// Unfortunately, this does not fully work as it detects lots of false positives.
  1462  	// But was useful to find real bugs as well. So for now it's disabled, but can be run manually.
  1463  	if true {
  1464  		return
  1465  	}
  1466  	dups := make(map[string]map[string]dupConstArg)
  1467  	for _, decl := range comp.desc.Nodes {
  1468  		switch n := decl.(type) {
  1469  		case *ast.Call:
  1470  			comp.checkDupConstsCall(n, dups)
  1471  		}
  1472  	}
  1473  }
  1474  
  1475  type dupConstArg struct {
  1476  	pos  ast.Pos
  1477  	name string
  1478  }
  1479  
  1480  func (comp *compiler) checkDupConstsCall(n *ast.Call, dups map[string]map[string]dupConstArg) {
  1481  	if n.NR == ^uint64(0) {
  1482  		return
  1483  	}
  1484  	for dups[n.CallName] == nil {
  1485  		dups[n.CallName] = make(map[string]dupConstArg)
  1486  	}
  1487  	hasConsts := false
  1488  	constArgID := ""
  1489  	for i, arg := range n.Args {
  1490  		desc := comp.getTypeDesc(arg.Type)
  1491  		if desc == typeConst {
  1492  			v := arg.Type.Args[0].Value
  1493  			if v != 0 && v != 18446744073709551516 { // AT_FDCWD
  1494  				constArgID += fmt.Sprintf("(%v-%v)", i, fmt.Sprintf("%v", v))
  1495  				hasConsts = true
  1496  			}
  1497  		} else if desc == typeResource {
  1498  			constArgID += fmt.Sprintf("(%v-%v)", i, arg.Type.Ident)
  1499  		}
  1500  	}
  1501  	if !hasConsts {
  1502  		return
  1503  	}
  1504  	dup, ok := dups[n.CallName][constArgID]
  1505  	if !ok {
  1506  		dups[n.CallName][constArgID] = dupConstArg{
  1507  			pos:  n.Pos,
  1508  			name: n.Name.Name,
  1509  		}
  1510  		return
  1511  	}
  1512  	comp.error(n.Pos, "call %v: duplicate const %v, previously used in call %v at %v",
  1513  		n.Name.Name, constArgID, dup.name, dup.pos)
  1514  }