C++: Introduce flag for forcing rules through macro

The flag `--incompatible_load_cc_rules_from_bzl` will be flipped for Bazel 1.0.

GitHub Issue: #8743

RELNOTES:none
PiperOrigin-RevId: 259285337
diff --git a/src/main/java/com/google/devtools/build/lib/rules/cpp/CcBinary.java b/src/main/java/com/google/devtools/build/lib/rules/cpp/CcBinary.java
index af2f72f..efe16b7 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/cpp/CcBinary.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/cpp/CcBinary.java
@@ -268,7 +268,7 @@
 
   public static ConfiguredTarget init(CppSemantics semantics, RuleContext ruleContext, boolean fake)
       throws InterruptedException, RuleErrorException, ActionConflictException {
-
+    CcCommon.checkRuleLoadedThroughMacro(ruleContext);
     semantics.validateDeps(ruleContext);
     if (ruleContext.hasErrors()) {
       return null;
diff --git a/src/main/java/com/google/devtools/build/lib/rules/cpp/CcCommon.java b/src/main/java/com/google/devtools/build/lib/rules/cpp/CcCommon.java
index fac7cb2..c8dcd2f 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/cpp/CcCommon.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/cpp/CcCommon.java
@@ -1061,4 +1061,31 @@
     }
     return outputGroupsBuilder.build();
   }
+
+  public static void checkRuleLoadedThroughMacro(RuleContext ruleContext)
+      throws RuleErrorException {
+    if (!ruleContext.getFragment(CppConfiguration.class).loadCcRulesFromBzl()) {
+      return;
+    }
+
+    if (!hasValidTag(ruleContext) || !ruleContext.getRule().wasCreatedByMacro()) {
+      registerMigrationRuleError(ruleContext);
+    }
+  }
+
+  private static boolean hasValidTag(RuleContext ruleContext) {
+    return ruleContext
+        .attributes()
+        .get("tags", Type.STRING_LIST)
+        .contains("__CC_RULES_MIGRATION_DO_NOT_USE_WILL_BREAK__");
+  }
+
+  private static void registerMigrationRuleError(RuleContext ruleContext)
+      throws RuleErrorException {
+    ruleContext.ruleError(
+        "The native C++/Objc rules are deprecated. Please load "
+            + ruleContext.getRule().getRuleClass()
+            + " from the rules_cc repository."
+            + " See http://github.com/bazelbuild/rules_cc.");
+  }
 }
