about summary refs log tree commit diff
diff options
context:
space:
mode:
authorEric Huss <eric@huss.org>2024-11-24 09:08:07 -0800
committerEric Huss <eric@huss.org>2024-11-27 06:01:46 -0800
commitf592dd95dbfc892c1153af67e0ab5b4e593d33e7 (patch)
tree75ac3f2405ef41a8033d1a9cdb1374f1a0b08c75
parent39cb3386ddc6c71657418be28dbb3987eea4aa4b (diff)
downloadrust-f592dd95dbfc892c1153af67e0ab5b4e593d33e7.tar.gz
rust-f592dd95dbfc892c1153af67e0ab5b4e593d33e7.zip
Compiletest: Add proc-macro header
This adds a proc-macro header to make it easier to depend on a
proc-macro, and remove some of the boilerplate necessary.
-rw-r--r--src/tools/compiletest/src/directive-list.rs1
-rw-r--r--src/tools/compiletest/src/header.rs1
-rw-r--r--src/tools/compiletest/src/header/auxiliary.rs11
-rw-r--r--src/tools/compiletest/src/runtest.rs76
4 files changed, 66 insertions, 23 deletions
diff --git a/src/tools/compiletest/src/directive-list.rs b/src/tools/compiletest/src/directive-list.rs
index 0c47ef871d2..952533e904c 100644
--- a/src/tools/compiletest/src/directive-list.rs
+++ b/src/tools/compiletest/src/directive-list.rs
@@ -215,6 +215,7 @@ const KNOWN_DIRECTIVE_NAMES: &[&str] = &[
     "pp-exact",
     "pretty-compare-only",
     "pretty-mode",
+    "proc-macro",
     "reference",
     "regex-error-pattern",
     "remap-src-base",
diff --git a/src/tools/compiletest/src/header.rs b/src/tools/compiletest/src/header.rs
index e945797647e..fe4c5fdd8b5 100644
--- a/src/tools/compiletest/src/header.rs
+++ b/src/tools/compiletest/src/header.rs
@@ -221,6 +221,7 @@ mod directives {
     pub const AUX_BIN: &'static str = "aux-bin";
     pub const AUX_BUILD: &'static str = "aux-build";
     pub const AUX_CRATE: &'static str = "aux-crate";
+    pub const PROC_MACRO: &'static str = "proc-macro";
     pub const AUX_CODEGEN_BACKEND: &'static str = "aux-codegen-backend";
     pub const EXEC_ENV: &'static str = "exec-env";
     pub const RUSTC_ENV: &'static str = "rustc-env";
diff --git a/src/tools/compiletest/src/header/auxiliary.rs b/src/tools/compiletest/src/header/auxiliary.rs
index 6f6538ce196..0e1f3a785f8 100644
--- a/src/tools/compiletest/src/header/auxiliary.rs
+++ b/src/tools/compiletest/src/header/auxiliary.rs
@@ -4,7 +4,7 @@
 use std::iter;
 
 use crate::common::Config;
-use crate::header::directives::{AUX_BIN, AUX_BUILD, AUX_CODEGEN_BACKEND, AUX_CRATE};
+use crate::header::directives::{AUX_BIN, AUX_BUILD, AUX_CODEGEN_BACKEND, AUX_CRATE, PROC_MACRO};
 
 /// Properties parsed from `aux-*` test directives.
 #[derive(Clone, Debug, Default)]
@@ -17,6 +17,8 @@ pub(crate) struct AuxProps {
     /// Similar to `builds`, but a list of NAME=somelib.rs of dependencies
     /// to build and pass with the `--extern` flag.
     pub(crate) crates: Vec<(String, String)>,
+    /// Same as `builds`, but for proc-macros.
+    pub(crate) proc_macros: Vec<String>,
     /// Similar to `builds`, but also uses the resulting dylib as a
     /// `-Zcodegen-backend` when compiling the test file.
     pub(crate) codegen_backend: Option<String>,
@@ -26,12 +28,13 @@ impl AuxProps {
     /// Yields all of the paths (relative to `./auxiliary/`) that have been
     /// specified in `aux-*` directives for this test.
     pub(crate) fn all_aux_path_strings(&self) -> impl Iterator<Item = &str> {
-        let Self { builds, bins, crates, codegen_backend } = self;
+        let Self { builds, bins, crates, proc_macros, codegen_backend } = self;
 
         iter::empty()
             .chain(builds.iter().map(String::as_str))
             .chain(bins.iter().map(String::as_str))
             .chain(crates.iter().map(|(_, path)| path.as_str()))
+            .chain(proc_macros.iter().map(String::as_str))
             .chain(codegen_backend.iter().map(String::as_str))
     }
 }
@@ -39,13 +42,15 @@ impl AuxProps {
 /// If the given test directive line contains an `aux-*` directive, parse it
 /// and update [`AuxProps`] accordingly.
 pub(super) fn parse_and_update_aux(config: &Config, ln: &str, aux: &mut AuxProps) {
-    if !ln.starts_with("aux-") {
+    if !(ln.starts_with("aux-") || ln.starts_with("proc-macro")) {
         return;
     }
 
     config.push_name_value_directive(ln, AUX_BUILD, &mut aux.builds, |r| r.trim().to_string());
     config.push_name_value_directive(ln, AUX_BIN, &mut aux.bins, |r| r.trim().to_string());
     config.push_name_value_directive(ln, AUX_CRATE, &mut aux.crates, parse_aux_crate);
+    config
+        .push_name_value_directive(ln, PROC_MACRO, &mut aux.proc_macros, |r| r.trim().to_string());
     if let Some(r) = config.parse_name_value_directive(ln, AUX_CODEGEN_BACKEND) {
         aux.codegen_backend = Some(r.trim().to_owned());
     }
diff --git a/src/tools/compiletest/src/runtest.rs b/src/tools/compiletest/src/runtest.rs
index bc80c8246ad..93e5980f1f5 100644
--- a/src/tools/compiletest/src/runtest.rs
+++ b/src/tools/compiletest/src/runtest.rs
@@ -102,7 +102,7 @@ fn get_lib_name(name: &str, aux_type: AuxType) -> Option<String> {
         // In this case, the only path we can pass
         // with '--extern-meta' is the '.rlib' file
         AuxType::Lib => Some(format!("lib{name}.rlib")),
-        AuxType::Dylib => Some(dylib_name(name)),
+        AuxType::Dylib | AuxType::ProcMacro => Some(dylib_name(name)),
     }
 }
 
@@ -1097,7 +1097,9 @@ impl<'test> TestCx<'test> {
     }
 
     fn has_aux_dir(&self) -> bool {
-        !self.props.aux.builds.is_empty() || !self.props.aux.crates.is_empty()
+        !self.props.aux.builds.is_empty()
+            || !self.props.aux.crates.is_empty()
+            || !self.props.aux.proc_macros.is_empty()
     }
 
     fn aux_output_dir(&self) -> PathBuf {
@@ -1118,31 +1120,48 @@ impl<'test> TestCx<'test> {
 
     fn build_all_auxiliary(&self, of: &TestPaths, aux_dir: &Path, rustc: &mut Command) {
         for rel_ab in &self.props.aux.builds {
-            self.build_auxiliary(of, rel_ab, &aux_dir, false /* is_bin */);
+            self.build_auxiliary(of, rel_ab, &aux_dir, None);
         }
 
         for rel_ab in &self.props.aux.bins {
-            self.build_auxiliary(of, rel_ab, &aux_dir, true /* is_bin */);
+            self.build_auxiliary(of, rel_ab, &aux_dir, Some(AuxType::Bin));
         }
 
+        let path_to_crate_name = |path: &str| -> String {
+            path.rsplit_once('/')
+                .map_or(path, |(_, tail)| tail)
+                .trim_end_matches(".rs")
+                .replace('-', "_")
+        };
+
+        let add_extern =
+            |rustc: &mut Command, aux_name: &str, aux_path: &str, aux_type: AuxType| {
+                let lib_name = get_lib_name(&path_to_crate_name(aux_path), aux_type);
+                if let Some(lib_name) = lib_name {
+                    rustc.arg("--extern").arg(format!(
+                        "{}={}/{}",
+                        aux_name,
+                        aux_dir.display(),
+                        lib_name
+                    ));
+                }
+            };
+
         for (aux_name, aux_path) in &self.props.aux.crates {
-            let aux_type = self.build_auxiliary(of, &aux_path, &aux_dir, false /* is_bin */);
-            let lib_name =
-                get_lib_name(&aux_path.trim_end_matches(".rs").replace('-', "_"), aux_type);
-            if let Some(lib_name) = lib_name {
-                rustc.arg("--extern").arg(format!(
-                    "{}={}/{}",
-                    aux_name,
-                    aux_dir.display(),
-                    lib_name
-                ));
-            }
+            let aux_type = self.build_auxiliary(of, &aux_path, &aux_dir, None);
+            add_extern(rustc, aux_name, aux_path, aux_type);
+        }
+
+        for proc_macro in &self.props.aux.proc_macros {
+            self.build_auxiliary(of, proc_macro, &aux_dir, Some(AuxType::ProcMacro));
+            let crate_name = path_to_crate_name(proc_macro);
+            add_extern(rustc, &crate_name, proc_macro, AuxType::ProcMacro);
         }
 
         // Build any `//@ aux-codegen-backend`, and pass the resulting library
         // to `-Zcodegen-backend` when compiling the test file.
         if let Some(aux_file) = &self.props.aux.codegen_backend {
-            let aux_type = self.build_auxiliary(of, aux_file, aux_dir, false);
+            let aux_type = self.build_auxiliary(of, aux_file, aux_dir, None);
             if let Some(lib_name) = get_lib_name(aux_file.trim_end_matches(".rs"), aux_type) {
                 let lib_path = aux_dir.join(&lib_name);
                 rustc.arg(format!("-Zcodegen-backend={}", lib_path.display()));
@@ -1209,17 +1228,23 @@ impl<'test> TestCx<'test> {
     }
 
     /// Builds an aux dependency.
+    ///
+    /// If `aux_type` is `None`, then this will determine the aux-type automatically.
     fn build_auxiliary(
         &self,
         of: &TestPaths,
         source_path: &str,
         aux_dir: &Path,
-        is_bin: bool,
+        aux_type: Option<AuxType>,
     ) -> AuxType {
         let aux_testpaths = self.compute_aux_test_paths(of, source_path);
-        let aux_props = self.props.from_aux_file(&aux_testpaths.file, self.revision, self.config);
+        let mut aux_props =
+            self.props.from_aux_file(&aux_testpaths.file, self.revision, self.config);
+        if aux_type == Some(AuxType::ProcMacro) {
+            aux_props.force_host = true;
+        }
         let mut aux_dir = aux_dir.to_path_buf();
-        if is_bin {
+        if aux_type == Some(AuxType::Bin) {
             // On unix, the binary of `auxiliary/foo.rs` will be named
             // `auxiliary/foo` which clashes with the _dir_ `auxiliary/foo`, so
             // put bins in a `bin` subfolder.
@@ -1250,8 +1275,12 @@ impl<'test> TestCx<'test> {
             aux_rustc.env_remove(key);
         }
 
-        let (aux_type, crate_type) = if is_bin {
+        let (aux_type, crate_type) = if aux_type == Some(AuxType::Bin) {
             (AuxType::Bin, Some("bin"))
+        } else if aux_type == Some(AuxType::ProcMacro) {
+            (AuxType::ProcMacro, Some("proc-macro"))
+        } else if aux_type.is_some() {
+            panic!("aux_type {aux_type:?} not expected");
         } else if aux_props.no_prefer_dynamic {
             (AuxType::Dylib, None)
         } else if self.config.target.contains("emscripten")
@@ -1287,6 +1316,11 @@ impl<'test> TestCx<'test> {
             aux_rustc.args(&["--crate-type", crate_type]);
         }
 
+        if aux_type == AuxType::ProcMacro {
+            // For convenience, but this only works on 2018.
+            aux_rustc.args(&["--extern", "proc_macro"]);
+        }
+
         aux_rustc.arg("-L").arg(&aux_dir);
 
         let auxres = aux_cx.compose_and_run(
@@ -2768,8 +2802,10 @@ enum LinkToAux {
     No,
 }
 
+#[derive(Debug, PartialEq)]
 enum AuxType {
     Bin,
     Lib,
     Dylib,
+    ProcMacro,
 }