1
2
3
4
5 package noder
6
7 import (
8 "fmt"
9 "internal/buildcfg"
10 "strings"
11
12 "cmd/compile/internal/ir"
13 "cmd/compile/internal/syntax"
14 )
15
16 func isSpace(c rune) bool {
17 return c == ' ' || c == '\t' || c == '\n' || c == '\r'
18 }
19
20 func isQuoted(s string) bool {
21 return len(s) >= 2 && s[0] == '"' && s[len(s)-1] == '"'
22 }
23
24 const (
25 funcPragmas = ir.Nointerface |
26 ir.Noescape |
27 ir.Norace |
28 ir.Nosplit |
29 ir.Noinline |
30 ir.NoCheckPtr |
31 ir.RegisterParams |
32 ir.CgoUnsafeArgs |
33 ir.UintptrEscapes |
34 ir.Systemstack |
35 ir.Nowritebarrier |
36 ir.Nowritebarrierrec |
37 ir.Yeswritebarrierrec
38
39 typePragmas = ir.NotInHeap
40 )
41
42 func pragmaFlag(verb string) ir.PragmaFlag {
43 switch verb {
44 case "go:build":
45 return ir.GoBuildPragma
46 case "go:nointerface":
47 if buildcfg.Experiment.FieldTrack {
48 return ir.Nointerface
49 }
50 case "go:noescape":
51 return ir.Noescape
52 case "go:norace":
53 return ir.Norace
54 case "go:nosplit":
55 return ir.Nosplit | ir.NoCheckPtr
56 case "go:noinline":
57 return ir.Noinline
58 case "go:nocheckptr":
59 return ir.NoCheckPtr
60 case "go:systemstack":
61 return ir.Systemstack
62 case "go:nowritebarrier":
63 return ir.Nowritebarrier
64 case "go:nowritebarrierrec":
65 return ir.Nowritebarrierrec | ir.Nowritebarrier
66 case "go:yeswritebarrierrec":
67 return ir.Yeswritebarrierrec
68 case "go:cgo_unsafe_args":
69 return ir.CgoUnsafeArgs | ir.NoCheckPtr
70 case "go:uintptrescapes":
71
72
73
74
75
76
77
78
79
80
81
82 return ir.UintptrEscapes
83 case "go:registerparams":
84 return ir.RegisterParams
85 case "go:notinheap":
86 return ir.NotInHeap
87 }
88 return 0
89 }
90
91
92 func (p *noder) pragcgo(pos syntax.Pos, text string) {
93 f := pragmaFields(text)
94
95 verb := strings.TrimPrefix(f[0], "go:")
96 f[0] = verb
97
98 switch verb {
99 case "cgo_export_static", "cgo_export_dynamic":
100 switch {
101 case len(f) == 2 && !isQuoted(f[1]):
102 case len(f) == 3 && !isQuoted(f[1]) && !isQuoted(f[2]):
103 default:
104 p.error(syntax.Error{Pos: pos, Msg: fmt.Sprintf(`usage: //go:%s local [remote]`, verb)})
105 return
106 }
107 case "cgo_import_dynamic":
108 switch {
109 case len(f) == 2 && !isQuoted(f[1]):
110 case len(f) == 3 && !isQuoted(f[1]) && !isQuoted(f[2]):
111 case len(f) == 4 && !isQuoted(f[1]) && !isQuoted(f[2]) && isQuoted(f[3]):
112 f[3] = strings.Trim(f[3], `"`)
113 if buildcfg.GOOS == "aix" && f[3] != "" {
114
115
116 n := strings.Split(f[3], "/")
117 if len(n) != 2 || !strings.HasSuffix(n[0], ".a") || (!strings.HasSuffix(n[1], ".o") && !strings.Contains(n[1], ".so.")) {
118 p.error(syntax.Error{Pos: pos, Msg: `usage: //go:cgo_import_dynamic local [remote ["lib.a/object.o"]]`})
119 return
120 }
121 }
122 default:
123 p.error(syntax.Error{Pos: pos, Msg: `usage: //go:cgo_import_dynamic local [remote ["library"]]`})
124 return
125 }
126 case "cgo_import_static":
127 switch {
128 case len(f) == 2 && !isQuoted(f[1]):
129 default:
130 p.error(syntax.Error{Pos: pos, Msg: `usage: //go:cgo_import_static local`})
131 return
132 }
133 case "cgo_dynamic_linker":
134 switch {
135 case len(f) == 2 && isQuoted(f[1]):
136 f[1] = strings.Trim(f[1], `"`)
137 default:
138 p.error(syntax.Error{Pos: pos, Msg: `usage: //go:cgo_dynamic_linker "path"`})
139 return
140 }
141 case "cgo_ldflag":
142 switch {
143 case len(f) == 2 && isQuoted(f[1]):
144 f[1] = strings.Trim(f[1], `"`)
145 default:
146 p.error(syntax.Error{Pos: pos, Msg: `usage: //go:cgo_ldflag "arg"`})
147 return
148 }
149 default:
150 return
151 }
152 p.pragcgobuf = append(p.pragcgobuf, f)
153 }
154
155
156
157
158
159
160 func pragmaFields(s string) []string {
161 var a []string
162 inQuote := false
163 fieldStart := -1
164 for i, c := range s {
165 switch {
166 case c == '"':
167 if inQuote {
168 inQuote = false
169 a = append(a, s[fieldStart:i+1])
170 fieldStart = -1
171 } else {
172 inQuote = true
173 if fieldStart >= 0 {
174 a = append(a, s[fieldStart:i])
175 }
176 fieldStart = i
177 }
178 case !inQuote && isSpace(c):
179 if fieldStart >= 0 {
180 a = append(a, s[fieldStart:i])
181 fieldStart = -1
182 }
183 default:
184 if fieldStart == -1 {
185 fieldStart = i
186 }
187 }
188 }
189 if !inQuote && fieldStart >= 0 {
190 a = append(a, s[fieldStart:])
191 }
192 return a
193 }
194
View as plain text