Propagate rustc_env{,_files} from rust_test.crate (#1443)

rust_test.crate builds the same file as the rust_library it's pointing
to, which will almost certainly depend on the same environment variables
being set.
diff --git a/docs/flatten.md b/docs/flatten.md
index c3324b9..adde2af 100644
--- a/docs/flatten.md
+++ b/docs/flatten.md
@@ -1353,7 +1353,7 @@
 
 <pre>
 CrateInfo(<a href="#CrateInfo-aliases">aliases</a>, <a href="#CrateInfo-compile_data">compile_data</a>, <a href="#CrateInfo-deps">deps</a>, <a href="#CrateInfo-edition">edition</a>, <a href="#CrateInfo-is_test">is_test</a>, <a href="#CrateInfo-metadata">metadata</a>, <a href="#CrateInfo-name">name</a>, <a href="#CrateInfo-output">output</a>, <a href="#CrateInfo-owner">owner</a>,
-          <a href="#CrateInfo-proc_macro_deps">proc_macro_deps</a>, <a href="#CrateInfo-root">root</a>, <a href="#CrateInfo-rustc_env">rustc_env</a>, <a href="#CrateInfo-srcs">srcs</a>, <a href="#CrateInfo-type">type</a>, <a href="#CrateInfo-wrapped_crate_type">wrapped_crate_type</a>)
+          <a href="#CrateInfo-proc_macro_deps">proc_macro_deps</a>, <a href="#CrateInfo-root">root</a>, <a href="#CrateInfo-rustc_env">rustc_env</a>, <a href="#CrateInfo-rustc_env_files">rustc_env_files</a>, <a href="#CrateInfo-srcs">srcs</a>, <a href="#CrateInfo-type">type</a>, <a href="#CrateInfo-wrapped_crate_type">wrapped_crate_type</a>)
 </pre>
 
 A provider containing general Crate information.
@@ -1375,6 +1375,7 @@
 | <a id="CrateInfo-proc_macro_deps"></a>proc_macro_deps |  depset[DepVariantInfo]: This crate's rust proc_macro dependencies' providers.    |
 | <a id="CrateInfo-root"></a>root |  File: The source File entrypoint to this crate, eg. lib.rs    |
 | <a id="CrateInfo-rustc_env"></a>rustc_env |  Dict[String, String]: Additional <code>"key": "value"</code> environment variables to set for rustc.    |
