Add a new toolchain type for c++.  In order to do this, PlatformConfiguration is made a legal configuration fragment for every rule class.

Add a default "dummy" c++ toolchain to prevent resolution errors when legacy toolchain selection logic is used.  Add toolchain mocks to java and shell tests.

PiperOrigin-RevId: 167901210
diff --git a/src/main/java/com/google/devtools/build/lib/analysis/BaseRuleClasses.java b/src/main/java/com/google/devtools/build/lib/analysis/BaseRuleClasses.java
index 817f4d1..f52d66f 100644
--- a/src/main/java/com/google/devtools/build/lib/analysis/BaseRuleClasses.java
+++ b/src/main/java/com/google/devtools/build/lib/analysis/BaseRuleClasses.java
@@ -182,41 +182,60 @@
    * Share common attributes across both base and Skylark base rules.
    */
   public static RuleClass.Builder commonCoreAndSkylarkAttributes(RuleClass.Builder builder) {
-    return builder
+    return PlatformSemantics.platformAttributes(builder)
         // The visibility attribute is special: it is a nodep label, and loading the
         // necessary package groups is handled by {@link LabelVisitor#visitTargetVisibility}.
         // Package groups always have the null configuration so that they are not duplicated
         // needlessly.
-        .add(attr("visibility", NODEP_LABEL_LIST).orderIndependent().cfg(HOST)
-            .nonconfigurable("special attribute integrated more deeply into Bazel's core logic"))
-        .add(attr("deprecation", STRING).value(deprecationDefault)
-            .nonconfigurable("Used in core loading phase logic with no access to configs"))
-        .add(attr("tags", STRING_LIST).orderIndependent().taggable()
-            .nonconfigurable("low-level attribute, used in TargetUtils without configurations"))
-        .add(attr("generator_name", STRING).undocumented("internal")
-            .nonconfigurable("static structure of a rule"))
-        .add(attr("generator_function", STRING).undocumented("internal")
-            .nonconfigurable("static structure of a rule"))
-        .add(attr("generator_location", STRING).undocumented("internal")
-            .nonconfigurable("static structure of a rule"))
-        .add(attr("testonly", BOOLEAN).value(testonlyDefault)
-            .nonconfigurable("policy decision: rules testability should be consistent"))
+        .add(
+            attr("visibility", NODEP_LABEL_LIST)
+                .orderIndependent()
+                .cfg(HOST)
+                .nonconfigurable(
+                    "special attribute integrated more deeply into Bazel's core logic"))
+        .add(
+            attr("deprecation", STRING)
+                .value(deprecationDefault)
+                .nonconfigurable("Used in core loading phase logic with no access to configs"))
+        .add(
+            attr("tags", STRING_LIST)
+                .orderIndependent()
+                .taggable()
+                .nonconfigurable("low-level attribute, used in TargetUtils without configurations"))
+        .add(
+            attr("generator_name", STRING)
+                .undocumented("internal")
+                .nonconfigurable("static structure of a rule"))
+        .add(
+            attr("generator_function", STRING)
+                .undocumented("internal")
+                .nonconfigurable("static structure of a rule"))
+        .add(
+            attr("generator_location", STRING)
+                .undocumented("internal")
+                .nonconfigurable("static structure of a rule"))
+        .add(
+            attr("testonly", BOOLEAN)
+                .value(testonlyDefault)
+                .nonconfigurable("policy decision: rules testability should be consistent"))
         .add(attr("features", STRING_LIST).orderIndependent())
         .add(attr(":action_listener", LABEL_LIST).cfg(HOST).value(ACTION_LISTENER))
-        .add(attr(RuleClass.COMPATIBLE_ENVIRONMENT_ATTR, LABEL_LIST)
-            .allowedRuleClasses(EnvironmentRule.RULE_NAME)
-            .cfg(Attribute.ConfigurationTransition.HOST)
-            .allowedFileTypes(FileTypeSet.NO_FILE)
-            .dontCheckConstraints()
-            .nonconfigurable("special logic for constraints and select: see ConstraintSemantics")
-        )
-        .add(attr(RuleClass.RESTRICTED_ENVIRONMENT_ATTR, LABEL_LIST)
-            .allowedRuleClasses(EnvironmentRule.RULE_NAME)
-            .cfg(Attribute.ConfigurationTransition.HOST)
-            .allowedFileTypes(FileTypeSet.NO_FILE)
-            .dontCheckConstraints()
-            .nonconfigurable("special logic for constraints and select: see ConstraintSemantics")
-        );
+        .add(
+            attr(RuleClass.COMPATIBLE_ENVIRONMENT_ATTR, LABEL_LIST)
+                .allowedRuleClasses(EnvironmentRule.RULE_NAME)
+                .cfg(Attribute.ConfigurationTransition.HOST)
+                .allowedFileTypes(FileTypeSet.NO_FILE)
+                .dontCheckConstraints()
+                .nonconfigurable(
+                    "special logic for constraints and select: see ConstraintSemantics"))
+        .add(
+            attr(RuleClass.RESTRICTED_ENVIRONMENT_ATTR, LABEL_LIST)
+                .allowedRuleClasses(EnvironmentRule.RULE_NAME)
+                .cfg(Attribute.ConfigurationTransition.HOST)
+                .allowedFileTypes(FileTypeSet.NO_FILE)
+                .dontCheckConstraints()
+                .nonconfigurable(
+                    "special logic for constraints and select: see ConstraintSemantics"));
   }
 
   public static RuleClass.Builder nameAttribute(RuleClass.Builder builder) {
diff --git a/src/main/java/com/google/devtools/build/lib/analysis/PlatformOptions.java b/src/main/java/com/google/devtools/build/lib/analysis/PlatformOptions.java
index 3376e96..e2bf25b 100644
--- a/src/main/java/com/google/devtools/build/lib/analysis/PlatformOptions.java
+++ b/src/main/java/com/google/devtools/build/lib/analysis/PlatformOptions.java
@@ -60,7 +60,7 @@
   @Option(
     name = "extra_toolchains",
     converter = LabelListConverter.class,
-    defaultValue = "",
+    defaultValue = "@bazel_tools//tools/cpp:dummy_cc_toolchain",
     documentationCategory = OptionDocumentationCategory.UNDOCUMENTED,
     effectTags = {OptionEffectTag.UNKNOWN},
     metadataTags = {OptionMetadataTag.HIDDEN},
@@ -98,6 +98,8 @@
   public PlatformOptions getHost(boolean fallback) {
     PlatformOptions host = (PlatformOptions) getDefault();
     host.platforms = ImmutableList.of(this.hostPlatform);
+    host.hostPlatform = this.hostPlatform;
+    host.extraToolchains = this.extraToolchains;
     return host;
   }
 
diff --git a/src/main/java/com/google/devtools/build/lib/analysis/PlatformSemantics.java b/src/main/java/com/google/devtools/build/lib/analysis/PlatformSemantics.java
index bc47c69..45c967e 100644
--- a/src/main/java/com/google/devtools/build/lib/analysis/PlatformSemantics.java
+++ b/src/main/java/com/google/devtools/build/lib/analysis/PlatformSemantics.java
@@ -26,6 +26,7 @@
 import com.google.devtools.build.lib.packages.Rule;
 import com.google.devtools.build.lib.packages.RuleClass;
 import java.util.List;
+import javax.annotation.Nullable;
 
 /** Helper class to manage rules' use of platforms. */
 public class PlatformSemantics {
@@ -49,6 +50,7 @@
       };
 
   /** Implementation for the :execution_platform attribute. */
+  @Nullable
   public static final Attribute.LateBoundLabel<BuildConfiguration> EXECUTION_PLATFORM =
       new Attribute.LateBoundLabel<BuildConfiguration>(PlatformConfiguration.class) {
         @Override
diff --git a/src/main/java/com/google/devtools/build/lib/analysis/skylark/SkylarkRuleClassFunctions.java b/src/main/java/com/google/devtools/build/lib/analysis/skylark/SkylarkRuleClassFunctions.java
index 3e850d9..6c84873 100644
--- a/src/main/java/com/google/devtools/build/lib/analysis/skylark/SkylarkRuleClassFunctions.java
+++ b/src/main/java/com/google/devtools/build/lib/analysis/skylark/SkylarkRuleClassFunctions.java
@@ -39,7 +39,6 @@
 import com.google.devtools.build.lib.analysis.BaseRuleClasses;
 import com.google.devtools.build.lib.analysis.DefaultInfo;
 import com.google.devtools.build.lib.analysis.OutputGroupProvider;
-import com.google.devtools.build.lib.analysis.PlatformSemantics;
 import com.google.devtools.build.lib.analysis.TransitiveInfoCollection;
 import com.google.devtools.build.lib.analysis.skylark.SkylarkAttr.Descriptor;
 import com.google.devtools.build.lib.analysis.test.TestConfiguration;
@@ -129,10 +128,9 @@
   /** Parent rule class for non-executable non-test Skylark rules. */
   public static final RuleClass baseRule =
       BaseRuleClasses.commonCoreAndSkylarkAttributes(
-              PlatformSemantics.platformAttributes(
-                  BaseRuleClasses.nameAttribute(
-                          new RuleClass.Builder("$base_rule", RuleClassType.ABSTRACT, true))
-                      .add(attr("expect_failure", STRING))))
+              BaseRuleClasses.nameAttribute(
+                      new RuleClass.Builder("$base_rule", RuleClassType.ABSTRACT, true))
+                  .add(attr("expect_failure", STRING)))
           .build();
 
   /** Parent rule class for executable non-test Skylark rules. */
diff --git a/src/main/java/com/google/devtools/build/lib/bazel/rules/cpp/BazelCppRuleClasses.java b/src/main/java/com/google/devtools/build/lib/bazel/rules/cpp/BazelCppRuleClasses.java
index 99abec3..8d494c8 100644
--- a/src/main/java/com/google/devtools/build/lib/bazel/rules/cpp/BazelCppRuleClasses.java
+++ b/src/main/java/com/google/devtools/build/lib/bazel/rules/cpp/BazelCppRuleClasses.java
@@ -57,6 +57,7 @@
 import com.google.devtools.build.lib.rules.cpp.CcToolchain;
 import com.google.devtools.build.lib.rules.cpp.CppConfiguration;
 import com.google.devtools.build.lib.rules.cpp.CppFileTypes;
+import com.google.devtools.build.lib.rules.cpp.CppHelper;
 import com.google.devtools.build.lib.rules.cpp.CppRuleClasses;
 import com.google.devtools.build.lib.rules.cpp.CppRuleClasses.LipoTransition;
 import com.google.devtools.build.lib.util.FileTypeSet;
@@ -139,6 +140,7 @@
               attr(CcToolchain.CC_TOOLCHAIN_DEFAULT_ATTRIBUTE_NAME, LABEL)
                   .value(CppRuleClasses.ccToolchainAttribute(env)))
           .setPreferredDependencyPredicate(Predicates.<String>or(CPP_SOURCE, C_SOURCE, CPP_HEADER))
+          .addRequiredToolchains(CppHelper.getCcToolchainType(env.getToolsRepository()))
           .build();
     }
 
