diff options
| author | Matthias Krüger <matthias.krueger@famsik.de> | 2022-02-18 23:23:10 +0100 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2022-02-18 23:23:10 +0100 |
| commit | 576afec73a15e918ab6d1e85ba7d8dd6fb1626d3 (patch) | |
| tree | fd3b716d65ff9c13141b7de328cc53eeee2b824e /compiler/rustc_interface/src | |
| parent | 1e2f63de0a5e9a32d97d355f6351665e77455be2 (diff) | |
| parent | 3a73ca587bb8a8fb52d6045fbe31d50d5a56ff19 (diff) | |
| download | rust-576afec73a15e918ab6d1e85ba7d8dd6fb1626d3.tar.gz rust-576afec73a15e918ab6d1e85ba7d8dd6fb1626d3.zip | |
Rollup merge of #93915 - Urgau:rfc-3013, r=petrochenkov
Implement --check-cfg option (RFC 3013), take 2 This pull-request implement RFC 3013: Checking conditional compilation at compile time (https://github.com/rust-lang/rfcs/pull/3013) and is based on the previous attempt https://github.com/rust-lang/rust/pull/89346 by `@mwkmwkmwk` that was closed due to inactivity. I have address all the review comments from the previous attempt and added some more tests. cc https://github.com/rust-lang/rust/issues/82450 r? `@petrochenkov`
Diffstat (limited to 'compiler/rustc_interface/src')
| -rw-r--r-- | compiler/rustc_interface/src/interface.rs | 91 | ||||
| -rw-r--r-- | compiler/rustc_interface/src/util.rs | 8 |
2 files changed, 97 insertions, 2 deletions
diff --git a/compiler/rustc_interface/src/interface.rs b/compiler/rustc_interface/src/interface.rs index 9a588b55393..609fc4b78c0 100644 --- a/compiler/rustc_interface/src/interface.rs +++ b/compiler/rustc_interface/src/interface.rs @@ -2,7 +2,7 @@ pub use crate::passes::BoxedResolver; use crate::util; use rustc_ast::token; -use rustc_ast::{self as ast, MetaItemKind}; +use rustc_ast::{self as ast, LitKind, MetaItemKind}; use rustc_codegen_ssa::traits::CodegenBackend; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_data_structures::sync::Lrc; @@ -13,12 +13,13 @@ use rustc_lint::LintStore; use rustc_middle::ty; use rustc_parse::maybe_new_parser_from_source_str; use rustc_query_impl::QueryCtxt; -use rustc_session::config::{self, ErrorOutputType, Input, OutputFilenames}; +use rustc_session::config::{self, CheckCfg, ErrorOutputType, Input, OutputFilenames}; use rustc_session::early_error; use rustc_session::lint; use rustc_session::parse::{CrateConfig, ParseSess}; use rustc_session::{DiagnosticOutput, Session}; use rustc_span::source_map::{FileLoader, FileName}; +use rustc_span::symbol::sym; use std::path::PathBuf; use std::result; @@ -139,6 +140,90 @@ pub fn parse_cfgspecs(cfgspecs: Vec<String>) -> FxHashSet<(String, Option<String }) } +/// Converts strings provided as `--check-cfg [specs]` into a `CheckCfg`. +pub fn parse_check_cfg(specs: Vec<String>) -> CheckCfg { + rustc_span::create_default_session_if_not_set_then(move |_| { + let mut cfg = CheckCfg::default(); + + 'specs: 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) => { + early_error( + ErrorOutputType::default(), + &format!( + concat!("invalid `--check-cfg` argument: `{}` (", $reason, ")"), + s + ), + ); + }; + } + + match maybe_new_parser_from_source_str(&sess, filename, s.to_string()) { + Ok(mut parser) => match &mut parser.parse_meta_item() { + Ok(meta_item) if parser.token == token::Eof => { + if let Some(args) = meta_item.meta_item_list() { + if meta_item.has_name(sym::names) { + cfg.names_checked = true; + for arg in args { + if arg.is_word() && arg.ident().is_some() { + let ident = arg.ident().expect("multi-segment cfg key"); + cfg.names_valid.insert(ident.name.to_string()); + } else { + error!("`names()` arguments must be simple identifers"); + } + } + continue 'specs; + } else if meta_item.has_name(sym::values) { + 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"); + cfg.values_checked.insert(ident.to_string()); + for val in values { + if let Some(LitKind::Str(s, _)) = + val.literal().map(|lit| &lit.kind) + { + cfg.values_valid + .insert((ident.to_string(), s.to_string())); + } else { + error!( + "`values()` arguments must be string literals" + ); + } + } + + continue 'specs; + } else { + error!( + "`values()` first argument must be a simple identifer" + ); + } + } + } + } + } + Ok(..) => {} + Err(err) => err.cancel(), + }, + Err(errs) => errs.into_iter().for_each(|mut err| err.cancel()), + } + + error!( + "expected `names(name1, name2, ... nameN)` or \ + `values(name, \"value1\", \"value2\", ... \"valueN\")`" + ); + } + + cfg.names_valid.extend(cfg.values_checked.iter().cloned()); + cfg + }) +} + /// The compiler configuration pub struct Config { /// Command line options @@ -146,6 +231,7 @@ pub struct Config { /// cfg! configuration in addition to the default ones pub crate_cfg: FxHashSet<(String, Option<String>)>, + pub crate_check_cfg: CheckCfg, pub input: Input, pub input_path: Option<PathBuf>, @@ -188,6 +274,7 @@ pub fn create_compiler_and_run<R>(config: Config, f: impl FnOnce(&Compiler) -> R let (mut sess, codegen_backend) = util::create_session( config.opts, config.crate_cfg, + config.crate_check_cfg, config.diagnostic_output, config.file_loader, config.input_path.clone(), diff --git a/compiler/rustc_interface/src/util.rs b/compiler/rustc_interface/src/util.rs index 700710c82c9..46964f52685 100644 --- a/compiler/rustc_interface/src/util.rs +++ b/compiler/rustc_interface/src/util.rs @@ -15,6 +15,7 @@ use rustc_parse::validate_attr; use rustc_query_impl::QueryCtxt; use rustc_resolve::{self, Resolver}; use rustc_session as session; +use rustc_session::config::CheckCfg; use rustc_session::config::{self, CrateType}; use rustc_session::config::{ErrorOutputType, Input, OutputFilenames}; use rustc_session::lint::{self, BuiltinLintDiagnostics, LintBuffer}; @@ -65,6 +66,7 @@ pub fn add_configuration( pub fn create_session( sopts: config::Options, cfg: FxHashSet<(String, Option<String>)>, + check_cfg: CheckCfg, diagnostic_output: DiagnosticOutput, file_loader: Option<Box<dyn FileLoader + Send + Sync + 'static>>, input_path: Option<PathBuf>, @@ -100,7 +102,13 @@ pub fn create_session( let mut cfg = config::build_configuration(&sess, config::to_crate_config(cfg)); add_configuration(&mut cfg, &mut sess, &*codegen_backend); + + let mut check_cfg = config::to_crate_check_config(check_cfg); + check_cfg.fill_well_known(); + check_cfg.fill_actual(&cfg); + sess.parse_sess.config = cfg; + sess.parse_sess.check_config = check_cfg; (Lrc::new(sess), Lrc::new(codegen_backend)) } |
