about summary refs log tree commit diff
path: root/compiler/rustc_interface/src/interface.rs
diff options
context:
space:
mode:
Diffstat (limited to 'compiler/rustc_interface/src/interface.rs')
-rw-r--r--compiler/rustc_interface/src/interface.rs497
1 files changed, 244 insertions, 253 deletions
diff --git a/compiler/rustc_interface/src/interface.rs b/compiler/rustc_interface/src/interface.rs
index e703fe228c3..6b51dfea9ec 100644
--- a/compiler/rustc_interface/src/interface.rs
+++ b/compiler/rustc_interface/src/interface.rs
@@ -65,295 +65,286 @@ impl Compiler {
 
 /// Converts strings provided as `--cfg [cfgspec]` into a `Cfg`.
 pub fn parse_cfg(handler: &EarlyErrorHandler, cfgs: Vec<String>) -> Cfg<String> {
-    // This creates a short-lived `SessionGlobals`, containing an interner. The
-    // parsed values are converted from symbols to strings before exiting
-    // because the symbols are meaningless once the interner is gone.
-    rustc_span::create_default_session_if_not_set_then(move |_| {
-        cfgs.into_iter()
-            .map(|s| {
-                let sess = ParseSess::with_silent_emitter(Some(format!(
-                    "this error occurred on the command line: `--cfg={s}`"
-                )));
-                let filename = FileName::cfg_spec_source_code(&s);
-
-                macro_rules! error {
-                    ($reason: expr) => {
-                        handler.early_error(format!(
-                            concat!("invalid `--cfg` argument: `{}` (", $reason, ")"),
-                            s
-                        ));
-                    };
-                }
-
-                match maybe_new_parser_from_source_str(&sess, filename, s.to_string()) {
-                    Ok(mut parser) => match parser.parse_meta_item() {
-                        Ok(meta_item) if parser.token == token::Eof => {
-                            if meta_item.path.segments.len() != 1 {
-                                error!("argument key must be an identifier");
-                            }
-                            match &meta_item.kind {
-                                MetaItemKind::List(..) => {}
-                                MetaItemKind::NameValue(lit) if !lit.kind.is_str() => {
-                                    error!("argument value must be a string");
-                                }
-                                MetaItemKind::NameValue(..) | MetaItemKind::Word => {
-                                    let ident = meta_item.ident().expect("multi-segment cfg key");
-                                    return (
-                                        ident.name.to_string(),
-                                        meta_item.value_str().map(|sym| sym.to_string()),
-                                    );
-                                }
-                            }
-                        }
-                        Ok(..) => {}
-                        Err(err) => err.cancel(),
-                    },
-                    Err(errs) => drop(errs),
-                }
-
-                // If the user tried to use a key="value" flag, but is missing the quotes, provide
-                // a hint about how to resolve this.
-                if s.contains('=') && !s.contains("=\"") && !s.ends_with('"') {
-                    error!(concat!(
-                        r#"expected `key` or `key="value"`, ensure escaping is appropriate"#,
-                        r#" for your shell, try 'key="value"' or key=\"value\""#
-                    ));
-                } else {
-                    error!(r#"expected `key` or `key="value"`"#);
-                }
-            })
-            .collect::<Cfg<String>>()
-    })
-}
-
-/// Converts strings provided as `--check-cfg [specs]` into a `CheckCfg`.
-pub fn parse_check_cfg(handler: &EarlyErrorHandler, specs: Vec<String>) -> CheckCfg<String> {
-    // The comment about `SessionGlobals` and symbols in `parse_cfg` above
-    // applies here too.
-    rustc_span::create_default_session_if_not_set_then(move |_| {
-        // If any --check-cfg is passed then exhaustive_values and exhaustive_names
-        // are enabled by default.
-        let exhaustive_names = !specs.is_empty();
-        let exhaustive_values = !specs.is_empty();
-        let mut check_cfg = CheckCfg { exhaustive_names, exhaustive_values, ..CheckCfg::default() };
-
-        let mut old_syntax = None;
-        for s in specs {
+    cfgs.into_iter()
+        .map(|s| {
             let sess = ParseSess::with_silent_emitter(Some(format!(
-                "this error occurred on the command line: `--check-cfg={s}`"
+                "this error occurred on the command line: `--cfg={s}`"
             )));
             let filename = FileName::cfg_spec_source_code(&s);
 
             macro_rules! error {
-                ($reason:expr) => {
+                ($reason: expr) => {
                     handler.early_error(format!(
-                        concat!("invalid `--check-cfg` argument: `{}` (", $reason, ")"),
+                        concat!("invalid `--cfg` argument: `{}` (", $reason, ")"),
                         s
-                    ))
+                    ));
                 };
             }
 
-            let expected_error = || -> ! {
-                error!("expected `cfg(name, values(\"value1\", \"value2\", ... \"valueN\"))`")
-            };
+            match maybe_new_parser_from_source_str(&sess, filename, s.to_string()) {
+                Ok(mut parser) => match parser.parse_meta_item() {
+                    Ok(meta_item) if parser.token == token::Eof => {
+                        if meta_item.path.segments.len() != 1 {
+                            error!("argument key must be an identifier");
+                        }
+                        match &meta_item.kind {
+                            MetaItemKind::List(..) => {}
+                            MetaItemKind::NameValue(lit) if !lit.kind.is_str() => {
+                                error!("argument value must be a string");
+                            }
+                            MetaItemKind::NameValue(..) | MetaItemKind::Word => {
+                                let ident = meta_item.ident().expect("multi-segment cfg key");
+                                return (
+                                    ident.name.to_string(),
+                                    meta_item.value_str().map(|sym| sym.to_string()),
+                                );
+                            }
+                        }
+                    }
+                    Ok(..) => {}
+                    Err(err) => err.cancel(),
+                },
+                Err(errs) => drop(errs),
+            }
 
-            let Ok(mut parser) = maybe_new_parser_from_source_str(&sess, filename, s.to_string())
-            else {
-                expected_error();
-            };
+            // If the user tried to use a key="value" flag, but is missing the quotes, provide
+            // a hint about how to resolve this.
+            if s.contains('=') && !s.contains("=\"") && !s.ends_with('"') {
+                error!(concat!(
+                    r#"expected `key` or `key="value"`, ensure escaping is appropriate"#,
+                    r#" for your shell, try 'key="value"' or key=\"value\""#
+                ));
+            } else {
+                error!(r#"expected `key` or `key="value"`"#);
+            }
+        })
+        .collect::<Cfg<String>>()
+}
 
-            let meta_item = match parser.parse_meta_item() {
-                Ok(meta_item) if parser.token == token::Eof => meta_item,
-                Ok(..) => expected_error(),
-                Err(err) => {
-                    err.cancel();
-                    expected_error();
-                }
+/// Converts strings provided as `--check-cfg [specs]` into a `CheckCfg`.
+pub fn parse_check_cfg(handler: &EarlyErrorHandler, specs: Vec<String>) -> CheckCfg<String> {
+    // If any --check-cfg is passed then exhaustive_values and exhaustive_names
+    // are enabled by default.
+    let exhaustive_names = !specs.is_empty();
+    let exhaustive_values = !specs.is_empty();
+    let mut check_cfg = CheckCfg { exhaustive_names, exhaustive_values, ..CheckCfg::default() };
+
+    let mut old_syntax = None;
+    for s in specs {
+        let sess = ParseSess::with_silent_emitter(Some(format!(
+            "this error occurred on the command line: `--check-cfg={s}`"
+        )));
+        let filename = FileName::cfg_spec_source_code(&s);
+
+        macro_rules! error {
+            ($reason:expr) => {
+                handler.early_error(format!(
+                    concat!("invalid `--check-cfg` argument: `{}` (", $reason, ")"),
+                    s
+                ))
             };
+        }
+
+        let expected_error = || -> ! {
+            error!("expected `cfg(name, values(\"value1\", \"value2\", ... \"valueN\"))`")
+        };
+
+        let Ok(mut parser) = maybe_new_parser_from_source_str(&sess, filename, s.to_string())
+        else {
+            expected_error();
+        };
 
-            let Some(args) = meta_item.meta_item_list() else {
+        let meta_item = match parser.parse_meta_item() {
+            Ok(meta_item) if parser.token == token::Eof => meta_item,
+            Ok(..) => expected_error(),
+            Err(err) => {
+                err.cancel();
                 expected_error();
-            };
+            }
+        };
 
-            if meta_item.has_name(sym::names) {
-                // defaults are flipped for the old syntax
-                if old_syntax == None {
-                    check_cfg.exhaustive_names = false;
-                    check_cfg.exhaustive_values = false;
-                }
-                old_syntax = Some(true);
-
-                check_cfg.exhaustive_names = true;
-                for arg in args {
-                    if arg.is_word() && arg.ident().is_some() {
-                        let ident = arg.ident().expect("multi-segment cfg key");
-                        check_cfg
-                            .expecteds
-                            .entry(ident.name.to_string())
-                            .or_insert(ExpectedValues::Any);
-                    } else {
-                        error!("`names()` arguments must be simple identifiers");
-                    }
-                }
-            } else if meta_item.has_name(sym::values) {
-                // defaults are flipped for the old syntax
-                if old_syntax == None {
-                    check_cfg.exhaustive_names = false;
-                    check_cfg.exhaustive_values = false;
+        let Some(args) = meta_item.meta_item_list() else {
+            expected_error();
+        };
+
+        if meta_item.has_name(sym::names) {
+            // defaults are flipped for the old syntax
+            if old_syntax == None {
+                check_cfg.exhaustive_names = false;
+                check_cfg.exhaustive_values = false;
+            }
+            old_syntax = Some(true);
+
+            check_cfg.exhaustive_names = true;
+            for arg in args {
+                if arg.is_word() && arg.ident().is_some() {
+                    let ident = arg.ident().expect("multi-segment cfg key");
+                    check_cfg
+                        .expecteds
+                        .entry(ident.name.to_string())
+                        .or_insert(ExpectedValues::Any);
+                } else {
+                    error!("`names()` arguments must be simple identifiers");
                 }
-                old_syntax = Some(true);
-
-                if let Some((name, values)) = args.split_first() {
-                    if name.is_word() && name.ident().is_some() {
-                        let ident = name.ident().expect("multi-segment cfg key");
-                        let expected_values = check_cfg
-                            .expecteds
-                            .entry(ident.name.to_string())
-                            .and_modify(|expected_values| match expected_values {
-                                ExpectedValues::Some(_) => {}
-                                ExpectedValues::Any => {
-                                    // handle the case where names(...) was done
-                                    // before values by changing to a list
-                                    *expected_values = ExpectedValues::Some(FxHashSet::default());
-                                }
-                            })
-                            .or_insert_with(|| ExpectedValues::Some(FxHashSet::default()));
-
-                        let ExpectedValues::Some(expected_values) = expected_values else {
-                            bug!("`expected_values` should be a list a values")
-                        };
-
-                        for val in values {
-                            if let Some(LitKind::Str(s, _)) = val.lit().map(|lit| &lit.kind) {
-                                expected_values.insert(Some(s.to_string()));
-                            } else {
-                                error!("`values()` arguments must be string literals");
+            }
+        } else if meta_item.has_name(sym::values) {
+            // defaults are flipped for the old syntax
+            if old_syntax == None {
+                check_cfg.exhaustive_names = false;
+                check_cfg.exhaustive_values = false;
+            }
+            old_syntax = Some(true);
+
+            if let Some((name, values)) = args.split_first() {
+                if name.is_word() && name.ident().is_some() {
+                    let ident = name.ident().expect("multi-segment cfg key");
+                    let expected_values = check_cfg
+                        .expecteds
+                        .entry(ident.name.to_string())
+                        .and_modify(|expected_values| match expected_values {
+                            ExpectedValues::Some(_) => {}
+                            ExpectedValues::Any => {
+                                // handle the case where names(...) was done
+                                // before values by changing to a list
+                                *expected_values = ExpectedValues::Some(FxHashSet::default());
                             }
-                        }
+                        })
+                        .or_insert_with(|| ExpectedValues::Some(FxHashSet::default()));
+
+                    let ExpectedValues::Some(expected_values) = expected_values else {
+                        bug!("`expected_values` should be a list a values")
+                    };
 
-                        if values.is_empty() {
-                            expected_values.insert(None);
+                    for val in values {
+                        if let Some(LitKind::Str(s, _)) = val.lit().map(|lit| &lit.kind) {
+                            expected_values.insert(Some(s.to_string()));
+                        } else {
+                            error!("`values()` arguments must be string literals");
                         }
-                    } else {
-                        error!("`values()` first argument must be a simple identifier");
                     }
-                } else if args.is_empty() {
-                    check_cfg.exhaustive_values = true;
+
+                    if values.is_empty() {
+                        expected_values.insert(None);
+                    }
                 } else {
-                    expected_error();
+                    error!("`values()` first argument must be a simple identifier");
                 }
-            } else if meta_item.has_name(sym::cfg) {
-                old_syntax = Some(false);
+            } else if args.is_empty() {
+                check_cfg.exhaustive_values = true;
+            } else {
+                expected_error();
+            }
+        } else if meta_item.has_name(sym::cfg) {
+            old_syntax = Some(false);
 
-                let mut names = Vec::new();
-                let mut values: FxHashSet<_> = Default::default();
+            let mut names = Vec::new();
+            let mut values: FxHashSet<_> = Default::default();
 
-                let mut any_specified = false;
-                let mut values_specified = false;
-                let mut values_any_specified = false;
+            let mut any_specified = false;
+            let mut values_specified = false;
+            let mut values_any_specified = false;
 
-                for arg in args {
-                    if arg.is_word() && let Some(ident) = arg.ident() {
-                        if values_specified {
-                            error!("`cfg()` names cannot be after values");
-                        }
-                        names.push(ident);
-                    } else if arg.has_name(sym::any)
-                        && let Some(args) = arg.meta_item_list()
-                    {
-                        if any_specified {
-                            error!("`any()` cannot be specified multiple times");
-                        }
-                        any_specified = true;
-                        if !args.is_empty() {
-                            error!("`any()` must be empty");
-                        }
-                    } else if arg.has_name(sym::values)
-                        && let Some(args) = arg.meta_item_list()
-                    {
-                        if names.is_empty() {
-                            error!("`values()` cannot be specified before the names");
-                        } else if values_specified {
-                            error!("`values()` cannot be specified multiple times");
-                        }
-                        values_specified = true;
-
-                        for arg in args {
-                            if let Some(LitKind::Str(s, _)) =
-                                arg.lit().map(|lit| &lit.kind)
-                            {
-                                values.insert(Some(s.to_string()));
-                            } else if arg.has_name(sym::any)
-                                && let Some(args) = arg.meta_item_list()
-                            {
-                                if values_any_specified {
-                                    error!(
-                                        "`any()` in `values()` cannot be specified multiple times"
-                                    );
-                                }
-                                values_any_specified = true;
-                                if !args.is_empty() {
-                                    error!("`any()` must be empty");
-                                }
-                            } else {
+            for arg in args {
+                if arg.is_word() && let Some(ident) = arg.ident() {
+                    if values_specified {
+                        error!("`cfg()` names cannot be after values");
+                    }
+                    names.push(ident);
+                } else if arg.has_name(sym::any)
+                    && let Some(args) = arg.meta_item_list()
+                {
+                    if any_specified {
+                        error!("`any()` cannot be specified multiple times");
+                    }
+                    any_specified = true;
+                    if !args.is_empty() {
+                        error!("`any()` must be empty");
+                    }
+                } else if arg.has_name(sym::values)
+                    && let Some(args) = arg.meta_item_list()
+                {
+                    if names.is_empty() {
+                        error!("`values()` cannot be specified before the names");
+                    } else if values_specified {
+                        error!("`values()` cannot be specified multiple times");
+                    }
+                    values_specified = true;
+
+                    for arg in args {
+                        if let Some(LitKind::Str(s, _)) =
+                            arg.lit().map(|lit| &lit.kind)
+                        {
+                            values.insert(Some(s.to_string()));
+                        } else if arg.has_name(sym::any)
+                            && let Some(args) = arg.meta_item_list()
+                        {
+                            if values_any_specified {
                                 error!(
-                                    "`values()` arguments must be string literals or `any()`"
+                                    "`any()` in `values()` cannot be specified multiple times"
                                 );
                             }
+                            values_any_specified = true;
+                            if !args.is_empty() {
+                                error!("`any()` must be empty");
+                            }
+                        } else {
+                            error!(
+                                "`values()` arguments must be string literals or `any()`"
+                            );
                         }
-                    } else {
-                        error!(
-                            "`cfg()` arguments must be simple identifiers, `any()` or `values(...)`"
-                        );
                     }
-                }
-
-                if values.is_empty() && !values_any_specified && !any_specified {
-                    values.insert(None);
-                } else if !values.is_empty() && values_any_specified {
+                } else {
                     error!(
-                        "`values()` arguments cannot specify string literals and `any()` at the same time"
+                        "`cfg()` arguments must be simple identifiers, `any()` or `values(...)`"
                     );
                 }
+            }
 
-                if any_specified {
-                    if names.is_empty()
-                        && values.is_empty()
-                        && !values_specified
-                        && !values_any_specified
-                    {
-                        check_cfg.exhaustive_names = false;
-                    } else {
-                        error!("`cfg(any())` can only be provided in isolation");
-                    }
+            if values.is_empty() && !values_any_specified && !any_specified {
+                values.insert(None);
+            } else if !values.is_empty() && values_any_specified {
+                error!(
+                    "`values()` arguments cannot specify string literals and `any()` at the same time"
+                );
+            }
+
+            if any_specified {
+                if names.is_empty()
+                    && values.is_empty()
+                    && !values_specified
+                    && !values_any_specified
+                {
+                    check_cfg.exhaustive_names = false;
                 } else {
-                    for name in names {
-                        check_cfg
-                            .expecteds
-                            .entry(name.to_string())
-                            .and_modify(|v| match v {
-                                ExpectedValues::Some(v) if !values_any_specified => {
-                                    v.extend(values.clone())
-                                }
-                                ExpectedValues::Some(_) => *v = ExpectedValues::Any,
-                                ExpectedValues::Any => {}
-                            })
-                            .or_insert_with(|| {
-                                if values_any_specified {
-                                    ExpectedValues::Any
-                                } else {
-                                    ExpectedValues::Some(values.clone())
-                                }
-                            });
-                    }
+                    error!("`cfg(any())` can only be provided in isolation");
                 }
             } else {
-                expected_error();
+                for name in names {
+                    check_cfg
+                        .expecteds
+                        .entry(name.to_string())
+                        .and_modify(|v| match v {
+                            ExpectedValues::Some(v) if !values_any_specified => {
+                                v.extend(values.clone())
+                            }
+                            ExpectedValues::Some(_) => *v = ExpectedValues::Any,
+                            ExpectedValues::Any => {}
+                        })
+                        .or_insert_with(|| {
+                            if values_any_specified {
+                                ExpectedValues::Any
+                            } else {
+                                ExpectedValues::Some(values.clone())
+                            }
+                        });
+                }
             }
+        } else {
+            expected_error();
         }
+    }
 
-        check_cfg
-    })
+    check_cfg
 }
 
 /// The compiler configuration
@@ -361,9 +352,9 @@ pub struct Config {
     /// Command line options
     pub opts: config::Options,
 
-    /// cfg! configuration in addition to the default ones
-    pub crate_cfg: Cfg<String>,
-    pub crate_check_cfg: CheckCfg<String>,
+    /// Unparsed cfg! configuration in addition to the default ones.
+    pub crate_cfg: Vec<String>,
+    pub crate_check_cfg: Vec<String>,
 
     pub input: Input,
     pub output_dir: Option<PathBuf>,
@@ -436,8 +427,8 @@ pub fn run_compiler<R: Send>(config: Config, f: impl FnOnce(&Compiler) -> R + Se
             let (mut sess, codegen_backend) = util::create_session(
                 &handler,
                 config.opts,
-                config.crate_cfg,
-                config.crate_check_cfg,
+                parse_cfg(&handler, config.crate_cfg),
+                parse_check_cfg(&handler, config.crate_check_cfg),
                 config.locale_resources,
                 config.file_loader,
                 CompilerIO {