pkg      string
        commands map[string][]string
        lineNum  int // current line number.
+       env      []string
 }
 
 // run runs the generators in the current file.
                        }
                }
 
+               g.setEnv()
                words := g.split(string(buf))
                if len(words) == 0 {
                        g.errorf("no arguments to directive")
        return bytes.HasPrefix(buf, []byte("//go:generate ")) || bytes.HasPrefix(buf, []byte("//go:generate\t"))
 }
 
+// setEnv sets the extra environment variables used when executing a
+// single go:generate command.
+func (g *Generator) setEnv() {
+       g.env = []string{
+               "GOARCH=" + runtime.GOARCH,
+               "GOOS=" + runtime.GOOS,
+               "GOFILE=" + g.file,
+               "GOLINE=" + strconv.Itoa(g.lineNum),
+               "GOPACKAGE=" + g.pkg,
+               "DOLLAR=" + "$",
+       }
+}
+
 // split breaks the line into words, evaluating quoted
 // strings and evaluating environment variables.
 // The initial //go:generate element is present in line.
 // expandVar expands the $XXX invocation in word. It is called
 // by os.Expand.
 func (g *Generator) expandVar(word string) string {
-       switch word {
-       case "GOARCH":
-               return buildContext.GOARCH
-       case "GOOS":
-               return buildContext.GOOS
-       case "GOFILE":
-               return g.file
-       case "GOLINE":
-               return fmt.Sprint(g.lineNum)
-       case "GOPACKAGE":
-               return g.pkg
-       case "DOLLAR":
-               return "$"
-       default:
-               return os.Getenv(word)
+       w := word + "="
+       for _, e := range g.env {
+               if strings.HasPrefix(e, w) {
+                       return e[len(w):]
+               }
        }
+       return os.Getenv(word)
 }
 
 // identLength returns the length of the identifier beginning the string.
        cmd.Stderr = os.Stderr
        // Run the command in the package directory.
        cmd.Dir = g.dir
-       env := []string{
-               "GOARCH=" + runtime.GOARCH,
-               "GOOS=" + runtime.GOOS,
-               "GOFILE=" + g.file,
-               "GOPACKAGE=" + g.pkg,
-       }
-       cmd.Env = mergeEnvLists(env, origEnv)
+       cmd.Env = mergeEnvLists(g.env, origEnv)
        err := cmd.Run()
        if err != nil {
                g.errorf("running %q: %s", words[0], err)
 
        tg.grepStdoutNot("no", "go generate -run yes ./testdata/generate/test4.go selected no")
 }
 
+func TestGoGenerateEnv(t *testing.T) {
+       if runtime.GOOS == "windows" {
+               t.Skip("skipping because windows does not have the env command")
+       }
+       tg := testgo(t)
+       defer tg.cleanup()
+       tg.parallel()
+       tg.tempFile("env.go", "package main\n\n//go:generate env")
+       tg.run("generate", tg.path("env.go"))
+       for _, v := range []string{"GOARCH", "GOOS", "GOFILE", "GOLINE", "GOPACKAGE", "DOLLAR"} {
+               tg.grepStdout("^"+v+"=", "go generate environment missing "+v)
+       }
+}
+
 func TestGoGetCustomDomainWildcard(t *testing.T) {
        testenv.MustHaveExternalNetwork(t)