1
2
3
4
5 package walk
6
7 import (
8 "fmt"
9 "go/constant"
10 "go/token"
11 "strings"
12
13 "cmd/compile/internal/base"
14 "cmd/compile/internal/escape"
15 "cmd/compile/internal/ir"
16 "cmd/compile/internal/reflectdata"
17 "cmd/compile/internal/typecheck"
18 "cmd/compile/internal/types"
19 )
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42 func walkAppend(n *ir.CallExpr, init *ir.Nodes, dst ir.Node) ir.Node {
43 if !ir.SameSafeExpr(dst, n.Args[0]) {
44 n.Args[0] = safeExpr(n.Args[0], init)
45 n.Args[0] = walkExpr(n.Args[0], init)
46 }
47 walkExprListSafe(n.Args[1:], init)
48
49 nsrc := n.Args[0]
50
51
52
53
54
55
56
57 ls := n.Args[1:]
58 for i, n := range ls {
59 n = cheapExpr(n, init)
60 if !types.Identical(n.Type(), nsrc.Type().Elem()) {
61 n = typecheck.AssignConv(n, nsrc.Type().Elem(), "append")
62 n = walkExpr(n, init)
63 }
64 ls[i] = n
65 }
66
67 argc := len(n.Args) - 1
68 if argc < 1 {
69 return nsrc
70 }
71
72
73
74 if !base.Flag.Cfg.Instrumenting || base.Flag.CompilingRuntime {
75 return n
76 }
77
78 var l []ir.Node
79
80 ns := typecheck.Temp(nsrc.Type())
81 l = append(l, ir.NewAssignStmt(base.Pos, ns, nsrc))
82
83 na := ir.NewInt(int64(argc))
84 nif := ir.NewIfStmt(base.Pos, nil, nil, nil)
85 nif.Cond = ir.NewBinaryExpr(base.Pos, ir.OLT, ir.NewBinaryExpr(base.Pos, ir.OSUB, ir.NewUnaryExpr(base.Pos, ir.OCAP, ns), ir.NewUnaryExpr(base.Pos, ir.OLEN, ns)), na)
86
87 fn := typecheck.LookupRuntime("growslice")
88 fn = typecheck.SubstArgTypes(fn, ns.Type().Elem(), ns.Type().Elem())
89
90 nif.Body = []ir.Node{ir.NewAssignStmt(base.Pos, ns, mkcall1(fn, ns.Type(), nif.PtrInit(), reflectdata.TypePtr(ns.Type().Elem()), ns,
91 ir.NewBinaryExpr(base.Pos, ir.OADD, ir.NewUnaryExpr(base.Pos, ir.OLEN, ns), na)))}
92
93 l = append(l, nif)
94
95 nn := typecheck.Temp(types.Types[types.TINT])
96 l = append(l, ir.NewAssignStmt(base.Pos, nn, ir.NewUnaryExpr(base.Pos, ir.OLEN, ns)))
97
98 slice := ir.NewSliceExpr(base.Pos, ir.OSLICE, ns, nil, ir.NewBinaryExpr(base.Pos, ir.OADD, nn, na), nil)
99 slice.SetBounded(true)
100 l = append(l, ir.NewAssignStmt(base.Pos, ns, slice))
101
102 ls = n.Args[1:]
103 for i, n := range ls {
104 ix := ir.NewIndexExpr(base.Pos, ns, nn)
105 ix.SetBounded(true)
106 l = append(l, ir.NewAssignStmt(base.Pos, ix, n))
107 if i+1 < len(ls) {
108 l = append(l, ir.NewAssignStmt(base.Pos, nn, ir.NewBinaryExpr(base.Pos, ir.OADD, nn, ir.NewInt(1))))
109 }
110 }
111
112 typecheck.Stmts(l)
113 walkStmtList(l)
114 init.Append(l...)
115 return ns
116 }
117
118
119 func walkClose(n *ir.UnaryExpr, init *ir.Nodes) ir.Node {
120
121 fn := typecheck.LookupRuntime("closechan")
122 fn = typecheck.SubstArgTypes(fn, n.X.Type())
123 return mkcall1(fn, nil, init, n.X)
124 }
125
126
127
128
129
130
131
132
133
134
135
136
137 func walkCopy(n *ir.BinaryExpr, init *ir.Nodes, runtimecall bool) ir.Node {
138 if n.X.Type().Elem().HasPointers() {
139 ir.CurFunc.SetWBPos(n.Pos())
140 fn := writebarrierfn("typedslicecopy", n.X.Type().Elem(), n.Y.Type().Elem())
141 n.X = cheapExpr(n.X, init)
142 ptrL, lenL := backingArrayPtrLen(n.X)
143 n.Y = cheapExpr(n.Y, init)
144 ptrR, lenR := backingArrayPtrLen(n.Y)
145 return mkcall1(fn, n.Type(), init, reflectdata.TypePtr(n.X.Type().Elem()), ptrL, lenL, ptrR, lenR)
146 }
147
148 if runtimecall {
149
150
151
152
153 n.X = cheapExpr(n.X, init)
154 ptrL, lenL := backingArrayPtrLen(n.X)
155 n.Y = cheapExpr(n.Y, init)
156 ptrR, lenR := backingArrayPtrLen(n.Y)
157
158 fn := typecheck.LookupRuntime("slicecopy")
159 fn = typecheck.SubstArgTypes(fn, ptrL.Type().Elem(), ptrR.Type().Elem())
160
161 return mkcall1(fn, n.Type(), init, ptrL, lenL, ptrR, lenR, ir.NewInt(n.X.Type().Elem().Size()))
162 }
163
164 n.X = walkExpr(n.X, init)
165 n.Y = walkExpr(n.Y, init)
166 nl := typecheck.Temp(n.X.Type())
167 nr := typecheck.Temp(n.Y.Type())
168 var l []ir.Node
169 l = append(l, ir.NewAssignStmt(base.Pos, nl, n.X))
170 l = append(l, ir.NewAssignStmt(base.Pos, nr, n.Y))
171
172 nfrm := ir.NewUnaryExpr(base.Pos, ir.OSPTR, nr)
173 nto := ir.NewUnaryExpr(base.Pos, ir.OSPTR, nl)
174
175 nlen := typecheck.Temp(types.Types[types.TINT])
176
177
178 l = append(l, ir.NewAssignStmt(base.Pos, nlen, ir.NewUnaryExpr(base.Pos, ir.OLEN, nl)))
179
180
181 nif := ir.NewIfStmt(base.Pos, nil, nil, nil)
182
183 nif.Cond = ir.NewBinaryExpr(base.Pos, ir.OGT, nlen, ir.NewUnaryExpr(base.Pos, ir.OLEN, nr))
184 nif.Body.Append(ir.NewAssignStmt(base.Pos, nlen, ir.NewUnaryExpr(base.Pos, ir.OLEN, nr)))
185 l = append(l, nif)
186
187
188 ne := ir.NewIfStmt(base.Pos, ir.NewBinaryExpr(base.Pos, ir.ONE, nto, nfrm), nil, nil)
189 ne.Likely = true
190 l = append(l, ne)
191
192 fn := typecheck.LookupRuntime("memmove")
193 fn = typecheck.SubstArgTypes(fn, nl.Type().Elem(), nl.Type().Elem())
194 nwid := ir.Node(typecheck.Temp(types.Types[types.TUINTPTR]))
195 setwid := ir.NewAssignStmt(base.Pos, nwid, typecheck.Conv(nlen, types.Types[types.TUINTPTR]))
196 ne.Body.Append(setwid)
197 nwid = ir.NewBinaryExpr(base.Pos, ir.OMUL, nwid, ir.NewInt(nl.Type().Elem().Size()))
198 call := mkcall1(fn, nil, init, nto, nfrm, nwid)
199 ne.Body.Append(call)
200
201 typecheck.Stmts(l)
202 walkStmtList(l)
203 init.Append(l...)
204 return nlen
205 }
206
207
208 func walkDelete(init *ir.Nodes, n *ir.CallExpr) ir.Node {
209 init.Append(ir.TakeInit(n)...)
210 map_ := n.Args[0]
211 key := n.Args[1]
212 map_ = walkExpr(map_, init)
213 key = walkExpr(key, init)
214
215 t := map_.Type()
216 fast := mapfast(t)
217 key = mapKeyArg(fast, n, key)
218 return mkcall1(mapfndel(mapdelete[fast], t), nil, init, reflectdata.TypePtr(t), map_, key)
219 }
220
221
222 func walkLenCap(n *ir.UnaryExpr, init *ir.Nodes) ir.Node {
223 if isRuneCount(n) {
224
225 return mkcall("countrunes", n.Type(), init, typecheck.Conv(n.X.(*ir.ConvExpr).X, types.Types[types.TSTRING]))
226 }
227
228 n.X = walkExpr(n.X, init)
229
230
231
232 t := n.X.Type()
233
234 if t.IsPtr() {
235 t = t.Elem()
236 }
237 if t.IsArray() {
238 safeExpr(n.X, init)
239 con := typecheck.OrigInt(n, t.NumElem())
240 con.SetTypecheck(1)
241 return con
242 }
243 return n
244 }
245
246
247 func walkMakeChan(n *ir.MakeExpr, init *ir.Nodes) ir.Node {
248
249
250 size := n.Len
251 fnname := "makechan64"
252 argtype := types.Types[types.TINT64]
253
254
255
256
257 if size.Type().IsKind(types.TIDEAL) || size.Type().Size() <= types.Types[types.TUINT].Size() {
258 fnname = "makechan"
259 argtype = types.Types[types.TINT]
260 }
261
262 return mkcall1(chanfn(fnname, 1, n.Type()), n.Type(), init, reflectdata.TypePtr(n.Type()), typecheck.Conv(size, argtype))
263 }
264
265
266 func walkMakeMap(n *ir.MakeExpr, init *ir.Nodes) ir.Node {
267 t := n.Type()
268 hmapType := reflectdata.MapType(t)
269 hint := n.Len
270
271
272 var h ir.Node
273 if n.Esc() == ir.EscNone {
274
275
276
277
278 h = stackTempAddr(init, hmapType)
279
280
281
282
283
284
285 if !ir.IsConst(hint, constant.Int) ||
286 constant.Compare(hint.Val(), token.LEQ, constant.MakeInt64(reflectdata.BUCKETSIZE)) {
287
288
289
290
291
292
293
294
295
296
297 nif := ir.NewIfStmt(base.Pos, ir.NewBinaryExpr(base.Pos, ir.OLE, hint, ir.NewInt(reflectdata.BUCKETSIZE)), nil, nil)
298 nif.Likely = true
299
300
301
302 b := stackTempAddr(&nif.Body, reflectdata.MapBucketType(t))
303
304
305 bsym := hmapType.Field(5).Sym
306 na := ir.NewAssignStmt(base.Pos, ir.NewSelectorExpr(base.Pos, ir.ODOT, h, bsym), b)
307 nif.Body.Append(na)
308 appendWalkStmt(init, nif)
309 }
310 }
311
312 if ir.IsConst(hint, constant.Int) && constant.Compare(hint.Val(), token.LEQ, constant.MakeInt64(reflectdata.BUCKETSIZE)) {
313
314
315
316
317
318
319
320 if n.Esc() == ir.EscNone {
321
322
323
324 rand := mkcall("fastrand", types.Types[types.TUINT32], init)
325 hashsym := hmapType.Field(4).Sym
326 appendWalkStmt(init, ir.NewAssignStmt(base.Pos, ir.NewSelectorExpr(base.Pos, ir.ODOT, h, hashsym), rand))
327 return typecheck.ConvNop(h, t)
328 }
329
330
331 fn := typecheck.LookupRuntime("makemap_small")
332 fn = typecheck.SubstArgTypes(fn, t.Key(), t.Elem())
333 return mkcall1(fn, n.Type(), init)
334 }
335
336 if n.Esc() != ir.EscNone {
337 h = typecheck.NodNil()
338 }
339
340
341
342
343
344
345
346 fnname := "makemap64"
347 argtype := types.Types[types.TINT64]
348
349
350
351
352
353 if hint.Type().IsKind(types.TIDEAL) || hint.Type().Size() <= types.Types[types.TUINT].Size() {
354 fnname = "makemap"
355 argtype = types.Types[types.TINT]
356 }
357
358 fn := typecheck.LookupRuntime(fnname)
359 fn = typecheck.SubstArgTypes(fn, hmapType, t.Key(), t.Elem())
360 return mkcall1(fn, n.Type(), init, reflectdata.TypePtr(n.Type()), typecheck.Conv(hint, argtype), h)
361 }
362
363
364 func walkMakeSlice(n *ir.MakeExpr, init *ir.Nodes) ir.Node {
365 l := n.Len
366 r := n.Cap
367 if r == nil {
368 r = safeExpr(l, init)
369 l = r
370 }
371 t := n.Type()
372 if t.Elem().NotInHeap() {
373 base.Errorf("%v can't be allocated in Go; it is incomplete (or unallocatable)", t.Elem())
374 }
375 if n.Esc() == ir.EscNone {
376 if why := escape.HeapAllocReason(n); why != "" {
377 base.Fatalf("%v has EscNone, but %v", n, why)
378 }
379
380
381 i := typecheck.IndexConst(r)
382 if i < 0 {
383 base.Fatalf("walkExpr: invalid index %v", r)
384 }
385
386
387
388
389
390
391
392
393 nif := ir.NewIfStmt(base.Pos, ir.NewBinaryExpr(base.Pos, ir.OGT, typecheck.Conv(l, types.Types[types.TUINT64]), ir.NewInt(i)), nil, nil)
394 niflen := ir.NewIfStmt(base.Pos, ir.NewBinaryExpr(base.Pos, ir.OLT, l, ir.NewInt(0)), nil, nil)
395 niflen.Body = []ir.Node{mkcall("panicmakeslicelen", nil, init)}
396 nif.Body.Append(niflen, mkcall("panicmakeslicecap", nil, init))
397 init.Append(typecheck.Stmt(nif))
398
399 t = types.NewArray(t.Elem(), i)
400 var_ := typecheck.Temp(t)
401 appendWalkStmt(init, ir.NewAssignStmt(base.Pos, var_, nil))
402 r := ir.NewSliceExpr(base.Pos, ir.OSLICE, var_, nil, l, nil)
403
404 return walkExpr(typecheck.Expr(typecheck.Conv(r, n.Type())), init)
405 }
406
407
408
409
410
411 len, cap := l, r
412
413 fnname := "makeslice64"
414 argtype := types.Types[types.TINT64]
415
416
417
418
419 if (len.Type().IsKind(types.TIDEAL) || len.Type().Size() <= types.Types[types.TUINT].Size()) &&
420 (cap.Type().IsKind(types.TIDEAL) || cap.Type().Size() <= types.Types[types.TUINT].Size()) {
421 fnname = "makeslice"
422 argtype = types.Types[types.TINT]
423 }
424 fn := typecheck.LookupRuntime(fnname)
425 ptr := mkcall1(fn, types.Types[types.TUNSAFEPTR], init, reflectdata.TypePtr(t.Elem()), typecheck.Conv(len, argtype), typecheck.Conv(cap, argtype))
426 ptr.MarkNonNil()
427 len = typecheck.Conv(len, types.Types[types.TINT])
428 cap = typecheck.Conv(cap, types.Types[types.TINT])
429 sh := ir.NewSliceHeaderExpr(base.Pos, t, ptr, len, cap)
430 return walkExpr(typecheck.Expr(sh), init)
431 }
432
433
434 func walkMakeSliceCopy(n *ir.MakeExpr, init *ir.Nodes) ir.Node {
435 if n.Esc() == ir.EscNone {
436 base.Fatalf("OMAKESLICECOPY with EscNone: %v", n)
437 }
438
439 t := n.Type()
440 if t.Elem().NotInHeap() {
441 base.Errorf("%v can't be allocated in Go; it is incomplete (or unallocatable)", t.Elem())
442 }
443
444 length := typecheck.Conv(n.Len, types.Types[types.TINT])
445 copylen := ir.NewUnaryExpr(base.Pos, ir.OLEN, n.Cap)
446 copyptr := ir.NewUnaryExpr(base.Pos, ir.OSPTR, n.Cap)
447
448 if !t.Elem().HasPointers() && n.Bounded() {
449
450
451
452
453
454
455 size := ir.NewBinaryExpr(base.Pos, ir.OMUL, typecheck.Conv(length, types.Types[types.TUINTPTR]), typecheck.Conv(ir.NewInt(t.Elem().Size()), types.Types[types.TUINTPTR]))
456
457
458 fn := typecheck.LookupRuntime("mallocgc")
459 ptr := mkcall1(fn, types.Types[types.TUNSAFEPTR], init, size, typecheck.NodNil(), ir.NewBool(false))
460 ptr.MarkNonNil()
461 sh := ir.NewSliceHeaderExpr(base.Pos, t, ptr, length, length)
462
463 s := typecheck.Temp(t)
464 r := typecheck.Stmt(ir.NewAssignStmt(base.Pos, s, sh))
465 r = walkExpr(r, init)
466 init.Append(r)
467
468
469 fn = typecheck.LookupRuntime("memmove")
470 fn = typecheck.SubstArgTypes(fn, t.Elem(), t.Elem())
471 ncopy := mkcall1(fn, nil, init, ir.NewUnaryExpr(base.Pos, ir.OSPTR, s), copyptr, size)
472 init.Append(walkExpr(typecheck.Stmt(ncopy), init))
473
474 return s
475 }
476
477
478 fn := typecheck.LookupRuntime("makeslicecopy")
479 ptr := mkcall1(fn, types.Types[types.TUNSAFEPTR], init, reflectdata.TypePtr(t.Elem()), length, copylen, typecheck.Conv(copyptr, types.Types[types.TUNSAFEPTR]))
480 ptr.MarkNonNil()
481 sh := ir.NewSliceHeaderExpr(base.Pos, t, ptr, length, length)
482 return walkExpr(typecheck.Expr(sh), init)
483 }
484
485
486 func walkNew(n *ir.UnaryExpr, init *ir.Nodes) ir.Node {
487 t := n.Type().Elem()
488 if t.NotInHeap() {
489 base.Errorf("%v can't be allocated in Go; it is incomplete (or unallocatable)", n.Type().Elem())
490 }
491 if n.Esc() == ir.EscNone {
492 if t.Size() > ir.MaxImplicitStackVarSize {
493 base.Fatalf("large ONEW with EscNone: %v", n)
494 }
495 return stackTempAddr(init, t)
496 }
497 types.CalcSize(t)
498 n.MarkNonNil()
499 return n
500 }
501
502
503 func walkPrint(nn *ir.CallExpr, init *ir.Nodes) ir.Node {
504
505 walkExprListCheap(nn.Args, init)
506
507
508 if nn.Op() == ir.OPRINTN {
509 s := nn.Args
510 t := make([]ir.Node, 0, len(s)*2)
511 for i, n := range s {
512 if i != 0 {
513 t = append(t, ir.NewString(" "))
514 }
515 t = append(t, n)
516 }
517 t = append(t, ir.NewString("\n"))
518 nn.Args = t
519 }
520
521
522 s := nn.Args
523 t := make([]ir.Node, 0, len(s))
524 for i := 0; i < len(s); {
525 var strs []string
526 for i < len(s) && ir.IsConst(s[i], constant.String) {
527 strs = append(strs, ir.StringVal(s[i]))
528 i++
529 }
530 if len(strs) > 0 {
531 t = append(t, ir.NewString(strings.Join(strs, "")))
532 }
533 if i < len(s) {
534 t = append(t, s[i])
535 i++
536 }
537 }
538 nn.Args = t
539
540 calls := []ir.Node{mkcall("printlock", nil, init)}
541 for i, n := range nn.Args {
542 if n.Op() == ir.OLITERAL {
543 if n.Type() == types.UntypedRune {
544 n = typecheck.DefaultLit(n, types.RuneType)
545 }
546
547 switch n.Val().Kind() {
548 case constant.Int:
549 n = typecheck.DefaultLit(n, types.Types[types.TINT64])
550
551 case constant.Float:
552 n = typecheck.DefaultLit(n, types.Types[types.TFLOAT64])
553 }
554 }
555
556 if n.Op() != ir.OLITERAL && n.Type() != nil && n.Type().Kind() == types.TIDEAL {
557 n = typecheck.DefaultLit(n, types.Types[types.TINT64])
558 }
559 n = typecheck.DefaultLit(n, nil)
560 nn.Args[i] = n
561 if n.Type() == nil || n.Type().Kind() == types.TFORW {
562 continue
563 }
564
565 var on *ir.Name
566 switch n.Type().Kind() {
567 case types.TINTER:
568 if n.Type().IsEmptyInterface() {
569 on = typecheck.LookupRuntime("printeface")
570 } else {
571 on = typecheck.LookupRuntime("printiface")
572 }
573 on = typecheck.SubstArgTypes(on, n.Type())
574 case types.TPTR:
575 if n.Type().Elem().NotInHeap() {
576 on = typecheck.LookupRuntime("printuintptr")
577 n = ir.NewConvExpr(base.Pos, ir.OCONV, nil, n)
578 n.SetType(types.Types[types.TUNSAFEPTR])
579 n = ir.NewConvExpr(base.Pos, ir.OCONV, nil, n)
580 n.SetType(types.Types[types.TUINTPTR])
581 break
582 }
583 fallthrough
584 case types.TCHAN, types.TMAP, types.TFUNC, types.TUNSAFEPTR:
585 on = typecheck.LookupRuntime("printpointer")
586 on = typecheck.SubstArgTypes(on, n.Type())
587 case types.TSLICE:
588 on = typecheck.LookupRuntime("printslice")
589 on = typecheck.SubstArgTypes(on, n.Type())
590 case types.TUINT, types.TUINT8, types.TUINT16, types.TUINT32, types.TUINT64, types.TUINTPTR:
591 if types.IsRuntimePkg(n.Type().Sym().Pkg) && n.Type().Sym().Name == "hex" {
592 on = typecheck.LookupRuntime("printhex")
593 } else {
594 on = typecheck.LookupRuntime("printuint")
595 }
596 case types.TINT, types.TINT8, types.TINT16, types.TINT32, types.TINT64:
597 on = typecheck.LookupRuntime("printint")
598 case types.TFLOAT32, types.TFLOAT64:
599 on = typecheck.LookupRuntime("printfloat")
600 case types.TCOMPLEX64, types.TCOMPLEX128:
601 on = typecheck.LookupRuntime("printcomplex")
602 case types.TBOOL:
603 on = typecheck.LookupRuntime("printbool")
604 case types.TSTRING:
605 cs := ""
606 if ir.IsConst(n, constant.String) {
607 cs = ir.StringVal(n)
608 }
609 switch cs {
610 case " ":
611 on = typecheck.LookupRuntime("printsp")
612 case "\n":
613 on = typecheck.LookupRuntime("printnl")
614 default:
615 on = typecheck.LookupRuntime("printstring")
616 }
617 default:
618 badtype(ir.OPRINT, n.Type(), nil)
619 continue
620 }
621
622 r := ir.NewCallExpr(base.Pos, ir.OCALL, on, nil)
623 if params := on.Type().Params().FieldSlice(); len(params) > 0 {
624 t := params[0].Type
625 n = typecheck.Conv(n, t)
626 r.Args.Append(n)
627 }
628 calls = append(calls, r)
629 }
630
631 calls = append(calls, mkcall("printunlock", nil, init))
632
633 typecheck.Stmts(calls)
634 walkExprList(calls, init)
635
636 r := ir.NewBlockStmt(base.Pos, nil)
637 r.List = calls
638 return walkStmt(typecheck.Stmt(r))
639 }
640
641
642 func walkRecoverFP(nn *ir.CallExpr, init *ir.Nodes) ir.Node {
643 return mkcall("gorecover", nn.Type(), init, walkExpr(nn.Args[0], init))
644 }
645
646 func walkUnsafeSlice(n *ir.BinaryExpr, init *ir.Nodes) ir.Node {
647 ptr := safeExpr(n.X, init)
648 len := safeExpr(n.Y, init)
649
650 fnname := "unsafeslice64"
651 lenType := types.Types[types.TINT64]
652
653
654
655
656 if ir.ShouldCheckPtr(ir.CurFunc, 1) {
657 fnname = "unsafeslicecheckptr"
658
659 } else if len.Type().IsKind(types.TIDEAL) || len.Type().Size() <= types.Types[types.TUINT].Size() {
660 fnname = "unsafeslice"
661 lenType = types.Types[types.TINT]
662 }
663
664 t := n.Type()
665
666
667 fn := typecheck.LookupRuntime(fnname)
668 init.Append(mkcall1(fn, nil, init, reflectdata.TypePtr(t.Elem()), typecheck.Conv(ptr, types.Types[types.TUNSAFEPTR]), typecheck.Conv(len, lenType)))
669
670 h := ir.NewSliceHeaderExpr(n.Pos(), t,
671 typecheck.Conv(ptr, types.Types[types.TUNSAFEPTR]),
672 typecheck.Conv(len, types.Types[types.TINT]),
673 typecheck.Conv(len, types.Types[types.TINT]))
674 return walkExpr(typecheck.Expr(h), init)
675 }
676
677 func badtype(op ir.Op, tl, tr *types.Type) {
678 var s string
679 if tl != nil {
680 s += fmt.Sprintf("\n\t%v", tl)
681 }
682 if tr != nil {
683 s += fmt.Sprintf("\n\t%v", tr)
684 }
685
686
687 if tl != nil && tr != nil && tl.IsPtr() && tr.IsPtr() {
688 if tl.Elem().IsStruct() && tr.Elem().IsInterface() {
689 s += "\n\t(*struct vs *interface)"
690 } else if tl.Elem().IsInterface() && tr.Elem().IsStruct() {
691 s += "\n\t(*interface vs *struct)"
692 }
693 }
694
695 base.Errorf("illegal types for operand: %v%s", op, s)
696 }
697
698 func writebarrierfn(name string, l *types.Type, r *types.Type) ir.Node {
699 fn := typecheck.LookupRuntime(name)
700 fn = typecheck.SubstArgTypes(fn, l, r)
701 return fn
702 }
703
704
705
706 func isRuneCount(n ir.Node) bool {
707 return base.Flag.N == 0 && !base.Flag.Cfg.Instrumenting && n.Op() == ir.OLEN && n.(*ir.UnaryExpr).X.Op() == ir.OSTR2RUNES
708 }
709
View as plain text