src/cmd/compile/internal/base/flag.go GO 613 lines View on github.com → Search inside
1// Copyright 2009 The Go Authors. All rights reserved.2// Use of this source code is governed by a BSD-style3// license that can be found in the LICENSE file.45package base67import (8	"cmd/internal/cov/covcmd"9	"cmd/internal/telemetry/counter"10	"encoding/json"11	"flag"12	"fmt"13	"internal/buildcfg"14	"internal/platform"15	"log"16	"os"17	"reflect"18	"runtime"19	"strings"2021	"cmd/internal/obj"22	"cmd/internal/objabi"23	"cmd/internal/sys"24)2526func usage() {27	fmt.Fprintf(os.Stderr, "usage: compile [options] file.go...\n")28	objabi.Flagprint(os.Stderr)29	Exit(2)30}3132// Flag holds the parsed command-line flags.33// See ParseFlag for non-zero defaults.34var Flag CmdFlags3536// A CountFlag is a counting integer flag.37// It accepts -name=value to set the value directly,38// but it also accepts -name with no =value to increment the count.39type CountFlag int4041// CmdFlags defines the command-line flags (see var Flag).42// Each struct field is a different flag, by default named for the lower-case of the field name.43// If the flag name is a single letter, the default flag name is left upper-case.44// If the flag name is "Lower" followed by a single letter, the default flag name is the lower-case of the last letter.45//46// If this default flag name can't be made right, the `flag` struct tag can be used to replace it,47// but this should be done only in exceptional circumstances: it helps everyone if the flag name48// is obvious from the field name when the flag is used elsewhere in the compiler sources.49// The `flag:"-"` struct tag makes a field invisible to the flag logic and should also be used sparingly.50//51// Each field must have a `help` struct tag giving the flag help message.52//53// The allowed field types are bool, int, string, pointers to those (for values stored elsewhere),54// CountFlag (for a counting flag), and func(string) (for a flag that uses special code for parsing).55type CmdFlags struct {56	// Single letters57	B CountFlag    "help:\"disable bounds checking\""58	C CountFlag    "help:\"disable printing of columns in error messages\""59	D string       "help:\"set relative `path` for local imports\""60	E CountFlag    "help:\"debug symbol export\""61	I func(string) "help:\"add `directory` to import search path\""62	K CountFlag    "help:\"debug missing line numbers\""63	L CountFlag    "help:\"also show actual source file names in error messages for positions affected by //line directives\""64	N CountFlag    "help:\"disable optimizations\""65	S CountFlag    "help:\"print assembly listing\""66	// V is added by objabi.AddVersionFlag67	W CountFlag "help:\"debug parse tree after type checking\""6869	LowerC int        "help:\"concurrency during compilation (1 means no concurrency)\""70	LowerD flag.Value "help:\"enable debugging settings; try -d help\""71	LowerE CountFlag  "help:\"no limit on number of errors reported\""72	LowerH CountFlag  "help:\"halt on error\""73	LowerJ CountFlag  "help:\"debug runtime-initialized variables\""74	LowerL CountFlag  "help:\"disable inlining\""75	LowerM CountFlag  "help:\"print optimization decisions\""76	LowerO string     "help:\"write output to `file`\""77	LowerP *string    "help:\"set expected package import `path`\"" // &Ctxt.Pkgpath, set below78	LowerR CountFlag  "help:\"debug generated wrappers\""79	LowerT bool       "help:\"enable tracing for debugging the compiler\""80	LowerW CountFlag  "help:\"debug type checking\""81	LowerU CountFlag  "help:\"emit unsorted warnings/errors\""82	LowerV *bool      "help:\"increase debug verbosity\""8384	// Special characters85	Percent          CountFlag "flag:\"%\" help:\"debug non-static initializers\""86	CompilingRuntime bool      "flag:\"+\" help:\"compiling runtime\""8788	// Longer names89	AsmHdr             string       "help:\"write assembly header to `file`\""90	ASan               bool         "help:\"build code compatible with C/C++ address sanitizer\""91	Bench              string       "help:\"append benchmark times to `file`\""92	BlockProfile       string       "help:\"write block profile to `file`\""93	BuildID            string       "help:\"record `id` as the build id in the export metadata\""94	CPUProfile         string       "help:\"write cpu profile to `file`\""95	Complete           bool         "help:\"compiling complete package (no C or assembly)\""96	ClobberDead        bool         "help:\"clobber dead stack slots (for debugging)\""97	ClobberDeadReg     bool         "help:\"clobber dead registers (for debugging)\""98	Dwarf              bool         "help:\"generate DWARF symbols\""99	DwarfBASEntries    *bool        "help:\"use base address selection entries in DWARF\""                        // &Ctxt.UseBASEntries, set below100	DwarfLocationLists *bool        "help:\"add location lists to DWARF in optimized mode\""                      // &Ctxt.Flag_locationlists, set below101	Dynlink            *bool        "help:\"support references to Go symbols defined in other shared libraries\"" // &Ctxt.Flag_dynlink, set below102	EmbedCfg           func(string) "help:\"read go:embed configuration from `file`\""103	Env                func(string) "help:\"add `definition` of the form key=value to environment\""104	GenDwarfInl        int          "help:\"generate DWARF inline info records\"" // 0=disabled, 1=funcs, 2=funcs+formals/locals105	GoVersion          string       "help:\"required version of the runtime\""106	ImportCfg          func(string) "help:\"read import configuration from `file`\""107	InstallSuffix      string       "help:\"set pkg directory `suffix`\""108	JSON               string       "help:\"version,file for JSON compiler/optimizer detail output\""109	Lang               string       "help:\"Go language version source code expects\""110	LinkObj            string       "help:\"write linker-specific object to `file`\""111	LinkShared         *bool        "help:\"generate code that will be linked against Go shared libraries\"" // &Ctxt.Flag_linkshared, set below112	Live               CountFlag    "help:\"debug liveness analysis\""113	MSan               bool         "help:\"build code compatible with C/C++ memory sanitizer\""114	MemProfile         string       "help:\"write memory profile to `file`\""115	MemProfileRate     int          "help:\"set runtime.MemProfileRate to `rate`\""116	MutexProfile       string       "help:\"write mutex profile to `file`\""117	NoLocalImports     bool         "help:\"reject local (relative) imports\""118	CoverageCfg        func(string) "help:\"read coverage configuration from `file`\""119	Pack               bool         "help:\"write to file.a instead of file.o\""120	Race               bool         "help:\"enable race detector\""121	Shared             *bool        "help:\"generate code that can be linked into a shared library\"" // &Ctxt.Flag_shared, set below122	SmallFrames        bool         "help:\"reduce the size limit for stack allocated objects\""      // small stacks, to diagnose GC latency; see golang.org/issue/27732123	Spectre            string       "help:\"enable spectre mitigations in `list` (all, index, ret)\""124	Std                bool         "help:\"compiling standard library\""125	SymABIs            string       "help:\"read symbol ABIs from `file`\""126	TraceProfile       string       "help:\"write an execution trace to `file`\""127	TrimPath           string       "help:\"remove `prefix` from recorded source file paths\""128	WB                 bool         "help:\"enable write barrier\"" // TODO: remove129	PgoProfile         string       "help:\"read profile or pre-process profile from `file`\""130	ErrorURL           bool         "help:\"print explanatory URL with error message if applicable\""131132	// Configuration derived from flags; not a flag itself.133	Cfg struct {134		Embed struct { // set by -embedcfg135			Patterns map[string][]string136			Files    map[string]string137		}138		ImportDirs   []string                 // appended to by -I139		ImportMap    map[string]string        // set by -importcfg140		PackageFile  map[string]string        // set by -importcfg; nil means not in use141		CoverageInfo *covcmd.CoverFixupConfig // set by -coveragecfg142		SpectreIndex bool                     // set by -spectre=index or -spectre=all143		// Whether we are adding any sort of code instrumentation, such as144		// when the race detector is enabled.145		Instrumenting bool146	}147}148149func addEnv(s string) {150	i := strings.Index(s, "=")151	if i < 0 {152		log.Fatal("-env argument must be of the form key=value")153	}154	os.Setenv(s[:i], s[i+1:])155}156157// ParseFlags parses the command-line flags into Flag.158func ParseFlags() {159	Flag.I = addImportDir160161	Flag.LowerC = runtime.GOMAXPROCS(0)162	Flag.LowerD = objabi.NewDebugFlag(&Debug, DebugSSA)163	Flag.LowerP = &Ctxt.Pkgpath164	Flag.LowerV = &Ctxt.Debugvlog165166	Flag.Dwarf = buildcfg.GOARCH != "wasm"167	Flag.DwarfBASEntries = &Ctxt.UseBASEntries168	Flag.DwarfLocationLists = &Ctxt.Flag_locationlists169	*Flag.DwarfLocationLists = true170	Flag.Dynlink = &Ctxt.Flag_dynlink171	Flag.EmbedCfg = readEmbedCfg172	Flag.Env = addEnv173	Flag.GenDwarfInl = 2174	Flag.ImportCfg = readImportCfg175	Flag.CoverageCfg = readCoverageCfg176	Flag.LinkShared = &Ctxt.Flag_linkshared177	Flag.Shared = &Ctxt.Flag_shared178	Flag.WB = true179180	Debug.ConcurrentOk = true181	Debug.CompressInstructions = 1182	Debug.MaxShapeLen = 500183	Debug.AlignHot = 1184	Debug.InlFuncsWithClosures = 1185	Debug.InlStaticInit = 1186	Debug.FreeAppend = 1187	Debug.PGOInline = 1188	Debug.PGODevirtualize = 2189	Debug.SyncFrames = -1            // disable sync markers by default190	Debug.VariableMakeThreshold = 32 // 32 byte default for stack allocated make results191	Debug.ZeroCopy = 1192	Debug.RangeFuncCheck = 1193	Debug.MergeLocals = 1194	Debug.RewriteResults = 1195196	Debug.Checkptr = -1 // so we can tell whether it is set explicitly197198	Flag.Cfg.ImportMap = make(map[string]string)199200	objabi.AddVersionFlag() // -V201	registerFlags()202	objabi.Flagparse(usage)203	counter.CountFlags("compile/flag:", *flag.CommandLine)204205	if gcd := os.Getenv("GOCOMPILEDEBUG"); gcd != "" {206		// This will only override the flags set in gcd;207		// any others set on the command line remain set.208		Flag.LowerD.Set(gcd)209	}210211	if Debug.Gossahash != "" {212		hashDebug = NewHashDebug("gossahash", Debug.Gossahash, nil)213	}214	obj.SetFIPSDebugHash(Debug.FIPSHash)215216	// Compute whether we're compiling the runtime from the package path. Test217	// code can also use the flag to set this explicitly.218	if Flag.Std && objabi.LookupPkgSpecial(Ctxt.Pkgpath).Runtime {219		Flag.CompilingRuntime = true220	}221222	Ctxt.Std = Flag.Std223224	// Three inputs govern loop iteration variable rewriting, hash, experiment, flag.225	// The loop variable rewriting is:226	// IF non-empty hash, then hash determines behavior (function+line match) (*)227	// ELSE IF experiment and flag==0, then experiment (set flag=1)228	// ELSE flag (note that build sets flag per-package), with behaviors:229	//  -1 => no change to behavior.230	//   0 => no change to behavior (unless non-empty hash, see above)231	//   1 => apply change to likely-iteration-variable-escaping loops232	//   2 => apply change, log results233	//   11 => apply change EVERYWHERE, do not log results (for debugging/benchmarking)234	//   12 => apply change EVERYWHERE, log results (for debugging/benchmarking)235	//236	// The expected uses of the these inputs are, in believed most-likely to least likely:237	//  GOEXPERIMENT=loopvar -- apply change to entire application238	//  -gcflags=some_package=-d=loopvar=1 -- apply change to some_package (**)239	//  -gcflags=some_package=-d=loopvar=2 -- apply change to some_package, log it240	//  GOEXPERIMENT=loopvar -gcflags=some_package=-d=loopvar=-1 -- apply change to all but one package241	//  GOCOMPILEDEBUG=loopvarhash=... -- search for failure cause242	//243	//  (*) For debugging purposes, providing loopvar flag >= 11 will expand the hash-eligible set of loops to all.244	// (**) Loop semantics, changed or not, follow code from a package when it is inlined; that is, the behavior245	//      of an application compiled with partially modified loop semantics does not depend on inlining.246247	if Debug.LoopVarHash != "" {248		// This first little bit controls the inputs for debug-hash-matching.249		mostInlineOnly := true250		if strings.HasPrefix(Debug.LoopVarHash, "IL") {251			// When hash-searching on a position that is an inline site, default is to use the252			// most-inlined position only.  This makes the hash faster, plus there's no point253			// reporting a problem with all the inlining; there's only one copy of the source.254			// However, if for some reason you wanted it per-site, you can get this.  (The default255			// hash-search behavior for compiler debugging is at an inline site.)256			Debug.LoopVarHash = Debug.LoopVarHash[2:]257			mostInlineOnly = false258		}259		// end of testing trickiness260		LoopVarHash = NewHashDebug("loopvarhash", Debug.LoopVarHash, nil)261		if Debug.LoopVar < 11 { // >= 11 means all loops are rewrite-eligible262			Debug.LoopVar = 1 // 1 means those loops that syntactically escape their dcl vars are eligible.263		}264		LoopVarHash.SetInlineSuffixOnly(mostInlineOnly)265	} else if buildcfg.Experiment.LoopVar && Debug.LoopVar == 0 {266		Debug.LoopVar = 1267	}268269	if Debug.Converthash != "" {270		ConvertHash = NewHashDebug("converthash", Debug.Converthash, nil)271	} else {272		// quietly disable the convert hash changes273		ConvertHash = NewHashDebug("converthash", "qn", nil)274	}275	if Debug.Fmahash != "" {276		FmaHash = NewHashDebug("fmahash", Debug.Fmahash, nil)277	}278	if Debug.PGOHash != "" {279		PGOHash = NewHashDebug("pgohash", Debug.PGOHash, nil)280	}281	if Debug.LiteralAllocHash != "" {282		LiteralAllocHash = NewHashDebug("literalalloc", Debug.LiteralAllocHash, nil)283	}284285	if Debug.MergeLocalsHash != "" {286		MergeLocalsHash = NewHashDebug("mergelocals", Debug.MergeLocalsHash, nil)287	}288	if Debug.VariableMakeHash != "" {289		VariableMakeHash = NewHashDebug("variablemake", Debug.VariableMakeHash, nil)290	}291292	if Flag.MSan && !platform.MSanSupported(buildcfg.GOOS, buildcfg.GOARCH) {293		log.Fatalf("%s/%s does not support -msan", buildcfg.GOOS, buildcfg.GOARCH)294	}295	if Flag.ASan && !platform.ASanSupported(buildcfg.GOOS, buildcfg.GOARCH) {296		log.Fatalf("%s/%s does not support -asan", buildcfg.GOOS, buildcfg.GOARCH)297	}298	if Flag.Race && !platform.RaceDetectorSupported(buildcfg.GOOS, buildcfg.GOARCH) {299		log.Fatalf("%s/%s does not support -race", buildcfg.GOOS, buildcfg.GOARCH)300	}301	if (*Flag.Shared || *Flag.Dynlink || *Flag.LinkShared) && !Ctxt.Arch.InFamily(sys.AMD64, sys.ARM, sys.ARM64, sys.I386, sys.Loong64, sys.MIPS64, sys.PPC64, sys.RISCV64, sys.S390X) {302		log.Fatalf("%s/%s does not support -shared", buildcfg.GOOS, buildcfg.GOARCH)303	}304	parseSpectre(Flag.Spectre) // left as string for RecordFlags305306	Ctxt.CompressInstructions = Debug.CompressInstructions != 0307	Ctxt.Flag_shared = Ctxt.Flag_dynlink || Ctxt.Flag_shared308	Ctxt.Flag_optimize = Flag.N == 0309	Ctxt.Debugasm = int(Flag.S)310	Ctxt.Flag_maymorestack = Debug.MayMoreStack311	Ctxt.Flag_noRefName = Debug.NoRefName != 0312313	if flag.NArg() < 1 {314		usage()315	}316317	if Flag.GoVersion != "" && Flag.GoVersion != runtime.Version() {318		fmt.Printf("compile: version %q does not match go tool version %q\n", runtime.Version(), Flag.GoVersion)319		Exit(2)320	}321322	if *Flag.LowerP == "" {323		*Flag.LowerP = obj.UnlinkablePkg324	}325326	if Flag.LowerO == "" {327		p := flag.Arg(0)328		if i := strings.LastIndex(p, "/"); i >= 0 {329			p = p[i+1:]330		}331		if runtime.GOOS == "windows" {332			if i := strings.LastIndex(p, `\`); i >= 0 {333				p = p[i+1:]334			}335		}336		if i := strings.LastIndex(p, "."); i >= 0 {337			p = p[:i]338		}339		suffix := ".o"340		if Flag.Pack {341			suffix = ".a"342		}343		Flag.LowerO = p + suffix344	}345	switch {346	case Flag.Race && Flag.MSan:347		log.Fatal("cannot use both -race and -msan")348	case Flag.Race && Flag.ASan:349		log.Fatal("cannot use both -race and -asan")350	case Flag.MSan && Flag.ASan:351		log.Fatal("cannot use both -msan and -asan")352	}353	if Flag.Race || Flag.MSan || Flag.ASan {354		// -race, -msan and -asan imply -d=checkptr for now.355		if Debug.Checkptr == -1 { // if not set explicitly356			Debug.Checkptr = 1357		}358	}359360	if Flag.LowerC < 1 {361		log.Fatalf("-c must be at least 1, got %d", Flag.LowerC)362	}363	if !concurrentBackendAllowed() {364		Flag.LowerC = 1365	}366367	if Flag.CompilingRuntime {368		// It is not possible to build the runtime with no optimizations,369		// because the compiler cannot eliminate enough write barriers.370		Flag.N = 0371		Ctxt.Flag_optimize = true372373		// Runtime can't use -d=checkptr, at least not yet.374		Debug.Checkptr = 0375376		// Fuzzing the runtime isn't interesting either.377		Debug.Libfuzzer = 0378	}379380	if len(Flag.Cfg.ImportDirs) > 0 && Flag.Cfg.PackageFile != nil {381		log.Fatalf("cannot use both -I and -importcfg")382	}383384	if Debug.Checkptr == -1 { // if not set explicitly385		Debug.Checkptr = 0386	}387388	// set via a -d flag389	Ctxt.Debugpcln = Debug.PCTab390391	// https://golang.org/issue/67502392	if buildcfg.GOOS == "plan9" && buildcfg.GOARCH == "386" {393		Debug.AlignHot = 0394	}395}396397// registerFlags adds flag registrations for all the fields in Flag.398// See the comment on type CmdFlags for the rules.399func registerFlags() {400	var (401		boolType      = reflect.TypeFor[bool]()402		intType       = reflect.TypeFor[int]()403		stringType    = reflect.TypeFor[string]()404		ptrBoolType   = reflect.TypeFor[*bool]()405		ptrIntType    = reflect.TypeFor[*int]()406		ptrStringType = reflect.TypeFor[*string]()407		countType     = reflect.TypeFor[CountFlag]()408		funcType      = reflect.TypeFor[func(string)]()409	)410411	v := reflect.ValueOf(&Flag).Elem()412	t := v.Type()413	for i := 0; i < t.NumField(); i++ {414		f := t.Field(i)415		if f.Name == "Cfg" {416			continue417		}418419		var name string420		if len(f.Name) == 1 {421			name = f.Name422		} else if len(f.Name) == 6 && f.Name[:5] == "Lower" && 'A' <= f.Name[5] && f.Name[5] <= 'Z' {423			name = string(rune(f.Name[5] + 'a' - 'A'))424		} else {425			name = strings.ToLower(f.Name)426		}427		if tag := f.Tag.Get("flag"); tag != "" {428			name = tag429		}430431		help := f.Tag.Get("help")432		if help == "" {433			panic(fmt.Sprintf("base.Flag.%s is missing help text", f.Name))434		}435436		if k := f.Type.Kind(); (k == reflect.Ptr || k == reflect.Func) && v.Field(i).IsNil() {437			panic(fmt.Sprintf("base.Flag.%s is uninitialized %v", f.Name, f.Type))438		}439440		switch f.Type {441		case boolType:442			p := v.Field(i).Addr().Interface().(*bool)443			flag.BoolVar(p, name, *p, help)444		case intType:445			p := v.Field(i).Addr().Interface().(*int)446			flag.IntVar(p, name, *p, help)447		case stringType:448			p := v.Field(i).Addr().Interface().(*string)449			flag.StringVar(p, name, *p, help)450		case ptrBoolType:451			p := v.Field(i).Interface().(*bool)452			flag.BoolVar(p, name, *p, help)453		case ptrIntType:454			p := v.Field(i).Interface().(*int)455			flag.IntVar(p, name, *p, help)456		case ptrStringType:457			p := v.Field(i).Interface().(*string)458			flag.StringVar(p, name, *p, help)459		case countType:460			p := (*int)(v.Field(i).Addr().Interface().(*CountFlag))461			objabi.Flagcount(name, help, p)462		case funcType:463			f := v.Field(i).Interface().(func(string))464			objabi.Flagfn1(name, help, f)465		default:466			if val, ok := v.Field(i).Interface().(flag.Value); ok {467				flag.Var(val, name, help)468			} else {469				panic(fmt.Sprintf("base.Flag.%s has unexpected type %s", f.Name, f.Type))470			}471		}472	}473}474475// concurrentFlagOk reports whether the current compiler flags476// are compatible with concurrent compilation.477func concurrentFlagOk() bool {478	// TODO(rsc): Many of these are fine. Remove them.479	return Flag.Percent == 0 &&480		Flag.E == 0 &&481		Flag.K == 0 &&482		Flag.L == 0 &&483		Flag.LowerJ == 0 &&484		Flag.LowerM == 0 &&485		Flag.LowerR == 0486}487488func concurrentBackendAllowed() bool {489	if !concurrentFlagOk() {490		return false491	}492493	// Debug.S by itself is ok, because all printing occurs494	// while writing the object file, and that is non-concurrent.495	// Adding Debug_vlog, however, causes Debug.S to also print496	// while flushing the plist, which happens concurrently.497	if Ctxt.Debugvlog || !Debug.ConcurrentOk || Flag.Live > 0 {498		return false499	}500	// TODO: Test and delete this condition.501	if buildcfg.Experiment.FieldTrack {502		return false503	}504	// TODO: fix races and enable the following flags505	if Ctxt.Flag_dynlink || Flag.Race {506		return false507	}508	return true509}510511func addImportDir(dir string) {512	if dir != "" {513		Flag.Cfg.ImportDirs = append(Flag.Cfg.ImportDirs, dir)514	}515}516517func readImportCfg(file string) {518	if Flag.Cfg.ImportMap == nil {519		Flag.Cfg.ImportMap = make(map[string]string)520	}521	Flag.Cfg.PackageFile = map[string]string{}522	data, err := os.ReadFile(file)523	if err != nil {524		log.Fatalf("-importcfg: %v", err)525	}526527	for lineNum, line := range strings.Split(string(data), "\n") {528		lineNum++ // 1-based529		line = strings.TrimSpace(line)530		if line == "" || strings.HasPrefix(line, "#") {531			continue532		}533534		verb, args, found := strings.Cut(line, " ")535		if found {536			args = strings.TrimSpace(args)537		}538		before, after, hasEq := strings.Cut(args, "=")539540		switch verb {541		default:542			log.Fatalf("%s:%d: unknown directive %q", file, lineNum, verb)543		case "importmap":544			if !hasEq || before == "" || after == "" {545				log.Fatalf(`%s:%d: invalid importmap: syntax is "importmap old=new"`, file, lineNum)546			}547			Flag.Cfg.ImportMap[before] = after548		case "packagefile":549			if !hasEq || before == "" || after == "" {550				log.Fatalf(`%s:%d: invalid packagefile: syntax is "packagefile path=filename"`, file, lineNum)551			}552			Flag.Cfg.PackageFile[before] = after553		}554	}555}556557func readCoverageCfg(file string) {558	var cfg covcmd.CoverFixupConfig559	data, err := os.ReadFile(file)560	if err != nil {561		log.Fatalf("-coveragecfg: %v", err)562	}563	if err := json.Unmarshal(data, &cfg); err != nil {564		log.Fatalf("error reading -coveragecfg file %q: %v", file, err)565	}566	Flag.Cfg.CoverageInfo = &cfg567}568569func readEmbedCfg(file string) {570	data, err := os.ReadFile(file)571	if err != nil {572		log.Fatalf("-embedcfg: %v", err)573	}574	if err := json.Unmarshal(data, &Flag.Cfg.Embed); err != nil {575		log.Fatalf("%s: %v", file, err)576	}577	if Flag.Cfg.Embed.Patterns == nil {578		log.Fatalf("%s: invalid embedcfg: missing Patterns", file)579	}580	if Flag.Cfg.Embed.Files == nil {581		log.Fatalf("%s: invalid embedcfg: missing Files", file)582	}583}584585// parseSpectre parses the spectre configuration from the string s.586func parseSpectre(s string) {587	for f := range strings.SplitSeq(s, ",") {588		f = strings.TrimSpace(f)589		switch f {590		default:591			log.Fatalf("unknown setting -spectre=%s", f)592		case "":593			// nothing594		case "all":595			Flag.Cfg.SpectreIndex = true596			Ctxt.Retpoline = true597		case "index":598			Flag.Cfg.SpectreIndex = true599		case "ret":600			Ctxt.Retpoline = true601		}602	}603604	if Flag.Cfg.SpectreIndex {605		switch buildcfg.GOARCH {606		case "amd64":607			// ok608		default:609			log.Fatalf("GOARCH=%s does not support -spectre=index", buildcfg.GOARCH)610		}611	}612}

Code quality findings 4

Manual scheduling hint; usually unnecessary and indicates deeper design issues
info correctness manual-scheduling
Flag.LowerC = runtime.GOMAXPROCS(0)
Formatted output to console; prefer structured logging for consistency
info correctness fmt-printf
fmt.Printf("compile: version %q does not match go tool version %q\n", runtime.Version(), Flag.GoVersion)
Map created without size hint before being populated in a loop; provide capacity hint to reduce allocations
info performance map-without-size-hint
Flag.Cfg.ImportMap = make(map[string]string)
Range over slice copies each element by value; use index or pointer receiver for large structs to avoid copies
info performance copy-large-struct
for lineNum, line := range strings.Split(string(data), "\n") {

Get this view in your editor

Same data, no extra tab — call code_get_file + code_get_findings over MCP from Claude/Cursor/Copilot.