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(),

`