cmd/internal/objabi,test: use correct GOEXPERIMENT build tags in test/run.go

Currently, run.go sets GOEXPERIMENT build tags based on the
*difference* from the baseline experiment configuration, rather than
the absolute experiment configuration. This differs from cmd/go. As a
result, if we set a baseline configuration and don't override it with
a GOEXPERIMENT setting, run.go won't set any GOEXPERIMENT build tags,
instead of setting the tags corresponding to the baseline
configuration.

Fix this by making compile -V=goexperiment produce the full
GOEXPERIMENT configuration, which run.go can then use to set exactly
the right set of build tags.

For #40724.

Change-Id: Ieda6ea62f1a1fabbe8d749d6d09c198fd5ca8377
Reviewed-on: https://go-review.googlesource.com/c/go/+/310171
Trust: Austin Clements <austin@google.com>
Run-TryBot: Austin Clements <austin@google.com>
TryBot-Result: Go Bot <gobot@golang.org>
Reviewed-by: Cherry Zhang <cherryyz@google.com>
This commit is contained in:
Austin Clements 2021-04-14 13:25:31 -04:00 committed by Russ Cox
parent cf2396c70e
commit d26fc68aa1
3 changed files with 35 additions and 25 deletions

View file

@ -108,8 +108,9 @@ func parseExperiments() goexperiment.Flags {
// expList returns the list of lower-cased experiment names for // expList returns the list of lower-cased experiment names for
// experiments that differ from base. base may be nil to indicate no // experiments that differ from base. base may be nil to indicate no
// experiments. // experiments. If all is true, then include all experiment flags,
func expList(exp, base *goexperiment.Flags) []string { // regardless of base.
func expList(exp, base *goexperiment.Flags, all bool) []string {
var list []string var list []string
rv := reflect.ValueOf(exp).Elem() rv := reflect.ValueOf(exp).Elem()
var rBase reflect.Value var rBase reflect.Value
@ -124,7 +125,7 @@ func expList(exp, base *goexperiment.Flags) []string {
if base != nil { if base != nil {
baseVal = rBase.Field(i).Bool() baseVal = rBase.Field(i).Bool()
} }
if val != baseVal { if all || val != baseVal {
if val { if val {
list = append(list, name) list = append(list, name)
} else { } else {
@ -140,11 +141,11 @@ func expList(exp, base *goexperiment.Flags) []string {
// GOEXPERIMENT is exactly what a user would set on the command line // GOEXPERIMENT is exactly what a user would set on the command line
// to get the set of enabled experiments. // to get the set of enabled experiments.
func GOEXPERIMENT() string { func GOEXPERIMENT() string {
return strings.Join(expList(&Experiment, &experimentBaseline), ",") return strings.Join(expList(&Experiment, &experimentBaseline, false), ",")
} }
// EnabledExperiments returns a list of enabled experiments, as // EnabledExperiments returns a list of enabled experiments, as
// lower-cased experiment names. // lower-cased experiment names.
func EnabledExperiments() []string { func EnabledExperiments() []string {
return expList(&Experiment, nil) return expList(&Experiment, nil, false)
} }

View file

@ -93,10 +93,16 @@ func (versionFlag) Set(s string) error {
p := "" p := ""
// If the enabled experiments differ from the defaults, if s == "goexperiment" {
// include that difference. // test/run.go uses this to discover the full set of
if goexperiment := GOEXPERIMENT(); goexperiment != "" { // experiment tags. Report everything.
p = " X:" + goexperiment p = " X:" + strings.Join(expList(&Experiment, nil, true), ",")
} else {
// If the enabled experiments differ from the defaults,
// include that difference.
if goexperiment := GOEXPERIMENT(); goexperiment != "" {
p = " X:" + goexperiment
}
} }
// The go command invokes -V=full to get a unique identifier // The go command invokes -V=full to get a unique identifier

View file

@ -376,6 +376,7 @@ type context struct {
GOARCH string GOARCH string
cgoEnabled bool cgoEnabled bool
noOptEnv bool noOptEnv bool
expTags map[string]bool // Set lazily
} }
// shouldTest looks for build tags in a source file and returns // shouldTest looks for build tags in a source file and returns
@ -445,26 +446,28 @@ func (ctxt *context) match(name string) bool {
} }
} }
exp := os.Getenv("GOEXPERIMENT") if strings.HasPrefix(name, "goexperiment.") {
if exp == "" { // Query goexperiment tags from the toolchain.
// If GOEXPERIMENT environment variable is unset, get the default value if ctxt.expTags == nil {
// that is baked into the toolchain. ctxt.expTags = make(map[string]bool)
cmd := exec.Command(goTool(), "tool", "compile", "-V") cmd := exec.Command(goTool(), "tool", "compile", "-V=goexperiment")
out, err := cmd.CombinedOutput() out, err := cmd.CombinedOutput()
if err == nil { if err != nil {
log.Fatalf("failed to get GOEXPERIMENT configuration:\n%s", out)
}
i := bytes.Index(out, []byte("X:")) i := bytes.Index(out, []byte("X:"))
if i != -1 { if i != -1 {
exp = string(out[i+2:]) for _, exp := range strings.Split(string(out[i+2:]), ",") {
} v := true
} if strings.HasPrefix(exp, "no") {
} v, exp = false, exp[2:]
if exp != "" { }
experiments := strings.Split(exp, ",") ctxt.expTags["goexperiment."+exp] = v
for _, e := range experiments { }
if name == "goexperiment."+e {
return true
} }
} }
return ctxt.expTags[name]
} }
if name == "cgo" && ctxt.cgoEnabled { if name == "cgo" && ctxt.cgoEnabled {