diff --git a/src/main/java/com/google/devtools/build/lib/rules/cpp/CcImport.java b/src/main/java/com/google/devtools/build/lib/rules/cpp/CcImport.java
index e9986bf..1d5c446 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/cpp/CcImport.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/cpp/CcImport.java
@@ -71,6 +71,7 @@
   @Override
   public ConfiguredTarget create(RuleContext ruleContext)
       throws InterruptedException, RuleErrorException, ActionConflictException {
+    CcCommon.checkRuleLoadedThroughMacro(ruleContext);
 
     boolean systemProvided = ruleContext.attributes().get("system_provided", Type.BOOLEAN);
     CcToolchainProvider ccToolchain =
diff --git a/src/main/java/com/google/devtools/build/lib/rules/cpp/CcLibrary.java b/src/main/java/com/google/devtools/build/lib/rules/cpp/CcLibrary.java
index 1f15172..1529277 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/cpp/CcLibrary.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/cpp/CcLibrary.java
@@ -111,7 +111,7 @@
       boolean linkStatic,
       boolean addDynamicRuntimeInputArtifactsToRunfiles)
       throws RuleErrorException, InterruptedException {
-
+    CcCommon.checkRuleLoadedThroughMacro(ruleContext);
     semantics.validateDeps(ruleContext);
     if (ruleContext.hasErrors()) {
       return;
diff --git a/src/main/java/com/google/devtools/build/lib/rules/cpp/CcToolchain.java b/src/main/java/com/google/devtools/build/lib/rules/cpp/CcToolchain.java
index 74db881..cb06563 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/cpp/CcToolchain.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/cpp/CcToolchain.java
@@ -45,6 +45,9 @@
   @Override
   public ConfiguredTarget create(RuleContext ruleContext)
       throws InterruptedException, RuleErrorException, ActionConflictException {
+    if (!isAppleToolchain()) {
+      CcCommon.checkRuleLoadedThroughMacro(ruleContext);
+    }
     validateToolchain(ruleContext);
     CcToolchainAttributesProvider attributes =
         new CcToolchainAttributesProvider(
diff --git a/src/main/java/com/google/devtools/build/lib/rules/cpp/CcToolchainSuite.java b/src/main/java/com/google/devtools/build/lib/rules/cpp/CcToolchainSuite.java
index 5075713..cae6d68 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/cpp/CcToolchainSuite.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/cpp/CcToolchainSuite.java
@@ -42,6 +42,7 @@
   @Override
   public ConfiguredTarget create(RuleContext ruleContext)
       throws InterruptedException, RuleErrorException, ActionConflictException {
+    CcCommon.checkRuleLoadedThroughMacro(ruleContext);
     CppConfiguration cppConfiguration = ruleContext.getFragment(CppConfiguration.class);
 
     String transformedCpu = cppConfiguration.getTransformedCpuFromOptions();
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 7824bc1..1b4fc33 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
@@ -694,4 +694,8 @@
   public boolean disableNoCopts() {
     return cppOptions.disableNoCopts;
   }
+
+  public boolean loadCcRulesFromBzl() {
+    return cppOptions.loadCcRulesFromBzl;
+  }
 }
diff --git a/src/main/java/com/google/devtools/build/lib/rules/cpp/CppOptions.java b/src/main/java/com/google/devtools/build/lib/rules/cpp/CppOptions.java
index f7e2345..d6eb56b 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/cpp/CppOptions.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/cpp/CppOptions.java
@@ -904,6 +904,20 @@
               + " https://github.com/bazelbuild/bazel/issues/8706 for details.")
   public boolean disableNoCopts;
 
+  @Option(
+      name = "incompatible_load_cc_rules_from_bzl",
+      defaultValue = "false",
+      documentationCategory = OptionDocumentationCategory.UNDOCUMENTED,
+      effectTags = {OptionEffectTag.LOADING_AND_ANALYSIS},
+      metadataTags = {
+        OptionMetadataTag.INCOMPATIBLE_CHANGE,
+        OptionMetadataTag.TRIGGERED_BY_ALL_INCOMPATIBLE_CHANGES
+      },
+      help =
+          "If enabled, direct usage of the native C++ and some Objc rules is disabled. Please use "
+              + "the Starlark rules instead https://github.com/bazelbuild/rules_cc")
+  public boolean loadCcRulesFromBzl;
+
   @Override
   public FragmentOptions getHost() {
     CppOptions host = (CppOptions) getDefault();
@@ -961,6 +975,7 @@
     host.useSpecificToolFiles = useSpecificToolFiles;
     host.disableStaticCcToolchains = disableStaticCcToolchains;
     host.disableNoCopts = disableNoCopts;
+    host.loadCcRulesFromBzl = loadCcRulesFromBzl;
 
     // Save host options for further use.
     host.hostCoptList = hostCoptList;
diff --git a/src/main/java/com/google/devtools/build/lib/rules/cpp/FdoPrefetchHints.java b/src/main/java/com/google/devtools/build/lib/rules/cpp/FdoPrefetchHints.java
index 24dd235..23a8d7f 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/cpp/FdoPrefetchHints.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/cpp/FdoPrefetchHints.java
@@ -28,6 +28,7 @@
   @Override
   public ConfiguredTarget create(RuleContext ruleContext)
       throws RuleErrorException, ActionConflictException {
+    CcCommon.checkRuleLoadedThroughMacro(ruleContext);
 
     FdoInputFile inputFile = FdoInputFile.fromProfileRule(ruleContext);
     if (ruleContext.hasErrors()) {
diff --git a/src/main/java/com/google/devtools/build/lib/rules/cpp/FdoProfile.java b/src/main/java/com/google/devtools/build/lib/rules/cpp/FdoProfile.java
index b9ae065..41c2c81 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/cpp/FdoProfile.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/cpp/FdoProfile.java
@@ -30,7 +30,7 @@
   @Override
   public ConfiguredTarget create(RuleContext ruleContext)
       throws RuleErrorException, ActionConflictException {
-
+    CcCommon.checkRuleLoadedThroughMacro(ruleContext);
     FdoInputFile inputFile = FdoInputFile.fromProfileRule(ruleContext);
     if (ruleContext.hasErrors()) {
       return null;
diff --git a/src/main/java/com/google/devtools/build/lib/rules/cpp/proto/CcProtoLibrary.java b/src/main/java/com/google/devtools/build/lib/rules/cpp/proto/CcProtoLibrary.java
index 3350623..3a504ed 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/cpp/proto/CcProtoLibrary.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/cpp/proto/CcProtoLibrary.java
@@ -24,6 +24,7 @@
 import com.google.devtools.build.lib.analysis.RuleContext;
 import com.google.devtools.build.lib.analysis.Runfiles;
 import com.google.devtools.build.lib.analysis.RunfilesProvider;
+import com.google.devtools.build.lib.rules.cpp.CcCommon;
 import com.google.devtools.build.lib.rules.cpp.CcSkylarkApiProvider;
 
 /** Part of the implementation of cc_proto_library. */
@@ -31,7 +32,7 @@
   @Override
   public ConfiguredTarget create(RuleContext ruleContext)
       throws InterruptedException, RuleErrorException, ActionConflictException {
-
+    CcCommon.checkRuleLoadedThroughMacro(ruleContext);
     if (ruleContext.getPrerequisites("deps", TARGET).size() != 1) {
       ruleContext.throwWithAttributeError(
           "deps",
diff --git a/src/main/java/com/google/devtools/build/lib/rules/objc/ObjcImport.java b/src/main/java/com/google/devtools/build/lib/rules/objc/ObjcImport.java
index 1f0901c..48a0a9e 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/objc/ObjcImport.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/objc/ObjcImport.java
@@ -21,6 +21,7 @@
 import com.google.devtools.build.lib.analysis.RuleContext;
 import com.google.devtools.build.lib.analysis.configuredtargets.RuleConfiguredTarget.Mode;
 import com.google.devtools.build.lib.collect.nestedset.NestedSetBuilder;
+import com.google.devtools.build.lib.rules.cpp.CcCommon;
 import com.google.devtools.build.lib.rules.cpp.CppModuleMap;
 import com.google.devtools.build.lib.syntax.Type;
 
@@ -31,6 +32,7 @@
   @Override
   public ConfiguredTarget create(RuleContext ruleContext)
       throws InterruptedException, RuleErrorException, ActionConflictException {
+    CcCommon.checkRuleLoadedThroughMacro(ruleContext);
     ObjcCommon common =
         new ObjcCommon.Builder(ruleContext)
             .setCompilationAttributes(
diff --git a/src/main/java/com/google/devtools/build/lib/rules/objc/ObjcImportRule.java b/src/main/java/com/google/devtools/build/lib/rules/objc/ObjcImportRule.java
index 1addc3f..f51da3d 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/objc/ObjcImportRule.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/objc/ObjcImportRule.java
@@ -22,6 +22,7 @@
 import com.google.devtools.build.lib.analysis.RuleDefinitionEnvironment;
 import com.google.devtools.build.lib.packages.RuleClass;
 import com.google.devtools.build.lib.rules.apple.AppleConfiguration;
+import com.google.devtools.build.lib.rules.cpp.CppConfiguration;
 import com.google.devtools.build.lib.rules.cpp.CppRuleClasses;
 import com.google.devtools.build.lib.util.FileType;
 
@@ -32,16 +33,17 @@
   @Override
   public RuleClass build(RuleClass.Builder builder, RuleDefinitionEnvironment environment) {
     return builder
-        .requiresConfigurationFragments(ObjcConfiguration.class, AppleConfiguration.class,
-            AppleConfiguration.class)
+        .requiresConfigurationFragments(
+            ObjcConfiguration.class,
+            AppleConfiguration.class,
+            AppleConfiguration.class,
+            CppConfiguration.class)
         /* <!-- #BLAZE_RULE(objc_import).ATTRIBUTE(archives) -->
         The list of <code>.a</code> files provided to Objective-C targets that
         depend on this target.
         <!-- #END_BLAZE_RULE.ATTRIBUTE --> */
-        .add(attr("archives", LABEL_LIST)
-            .mandatory()
-            .nonEmpty()
-            .allowedFileTypes(FileType.of(".a")))
+        .add(
+            attr("archives", LABEL_LIST).mandatory().nonEmpty().allowedFileTypes(FileType.of(".a")))
         .addRequiredToolchains(CppRuleClasses.ccToolchainTypeAttribute(environment))
         .build();
   }
diff --git a/src/main/java/com/google/devtools/build/lib/rules/objc/ObjcLibrary.java b/src/main/java/com/google/devtools/build/lib/rules/objc/ObjcLibrary.java
index f06af30..0f87bf4 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/objc/ObjcLibrary.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/objc/ObjcLibrary.java
@@ -25,6 +25,7 @@
 import com.google.devtools.build.lib.analysis.skylark.SymbolGenerator;
 import com.google.devtools.build.lib.collect.nestedset.NestedSet;
 import com.google.devtools.build.lib.collect.nestedset.NestedSetBuilder;
+import com.google.devtools.build.lib.rules.cpp.CcCommon;
 import com.google.devtools.build.lib.rules.cpp.CcCompilationContext;
 import com.google.devtools.build.lib.rules.cpp.CcInfo;
 import com.google.devtools.build.lib.rules.cpp.LibraryToLink;
@@ -60,6 +61,7 @@
   @Override
   public ConfiguredTarget create(RuleContext ruleContext)
       throws InterruptedException, RuleErrorException, ActionConflictException {
+    CcCommon.checkRuleLoadedThroughMacro(ruleContext);
     validateAttributes(ruleContext);
 
     ObjcCommon common = common(ruleContext);
diff --git a/src/test/java/com/google/devtools/build/lib/analysis/mock/BazelAnalysisMock.java b/src/test/java/com/google/devtools/build/lib/analysis/mock/BazelAnalysisMock.java
index e7e5ff2..6273e9a 100644
--- a/src/test/java/com/google/devtools/build/lib/analysis/mock/BazelAnalysisMock.java
+++ b/src/test/java/com/google/devtools/build/lib/analysis/mock/BazelAnalysisMock.java
@@ -257,6 +257,7 @@
     config.create(
         "/bazel_tools_workspace/tools/launcher/BUILD",
         "package(default_visibility=['//visibility:public'])",
+        "load('@bazel_tools//third_party/cc_rules/macros:defs.bzl', 'cc_binary')",
         "cc_binary(name='launcher', srcs=['launcher_main.cc'])");
 
     config.create(
diff --git a/src/test/java/com/google/devtools/build/lib/packages/util/BazelMockCcSupport.java b/src/test/java/com/google/devtools/build/lib/packages/util/BazelMockCcSupport.java
index 63cbad8..5a08062 100644
--- a/src/test/java/com/google/devtools/build/lib/packages/util/BazelMockCcSupport.java
+++ b/src/test/java/com/google/devtools/build/lib/packages/util/BazelMockCcSupport.java
@@ -70,6 +70,7 @@
 
   @Override
   public void setup(MockToolsConfig config) throws IOException {
+    writeMacroFile(config);
     setupCcToolchainConfig(config);
     MockPlatformSupport.setup(config);
   }
diff --git a/src/test/java/com/google/devtools/build/lib/packages/util/Crosstool.java b/src/test/java/com/google/devtools/build/lib/packages/util/Crosstool.java
index c160045..4317a31 100644
--- a/src/test/java/com/google/devtools/build/lib/packages/util/Crosstool.java
+++ b/src/test/java/com/google/devtools/build/lib/packages/util/Crosstool.java
@@ -464,6 +464,10 @@
                 "licenses(['restricted'])",
                 "",
                 "load(':cc_toolchain_config.bzl', 'cc_toolchain_config')",
+                "load('"
+                    + TestConstants.TOOLS_REPOSITORY
+                    + "//third_party/cc_rules/macros:defs.bzl', 'cc_library', 'cc_toolchain',"
+                    + " 'cc_toolchain_suite')",
                 "toolchain_type(name = 'toolchain_type')",
                 "cc_toolchain_alias(name = 'current_cc_toolchain')",
                 "alias(name = 'toolchain', actual = 'everything')",
@@ -533,6 +537,10 @@
             .add(
                 "package(default_visibility=['//visibility:public'])",
                 "load(':cc_toolchain_config.bzl', 'cc_toolchain_config')",
+                "load('"
+                    + TestConstants.TOOLS_REPOSITORY
+                    + "//third_party/cc_rules/macros:defs.bzl', 'cc_library',"
+                    + " 'cc_toolchain_suite')",
                 "exports_files(glob(['**']))",
                 "cc_toolchain_suite(",
                 "    name = 'crosstool',",
diff --git a/src/test/java/com/google/devtools/build/lib/packages/util/MockCcSupport.java b/src/test/java/com/google/devtools/build/lib/packages/util/MockCcSupport.java
index cfe4730..559d351 100644
--- a/src/test/java/com/google/devtools/build/lib/packages/util/MockCcSupport.java
+++ b/src/test/java/com/google/devtools/build/lib/packages/util/MockCcSupport.java
@@ -14,6 +14,7 @@
 package com.google.devtools.build.lib.packages.util;
 
 import com.google.common.base.Joiner;
+import com.google.common.base.Preconditions;
 import com.google.common.base.Predicate;
 import com.google.common.base.Verify;
 import com.google.common.collect.ImmutableList;
@@ -32,6 +33,7 @@
 import com.google.devtools.build.lib.testutil.TestConstants;
 import com.google.devtools.build.lib.vfs.PathFragment;
 import java.io.IOException;
+import java.util.List;
 
 /**
  * Creates mock BUILD files required for the C/C++ rules.
@@ -255,4 +257,58 @@
   public final Predicate<Label> labelFilter() {
     return ccLabelFilter;
   }
+
+  public void writeMacroFile(MockToolsConfig config) throws IOException {
+    List<String> ruleNames =
+        ImmutableList.of(
+            "cc_library",
+            "cc_binary",
+            "cc_test",
+            "cc_import",
+            "objc_import",
+            "objc_library",
+            "cc_toolchain",
+            "cc_toolchain_suite",
+            "fdo_profile",
+            "fdo_prefetch_hints",
+            "cc_proto_library");
+    config.create(TestConstants.TOOLS_REPOSITORY_SCRATCH + "third_party/cc_rules/macros/BUILD", "");
+
+    StringBuilder macros = new StringBuilder();
+    for (String ruleName : ruleNames) {
+      Joiner.on("\n")
+          .appendTo(
+              macros,
+              "def " + ruleName + "(**attrs):",
+              "    if 'tags' in attrs and attrs['tags'] != None:",
+              "        attrs['tags'] = attrs['tags'] +"
+                  + " ['__CC_RULES_MIGRATION_DO_NOT_USE_WILL_BREAK__']",
+              "    else:",
+              "        attrs['tags'] = ['__CC_RULES_MIGRATION_DO_NOT_USE_WILL_BREAK__']",
+              "    native." + ruleName + "(**attrs)");
+      macros.append("\n");
+    }
+    config.create(
+        TestConstants.TOOLS_REPOSITORY_SCRATCH + "third_party/cc_rules/macros/defs.bzl",
+        macros.toString());
+  }
+
+  public String getMacroLoadStatement(boolean loadMacro, String... ruleNames) {
+    if (!loadMacro) {
+      return "";
+    }
+    Preconditions.checkState(ruleNames.length > 0);
+    StringBuilder loadStatement =
+        new StringBuilder()
+            .append("load('")
+            .append(TestConstants.TOOLS_REPOSITORY)
+            .append("//third_party/cc_rules/macros:defs.bzl', ");
+    ImmutableList.Builder<String> quotedRuleNames = ImmutableList.builder();
+    for (String ruleName : ruleNames) {
+      quotedRuleNames.add(String.format("'%s'", ruleName));
+    }
+    Joiner.on(",").appendTo(loadStatement, quotedRuleNames.build());
+    loadStatement.append(")");
+    return loadStatement.toString();
+  }
 }
diff --git a/src/test/java/com/google/devtools/build/lib/rules/cpp/CcCommonTest.java b/src/test/java/com/google/devtools/build/lib/rules/cpp/CcCommonTest.java
index 675b84e..48099692 100644
--- a/src/test/java/com/google/devtools/build/lib/rules/cpp/CcCommonTest.java
+++ b/src/test/java/com/google/devtools/build/lib/rules/cpp/CcCommonTest.java
@@ -1057,6 +1057,78 @@
         .containsExactly("/usr/bin/mock-gcc", "@/k8-fastbuild/bin/a/_objs/foo/foo.o.params");
   }
 
+  @Test
+  public void testCcLibraryLoadedThroughMacro() throws Exception {
+    setupTestCcLibraryLoadedThroughMacro(/* loadMacro= */ true);
+    assertThat(getConfiguredTarget("//a:a")).isNotNull();
+    assertNoEvents();
+  }
+
+  @Test
+  public void testCcLibraryNotLoadedThroughMacro() throws Exception {
+    setupTestCcLibraryLoadedThroughMacro(/* loadMacro= */ false);
+    reporter.removeHandler(failFastHandler);
+    getConfiguredTarget("//a:a");
+    assertContainsEvent("rules are deprecated");
+  }
+
+  private void setupTestCcLibraryLoadedThroughMacro(boolean loadMacro) throws Exception {
+    useConfiguration("--incompatible_load_cc_rules_from_bzl");
+    scratch.file(
+        "a/BUILD",
+        getAnalysisMock().ccSupport().getMacroLoadStatement(loadMacro, "cc_library"),
+        "cc_library(name='a', srcs=['a.cc'])");
+  }
+
+  @Test
+  public void testFdoProfileLoadedThroughMacro() throws Exception {
+    setuptestFdoProfileLoadedThroughMacro(/* loadMacro= */ true);
+    assertThat(getConfiguredTarget("//a:a")).isNotNull();
+    assertNoEvents();
+  }
+
+  @Test
+  public void testFdoProfileNotLoadedThroughMacro() throws Exception {
+    setuptestFdoProfileLoadedThroughMacro(/* loadMacro= */ false);
+    reporter.removeHandler(failFastHandler);
+    getConfiguredTarget("//a:a");
+    assertContainsEvent("rules are deprecated");
+  }
+
+  private void setuptestFdoProfileLoadedThroughMacro(boolean loadMacro) throws Exception {
+    useConfiguration("--incompatible_load_cc_rules_from_bzl");
+    scratch.file(
+        "a/BUILD",
+        getAnalysisMock().ccSupport().getMacroLoadStatement(loadMacro, "fdo_profile"),
+        "fdo_profile(name='a', profile='profile.xfdo')");
+  }
+
+  @Test
+  public void testFdoPrefetchHintsLoadedThroughMacro() throws Exception {
+    setupTestFdoPrefetchHintsLoadedThroughMacro(/* loadMacro= */ true);
+    assertThat(getConfiguredTarget("//a:a")).isNotNull();
+    assertNoEvents();
+  }
+
+  @Test
+  public void testFdoPrefetchHintsNotLoadedThroughMacro() throws Exception {
+    setupTestFdoPrefetchHintsLoadedThroughMacro(/* loadMacro= */ false);
+    reporter.removeHandler(failFastHandler);
+    getConfiguredTarget("//a:a");
+    assertContainsEvent("rules are deprecated");
+  }
+
+  private void setupTestFdoPrefetchHintsLoadedThroughMacro(boolean loadMacro) throws Exception {
+    useConfiguration("--incompatible_load_cc_rules_from_bzl");
+    scratch.file(
+        "a/BUILD",
+        getAnalysisMock().ccSupport().getMacroLoadStatement(loadMacro, "fdo_prefetch_hints"),
+        "fdo_prefetch_hints(",
+        "    name = 'a',",
+        "    profile = 'profile.afdo',",
+        ")");
+  }
+
   private String removeOutDirectory(String s) {
     return s.replace("blaze-out", "").replace("bazel-out", "");
   }
diff --git a/src/test/java/com/google/devtools/build/lib/rules/cpp/CcImportBaseConfiguredTargetTest.java b/src/test/java/com/google/devtools/build/lib/rules/cpp/CcImportBaseConfiguredTargetTest.java
index 782e8cc..6b11984 100644
--- a/src/test/java/com/google/devtools/build/lib/rules/cpp/CcImportBaseConfiguredTargetTest.java
+++ b/src/test/java/com/google/devtools/build/lib/rules/cpp/CcImportBaseConfiguredTargetTest.java
@@ -279,4 +279,27 @@
             .getDeclaredIncludeSrcs();
     assertThat(artifactsToStrings(headers)).containsExactly("src a/foo.h");
   }
+
+  @Test
+  public void testCcImportLoadedThroughMacro() throws Exception {
+    setupTestCcImportLoadedThroughMacro(/* loadMacro= */ true);
+    assertThat(getConfiguredTarget("//a:a")).isNotNull();
+    assertNoEvents();
+  }
+
+  @Test
+  public void testCcImportNotLoadedThroughMacro() throws Exception {
+    setupTestCcImportLoadedThroughMacro(/* loadMacro= */ false);
+    reporter.removeHandler(failFastHandler);
+    getConfiguredTarget("//a:a");
+    assertContainsEvent("rules are deprecated");
+  }
+
+  private void setupTestCcImportLoadedThroughMacro(boolean loadMacro) throws Exception {
+    useConfiguration("--incompatible_load_cc_rules_from_bzl");
+    scratch.file(
+        "a/BUILD",
+        getAnalysisMock().ccSupport().getMacroLoadStatement(loadMacro, "cc_import"),
+        "cc_import(name='a', static_library='a.a')");
+  }
 }
diff --git a/src/test/java/com/google/devtools/build/lib/rules/cpp/CcToolchainTest.java b/src/test/java/com/google/devtools/build/lib/rules/cpp/CcToolchainTest.java
index dc6120c..9c00490 100644
--- a/src/test/java/com/google/devtools/build/lib/rules/cpp/CcToolchainTest.java
+++ b/src/test/java/com/google/devtools/build/lib/rules/cpp/CcToolchainTest.java
@@ -18,6 +18,7 @@
 import static com.google.common.truth.Truth.assertWithMessage;
 import static com.google.devtools.build.lib.testutil.MoreAsserts.assertThrows;
 
+import com.google.common.base.Joiner;
 import com.google.common.collect.ImmutableList;
 import com.google.common.collect.ImmutableSet;
 import com.google.common.collect.MoreCollectors;
@@ -748,4 +749,85 @@
     assertThat(preprocessedAsmAction.getInputs())
         .containsAtLeastElementsIn(toolchainProvider.getCompilerFiles());
   }
+
+  @Test
+  public void testCcToolchainLoadedThroughMacro() throws Exception {
+    setupTestCcToolchainLoadedThroughMacro(/* loadMacro= */ true);
+    assertThat(getConfiguredTarget("//a:a")).isNotNull();
+    assertNoEvents();
+  }
+
+  @Test
+  public void testCcToolchainNotLoadedThroughMacro() throws Exception {
+    setupTestCcToolchainLoadedThroughMacro(/* loadMacro= */ false);
+    reporter.removeHandler(failFastHandler);
+    getConfiguredTarget("//a:a");
+    assertContainsEvent("rules are deprecated");
+  }
+
+  private void setupTestCcToolchainLoadedThroughMacro(boolean loadMacro) throws Exception {
+    useConfiguration("--incompatible_load_cc_rules_from_bzl");
+    scratch.file("a/cc_toolchain_config.bzl", MockCcSupport.EMPTY_CC_TOOLCHAIN);
+    scratch.file(
+        "a/BUILD",
+        "load(':cc_toolchain_config.bzl', 'cc_toolchain_config')",
+        getAnalysisMock().ccSupport().getMacroLoadStatement(loadMacro, "cc_toolchain"),
+        getToolchainRule("a"));
+  }
+
+  @Test
+  public void setupTestCcToolchainSuiteLoadedThroughMacro() throws Exception {
+    setupTestCcToolchainSuiteLoadedThroughMacro(/* loadMacro= */ true);
+    assertThat(getConfiguredTarget("//a:a")).isNotNull();
+    assertNoEvents();
+  }
+
+  private void setupTestCcToolchainSuiteLoadedThroughMacro(boolean loadMacro) throws Exception {
+    useConfiguration("--incompatible_load_cc_rules_from_bzl");
+    scratch.file("a/cc_toolchain_config.bzl", MockCcSupport.EMPTY_CC_TOOLCHAIN);
+    scratch.file(
+        "a/BUILD",
+        "load(':cc_toolchain_config.bzl', 'cc_toolchain_config')",
+        getAnalysisMock()
+            .ccSupport()
+            .getMacroLoadStatement(loadMacro, "cc_toolchain", "cc_toolchain_suite"),
+        "cc_toolchain_suite(",
+        "    name = 'a',",
+        "    toolchains = { 'k8': ':b' },",
+        ")",
+        getToolchainRule("b"));
+  }
+
+  @Test
+  public void testCcToolchainSuiteNotLoadedThroughMacro() throws Exception {
+    setupTestCcToolchainSuiteLoadedThroughMacro(/* loadMacro= */ false);
+    reporter.removeHandler(failFastHandler);
+    getConfiguredTarget("//a:a");
+    assertContainsEvent("rules are deprecated");
+  }
+
+  private static String getToolchainRule(String targetName) {
+    return Joiner.on("\n")
+        .join(
+            "cc_toolchain(",
+            "    name = '" + targetName + "',",
+            "    toolchain_identifier = 'toolchain-identifier-k8',",
+            "    toolchain_config = ':toolchain_config',",
+            "    all_files = ':banana',",
+            "    ar_files = ':empty',",
+            "    as_files = ':empty',",
+            "    compiler_files = ':empty',",
+            "    dwp_files = ':empty',",
+            "    linker_files = ':empty',",
+            "    strip_files = ':empty',",
+            "    objcopy_files = ':empty',",
+            "    dynamic_runtime_lib = ':empty',",
+            "    static_runtime_lib = ':empty')",
+            "filegroup(",
+            "   name='empty')",
+            "filegroup(",
+            "    name = 'banana',",
+            "    srcs = ['banana1', 'banana2'])",
+            "cc_toolchain_config(name='toolchain_config')");
+  }
 }
diff --git a/src/test/java/com/google/devtools/build/lib/rules/cpp/proto/CcProtoLibraryTest.java b/src/test/java/com/google/devtools/build/lib/rules/cpp/proto/CcProtoLibraryTest.java
index eba60ec..ffcc51b 100644
--- a/src/test/java/com/google/devtools/build/lib/rules/cpp/proto/CcProtoLibraryTest.java
+++ b/src/test/java/com/google/devtools/build/lib/rules/cpp/proto/CcProtoLibraryTest.java
@@ -331,4 +331,41 @@
         ccInfo.getCcCompilationContext().getDeclaredIncludeSrcs().toList();
     return Iterables.getOnlyElement(headers).getExecPathString();
   }
+
+  @Test
+  public void testCcProtoLibraryLoadedThroughMacro() throws Exception {
+    if (!analysisMock.isThisBazel()) {
+      return;
+    }
+    setupTestCcProtoLibraryLoadedThroughMacro(/* loadMacro= */ true);
+    assertThat(getConfiguredTarget("//a:a")).isNotNull();
+    assertNoEvents();
+  }
+
+  @Test
+  public void testCcProtoLibraryNotLoadedThroughMacro() throws Exception {
+    if (!analysisMock.isThisBazel()) {
+      return;
+    }
+    setupTestCcProtoLibraryLoadedThroughMacro(/* loadMacro= */ false);
+    reporter.removeHandler(failFastHandler);
+    getConfiguredTarget("//a:a");
+    assertContainsEvent("rules are deprecated");
+  }
+
+  private void setupTestCcProtoLibraryLoadedThroughMacro(boolean loadMacro) throws Exception {
+    useConfiguration("--incompatible_load_cc_rules_from_bzl");
+
+    scratch.file(
+        "a/BUILD",
+        getAnalysisMock().ccSupport().getMacroLoadStatement(loadMacro, "cc_proto_library"),
+        "cc_proto_library(",
+        "    name='a',",
+        "    deps=[':a_p'],",
+        ")",
+        "proto_library(",
+        "    name='a_p',",
+        "    srcs = ['a.proto'],",
+        ")");
+  }
 }
diff --git a/src/test/java/com/google/devtools/build/lib/rules/objc/ObjcImportTest.java b/src/test/java/com/google/devtools/build/lib/rules/objc/ObjcImportTest.java
index 6c1cfac..33d4b14 100644
--- a/src/test/java/com/google/devtools/build/lib/rules/objc/ObjcImportTest.java
+++ b/src/test/java/com/google/devtools/build/lib/rules/objc/ObjcImportTest.java
@@ -122,4 +122,27 @@
   public void testSdkIncludesUsedInCompileActionsOfDependers() throws Exception {
     checkSdkIncludesUsedInCompileActionsOfDependers(RULE_TYPE);
   }
+
+  @Test
+  public void testObjcImportLoadedThroughMacro() throws Exception {
+    setupTestObjcImportLoadedThroughMacro(/* loadMacro= */ true);
+    assertThat(getConfiguredTarget("//a:a")).isNotNull();
+    assertNoEvents();
+  }
+
+  @Test
+  public void testObjcImportNotLoadedThroughMacro() throws Exception {
+    setupTestObjcImportLoadedThroughMacro(/* loadMacro= */ false);
+    reporter.removeHandler(failFastHandler);
+    getConfiguredTarget("//a:a");
+    assertContainsEvent("rules are deprecated");
+  }
+
+  private void setupTestObjcImportLoadedThroughMacro(boolean loadMacro) throws Exception {
+    useConfiguration("--incompatible_load_cc_rules_from_bzl");
+    scratch.file(
+        "a/BUILD",
+        getAnalysisMock().ccSupport().getMacroLoadStatement(loadMacro, "objc_import"),
+        "objc_import(name='a', archives=['a.a'])");
+  }
 }
diff --git a/src/test/java/com/google/devtools/build/lib/rules/objc/ObjcLibraryTest.java b/src/test/java/com/google/devtools/build/lib/rules/objc/ObjcLibraryTest.java
index 20d3f85..6a17487 100644
--- a/src/test/java/com/google/devtools/build/lib/rules/objc/ObjcLibraryTest.java
+++ b/src/test/java/com/google/devtools/build/lib/rules/objc/ObjcLibraryTest.java
@@ -1918,4 +1918,27 @@
             + "this attribute has unsupported character '/'",
         "objc_library(name = 'foo/bar', srcs = ['foo.m'])");
   }
+
+  @Test
+  public void testObjcLibraryLoadedThroughMacro() throws Exception {
+    setupTestObjcLibraryLoadedThroughMacro(/* loadMacro= */ true);
+    assertThat(getConfiguredTarget("//a:a")).isNotNull();
+    assertNoEvents();
+  }
+
+  @Test
+  public void testObjcLibraryNotLoadedThroughMacro() throws Exception {
+    setupTestObjcLibraryLoadedThroughMacro(/* loadMacro= */ false);
+    reporter.removeHandler(failFastHandler);
+    getConfiguredTarget("//a:a");
+    assertContainsEvent("rules are deprecated");
+  }
+
+  private void setupTestObjcLibraryLoadedThroughMacro(boolean loadMacro) throws Exception {
+    useConfiguration("--incompatible_load_cc_rules_from_bzl");
+    scratch.file(
+        "a/BUILD",
+        getAnalysisMock().ccSupport().getMacroLoadStatement(loadMacro, "objc_library"),
+        "objc_library(name='a', srcs=['a.cc'])");
+  }
 }
diff --git a/tools/cpp/BUILD.static.freebsd b/tools/cpp/BUILD.static.freebsd
index b21dc3d..a3a69d3 100644
--- a/tools/cpp/BUILD.static.freebsd
+++ b/tools/cpp/BUILD.static.freebsd
@@ -17,6 +17,7 @@
 package(default_visibility = ["//visibility:public"])
 
 load("@bazel_tools//tools/cpp:cc_toolchain_config.bzl", "cc_toolchain_config")
+load("@rules_cc//cc:defs.bzl", "cc_toolchain_suite", "cc_toolchain", "cc_library")
 
 cc_library(
     name = "malloc",
diff --git a/tools/cpp/BUILD.windows.tpl b/tools/cpp/BUILD.windows.tpl
index be903f9..260ed81 100644
--- a/tools/cpp/BUILD.windows.tpl
+++ b/tools/cpp/BUILD.windows.tpl
@@ -16,6 +16,7 @@
 
 package(default_visibility = ["//visibility:public"])
 
+load("@rules_cc//cc:defs.bzl", "cc_toolchain", "cc_toolchain_suite", "cc_library")
 load(":windows_cc_toolchain_config.bzl", "cc_toolchain_config")
 load(":armeabi_cc_toolchain_config.bzl", "armeabi_cc_toolchain_config")
 cc_library(
diff --git a/tools/osx/crosstool/BUILD.tpl b/tools/osx/crosstool/BUILD.tpl
index ee8f119..f6af2de 100644
--- a/tools/osx/crosstool/BUILD.tpl
+++ b/tools/osx/crosstool/BUILD.tpl
@@ -1,6 +1,7 @@
 package(default_visibility = ["//visibility:public"])
 
 load("@local_config_cc_toolchains//:osx_archs.bzl", "OSX_TOOLS_ARCHS")
+load("@rules_cc//cc:defs.bzl", "cc_toolchain_suite", "cc_library")
 load(":cc_toolchain_config.bzl", "cc_toolchain_config")
 
 # Reexporting osx_arch.bzl for backwards compatibility