Skip to main content

compiletest/directives/
auxiliary.rs

1//! Code for dealing with test directives that request an "auxiliary" crate to
2//! be built and made available to the test in some way.
3
4use std::iter;
5
6use super::directives::{AUX_BIN, AUX_BUILD, AUX_CODEGEN_BACKEND, AUX_CRATE, PROC_MACRO};
7use crate::common::Config;
8use crate::directives::DirectiveLine;
9use crate::util::static_regex;
10
11#[cfg(test)]
12mod tests;
13
14/// The value of an `aux-crate` directive.
15#[derive(Clone, Debug, Default, PartialEq, Eq)]
16pub struct AuxCrate {
17    /// Contains `--extern` modifiers, if any. See the tracking issue for more
18    /// info: <https://github.com/rust-lang/rust/issues/98405>
19    /// With `aux-crate: noprelude:foo=bar.rs` this will be `noprelude`.
20    pub extern_modifiers: Option<String>,
21    /// With `aux-crate: foo=bar.rs` this will be `foo`.
22    /// With `aux-crate: noprelude:foo=bar.rs` this will be `foo`.
23    pub name: String,
24    /// With `aux-crate: foo=bar.rs` this will be `bar.rs`.
25    pub path: String,
26}
27
28/// The value of a `proc-macro` directive.
29#[derive(Clone, Debug, Default, PartialEq, Eq)]
30pub(crate) struct ProcMacro {
31    /// Contains `--extern` modifiers, if any. See the tracking issue for more
32    /// info: <https://github.com/rust-lang/rust/issues/98405>
33    /// With `proc-macro: noprelude:bar.rs` this will be `noprelude`.
34    pub extern_modifiers: Option<String>,
35    /// With `proc-macro: bar.rs` this will be `bar.rs`.
36    pub path: String,
37}
38
39/// Properties parsed from `aux-*` test directives.
40#[derive(Clone, Debug, Default)]
41pub(crate) struct AuxProps {
42    /// Other crates that should be built and made available to this test.
43    /// These are filenames relative to `./auxiliary/` in the test's directory.
44    pub(crate) builds: Vec<String>,
45    /// Auxiliary crates that should be compiled as `#![crate_type = "bin"]`.
46    pub(crate) bins: Vec<String>,
47    /// Similar to `builds`, but a list of NAME=somelib.rs of dependencies
48    /// to build and pass with the `--extern` flag.
49    pub(crate) crates: Vec<AuxCrate>,
50    /// Same as `builds`, but for proc-macros.
51    pub(crate) proc_macros: Vec<ProcMacro>,
52    /// Similar to `builds`, but also uses the resulting dylib as a
53    /// `-Zcodegen-backend` when compiling the test file.
54    pub(crate) codegen_backend: Option<String>,
55}
56
57impl AuxProps {
58    /// Yields all of the paths (relative to `./auxiliary/`) that have been
59    /// specified in `aux-*` directives for this test.
60    pub(crate) fn all_aux_path_strings(&self) -> impl Iterator<Item = &str> {
61        let Self { builds, bins, crates, proc_macros, codegen_backend } = self;
62
63        iter::empty()
64            .chain(builds.iter().map(String::as_str))
65            .chain(bins.iter().map(String::as_str))
66            .chain(crates.iter().map(|c| c.path.as_str()))
67            .chain(proc_macros.iter().map(|p| p.path.as_str()))
68            .chain(codegen_backend.iter().map(String::as_str))
69    }
70}
71
72/// If the given test directive line contains an `aux-*` directive, parse it
73/// and update [`AuxProps`] accordingly.
74pub(super) fn parse_and_update_aux(
75    config: &Config,
76    directive_line: &DirectiveLine<'_>,
77    aux: &mut AuxProps,
78) {
79    if !(directive_line.name.starts_with("aux-") || directive_line.name == "proc-macro") {
80        return;
81    }
82
83    let ln = directive_line;
84
85    config.push_name_value_directive(ln, AUX_BUILD, &mut aux.builds, |r| r.trim().to_string());
86    config.push_name_value_directive(ln, AUX_BIN, &mut aux.bins, |r| r.trim().to_string());
87    config.push_name_value_directive(ln, AUX_CRATE, &mut aux.crates, parse_aux_crate);
88    config.push_name_value_directive(ln, PROC_MACRO, &mut aux.proc_macros, parse_proc_macro);
89
90    if let Some(r) = config.parse_name_value_directive(ln, AUX_CODEGEN_BACKEND) {
91        aux.codegen_backend = Some(r.trim().to_owned());
92    }
93}
94
95fn parse_aux_crate(r: String) -> AuxCrate {
96    let r = r.trim();
97
98    // Matches:
99    //   name=path
100    //   modifiers:name=path
101    let caps = static_regex!(r"^(?:(?<modifiers>[^=]*?):)?(?<name>[^=]*)=(?<path>.*)$")
102        .captures(r)
103        .unwrap_or_else(|| {
104            panic!("couldn't parse aux-crate value `{r}` (should be e.g. `log=log.rs`)")
105        });
106
107    let modifiers = caps.name("modifiers").map(|m| m.as_str().to_string());
108    let name = caps["name"].to_string();
109    let path = caps["path"].to_string();
110
111    AuxCrate { extern_modifiers: modifiers, name, path }
112}
113
114fn parse_proc_macro(r: String) -> ProcMacro {
115    let r = r.trim();
116
117    // Matches:
118    //   path
119    //   modifiers:path
120    let caps = static_regex!(r"^(?:(?<modifiers>[^=]*?):)?(?<path>.*)$")
121        .captures(r)
122        .expect("can never fail");
123
124    let modifiers = caps.name("modifiers").map(|m| m.as_str().to_string());
125    let path = caps["path"].to_string();
126
127    ProcMacro { extern_modifiers: modifiers, path }
128}