Source file src/pkg/cmd/compile/internal/gc/dcl.go
1
2
3
4
5 package gc
6
7 import (
8 "bytes"
9 "cmd/compile/internal/types"
10 "cmd/internal/obj"
11 "cmd/internal/src"
12 "fmt"
13 "strings"
14 )
15
16
17
18 var externdcl []*Node
19
20 func testdclstack() {
21 if !types.IsDclstackValid() {
22 if nerrors != 0 {
23 errorexit()
24 }
25 Fatalf("mark left on the dclstack")
26 }
27 }
28
29
30 func redeclare(pos src.XPos, s *types.Sym, where string) {
31 if !s.Lastlineno.IsKnown() {
32 pkg := s.Origpkg
33 if pkg == nil {
34 pkg = s.Pkg
35 }
36 yyerrorl(pos, "%v redeclared %s\n"+
37 "\tprevious declaration during import %q", s, where, pkg.Path)
38 } else {
39 prevPos := s.Lastlineno
40
41
42
43
44
45 if s.Def == nil {
46 pos, prevPos = prevPos, pos
47 }
48
49 yyerrorl(pos, "%v redeclared %s\n"+
50 "\tprevious declaration at %v", s, where, linestr(prevPos))
51 }
52 }
53
54 var vargen int
55
56
57
58 var declare_typegen int
59
60
61
62 func declare(n *Node, ctxt Class) {
63 if ctxt == PDISCARD {
64 return
65 }
66
67 if n.isBlank() {
68 return
69 }
70
71 if n.Name == nil {
72
73 n.Name = new(Name)
74 }
75
76 s := n.Sym
77
78
79 if !inimport && !typecheckok && s.Pkg != localpkg {
80 yyerrorl(n.Pos, "cannot declare name %v", s)
81 }
82
83 gen := 0
84 if ctxt == PEXTERN {
85 if s.Name == "init" {
86 yyerrorl(n.Pos, "cannot declare init - must be func")
87 }
88 if s.Name == "main" && s.Pkg.Name == "main" {
89 yyerrorl(n.Pos, "cannot declare main - must be func")
90 }
91 externdcl = append(externdcl, n)
92 } else {
93 if Curfn == nil && ctxt == PAUTO {
94 lineno = n.Pos
95 Fatalf("automatic outside function")
96 }
97 if Curfn != nil {
98 Curfn.Func.Dcl = append(Curfn.Func.Dcl, n)
99 }
100 if n.Op == OTYPE {
101 declare_typegen++
102 gen = declare_typegen
103 } else if n.Op == ONAME && ctxt == PAUTO && !strings.Contains(s.Name, "·") {
104 vargen++
105 gen = vargen
106 }
107 types.Pushdcl(s)
108 n.Name.Curfn = Curfn
109 }
110
111 if ctxt == PAUTO {
112 n.Xoffset = 0
113 }
114
115 if s.Block == types.Block {
116
117
118 if ctxt != PPARAM && ctxt != PPARAMOUT {
119 redeclare(n.Pos, s, "in this block")
120 }
121 }
122
123 s.Block = types.Block
124 s.Lastlineno = lineno
125 s.Def = asTypesNode(n)
126 n.Name.Vargen = int32(gen)
127 n.SetClass(ctxt)
128 if ctxt == PFUNC {
129 n.Sym.SetFunc(true)
130 }
131
132 autoexport(n, ctxt)
133 }
134
135 func addvar(n *Node, t *types.Type, ctxt Class) {
136 if n == nil || n.Sym == nil || (n.Op != ONAME && n.Op != ONONAME) || t == nil {
137 Fatalf("addvar: n=%v t=%v nil", n, t)
138 }
139
140 n.Op = ONAME
141 declare(n, ctxt)
142 n.Type = t
143 }
144
145
146
147 func variter(vl []*Node, t *Node, el []*Node) []*Node {
148 var init []*Node
149 doexpr := len(el) > 0
150
151 if len(el) == 1 && len(vl) > 1 {
152 e := el[0]
153 as2 := nod(OAS2, nil, nil)
154 as2.List.Set(vl)
155 as2.Rlist.Set1(e)
156 for _, v := range vl {
157 v.Op = ONAME
158 declare(v, dclcontext)
159 v.Name.Param.Ntype = t
160 v.Name.Defn = as2
161 if Curfn != nil {
162 init = append(init, nod(ODCL, v, nil))
163 }
164 }
165
166 return append(init, as2)
167 }
168
169 nel := len(el)
170 for _, v := range vl {
171 var e *Node
172 if doexpr {
173 if len(el) == 0 {
174 yyerror("assignment mismatch: %d variables but %d values", len(vl), nel)
175 break
176 }
177 e = el[0]
178 el = el[1:]
179 }
180
181 v.Op = ONAME
182 declare(v, dclcontext)
183 v.Name.Param.Ntype = t
184
185 if e != nil || Curfn != nil || v.isBlank() {
186 if Curfn != nil {
187 init = append(init, nod(ODCL, v, nil))
188 }
189 e = nod(OAS, v, e)
190 init = append(init, e)
191 if e.Right != nil {
192 v.Name.Defn = e
193 }
194 }
195 }
196
197 if len(el) != 0 {
198 yyerror("assignment mismatch: %d variables but %d values", len(vl), nel)
199 }
200 return init
201 }
202
203
204 func newnoname(s *types.Sym) *Node {
205 if s == nil {
206 Fatalf("newnoname nil")
207 }
208 n := nod(ONONAME, nil, nil)
209 n.Sym = s
210 n.SetAddable(true)
211 n.Xoffset = 0
212 return n
213 }
214
215
216
217 func newfuncnamel(pos src.XPos, s *types.Sym) *Node {
218 n := newnamel(pos, s)
219 n.Func = new(Func)
220 n.Func.SetIsHiddenClosure(Curfn != nil)
221 return n
222 }
223
224
225
226 func dclname(s *types.Sym) *Node {
227 n := newname(s)
228 n.Op = ONONAME
229 return n
230 }
231
232 func typenod(t *types.Type) *Node {
233 return typenodl(src.NoXPos, t)
234 }
235
236 func typenodl(pos src.XPos, t *types.Type) *Node {
237
238
239
240 if asNode(t.Nod) == nil || asNode(t.Nod).Type != t {
241 t.Nod = asTypesNode(nodl(pos, OTYPE, nil, nil))
242 asNode(t.Nod).Type = t
243 asNode(t.Nod).Sym = t.Sym
244 }
245
246 return asNode(t.Nod)
247 }
248
249 func anonfield(typ *types.Type) *Node {
250 return symfield(nil, typ)
251 }
252
253 func namedfield(s string, typ *types.Type) *Node {
254 return symfield(lookup(s), typ)
255 }
256
257 func symfield(s *types.Sym, typ *types.Type) *Node {
258 n := nodSym(ODCLFIELD, nil, s)
259 n.Type = typ
260 return n
261 }
262
263
264
265 func oldname(s *types.Sym) *Node {
266 n := asNode(s.Def)
267 if n == nil {
268
269
270
271 return newnoname(s)
272 }
273
274 if Curfn != nil && n.Op == ONAME && n.Name.Curfn != nil && n.Name.Curfn != Curfn {
275
276
277
278
279
280
281 c := n.Name.Param.Innermost
282 if c == nil || c.Name.Curfn != Curfn {
283
284 c = newname(s)
285 c.SetClass(PAUTOHEAP)
286 c.SetIsClosureVar(true)
287 c.SetIsDDD(n.IsDDD())
288 c.Name.Defn = n
289 c.SetAddable(false)
290
291
292
293 c.Name.Param.Outer = n.Name.Param.Innermost
294 n.Name.Param.Innermost = c
295
296 Curfn.Func.Cvars.Append(c)
297 }
298
299
300 return c
301 }
302
303 return n
304 }
305
306
307 func colasname(n *Node) bool {
308 switch n.Op {
309 case ONAME,
310 ONONAME,
311 OPACK,
312 OTYPE,
313 OLITERAL:
314 return n.Sym != nil
315 }
316
317 return false
318 }
319
320 func colasdefn(left []*Node, defn *Node) {
321 for _, n := range left {
322 if n.Sym != nil {
323 n.Sym.SetUniq(true)
324 }
325 }
326
327 var nnew, nerr int
328 for i, n := range left {
329 if n.isBlank() {
330 continue
331 }
332 if !colasname(n) {
333 yyerrorl(defn.Pos, "non-name %v on left side of :=", n)
334 nerr++
335 continue
336 }
337
338 if !n.Sym.Uniq() {
339 yyerrorl(defn.Pos, "%v repeated on left side of :=", n.Sym)
340 n.SetDiag(true)
341 nerr++
342 continue
343 }
344
345 n.Sym.SetUniq(false)
346 if n.Sym.Block == types.Block {
347 continue
348 }
349
350 nnew++
351 n = newname(n.Sym)
352 declare(n, dclcontext)
353 n.Name.Defn = defn
354 defn.Ninit.Append(nod(ODCL, n, nil))
355 left[i] = n
356 }
357
358 if nnew == 0 && nerr == 0 {
359 yyerrorl(defn.Pos, "no new variables on left side of :=")
360 }
361 }
362
363
364
365 func ifacedcl(n *Node) {
366 if n.Op != ODCLFIELD || n.Left == nil {
367 Fatalf("ifacedcl")
368 }
369
370 if n.Sym.IsBlank() {
371 yyerror("methods must have a unique non-blank name")
372 }
373 }
374
375
376
377
378
379 func funchdr(n *Node) {
380
381 if Curfn == nil && dclcontext != PEXTERN {
382 Fatalf("funchdr: dclcontext = %d", dclcontext)
383 }
384
385 dclcontext = PAUTO
386 types.Markdcl()
387 funcstack = append(funcstack, Curfn)
388 Curfn = n
389
390 if n.Func.Nname != nil {
391 funcargs(n.Func.Nname.Name.Param.Ntype)
392 } else if n.Func.Ntype != nil {
393 funcargs(n.Func.Ntype)
394 } else {
395 funcargs2(n.Type)
396 }
397 }
398
399 func funcargs(nt *Node) {
400 if nt.Op != OTFUNC {
401 Fatalf("funcargs %v", nt.Op)
402 }
403
404
405
406
407
408
409
410
411 vargen = nt.Rlist.Len()
412
413
414 if nt.Left != nil {
415 funcarg(nt.Left, PPARAM)
416 }
417 for _, n := range nt.List.Slice() {
418 funcarg(n, PPARAM)
419 }
420
421 oldvargen := vargen
422 vargen = 0
423
424
425 gen := nt.List.Len()
426 for _, n := range nt.Rlist.Slice() {
427 if n.Sym == nil {
428
429 n.Sym = lookupN("~r", gen)
430 gen++
431 }
432 if n.Sym.IsBlank() {
433
434
435
436
437
438
439 n.Sym = lookupN("~b", gen)
440 gen++
441 }
442
443 funcarg(n, PPARAMOUT)
444 }
445
446 vargen = oldvargen
447 }
448
449 func funcarg(n *Node, ctxt Class) {
450 if n.Op != ODCLFIELD {
451 Fatalf("funcarg %v", n.Op)
452 }
453 if n.Sym == nil {
454 return
455 }
456
457 n.Right = newnamel(n.Pos, n.Sym)
458 n.Right.Name.Param.Ntype = n.Left
459 n.Right.SetIsDDD(n.IsDDD())
460 declare(n.Right, ctxt)
461
462 vargen++
463 n.Right.Name.Vargen = int32(vargen)
464 }
465
466
467
468
469 func funcargs2(t *types.Type) {
470 if t.Etype != TFUNC {
471 Fatalf("funcargs2 %v", t)
472 }
473
474 for _, f := range t.Recvs().Fields().Slice() {
475 funcarg2(f, PPARAM)
476 }
477 for _, f := range t.Params().Fields().Slice() {
478 funcarg2(f, PPARAM)
479 }
480 for _, f := range t.Results().Fields().Slice() {
481 funcarg2(f, PPARAMOUT)
482 }
483 }
484
485 func funcarg2(f *types.Field, ctxt Class) {
486 if f.Sym == nil {
487 return
488 }
489 n := newnamel(f.Pos, f.Sym)
490 f.Nname = asTypesNode(n)
491 n.Type = f.Type
492 n.SetIsDDD(f.IsDDD())
493 declare(n, ctxt)
494 }
495
496 var funcstack []*Node
497
498
499
500
501 func funcbody() {
502
503 if dclcontext != PAUTO {
504 Fatalf("funcbody: unexpected dclcontext %d", dclcontext)
505 }
506 types.Popdcl()
507 funcstack, Curfn = funcstack[:len(funcstack)-1], funcstack[len(funcstack)-1]
508 if Curfn == nil {
509 dclcontext = PEXTERN
510 }
511 }
512
513
514
515 func checkembeddedtype(t *types.Type) {
516 if t == nil {
517 return
518 }
519
520 if t.Sym == nil && t.IsPtr() {
521 t = t.Elem()
522 if t.IsInterface() {
523 yyerror("embedded type cannot be a pointer to interface")
524 }
525 }
526
527 if t.IsPtr() || t.IsUnsafePtr() {
528 yyerror("embedded type cannot be a pointer")
529 } else if t.Etype == TFORW && !t.ForwardType().Embedlineno.IsKnown() {
530 t.ForwardType().Embedlineno = lineno
531 }
532 }
533
534 func structfield(n *Node) *types.Field {
535 lno := lineno
536 lineno = n.Pos
537
538 if n.Op != ODCLFIELD {
539 Fatalf("structfield: oops %v\n", n)
540 }
541
542 f := types.NewField()
543 f.Pos = n.Pos
544 f.Sym = n.Sym
545
546 if n.Left != nil {
547 n.Left = typecheck(n.Left, Etype)
548 n.Type = n.Left.Type
549 n.Left = nil
550 }
551
552 f.Type = n.Type
553 if f.Type == nil {
554 f.SetBroke(true)
555 }
556
557 if n.Embedded() {
558 checkembeddedtype(n.Type)
559 f.Embedded = 1
560 } else {
561 f.Embedded = 0
562 }
563
564 switch u := n.Val().U.(type) {
565 case string:
566 f.Note = u
567 default:
568 yyerror("field tag must be a string")
569 case nil:
570
571 }
572
573 lineno = lno
574 return f
575 }
576
577
578
579 func checkdupfields(what string, ts ...*types.Type) {
580 seen := make(map[*types.Sym]bool)
581 for _, t := range ts {
582 for _, f := range t.Fields().Slice() {
583 if f.Sym == nil || f.Sym.IsBlank() {
584 continue
585 }
586 if seen[f.Sym] {
587 yyerrorl(f.Pos, "duplicate %s %s", what, f.Sym.Name)
588 continue
589 }
590 seen[f.Sym] = true
591 }
592 }
593 }
594
595
596
597 func tostruct(l []*Node) *types.Type {
598 t := types.New(TSTRUCT)
599 tostruct0(t, l)
600 return t
601 }
602
603 func tostruct0(t *types.Type, l []*Node) {
604 if t == nil || !t.IsStruct() {
605 Fatalf("struct expected")
606 }
607
608 fields := make([]*types.Field, len(l))
609 for i, n := range l {
610 f := structfield(n)
611 if f.Broke() {
612 t.SetBroke(true)
613 }
614 fields[i] = f
615 }
616 t.SetFields(fields)
617
618 checkdupfields("field", t)
619
620 if !t.Broke() {
621 checkwidth(t)
622 }
623 }
624
625 func tofunargs(l []*Node, funarg types.Funarg) *types.Type {
626 t := types.New(TSTRUCT)
627 t.StructType().Funarg = funarg
628
629 fields := make([]*types.Field, len(l))
630 for i, n := range l {
631 f := structfield(n)
632 f.SetIsDDD(n.IsDDD())
633 if n.Right != nil {
634 n.Right.Type = f.Type
635 f.Nname = asTypesNode(n.Right)
636 }
637 if f.Broke() {
638 t.SetBroke(true)
639 }
640 fields[i] = f
641 }
642 t.SetFields(fields)
643 return t
644 }
645
646 func tofunargsfield(fields []*types.Field, funarg types.Funarg) *types.Type {
647 t := types.New(TSTRUCT)
648 t.StructType().Funarg = funarg
649 t.SetFields(fields)
650 return t
651 }
652
653 func interfacefield(n *Node) *types.Field {
654 lno := lineno
655 lineno = n.Pos
656
657 if n.Op != ODCLFIELD {
658 Fatalf("interfacefield: oops %v\n", n)
659 }
660
661 if n.Val().Ctype() != CTxxx {
662 yyerror("interface method cannot have annotation")
663 }
664
665
666
667
668
669
670 if n.Left != nil {
671 n.Left = typecheck(n.Left, Etype)
672 n.Type = n.Left.Type
673 n.Left = nil
674 }
675
676 f := types.NewField()
677 f.Pos = n.Pos
678 f.Sym = n.Sym
679 f.Type = n.Type
680 if f.Type == nil {
681 f.SetBroke(true)
682 }
683
684 lineno = lno
685 return f
686 }
687
688 func tointerface(l []*Node) *types.Type {
689 if len(l) == 0 {
690 return types.Types[TINTER]
691 }
692 t := types.New(TINTER)
693 tointerface0(t, l)
694 return t
695 }
696
697 func tointerface0(t *types.Type, l []*Node) {
698 if t == nil || !t.IsInterface() {
699 Fatalf("interface expected")
700 }
701
702 var fields []*types.Field
703 for _, n := range l {
704 f := interfacefield(n)
705 if f.Broke() {
706 t.SetBroke(true)
707 }
708 fields = append(fields, f)
709 }
710 t.SetInterface(fields)
711 }
712
713 func fakeRecv() *Node {
714 return anonfield(types.FakeRecvType())
715 }
716
717 func fakeRecvField() *types.Field {
718 f := types.NewField()
719 f.Type = types.FakeRecvType()
720 return f
721 }
722
723
724
725
726 func isifacemethod(f *types.Type) bool {
727 return f.Recv().Type == types.FakeRecvType()
728 }
729
730
731 func functype(this *Node, in, out []*Node) *types.Type {
732 t := types.New(TFUNC)
733 functype0(t, this, in, out)
734 return t
735 }
736
737 func functype0(t *types.Type, this *Node, in, out []*Node) {
738 if t == nil || t.Etype != TFUNC {
739 Fatalf("function type expected")
740 }
741
742 var rcvr []*Node
743 if this != nil {
744 rcvr = []*Node{this}
745 }
746 t.FuncType().Receiver = tofunargs(rcvr, types.FunargRcvr)
747 t.FuncType().Params = tofunargs(in, types.FunargParams)
748 t.FuncType().Results = tofunargs(out, types.FunargResults)
749
750 checkdupfields("argument", t.Recvs(), t.Params(), t.Results())
751
752 if t.Recvs().Broke() || t.Results().Broke() || t.Params().Broke() {
753 t.SetBroke(true)
754 }
755
756 t.FuncType().Outnamed = t.NumResults() > 0 && origSym(t.Results().Field(0).Sym) != nil
757 }
758
759 func functypefield(this *types.Field, in, out []*types.Field) *types.Type {
760 t := types.New(TFUNC)
761 functypefield0(t, this, in, out)
762 return t
763 }
764
765 func functypefield0(t *types.Type, this *types.Field, in, out []*types.Field) {
766 var rcvr []*types.Field
767 if this != nil {
768 rcvr = []*types.Field{this}
769 }
770 t.FuncType().Receiver = tofunargsfield(rcvr, types.FunargRcvr)
771 t.FuncType().Params = tofunargsfield(in, types.FunargParams)
772 t.FuncType().Results = tofunargsfield(out, types.FunargResults)
773
774 t.FuncType().Outnamed = t.NumResults() > 0 && origSym(t.Results().Field(0).Sym) != nil
775 }
776
777
778 func origSym(s *types.Sym) *types.Sym {
779 if s == nil {
780 return nil
781 }
782
783 if len(s.Name) > 1 && s.Name[0] == '~' {
784 switch s.Name[1] {
785 case 'r':
786 return nil
787 case 'b':
788
789 return nblank.Sym
790 }
791 return s
792 }
793
794 if strings.HasPrefix(s.Name, ".anon") {
795
796 return nil
797 }
798
799 return s
800 }
801
802
803
804
805
806
807
808
809
810 func methodSym(recv *types.Type, msym *types.Sym) *types.Sym {
811 sym := methodSymSuffix(recv, msym, "")
812 sym.SetFunc(true)
813 return sym
814 }
815
816
817
818
819 func methodSymSuffix(recv *types.Type, msym *types.Sym, suffix string) *types.Sym {
820 if msym.IsBlank() {
821 Fatalf("blank method name")
822 }
823
824 rsym := recv.Sym
825 if recv.IsPtr() {
826 if rsym != nil {
827 Fatalf("declared pointer receiver type: %v", recv)
828 }
829 rsym = recv.Elem().Sym
830 }
831
832
833
834
835 rpkg := gopkg
836 if rsym != nil {
837 rpkg = rsym.Pkg
838 }
839
840 var b bytes.Buffer
841 if recv.IsPtr() {
842
843
844 fmt.Fprintf(&b, "(%-S)", recv)
845 } else {
846 fmt.Fprintf(&b, "%-S", recv)
847 }
848
849
850
851
852
853 if !types.IsExported(msym.Name) && msym.Pkg != rpkg {
854 b.WriteString(".")
855 b.WriteString(msym.Pkg.Prefix)
856 }
857
858 b.WriteString(".")
859 b.WriteString(msym.Name)
860 b.WriteString(suffix)
861
862 return rpkg.LookupBytes(b.Bytes())
863 }
864
865
866
867
868
869 func addmethod(msym *types.Sym, t *types.Type, local, nointerface bool) *types.Field {
870 if msym == nil {
871 Fatalf("no method symbol")
872 }
873
874
875 rf := t.Recv()
876 if rf == nil {
877 yyerror("missing receiver")
878 return nil
879 }
880
881 mt := methtype(rf.Type)
882 if mt == nil || mt.Sym == nil {
883 pa := rf.Type
884 t := pa
885 if t != nil && t.IsPtr() {
886 if t.Sym != nil {
887 yyerror("invalid receiver type %v (%v is a pointer type)", pa, t)
888 return nil
889 }
890 t = t.Elem()
891 }
892
893 switch {
894 case t == nil || t.Broke():
895
896 case t.Sym == nil:
897 yyerror("invalid receiver type %v (%v is not a defined type)", pa, t)
898 case t.IsPtr():
899 yyerror("invalid receiver type %v (%v is a pointer type)", pa, t)
900 case t.IsInterface():
901 yyerror("invalid receiver type %v (%v is an interface type)", pa, t)
902 default:
903
904
905 yyerror("invalid receiver type %v (%L / %L)", pa, pa, t)
906 }
907 return nil
908 }
909
910 if local && mt.Sym.Pkg != localpkg {
911 yyerror("cannot define new methods on non-local type %v", mt)
912 return nil
913 }
914
915 if msym.IsBlank() {
916 return nil
917 }
918
919 if mt.IsStruct() {
920 for _, f := range mt.Fields().Slice() {
921 if f.Sym == msym {
922 yyerror("type %v has both field and method named %v", mt, msym)
923 f.SetBroke(true)
924 return nil
925 }
926 }
927 }
928
929 for _, f := range mt.Methods().Slice() {
930 if msym.Name != f.Sym.Name {
931 continue
932 }
933
934
935 if !types.Identical(t, f.Type) || !types.Identical(t.Recv().Type, f.Type.Recv().Type) {
936 yyerror("method redeclared: %v.%v\n\t%v\n\t%v", mt, msym, f.Type, t)
937 }
938 return f
939 }
940
941 f := types.NewField()
942 f.Pos = lineno
943 f.Sym = msym
944 f.Type = t
945 f.SetNointerface(nointerface)
946
947 mt.Methods().Append(f)
948 return f
949 }
950
951 func funcsymname(s *types.Sym) string {
952 return s.Name + "·f"
953 }
954
955
956 func funcsym(s *types.Sym) *types.Sym {
957
958
959
960
961
962
963
964
965
966 funcsymsmu.Lock()
967 sf, existed := s.Pkg.LookupOK(funcsymname(s))
968
969
970
971
972 if !Ctxt.Flag_dynlink && !existed {
973 funcsyms = append(funcsyms, s)
974 }
975 funcsymsmu.Unlock()
976 return sf
977 }
978
979
980
981
982
983
984
985
986
987
988 func makefuncsym(s *types.Sym) {
989 if !Ctxt.Flag_dynlink {
990 Fatalf("makefuncsym dynlink")
991 }
992 if s.IsBlank() {
993 return
994 }
995 if compiling_runtime && (s.Name == "getg" || s.Name == "getclosureptr" || s.Name == "getcallerpc" || s.Name == "getcallersp") {
996
997
998
999 return
1000 }
1001 if _, existed := s.Pkg.LookupOK(funcsymname(s)); !existed {
1002 funcsyms = append(funcsyms, s)
1003 }
1004 }
1005
1006
1007
1008 func disableExport(sym *types.Sym) {
1009 sym.SetOnExportList(true)
1010 }
1011
1012 func dclfunc(sym *types.Sym, tfn *Node) *Node {
1013 if tfn.Op != OTFUNC {
1014 Fatalf("expected OTFUNC node, got %v", tfn)
1015 }
1016
1017 fn := nod(ODCLFUNC, nil, nil)
1018 fn.Func.Nname = newfuncnamel(lineno, sym)
1019 fn.Func.Nname.Name.Defn = fn
1020 fn.Func.Nname.Name.Param.Ntype = tfn
1021 declare(fn.Func.Nname, PFUNC)
1022 funchdr(fn)
1023 fn.Func.Nname.Name.Param.Ntype = typecheck(fn.Func.Nname.Name.Param.Ntype, Etype)
1024 return fn
1025 }
1026
1027 type nowritebarrierrecChecker struct {
1028
1029
1030
1031 extraCalls map[*Node][]nowritebarrierrecCall
1032
1033
1034 curfn *Node
1035 }
1036
1037 type nowritebarrierrecCall struct {
1038 target *Node
1039 lineno src.XPos
1040 }
1041
1042 type nowritebarrierrecCallSym struct {
1043 target *obj.LSym
1044 lineno src.XPos
1045 }
1046
1047
1048
1049 func newNowritebarrierrecChecker() *nowritebarrierrecChecker {
1050 c := &nowritebarrierrecChecker{
1051 extraCalls: make(map[*Node][]nowritebarrierrecCall),
1052 }
1053
1054
1055
1056
1057
1058
1059 for _, n := range xtop {
1060 if n.Op != ODCLFUNC {
1061 continue
1062 }
1063 c.curfn = n
1064 inspect(n, c.findExtraCalls)
1065 }
1066 c.curfn = nil
1067 return c
1068 }
1069
1070 func (c *nowritebarrierrecChecker) findExtraCalls(n *Node) bool {
1071 if n.Op != OCALLFUNC {
1072 return true
1073 }
1074 fn := n.Left
1075 if fn == nil || fn.Op != ONAME || fn.Class() != PFUNC || fn.Name.Defn == nil {
1076 return true
1077 }
1078 if !isRuntimePkg(fn.Sym.Pkg) || fn.Sym.Name != "systemstack" {
1079 return true
1080 }
1081
1082 var callee *Node
1083 arg := n.List.First()
1084 switch arg.Op {
1085 case ONAME:
1086 callee = arg.Name.Defn
1087 case OCLOSURE:
1088 callee = arg.Func.Closure
1089 default:
1090 Fatalf("expected ONAME or OCLOSURE node, got %+v", arg)
1091 }
1092 if callee.Op != ODCLFUNC {
1093 Fatalf("expected ODCLFUNC node, got %+v", callee)
1094 }
1095 c.extraCalls[c.curfn] = append(c.extraCalls[c.curfn], nowritebarrierrecCall{callee, n.Pos})
1096 return true
1097 }
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107 func (c *nowritebarrierrecChecker) recordCall(from *Node, to *obj.LSym, pos src.XPos) {
1108 if from.Op != ODCLFUNC {
1109 Fatalf("expected ODCLFUNC, got %v", from)
1110 }
1111
1112
1113 fn := from.Func
1114 if fn.nwbrCalls == nil {
1115 fn.nwbrCalls = new([]nowritebarrierrecCallSym)
1116 }
1117 *fn.nwbrCalls = append(*fn.nwbrCalls, nowritebarrierrecCallSym{to, pos})
1118 }
1119
1120 func (c *nowritebarrierrecChecker) check() {
1121
1122
1123
1124
1125 symToFunc := make(map[*obj.LSym]*Node)
1126
1127
1128
1129
1130
1131
1132 funcs := make(map[*Node]nowritebarrierrecCall)
1133
1134 var q nodeQueue
1135
1136 for _, n := range xtop {
1137 if n.Op != ODCLFUNC {
1138 continue
1139 }
1140
1141 symToFunc[n.Func.lsym] = n
1142
1143
1144 if n.Func.Pragma&Nowritebarrierrec != 0 {
1145 funcs[n] = nowritebarrierrecCall{}
1146 q.pushRight(n)
1147 }
1148
1149 if n.Func.Pragma&Nowritebarrier != 0 && n.Func.WBPos.IsKnown() {
1150 yyerrorl(n.Func.WBPos, "write barrier prohibited")
1151 }
1152 }
1153
1154
1155
1156 enqueue := func(src, target *Node, pos src.XPos) {
1157 if target.Func.Pragma&Yeswritebarrierrec != 0 {
1158
1159 return
1160 }
1161 if _, ok := funcs[target]; ok {
1162
1163 return
1164 }
1165
1166
1167 funcs[target] = nowritebarrierrecCall{target: src, lineno: pos}
1168 q.pushRight(target)
1169 }
1170 for !q.empty() {
1171 fn := q.popLeft()
1172
1173
1174 if fn.Func.WBPos.IsKnown() {
1175 var err bytes.Buffer
1176 call := funcs[fn]
1177 for call.target != nil {
1178 fmt.Fprintf(&err, "\n\t%v: called by %v", linestr(call.lineno), call.target.Func.Nname)
1179 call = funcs[call.target]
1180 }
1181 yyerrorl(fn.Func.WBPos, "write barrier prohibited by caller; %v%s", fn.Func.Nname, err.String())
1182 continue
1183 }
1184
1185
1186 for _, callee := range c.extraCalls[fn] {
1187 enqueue(fn, callee.target, callee.lineno)
1188 }
1189 if fn.Func.nwbrCalls == nil {
1190 continue
1191 }
1192 for _, callee := range *fn.Func.nwbrCalls {
1193 target := symToFunc[callee.target]
1194 if target != nil {
1195 enqueue(fn, target, callee.lineno)
1196 }
1197 }
1198 }
1199 }
1200
View as plain text