Fix allowed values in 'compiler' attribute of cc_toolchain_config rule.

When cpu value is not enough to distinguish between two toolchains, we use the compiler value. In that case, the user needs to specify the compiler value for all cc_toolchain_config rules, even for the ones with unique cpu. This cl fixes the allowed values in the compiler attribute to account for the values from unique toolchains.

Issue #5380
RELNOTES: None.
PiperOrigin-RevId: 239396228
diff --git a/tools/migration/crosstool_to_starlark_lib.go b/tools/migration/crosstool_to_starlark_lib.go
index b7b11b0..4403a4b 100644
--- a/tools/migration/crosstool_to_starlark_lib.go
+++ b/tools/migration/crosstool_to_starlark_lib.go
@@ -273,13 +273,27 @@
 	return res
 }
 
-func getRule(cToolchainIdentifiers map[string]CToolchainIdentifier) string {
+func getUniqueValues(arr []string) []string {
+	valuesSet := make(map[string]bool)
+	for _, val := range arr {
+		valuesSet[val] = true
+	}
+	var uniques []string
+	for val, _ := range valuesSet {
+		uniques = append(uniques, val)
+	}
+	sort.Strings(uniques)
+	return uniques
+}
+
+func getRule(cToolchainIdentifiers map[string]CToolchainIdentifier,
+	allowedCompilers []string) string {
 	cpus := make(map[string]bool)
-	compilers := make(map[string]bool)
+	shouldUseCompilerAttribute := false
 	for _, val := range cToolchainIdentifiers {
 		cpus[val.cpu] = true
 		if val.compiler != "" {
-			compilers[val.compiler] = true
+			shouldUseCompilerAttribute = true
 		}
 	}
 
@@ -288,21 +302,19 @@
 		cpuValues = append(cpuValues, cpu)
 	}
 
-	var compilerValues []string
-	for compiler := range compilers {
-		compilerValues = append(compilerValues, compiler)
-	}
 	var args []string
 	sort.Strings(cpuValues)
 	args = append(args,
 		fmt.Sprintf(
 			`"cpu": attr.string(mandatory=True, values=["%s"]),`,
 			strings.Join(cpuValues, "\", \"")))
-	if len(compilerValues) != 0 {
-		sort.Strings(compilerValues)
+	if shouldUseCompilerAttribute {
+		// If there are two CToolchains that share the cpu we need the compiler attribute
+		// for our cc_toolchain_config rule.
+		allowedCompilers = getUniqueValues(allowedCompilers)
 		args = append(args,
-			fmt.Sprintf(`"compiler": attr.string(values=["%s"]),`,
-				strings.Join(compilerValues, "\", \"")))
+			fmt.Sprintf(`"compiler": attr.string(mandatory=True, values=["%s"]),`,
+				strings.Join(allowedCompilers, "\", \"")))
 	}
 	return fmt.Sprintf(`cc_toolchain_config =  rule(
     implementation = _impl,
@@ -1398,7 +1410,7 @@
 		return "", err
 	}
 
-	rule := getRule(cToolchainIdentifiers)
+	rule := getRule(cToolchainIdentifiers, getCompilers(crosstool))
 	if _, err := b.WriteString(rule); err != nil {
 		return "", err
 	}
diff --git a/tools/migration/crosstool_to_starlark_lib_test.go b/tools/migration/crosstool_to_starlark_lib_test.go
index 635616c..a95bac5 100644
--- a/tools/migration/crosstool_to_starlark_lib_test.go
+++ b/tools/migration/crosstool_to_starlark_lib_test.go
@@ -1677,3 +1677,80 @@
 			expected, got, simpleToolchain)
 	}
 }
+
+func TestAllowedCompilerValues(t *testing.T) {
+	toolchainAA := getCToolchain("1", "cpuA", "compilerA", []string{})
+	toolchainBA := getCToolchain("2", "cpuB", "compilerA", []string{})
+	toolchainBB := getCToolchain("3", "cpuB", "compilerB", []string{})
+	toolchainCC := getCToolchain("4", "cpuC", "compilerC", []string{})
+
+	testCases := []struct {
+		toolchains   []string
+		expectedText string
+	}{
+		{
+			toolchains: []string{toolchainAA, toolchainBA},
+			expectedText: `
+cc_toolchain_config =  rule(
+    implementation = _impl,
+    attrs = {
+        "cpu": attr.string(mandatory=True, values=["cpuA", "cpuB"]),
+    },
+    provides = [CcToolchainConfigInfo],
+    executable = True,
+)
+`},
+		{
+			toolchains: []string{toolchainBA, toolchainBB},
+			expectedText: `
+cc_toolchain_config =  rule(
+    implementation = _impl,
+    attrs = {
+        "cpu": attr.string(mandatory=True, values=["cpuB"]),
+        "compiler": attr.string(mandatory=True, values=["compilerA", "compilerB"]),
+    },
+    provides = [CcToolchainConfigInfo],
+    executable = True,
+)
+`},
+		{
+			toolchains: []string{toolchainAA, toolchainBA, toolchainBB},
+			expectedText: `
+cc_toolchain_config =  rule(
+    implementation = _impl,
+    attrs = {
+        "cpu": attr.string(mandatory=True, values=["cpuA", "cpuB"]),
+        "compiler": attr.string(mandatory=True, values=["compilerA", "compilerB"]),
+    },
+    provides = [CcToolchainConfigInfo],
+    executable = True,
+)
+`},
+		{
+			toolchains: []string{toolchainAA, toolchainBA, toolchainBB, toolchainCC},
+			expectedText: `
+cc_toolchain_config =  rule(
+    implementation = _impl,
+    attrs = {
+        "cpu": attr.string(mandatory=True, values=["cpuA", "cpuB", "cpuC"]),
+        "compiler": attr.string(mandatory=True, values=["compilerA", "compilerB", "compilerC"]),
+    },
+    provides = [CcToolchainConfigInfo],
+    executable = True,
+)
+`}}
+
+	for _, tc := range testCases {
+		crosstool := makeCrosstool(tc.toolchains)
+		got, err := Transform(crosstool)
+		if err != nil {
+			t.Fatalf("CROSSTOOL conversion failed: %v", err)
+		}
+		if !strings.Contains(got, tc.expectedText) {
+			t.Errorf("Failed to correctly declare the rule, expected to contain:\n%v\n",
+				tc.expectedText)
+			t.Fatalf("Tested CROSSTOOL:\n%v\n\nGenerated rule:\n%v\n",
+				strings.Join(tc.toolchains, "\n"), got)
+		}
+	}
+}