Implement --check-cfg option (RFC 3013) · rust-lang/rust@3a73ca5 (original) (raw)
`@@ -2,7 +2,7 @@ pub use crate::passes::BoxedResolver;
`
2
2
`use crate::util;
`
3
3
``
4
4
`use rustc_ast::token;
`
5
``
`-
use rustc_ast::{self as ast, MetaItemKind};
`
``
5
`+
use rustc_ast::{self as ast, LitKind, MetaItemKind};
`
6
6
`use rustc_codegen_ssa::traits::CodegenBackend;
`
7
7
`use rustc_data_structures::fx::{FxHashMap, FxHashSet};
`
8
8
`use rustc_data_structures::sync::Lrc;
`
`@@ -13,12 +13,13 @@ use rustc_lint::LintStore;
`
13
13
`use rustc_middle::ty;
`
14
14
`use rustc_parse::maybe_new_parser_from_source_str;
`
15
15
`use rustc_query_impl::QueryCtxt;
`
16
``
`-
use rustc_session::config::{self, ErrorOutputType, Input, OutputFilenames};
`
``
16
`+
use rustc_session::config::{self, CheckCfg, ErrorOutputType, Input, OutputFilenames};
`
17
17
`use rustc_session::early_error;
`
18
18
`use rustc_session::lint;
`
19
19
`use rustc_session::parse::{CrateConfig, ParseSess};
`
20
20
`use rustc_session::{DiagnosticOutput, Session};
`
21
21
`use rustc_span::source_map::{FileLoader, FileName};
`
``
22
`+
use rustc_span::symbol::sym;
`
22
23
`use std::path::PathBuf;
`
23
24
`use std::result;
`
24
25
`use std::sync::{Arc, Mutex};
`
`@@ -140,13 +141,98 @@ pub fn parse_cfgspecs(cfgspecs: Vec) -> FxHashSet<(String, Option<String
`
140
141
`})
`
141
142
`}
`
142
143
``
``
144
`` +
/// Converts strings provided as --check-cfg [specs]
into a CheckCfg
.
``
``
145
`+
pub fn parse_check_cfg(specs: Vec) -> CheckCfg {
`
``
146
`+
rustc_span::create_default_session_if_not_set_then(move |_| {
`
``
147
`+
let mut cfg = CheckCfg::default();
`
``
148
+
``
149
`+
'specs: for s in specs {
`
``
150
`+
let sess = ParseSess::with_silent_emitter(Some(format!(
`
``
151
`` +
"this error occurred on the command line: --check-cfg={}
",
``
``
152
`+
s
`
``
153
`+
)));
`
``
154
`+
let filename = FileName::cfg_spec_source_code(&s);
`
``
155
+
``
156
`+
macro_rules! error {
`
``
157
`+
($reason: expr) => {
`
``
158
`+
early_error(
`
``
159
`+
ErrorOutputType::default(),
`
``
160
`+
&format!(
`
``
161
`` +
concat!("invalid --check-cfg
argument: {}
(", $reason, ")"),
``
``
162
`+
s
`
``
163
`+
),
`
``
164
`+
);
`
``
165
`+
};
`
``
166
`+
}
`
``
167
+
``
168
`+
match maybe_new_parser_from_source_str(&sess, filename, s.to_string()) {
`
``
169
`+
Ok(mut parser) => match &mut parser.parse_meta_item() {
`
``
170
`+
Ok(meta_item) if parser.token == token::Eof => {
`
``
171
`+
if let Some(args) = meta_item.meta_item_list() {
`
``
172
`+
if meta_item.has_name(sym::names) {
`
``
173
`+
cfg.names_checked = true;
`
``
174
`+
for arg in args {
`
``
175
`+
if arg.is_word() && arg.ident().is_some() {
`
``
176
`+
let ident = arg.ident().expect("multi-segment cfg key");
`
``
177
`+
cfg.names_valid.insert(ident.name.to_string());
`
``
178
`+
} else {
`
``
179
`` +
error!("names()
arguments must be simple identifers");
``
``
180
`+
}
`
``
181
`+
}
`
``
182
`+
continue 'specs;
`
``
183
`+
} else if meta_item.has_name(sym::values) {
`
``
184
`+
if let Some((name, values)) = args.split_first() {
`
``
185
`+
if name.is_word() && name.ident().is_some() {
`
``
186
`+
let ident = name.ident().expect("multi-segment cfg key");
`
``
187
`+
cfg.values_checked.insert(ident.to_string());
`
``
188
`+
for val in values {
`
``
189
`+
if let Some(LitKind::Str(s, _)) =
`
``
190
`+
val.literal().map(|lit| &lit.kind)
`
``
191
`+
{
`
``
192
`+
cfg.values_valid
`
``
193
`+
.insert((ident.to_string(), s.to_string()));
`
``
194
`+
} else {
`
``
195
`+
error!(
`
``
196
`` +
"values()
arguments must be string literals"
``
``
197
`+
);
`
``
198
`+
}
`
``
199
`+
}
`
``
200
+
``
201
`+
continue 'specs;
`
``
202
`+
} else {
`
``
203
`+
error!(
`
``
204
`` +
"values()
first argument must be a simple identifer"
``
``
205
`+
);
`
``
206
`+
}
`
``
207
`+
}
`
``
208
`+
}
`
``
209
`+
}
`
``
210
`+
}
`
``
211
`+
Ok(..) => {}
`
``
212
`+
Err(err) => err.cancel(),
`
``
213
`+
},
`
``
214
`+
Err(errs) => errs.into_iter().for_each(|mut err| err.cancel()),
`
``
215
`+
}
`
``
216
+
``
217
`+
error!(
`
``
218
`` +
"expected names(name1, name2, ... nameN)
or \
``
``
219
`` +
values(name, \"value1\", \"value2\", ... \"valueN\")
"
``
``
220
`+
);
`
``
221
`+
}
`
``
222
+
``
223
`+
cfg.names_valid.extend(cfg.values_checked.iter().cloned());
`
``
224
`+
cfg
`
``
225
`+
})
`
``
226
`+
}
`
``
227
+
143
228
`/// The compiler configuration
`
144
229
`pub struct Config {
`
145
230
`/// Command line options
`
146
231
`pub opts: config::Options,
`
147
232
``
148
233
`/// cfg! configuration in addition to the default ones
`
149
234
`pub crate_cfg: FxHashSet<(String, Option)>,
`
``
235
`+
pub crate_check_cfg: CheckCfg,
`
150
236
``
151
237
`pub input: Input,
`
152
238
`pub input_path: Option,
`
`@@ -190,6 +276,7 @@ pub fn create_compiler_and_run(config: Config, f: impl FnOnce(&Compiler) -> R
`
190
276
`let (mut sess, codegen_backend) = util::create_session(
`
191
277
` config.opts,
`
192
278
` config.crate_cfg,
`
``
279
`+
config.crate_check_cfg,
`
193
280
` config.diagnostic_output,
`
194
281
` config.file_loader,
`
195
282
` config.input_path.clone(),
`