diff --git a/src/main/java/com/google/devtools/build/lib/packages/RuleClass.java b/src/main/java/com/google/devtools/build/lib/packages/RuleClass.java
index dcf6092..daa2e8e 100644
--- a/src/main/java/com/google/devtools/build/lib/packages/RuleClass.java
+++ b/src/main/java/com/google/devtools/build/lib/packages/RuleClass.java
@@ -28,6 +28,7 @@
 import com.google.common.collect.ImmutableMap;
 import com.google.common.collect.ImmutableSet;
 import com.google.common.collect.Iterables;
+import com.google.common.collect.Lists;
 import com.google.common.collect.Ordering;
 import com.google.devtools.build.lib.cmdline.Label;
 import com.google.devtools.build.lib.cmdline.LabelSyntaxException;
@@ -997,6 +998,11 @@
       return this;
     }
 
+    public Builder addRequiredToolchains(Label... toolchainLabels) {
+      Iterables.addAll(this.requiredToolchains, Lists.newArrayList(toolchainLabels));
+      return this;
+    }
+
     /**
      * Returns an Attribute.Builder object which contains a replica of the
      * same attribute in the parent rule if exists.
diff --git a/src/main/java/com/google/devtools/build/lib/rules/cpp/CppHelper.java b/src/main/java/com/google/devtools/build/lib/rules/cpp/CppHelper.java
index 1100576..87f43cc 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/cpp/CppHelper.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/cpp/CppHelper.java
@@ -87,6 +87,11 @@
   private static final ImmutableList<String> LINKOPTS_PREREQUISITE_LABEL_KINDS =
       ImmutableList.of("deps", "srcs");
 
+  /** Returns label used to select resolved cc_toolchain instances based on platform. */
+  public static Label getCcToolchainType(String toolsRepository) {
+    return Label.parseAbsoluteUnchecked(toolsRepository + "//tools/cpp:toolchain_type");
+  }
+
   private CppHelper() {
     // prevents construction
   }
