Support for ThinLTO to be enabled implicitly with AFDO

Allows for ThinLTO to be enabled once the --features=autofdo_implicit_thinlto feature is enabled in the crosstool. Also allows for --features=-thin_lto to override and prevent ThinLTO from being enabled.

RELNOTES: None.
PiperOrigin-RevId: 179687743
diff --git a/src/main/java/com/google/devtools/build/lib/analysis/RuleContext.java b/src/main/java/com/google/devtools/build/lib/analysis/RuleContext.java
index 86339da..b5d0834 100644
--- a/src/main/java/com/google/devtools/build/lib/analysis/RuleContext.java
+++ b/src/main/java/com/google/devtools/build/lib/analysis/RuleContext.java
@@ -222,24 +222,30 @@
     Set<String> globallyEnabled = new HashSet<>();
     Set<String> globallyDisabled = new HashSet<>();
     parseFeatures(getConfiguration().getDefaultFeatures(), globallyEnabled, globallyDisabled);
-    for (ImmutableMap.Entry<Class<? extends Fragment>, Fragment> entry :
-        getConfiguration().getAllFragments().entrySet()) {
-      if (isLegalFragment(entry.getKey())) {
-        globallyEnabled.addAll(entry.getValue().configurationEnabledFeatures(this));
-      }
-    }
     Set<String> packageEnabled = new HashSet<>();
     Set<String> packageDisabled = new HashSet<>();
     parseFeatures(getRule().getPackage().getFeatures(), packageEnabled, packageDisabled);
+    Set<String> ruleEnabled = new HashSet<>();
+    Set<String> ruleDisabled = new HashSet<>();
+    if (attributes().has("features", Type.STRING_LIST)) {
+      parseFeatures(attributes().get("features", Type.STRING_LIST), ruleEnabled, ruleDisabled);
+    }
+    Set<String> ruleDisabledFeatures =
+        Sets.union(ruleDisabled, Sets.difference(packageDisabled, ruleEnabled));
+    Set<String> disabledFeatures = Sets.union(ruleDisabledFeatures, globallyDisabled);
+    for (ImmutableMap.Entry<Class<? extends Fragment>, Fragment> entry :
+        getConfiguration().getAllFragments().entrySet()) {
+      if (isLegalFragment(entry.getKey())) {
+        globallyEnabled.addAll(
+            entry
+                .getValue()
+                .configurationEnabledFeatures(this, ImmutableSortedSet.copyOf(disabledFeatures)));
+      }
+    }
     Set<String> packageFeatures =
         Sets.difference(Sets.union(globallyEnabled, packageEnabled), packageDisabled);
-    Set<String> ruleFeatures = packageFeatures;
-    if (attributes().has("features", Type.STRING_LIST)) {
-      Set<String> ruleEnabled = new HashSet<>();
-      Set<String> ruleDisabled = new HashSet<>();
-      parseFeatures(attributes().get("features", Type.STRING_LIST), ruleEnabled, ruleDisabled);
-      ruleFeatures = Sets.difference(Sets.union(packageFeatures, ruleEnabled), ruleDisabled);
-    }
+    Set<String> ruleFeatures =
+        Sets.difference(Sets.union(packageFeatures, ruleEnabled), ruleDisabled);
     return ImmutableSortedSet.copyOf(Sets.difference(ruleFeatures, globallyDisabled));
   }
 
diff --git a/src/main/java/com/google/devtools/build/lib/analysis/config/BuildConfiguration.java b/src/main/java/com/google/devtools/build/lib/analysis/config/BuildConfiguration.java
index e6e6a36..c3b6c41 100644
--- a/src/main/java/com/google/devtools/build/lib/analysis/config/BuildConfiguration.java
+++ b/src/main/java/com/google/devtools/build/lib/analysis/config/BuildConfiguration.java
@@ -173,10 +173,9 @@
       return ImmutableMap.of();
     }
 
-    /**
-     * Return set of features enabled by this configuration.
-     */
-    public ImmutableSet<String> configurationEnabledFeatures(RuleContext ruleContext) {
+    /** Return set of features enabled by this configuration. */
+    public ImmutableSet<String> configurationEnabledFeatures(
+        RuleContext ruleContext, ImmutableSet<String> disabledFeatures) {
       return ImmutableSet.of();
     }
 
diff --git a/src/main/java/com/google/devtools/build/lib/rules/cpp/CppConfiguration.java b/src/main/java/com/google/devtools/build/lib/rules/cpp/CppConfiguration.java
index 974551f..d843154 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/cpp/CppConfiguration.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/cpp/CppConfiguration.java
@@ -1292,11 +1292,12 @@
   }
 
   /**
-   * Return set of features enabled by the CppConfiguration, specifically
-   * the FDO and LIPO related features enabled by options.
+   * Return set of features enabled by the CppConfiguration, specifically the FDO and LIPO related
+   * features enabled by options.
    */
   @Override
-  public ImmutableSet<String> configurationEnabledFeatures(RuleContext ruleContext) {
+  public ImmutableSet<String> configurationEnabledFeatures(
+      RuleContext ruleContext, ImmutableSet<String> disabledFeatures) {
     ImmutableSet.Builder<String> requestedFeatures = ImmutableSet.builder();
     if (cppOptions.getFdoInstrument() != null) {
       requestedFeatures.add(CppRuleClasses.FDO_INSTRUMENT);
@@ -1308,6 +1309,11 @@
     }
     if (isFdo && CppFileTypes.GCC_AUTO_PROFILE.matches(fdoZip)) {
       requestedFeatures.add(CppRuleClasses.AUTOFDO);
+      // For LLVM, support implicit enabling of ThinLTO for AFDO unless it has been
+      // explicitly disabled.
+      if (isLLVMCompiler() && !disabledFeatures.contains(CppRuleClasses.THIN_LTO)) {
+        requestedFeatures.add(CppRuleClasses.ENABLE_AFDO_THINLTO);
+      }
     }
     if (isLipoOptimizationOrInstrumentation()) {
       // Map LIPO to ThinLTO for LLVM builds.
diff --git a/src/main/java/com/google/devtools/build/lib/rules/cpp/CppRuleClasses.java b/src/main/java/com/google/devtools/build/lib/rules/cpp/CppRuleClasses.java
index ed54a38..af37c28 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/cpp/CppRuleClasses.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/cpp/CppRuleClasses.java
@@ -287,6 +287,16 @@
    */
   public static final String THIN_LTO = "thin_lto";
 
+  /*
+   * A string constant for allowing implicit ThinLTO enablement for AFDO.
+   */
+  public static final java.lang.String AUTOFDO_IMPLICIT_THINLTO = "autofdo_implicit_thinlto";
+
+  /*
+   * A string constant for enabling ThinLTO for AFDO implicitly.
+   */
+  public static final java.lang.String ENABLE_AFDO_THINLTO = "enable_afdo_thinlto";
+
   /**
    * A string constant for allowing use of shared LTO backend actions for linkstatic tests building
    * with ThinLTO.