{"action":"created","issue":{"url":"https://api.github.com/repos/golang/go/issues/15006","repository_url":"https://api.github.com/repos/golang/go","labels_url":"https://api.github.com/repos/golang/go/issues/15006/labels{/name}","comments_url":"https://api.github.com/repos/golang/go/issues/15006/comments","events_url":"https://api.github.com/repos/golang/go/issues/15006/events","html_url":"https://github.com/golang/go/issues/15006","id":144156717,"number":15006,"title":"cmd/compile: \"missing function body\" error when using the //go:linkname compiler directive","user":{"login":"tsuna","id":128281,"avatar_url":"https://avatars.githubusercontent.com/u/128281?v=3","gravatar_id":"","url":"https://api.github.com/users/tsuna","html_url":"https://github.com/tsuna","followers_url":"https://api.github.com/users/tsuna/followers","following_url":"https://api.github.com/users/tsuna/following{/other_user}","gists_url":"https://api.github.com/users/tsuna/gists{/gist_id}","starred_url":"https://api.github.com/users/tsuna/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/tsuna/subscriptions","organizations_url":"https://api.github.com/users/tsuna/orgs","repos_url":"https://api.github.com/users/tsuna/repos","events_url":"https://api.github.com/users/tsuna/events{/privacy}","received_events_url":"https://api.github.com/users/tsuna/received_events","type":"User","site_admin":false},"labels":[],"state":"open","locked":false,"assignee":null,"milestone":{"url":"https://api.github.com/repos/golang/go/milestones/6","html_url":"https://github.com/golang/go/milestones/Unplanned","labels_url":"https://api.github.com/repos/golang/go/milestones/6/labels","id":1055141,"number":6,"title":"Unplanned","description":"No plan to fix in any specific release.\r\n","creator":{"login":"rsc","id":104030,"avatar_url":"https://avatars.githubusercontent.com/u/104030?v=3","gravatar_id":"","url":"https://api.github.com/users/rsc","html_url":"https://github.com/rsc","followers_url":"https://api.github.com/users/rsc/followers","following_url":"https://api.github.com/users/rsc/following{/other_user}","gists_url":"https://api.github.com/users/rsc/gists{/gist_id}","starred_url":"https://api.github.com/users/rsc/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/rsc/subscriptions","organizations_url":"https://api.github.com/users/rsc/orgs","repos_url":"https://api.github.com/users/rsc/repos","events_url":"https://api.github.com/users/rsc/events{/privacy}","received_events_url":"https://api.github.com/users/rsc/received_events","type":"User","site_admin":false},"open_issues":1233,"closed_issues":306,"state":"open","created_at":"2015-04-06T20:47:19Z","updated_at":"2016-03-30T00:24:15Z","due_on":"2099-12-31T05:00:00Z","closed_at":null},"comments":3,"created_at":"2016-03-29T05:01:33Z","updated_at":"2016-03-30T16:01:49Z","closed_at":null,"body":"###### What version of Go are you using (`go version`)?\r\n\r\n`go version go1.6 darwin/amd64`\r\n`go version devel +aa3650f Wed Mar 9 09:13:43 2016 +0000 darwin/amd64`\r\n\r\n###### What operating system and processor architecture are you using (`go env`)?\r\n\r\nMac OS X 10.9.5 on Intel Core i7-3615QM\r\n\r\n```\r\nGOARCH=\"amd64\"\r\nGOHOSTARCH=\"amd64\"\r\nGOHOSTOS=\"darwin\"\r\nGOOS=\"darwin\"\r\nGOPATH=\"/Users/tsuna/go\"\r\nGOROOT=\"/usr/local/Cellar/go/1.6/libexec\"\r\nGOTOOLDIR=\"/usr/local/Cellar/go/1.6/libexec/pkg/tool/darwin_amd64\"\r\nGO15VENDOREXPERIMENT=\"1\"\r\nCC=\"clang\"\r\nGOGCCFLAGS=\"-fPIC -m64 -pthread -fno-caret-diagnostics -Qunused-arguments -fmessage-length=0 -fno-common\"\r\nCXX=\"clang++\"\r\nCGO_ENABLED=\"1\"\r\n```\r\n\r\n###### What did you do?\r\n\r\nThe Go manual on [Compiler Directives](https://golang.org/cmd/compile/#hdr-Compiler_Directives) says:\r\n> The //go:linkname directive instructs the compiler to use “importpath.name” as the object file symbol name for the variable or function declared as “localname” in the source code.\r\n\r\nFor example let's say (hypothetically) that I wanted to call the `strhash` function defined in the `runtime` package, I could do:\r\n\r\n```go\r\npackage key\r\n\r\nimport \"unsafe\"\r\n\r\n//go:linkname strhash runtime.strhash\r\nfunc strhash(a unsafe.Pointer, h uintptr) uintptr\r\n\r\nfunc hash(s string) uintptr {\r\n    return strhash(unsafe.Pointer(&s), 0)\r\n}\r\n```\r\n\r\n###### What did you expect to see?\r\n\r\nThe code above should build with no special ceremony.\r\n\r\n###### What did you see instead?\r\n\r\nThe code doesn't build for a silly reason:\r\n```\r\nstrhash.go:6: missing function body for \"strhash\"\r\n```\r\n\r\nThis comes from the fact that in `cmd/compile/internal/gc/pgen.go` we do:\r\n```go\r\n    if fn.Nbody == nil {\r\n        if pure_go != 0 || strings.HasPrefix(fn.Func.Nname.Sym.Name, \"init.\") {\r\n            Yyerror(\"missing function body for %q\", fn.Func.Nname.Sym.Name)\r\n            goto ret\r\n        }\r\n```\r\n\r\nSo in order to pass this check, we need to not have `pure_go`, which comes from the `-complete` flag in `cmd/compile/internal/gc/lex.go`:\r\n```go\r\n    obj.Flagcount(\"complete\", \"compiling complete package (no C or assembly)\", &pure_go)\r\n```\r\nwhich is passed from `cmd/go/build.go` under the following circumstances:\r\n```go\r\n    // If we're giving the compiler the entire package (no C etc files), tell it that,\r\n    // so that it can give good error messages about forward declarations.\r\n    // Exceptions: a few standard packages have forward declarations for\r\n    // pieces supplied behind-the-scenes by package runtime.\r\n    extFiles := len(p.CgoFiles) + len(p.CFiles) + len(p.CXXFiles) + len(p.MFiles) + len(p.SFiles) + len(p.SysoFiles) + len(p.SwigFiles) + len(p.SwigCXXFiles)\r\n    if p.Standard {\r\n        switch p.ImportPath {\r\n        case \"bytes\", \"net\", \"os\", \"runtime/pprof\", \"sync\", \"time\":\r\n            extFiles++\r\n        }\r\n    }\r\n    if extFiles == 0 {\r\n        gcargs = append(gcargs, \"-complete\")\r\n    }\r\n```\r\n\r\nSo one workaround to not be `-complete` is to include an empty `.s` file in the package using the `//go:linkname` directive, as this will make `len(p.SFiles)` be `1`, which in turn will make `extFiles` non-zero, so that the `-complete` flag won't get passed and we can pass the check above, and *then* the code builds and runs as expected.  Phew!"},"comment":{"url":"https://api.github.com/repos/golang/go/issues/comments/203503593","html_url":"https://github.com/golang/go/issues/15006#issuecomment-203503593","issue_url":"https://api.github.com/repos/golang/go/issues/15006","id":203503593,"user":{"login":"randall77","id":6889504,"avatar_url":"https://avatars.githubusercontent.com/u/6889504?v=3","gravatar_id":"","url":"https://api.github.com/users/randall77","html_url":"https://github.com/randall77","followers_url":"https://api.github.com/users/randall77/followers","following_url":"https://api.github.com/users/randall77/following{/other_user}","gists_url":"https://api.github.com/users/randall77/gists{/gist_id}","starred_url":"https://api.github.com/users/randall77/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/randall77/subscriptions","organizations_url":"https://api.github.com/users/randall77/orgs","repos_url":"https://api.github.com/users/randall77/repos","events_url":"https://api.github.com/users/randall77/events{/privacy}","received_events_url":"https://api.github.com/users/randall77/received_events","type":"User","site_admin":false},"created_at":"2016-03-30T16:01:49Z","updated_at":"2016-03-30T16:01:49Z","body":"I agree with Minux.  If you're looking at a Go package to import, you might want to know if it does any unsafe trickery.  Currently you have to grep for an import of unsafe and look for non-.go files.  If we got rid of the requirement for the empty .s file, then you'd have to grep for //go:linkname also."}}