diff --git a/src/main/java/com/google/devtools/build/lib/skyframe/SkyFunctionEnvironmentForTesting.java b/src/main/java/com/google/devtools/build/lib/skyframe/SkyFunctionEnvironmentForTesting.java
index 7df8afd..0acb49c 100644
--- a/src/main/java/com/google/devtools/build/lib/skyframe/SkyFunctionEnvironmentForTesting.java
+++ b/src/main/java/com/google/devtools/build/lib/skyframe/SkyFunctionEnvironmentForTesting.java
@@ -14,7 +14,9 @@
 
 package com.google.devtools.build.lib.skyframe;
 
+import com.google.common.collect.ImmutableList;
 import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.ImmutableSet;
 import com.google.devtools.build.lib.events.ExtendedEventHandler;
 import com.google.devtools.build.lib.util.ResourceUsage;
 import com.google.devtools.build.skyframe.AbstractSkyFunctionEnvironment;
@@ -33,21 +35,27 @@
 
   private final BuildDriver buildDriver;
   private final ExtendedEventHandler eventHandler;
+  private final SkyframeExecutor skyframeExecutor;
 
   /** Creates a SkyFunctionEnvironmentForTesting that uses a BuildDriver to evaluate skykeys. */
   public SkyFunctionEnvironmentForTesting(
-      BuildDriver buildDriver, ExtendedEventHandler eventHandler) {
+      BuildDriver buildDriver,
+      ExtendedEventHandler eventHandler,
+      SkyframeExecutor skyframeExecutor) {
     this.buildDriver = buildDriver;
     this.eventHandler = eventHandler;
+    this.skyframeExecutor = skyframeExecutor;
   }
 
   @Override
   protected Map<SkyKey, ValueOrUntypedException> getValueOrUntypedExceptions(
       Iterable<? extends SkyKey> depKeys) throws InterruptedException {
     ImmutableMap.Builder<SkyKey, ValueOrUntypedException> resultMap = ImmutableMap.builder();
+    Iterable<SkyKey> keysToEvaluate = ImmutableList.copyOf(depKeys);
     EvaluationResult<SkyValue> evaluationResult =
+        skyframeExecutor.evaluateSkyKeys(eventHandler, keysToEvaluate, true);
         buildDriver.evaluate(depKeys, true, ResourceUsage.getAvailableProcessors(), eventHandler);
-    for (SkyKey depKey : depKeys) {
+    for (SkyKey depKey : ImmutableSet.copyOf(depKeys)) {
       resultMap.put(depKey, ValueOrExceptionUtils.ofValue(evaluationResult.get(depKey)));
     }
     return resultMap.build();
diff --git a/src/main/java/com/google/devtools/build/lib/skyframe/SkyframeExecutor.java b/src/main/java/com/google/devtools/build/lib/skyframe/SkyframeExecutor.java
index f592d39..9c952ac 100644
--- a/src/main/java/com/google/devtools/build/lib/skyframe/SkyframeExecutor.java
+++ b/src/main/java/com/google/devtools/build/lib/skyframe/SkyframeExecutor.java
@@ -837,7 +837,7 @@
       Set<Label> requiredToolchains, BuildConfiguration config, ExtendedEventHandler eventHandler)
       throws ToolchainContextException, InterruptedException {
     SkyFunctionEnvironmentForTesting env =
-        new SkyFunctionEnvironmentForTesting(buildDriver, eventHandler);
+        new SkyFunctionEnvironmentForTesting(buildDriver, eventHandler, this);
     return ToolchainUtil.createToolchainContext(env, "", requiredToolchains, config);
   }
 
@@ -1534,7 +1534,7 @@
    * Evaluates the given sky keys, blocks, and returns their evaluation results. Enables/disables
    * "keep going" on evaluation errors as specified.
    */
-  private EvaluationResult<SkyValue> evaluateSkyKeys(
+  EvaluationResult<SkyValue> evaluateSkyKeys(
       final ExtendedEventHandler eventHandler,
       final Iterable<SkyKey> skyKeys,
       final boolean keepGoing) {