@@ -273,129 +273,132 @@ func (c *compilerContext) parsePragmas(info *functionInfo, f *ssa.Function) {
273
273
if syntax == nil {
274
274
return
275
275
}
276
+
277
+ // Read all pragmas of this function.
278
+ var pragmas []* ast.Comment
279
+ hasWasmExport := false
276
280
if decl , ok := syntax .(* ast.FuncDecl ); ok && decl .Doc != nil {
277
281
for _ , comment := range decl .Doc .List {
278
282
text := comment .Text
279
- if strings .HasPrefix (text , "//export " ) {
280
- // Rewrite '//export' to '//go:export' for compatibility with
281
- // gc.
282
- text = "//go:" + text [2 :]
283
+ if strings .HasPrefix (text , "//go:" ) || strings .HasPrefix (text , "//export " ) {
284
+ pragmas = append (pragmas , comment )
285
+ if strings .HasPrefix (comment .Text , "//go:wasmexport " ) {
286
+ hasWasmExport = true
287
+ }
283
288
}
284
- if ! strings .HasPrefix (text , "//go:" ) {
289
+ }
290
+ }
291
+
292
+ // Parse each pragma.
293
+ for _ , comment := range pragmas {
294
+ parts := strings .Fields (comment .Text )
295
+ switch parts [0 ] {
296
+ case "//export" , "//go:export" :
297
+ if len (parts ) != 2 {
298
+ continue
299
+ }
300
+ if hasWasmExport {
301
+ // //go:wasmexport overrides //export.
285
302
continue
286
303
}
287
- parts := strings .Fields (text )
288
- switch parts [0 ] {
289
- case "//go:export" :
290
- if len (parts ) != 2 {
291
- continue
292
- }
293
304
294
- info .linkName = parts [1 ]
295
- info .wasmName = info .linkName
296
- info .exported = true
297
- case "//go:interrupt" :
298
- if hasUnsafeImport (f .Pkg .Pkg ) {
299
- info .interrupt = true
300
- }
301
- case "//go:wasm-module" :
302
- // Alternative comment for setting the import module.
303
- // This is deprecated, use //go:wasmimport instead.
304
- if len (parts ) != 2 {
305
- continue
306
- }
307
- info .wasmModule = parts [1 ]
308
- case "//go:wasmimport" :
309
- // Import a WebAssembly function, for example a WASI function.
310
- // Original proposal: https://github.com/golang/go/issues/38248
311
- // Allow globally: https://github.com/golang/go/issues/59149
312
- if len (parts ) != 3 {
313
- continue
314
- }
315
- if f .Blocks != nil {
316
- // Defined functions cannot be exported.
317
- c .addError (f .Pos (), "can only use //go:wasmimport on declarations" )
318
- continue
319
- }
320
- c .checkWasmImportExport (f , comment .Text )
321
- info .exported = true
322
- info .wasmModule = parts [1 ]
323
- info .wasmName = parts [2 ]
324
- case "//go:wasmexport" :
325
- if f .Blocks == nil {
326
- c .addError (f .Pos (), "can only use //go:wasmexport on definitions" )
327
- continue
328
- }
329
- if len (parts ) != 2 {
330
- c .addError (f .Pos (), fmt .Sprintf ("expected one parameter to //go:wasmimport, not %d" , len (parts )- 1 ))
331
- continue
332
- }
333
- name := parts [1 ]
334
- if name == "_start" || name == "_initialize" {
335
- c .addError (f .Pos (), fmt .Sprintf ("//go:wasmexport does not allow %#v" , name ))
336
- continue
337
- }
338
- if c .BuildMode != "c-shared" && f .RelString (nil ) == "main.main" {
339
- c .addError (f .Pos (), fmt .Sprintf ("//go:wasmexport does not allow main.main to be exported with -buildmode=%s" , c .BuildMode ))
340
- continue
341
- }
342
- if c .archFamily () != "wasm32" {
343
- c .addError (f .Pos (), "//go:wasmexport is only supported on wasm" )
344
- }
345
- c .checkWasmImportExport (f , comment .Text )
346
- info .wasmExport = name
347
- info .wasmExportPos = comment .Slash
348
- case "//go:inline" :
349
- info .inline = inlineHint
350
- case "//go:noinline" :
305
+ info .linkName = parts [1 ]
306
+ info .wasmName = info .linkName
307
+ info .exported = true
308
+ case "//go:interrupt" :
309
+ if hasUnsafeImport (f .Pkg .Pkg ) {
310
+ info .interrupt = true
311
+ }
312
+ case "//go:wasm-module" :
313
+ // Alternative comment for setting the import module.
314
+ // This is deprecated, use //go:wasmimport instead.
315
+ if len (parts ) != 2 {
316
+ continue
317
+ }
318
+ info .wasmModule = parts [1 ]
319
+ case "//go:wasmimport" :
320
+ // Import a WebAssembly function, for example a WASI function.
321
+ // Original proposal: https://github.com/golang/go/issues/38248
322
+ // Allow globally: https://github.com/golang/go/issues/59149
323
+ if len (parts ) != 3 {
324
+ continue
325
+ }
326
+ if f .Blocks != nil {
327
+ // Defined functions cannot be exported.
328
+ c .addError (f .Pos (), "can only use //go:wasmimport on declarations" )
329
+ continue
330
+ }
331
+ c .checkWasmImportExport (f , comment .Text )
332
+ info .exported = true
333
+ info .wasmModule = parts [1 ]
334
+ info .wasmName = parts [2 ]
335
+ case "//go:wasmexport" :
336
+ if f .Blocks == nil {
337
+ c .addError (f .Pos (), "can only use //go:wasmexport on definitions" )
338
+ continue
339
+ }
340
+ if len (parts ) != 2 {
341
+ c .addError (f .Pos (), fmt .Sprintf ("expected one parameter to //go:wasmimport, not %d" , len (parts )- 1 ))
342
+ continue
343
+ }
344
+ name := parts [1 ]
345
+ if name == "_start" || name == "_initialize" {
346
+ c .addError (f .Pos (), fmt .Sprintf ("//go:wasmexport does not allow %#v" , name ))
347
+ continue
348
+ }
349
+ if c .BuildMode != "c-shared" && f .RelString (nil ) == "main.main" {
350
+ c .addError (f .Pos (), fmt .Sprintf ("//go:wasmexport does not allow main.main to be exported with -buildmode=%s" , c .BuildMode ))
351
+ continue
352
+ }
353
+ if c .archFamily () != "wasm32" {
354
+ c .addError (f .Pos (), "//go:wasmexport is only supported on wasm" )
355
+ }
356
+ c .checkWasmImportExport (f , comment .Text )
357
+ info .wasmExport = name
358
+ info .wasmExportPos = comment .Slash
359
+ case "//go:inline" :
360
+ info .inline = inlineHint
361
+ case "//go:noinline" :
362
+ info .inline = inlineNone
363
+ case "//go:linkname" :
364
+ if len (parts ) != 3 || parts [1 ] != f .Name () {
365
+ continue
366
+ }
367
+ // Only enable go:linkname when the package imports "unsafe".
368
+ // This is a slightly looser requirement than what gc uses: gc
369
+ // requires the file to import "unsafe", not the package as a
370
+ // whole.
371
+ if hasUnsafeImport (f .Pkg .Pkg ) {
372
+ info .linkName = parts [2 ]
373
+ }
374
+ case "//go:section" :
375
+ // Only enable go:section when the package imports "unsafe".
376
+ // go:section also implies go:noinline since inlining could
377
+ // move the code to a different section than that requested.
378
+ if len (parts ) == 2 && hasUnsafeImport (f .Pkg .Pkg ) {
379
+ info .section = parts [1 ]
351
380
info .inline = inlineNone
352
- case "//go:linkname" :
353
- if len (parts ) != 3 || parts [1 ] != f .Name () {
354
- continue
355
- }
356
- // Only enable go:linkname when the package imports "unsafe".
357
- // This is a slightly looser requirement than what gc uses: gc
358
- // requires the file to import "unsafe", not the package as a
359
- // whole.
360
- if hasUnsafeImport (f .Pkg .Pkg ) {
361
- info .linkName = parts [2 ]
362
- }
363
- case "//go:section" :
364
- // Only enable go:section when the package imports "unsafe".
365
- // go:section also implies go:noinline since inlining could
366
- // move the code to a different section than that requested.
367
- if len (parts ) == 2 && hasUnsafeImport (f .Pkg .Pkg ) {
368
- info .section = parts [1 ]
369
- info .inline = inlineNone
370
- }
371
- case "//go:nobounds" :
372
- // Skip bounds checking in this function. Useful for some
373
- // runtime functions.
374
- // This is somewhat dangerous and thus only imported in packages
375
- // that import unsafe.
376
- if hasUnsafeImport (f .Pkg .Pkg ) {
377
- info .nobounds = true
378
- }
379
- case "//go:variadic" :
380
- // The //go:variadic pragma is emitted by the CGo preprocessing
381
- // pass for C variadic functions. This includes both explicit
382
- // (with ...) and implicit (no parameters in signature)
383
- // functions.
384
- if strings .HasPrefix (f .Name (), "C." ) {
385
- // This prefix cannot naturally be created, it must have
386
- // been created as a result of CGo preprocessing.
387
- info .variadic = true
388
- }
381
+ }
382
+ case "//go:nobounds" :
383
+ // Skip bounds checking in this function. Useful for some
384
+ // runtime functions.
385
+ // This is somewhat dangerous and thus only imported in packages
386
+ // that import unsafe.
387
+ if hasUnsafeImport (f .Pkg .Pkg ) {
388
+ info .nobounds = true
389
+ }
390
+ case "//go:variadic" :
391
+ // The //go:variadic pragma is emitted by the CGo preprocessing
392
+ // pass for C variadic functions. This includes both explicit
393
+ // (with ...) and implicit (no parameters in signature)
394
+ // functions.
395
+ if strings .HasPrefix (f .Name (), "C." ) {
396
+ // This prefix cannot naturally be created, it must have
397
+ // been created as a result of CGo preprocessing.
398
+ info .variadic = true
389
399
}
390
400
}
391
401
}
392
-
393
- // If both //go:wasmexport and //go:export or //export are declared,
394
- // only honor go:wasmexport.
395
- if info .wasmExport != "" {
396
- // TODO: log warning?
397
- info .exported = false
398
- }
399
402
}
400
403
401
404
// Check whether this function can be used in //go:wasmimport or
0 commit comments