+| <a id="CrateInfo-rustc_env_files"></a>rustc_env_files |  [File]: Files containing additional environment variables to set for rustc.    |
 | <a id="CrateInfo-srcs"></a>srcs |  depset[File]: All source Files that are part of the crate.    |
 | <a id="CrateInfo-type"></a>type |  str: The type of this crate (see [rustc --crate-type](https://doc.rust-lang.org/rustc/command-line-arguments.html#--crate-type-a-list-of-types-of-crates-for-the-compiler-to-emit)).    |
 | <a id="CrateInfo-wrapped_crate_type"></a>wrapped_crate_type |  str, optional: The original crate type for targets generated using a previously defined crate (typically tests using the <code>rust_test::crate</code> attribute)    |
diff --git a/docs/providers.md b/docs/providers.md
index 775dbd9..11f77b7 100644
--- a/docs/providers.md
+++ b/docs/providers.md
@@ -11,7 +11,7 @@
 
 <pre>
 CrateInfo(<a href="#CrateInfo-aliases">aliases</a>, <a href="#CrateInfo-compile_data">compile_data</a>, <a href="#CrateInfo-deps">deps</a>, <a href="#CrateInfo-edition">edition</a>, <a href="#CrateInfo-is_test">is_test</a>, <a href="#CrateInfo-metadata">metadata</a>, <a href="#CrateInfo-name">name</a>, <a href="#CrateInfo-output">output</a>, <a href="#CrateInfo-owner">owner</a>,
-          <a href="#CrateInfo-proc_macro_deps">proc_macro_deps</a>, <a href="#CrateInfo-root">root</a>, <a href="#CrateInfo-rustc_env">rustc_env</a>, <a href="#CrateInfo-srcs">srcs</a>, <a href="#CrateInfo-type">type</a>, <a href="#CrateInfo-wrapped_crate_type">wrapped_crate_type</a>)
+          <a href="#CrateInfo-proc_macro_deps">proc_macro_deps</a>, <a href="#CrateInfo-root">root</a>, <a href="#CrateInfo-rustc_env">rustc_env</a>, <a href="#CrateInfo-rustc_env_files">rustc_env_files</a>, <a href="#CrateInfo-srcs">srcs</a>, <a href="#CrateInfo-type">type</a>, <a href="#CrateInfo-wrapped_crate_type">wrapped_crate_type</a>)
 </pre>
 
 A provider containing general Crate information.
@@ -33,6 +33,7 @@
 | <a id="CrateInfo-proc_macro_deps"></a>proc_macro_deps |  depset[DepVariantInfo]: This crate's rust proc_macro dependencies' providers.    |
 | <a id="CrateInfo-root"></a>root |  File: The source File entrypoint to this crate, eg. lib.rs    |
 | <a id="CrateInfo-rustc_env"></a>rustc_env |  Dict[String, String]: Additional <code>"key": "value"</code> environment variables to set for rustc.    |
+| <a id="CrateInfo-rustc_env_files"></a>rustc_env_files |  [File]: Files containing additional environment variables to set for rustc.    |
 | <a id="CrateInfo-srcs"></a>srcs |  depset[File]: All source Files that are part of the crate.    |
 | <a id="CrateInfo-type"></a>type |  str: The type of this crate (see [rustc --crate-type](https://doc.rust-lang.org/rustc/command-line-arguments.html#--crate-type-a-list-of-types-of-crates-for-the-compiler-to-emit)).    |
 | <a id="CrateInfo-wrapped_crate_type"></a>wrapped_crate_type |  str, optional: The original crate type for targets generated using a previously defined crate (typically tests using the <code>rust_test::crate</code> attribute)    |
diff --git a/rust/private/common.bzl b/rust/private/common.bzl
index 3de7cb5..025c4d7 100644
--- a/rust/private/common.bzl
+++ b/rust/private/common.bzl
@@ -49,6 +49,8 @@
         kwargs.update({"wrapped_crate_type": None})
     if not "metadata" in kwargs:
         kwargs.update({"metadata": None})
+    if not "rustc_env_files" in kwargs:
+        kwargs.update({"rustc_env_files": []})
     return CrateInfo(**kwargs)
 
 rust_common = struct(
diff --git a/rust/private/providers.bzl b/rust/private/providers.bzl
index 7533349..464444b 100644
--- a/rust/private/providers.bzl
+++ b/rust/private/providers.bzl
@@ -29,6 +29,7 @@
         "proc_macro_deps": "depset[DepVariantInfo]: This crate's rust proc_macro dependencies' providers.",
         "root": "File: The source File entrypoint to this crate, eg. lib.rs",
         "rustc_env": "Dict[String, String]: Additional `\"key\": \"value\"` environment variables to set for rustc.",
+        "rustc_env_files": "[File]: Files containing additional environment variables to set for rustc.",
         "srcs": "depset[File]: All source Files that are part of the crate.",
         "type": (
             "str: The type of this crate " +
diff --git a/rust/private/rust.bzl b/rust/private/rust.bzl
index 25e56bf..66c699e 100644
--- a/rust/private/rust.bzl
+++ b/rust/private/rust.bzl
@@ -343,6 +343,7 @@
             metadata = rust_metadata,
             edition = get_edition(ctx.attr, toolchain, ctx.label),
             rustc_env = ctx.attr.rustc_env,
+            rustc_env_files = ctx.files.rustc_env_files,
             is_test = False,
             compile_data = depset(ctx.files.compile_data),
             owner = ctx.label,
@@ -387,6 +388,7 @@
             output = output,
             edition = get_edition(ctx.attr, toolchain, ctx.label),
             rustc_env = ctx.attr.rustc_env,
+            rustc_env_files = ctx.files.rustc_env_files,
             is_test = False,
             compile_data = depset(ctx.files.compile_data),
             owner = ctx.label,
@@ -431,6 +433,9 @@
             compile_data = depset(ctx.files.compile_data, transitive = [crate.compile_data])
         else:
             compile_data = depset(ctx.files.compile_data)
+        rustc_env_files = ctx.files.rustc_env_files + crate.rustc_env_files
+        rustc_env = dict(crate.rustc_env)
+        rustc_env.update(**ctx.attr.rustc_env)
 
         # Build the test binary using the dependency's srcs.
         crate_info = rust_common.create_crate_info(
@@ -443,7 +448,8 @@
             aliases = ctx.attr.aliases,
             output = output,
             edition = crate.edition,
-            rustc_env = ctx.attr.rustc_env,
+            rustc_env = rustc_env,
+            rustc_env_files = rustc_env_files,
             is_test = True,
             compile_data = compile_data,
             wrapped_crate_type = crate.type,
@@ -474,6 +480,7 @@
             output = output,
             edition = get_edition(ctx.attr, toolchain, ctx.label),
             rustc_env = ctx.attr.rustc_env,
+            rustc_env_files = ctx.files.rustc_env_files,
             is_test = True,
             compile_data = depset(ctx.files.compile_data),
             owner = ctx.label,
diff --git a/rust/private/rustc.bzl b/rust/private/rustc.bzl
index 70193d3..efecc3b 100644
--- a/rust/private/rustc.bzl
+++ b/rust/private/rustc.bzl
@@ -672,7 +672,9 @@
         ],
     )
 
-    build_env_files = getattr(files, "rustc_env_files", [])
+    # For backwards compatibility, we also check the value of the `rustc_env_files` attribute when
+    # `crate_info.rustc_env_files` is not populated.
+    build_env_files = crate_info.rustc_env_files if crate_info.rustc_env_files else getattr(files, "rustc_env_files", [])
     compile_inputs, out_dir, build_env_file, build_flags_files = _process_build_scripts(build_info, dep_info, compile_inputs)
     if build_env_file:
         build_env_files = [f for f in build_env_files] + [build_env_file]
diff --git a/rust/private/rustdoc.bzl b/rust/private/rustdoc.bzl
index 6874717..ba3a12c 100644
--- a/rust/private/rustdoc.bzl
+++ b/rust/private/rustdoc.bzl
@@ -40,6 +40,7 @@
         metadata = None,
         edition = crate_info.edition,
         rustc_env = crate_info.rustc_env,
+        rustc_env_files = crate_info.rustc_env_files,
         is_test = crate_info.is_test,
         compile_data = crate_info.compile_data,
     )
diff --git a/rust/private/rustdoc_test.bzl b/rust/private/rustdoc_test.bzl
index a2ee98c..525838e 100644
--- a/rust/private/rustdoc_test.bzl
+++ b/rust/private/rustdoc_test.bzl
@@ -119,6 +119,7 @@
         output = crate.output,
         edition = crate.edition,
         rustc_env = crate.rustc_env,
+        rustc_env_files = crate.rustc_env_files,
         is_test = True,
         compile_data = crate.compile_data,
         wrapped_crate_type = crate.type,
diff --git a/test/build_env/BUILD.bazel b/test/build_env/BUILD.bazel
index 908749a..b4e1a92 100644
--- a/test/build_env/BUILD.bazel
+++ b/test/build_env/BUILD.bazel
@@ -2,7 +2,7 @@
     "//cargo:cargo_build_script.bzl",
     "cargo_build_script",
 )
-load("//rust:defs.bzl", "rust_test")
+load("//rust:defs.bzl", "rust_library", "rust_test")
 
 package(default_visibility = ["//visibility:public"])
 
@@ -13,6 +13,39 @@
     edition = "2018",
 )
 
+rust_library(
+    name = "arbitrary_env_lib",
+    srcs = ["tests/arbitrary_env_lib.rs"],
+    edition = "2018",
+    rustc_env = {
+        "USER_DEFINED_KEY": "USER_DEFINED_VALUE",
+    },
+)
+
+rust_test(
+    name = "arbitrary_env_lib_test",
+    crate = ":arbitrary_env_lib",
+    edition = "2018",
+)
+
+rust_library(
+    name = "arbitrary_env_lib_in_test",
+    srcs = ["tests/arbitrary_env_lib.rs"],
+    edition = "2018",
+    rustc_env = {
+        "USER_DEFINED_KEY": "DIFFERENT_USER_DEFINED_VALUE",
+    },
+)
+
+rust_test(
+    name = "arbitrary_env_lib_test_in_test",
+    crate = ":arbitrary_env_lib_in_test",
+    edition = "2018",
+    rustc_env = {
+        "USER_DEFINED_KEY": "USER_DEFINED_VALUE",
+    },
+)
+
 rust_test(
     name = "arbitrary_env_test",
     srcs = ["tests/arbitrary_env.rs"],
diff --git a/test/build_env/tests/arbitrary_env_lib.rs b/test/build_env/tests/arbitrary_env_lib.rs
new file mode 100644
index 0000000..e89fc2e
--- /dev/null
+++ b/test/build_env/tests/arbitrary_env_lib.rs
@@ -0,0 +1,16 @@
+pub fn from_lib() -> &'static str {
+    env!("USER_DEFINED_KEY")
+}
+
+#[cfg(test)]
+mod tests {
+    #[test]
+    fn verify_from_lib() {
+        assert_eq!(super::from_lib(), "USER_DEFINED_VALUE");
+    }
+
+    #[test]
+    fn verify_from_test() {
+        assert_eq!(env!("USER_DEFINED_KEY"), "USER_DEFINED_VALUE");
+    }
+}
diff --git a/test/rustc_env_files/BUILD.bazel b/test/rustc_env_files/BUILD.bazel
index 4139825..cb48b2e 100644
--- a/test/rustc_env_files/BUILD.bazel
+++ b/test/rustc_env_files/BUILD.bazel
@@ -1,5 +1,5 @@
 load("@bazel_skylib//rules:write_file.bzl", "write_file")
-load("//rust:defs.bzl", "rust_binary")
+load("//rust:defs.bzl", "rust_binary", "rust_library", "rust_test")
 
 package(default_visibility = ["//visibility:public"])
 
@@ -26,3 +26,15 @@
     args = ["$(rootpath :hello_env)"],
     data = [":hello_env"],
 )
+
+rust_library(
+    name = "hello_env_crate",
+    srcs = ["src/lib.rs"],
+    edition = "2018",
+    rustc_env_files = [":generate_rustc_env_file"],
+)
+
+rust_test(
+    name = "hello_env_crate_test",
+    crate = ":hello_env_crate",
+)
diff --git a/test/rustc_env_files/src/lib.rs b/test/rustc_env_files/src/lib.rs
new file mode 100644
index 0000000..8cd7cab
--- /dev/null
+++ b/test/rustc_env_files/src/lib.rs
@@ -0,0 +1,16 @@
+pub fn from_lib() -> &'static str {
+    env!("GREETING")
+}
+
+#[cfg(test)]
+mod tests {
+    #[test]
+    fn verify_from_lib() {
+        assert_eq!(super::from_lib(), "Howdy");
+    }
+
+    #[test]
+    fn verify_from_test() {
+        assert_eq!(env!("GREETING"), "Howdy");
+    }
+}