diff --git a/src/librustc/session/config.rs b/src/librustc/session/config.rs index 1502811baee..d22d5d915f6 100644 --- a/src/librustc/session/config.rs +++ b/src/librustc/session/config.rs @@ -25,7 +25,6 @@ use lint; use middle::cstore; use syntax::ast::{self, IntTy, UintTy}; -use syntax::attr; use syntax::parse::{self, token}; use syntax::parse::token::InternedString; use syntax::feature_gate::UnstableFeatures; @@ -41,6 +40,7 @@ use std::collections::btree_map::Values as BTreeMapValuesIter; use std::fmt; use std::hash::Hasher; use std::collections::hash_map::DefaultHasher; +use std::collections::HashSet; use std::iter::FromIterator; use std::path::PathBuf; @@ -945,47 +945,39 @@ pub fn default_configuration(sess: &Session) -> ast::CrateConfig { InternedString::new("unix") }; - let mk = attr::mk_name_value_item_str; - let mut ret = vec![ // Target bindings. - mk(token::intern("target_os"), intern(os)), - mk(token::intern("target_family"), fam.clone()), - mk(token::intern("target_arch"), intern(arch)), - mk(token::intern("target_endian"), intern(end)), - mk(token::intern("target_pointer_width"), intern(wordsz)), - mk(token::intern("target_env"), intern(env)), - mk(token::intern("target_vendor"), intern(vendor)), - ]; - match &fam[..] { - "windows" | "unix" => ret.push(attr::mk_word_item(token::intern(&fam))), - _ => (), + let mut ret = HashSet::new(); + // Target bindings. + ret.insert((token::intern("target_os"), Some(intern(os)))); + ret.insert((token::intern("target_family"), Some(fam.clone()))); + ret.insert((token::intern("target_arch"), Some(intern(arch)))); + ret.insert((token::intern("target_endian"), Some(intern(end)))); + ret.insert((token::intern("target_pointer_width"), Some(intern(wordsz)))); + ret.insert((token::intern("target_env"), Some(intern(env)))); + ret.insert((token::intern("target_vendor"), Some(intern(vendor)))); + if &fam == "windows" || &fam == "unix" { + ret.insert((token::intern(&fam), None)); } if sess.target.target.options.has_elf_tls { - ret.push(attr::mk_word_item(token::intern("target_thread_local"))); + ret.insert((token::intern("target_thread_local"), None)); } for &i in &[8, 16, 32, 64, 128] { if i <= max_atomic_width { let s = i.to_string(); - ret.push(mk(token::intern("target_has_atomic"), intern(&s))); + ret.insert((token::intern("target_has_atomic"), Some(intern(&s)))); if &s == wordsz { - ret.push(mk(token::intern("target_has_atomic"), intern("ptr"))); + ret.insert((token::intern("target_has_atomic"), Some(intern("ptr")))); } } } if sess.opts.debug_assertions { - ret.push(attr::mk_word_item(token::intern("debug_assertions"))); + ret.insert((token::intern("debug_assertions"), None)); } if sess.opts.crate_types.contains(&CrateTypeProcMacro) { - ret.push(attr::mk_word_item(token::intern("proc_macro"))); + ret.insert((token::intern("proc_macro"), None)); } return ret; } -pub fn append_configuration(cfg: &mut ast::CrateConfig, name: ast::Name) { - if !cfg.iter().any(|mi| mi.name() == name) { - cfg.push(attr::mk_word_item(name)) - } -} - pub fn build_configuration(sess: &Session, mut user_cfg: ast::CrateConfig) -> ast::CrateConfig { @@ -994,11 +986,10 @@ pub fn build_configuration(sess: &Session, let default_cfg = default_configuration(sess); // If the user wants a test runner, then add the test cfg if sess.opts.test { - append_configuration(&mut user_cfg, token::intern("test")) + user_cfg.insert((token::intern("test"), None)); } - let mut v = user_cfg.into_iter().collect::>(); - v.extend_from_slice(&default_cfg[..]); - v + user_cfg.extend(default_cfg.iter().cloned()); + user_cfg } pub fn build_target_config(opts: &Options, sp: &Handler) -> Config { @@ -1244,11 +1235,14 @@ pub fn parse_cfgspecs(cfgspecs: Vec ) -> ast::CrateConfig { let meta_item = panictry!(parser.parse_meta_item()); if !parser.reader.is_eof() { - early_error(ErrorOutputType::default(), &format!("invalid --cfg argument: {}", - s)) + early_error(ErrorOutputType::default(), &format!("invalid --cfg argument: {}", s)) + } else if meta_item.is_meta_item_list() { + let msg = + format!("invalid predicate in --cfg command line argument: `{}`", meta_item.name()); + early_error(ErrorOutputType::default(), &msg) } - meta_item + (meta_item.name(), meta_item.value_str()) }).collect::() } diff --git a/src/librustc_driver/lib.rs b/src/librustc_driver/lib.rs index 7e60c40220f..e0a2eb6ae5e 100644 --- a/src/librustc_driver/lib.rs +++ b/src/librustc_driver/lib.rs @@ -95,12 +95,11 @@ use std::str; use std::sync::{Arc, Mutex}; use std::thread; -use syntax::{ast, json}; +use syntax::ast; use syntax::codemap::{CodeMap, FileLoader, RealFileLoader}; use syntax::feature_gate::{GatedCfg, UnstableFeatures}; use syntax::parse::{self, PResult}; -use syntax_pos::MultiSpan; -use errors::emitter::Emitter; +use syntax_pos::{DUMMY_SP, MultiSpan}; #[cfg(test)] pub mod test; @@ -374,37 +373,11 @@ fn handle_explain(code: &str, } } -fn check_cfg(cfg: &ast::CrateConfig, - output: ErrorOutputType) { - let emitter: Box = match output { - config::ErrorOutputType::HumanReadable(color_config) => { - Box::new(errors::emitter::EmitterWriter::stderr(color_config, None)) - } - config::ErrorOutputType::Json => Box::new(json::JsonEmitter::basic()), - }; - let handler = errors::Handler::with_emitter(true, false, emitter); - - let mut saw_invalid_predicate = false; - for item in cfg.iter() { - if item.is_meta_item_list() { - saw_invalid_predicate = true; - handler.emit(&MultiSpan::new(), - &format!("invalid predicate in --cfg command line argument: `{}`", - item.name()), - errors::Level::Fatal); - } - } - - if saw_invalid_predicate { - panic!(errors::FatalError); - } -} - impl<'a> CompilerCalls<'a> for RustcDefaultCalls { fn early_callback(&mut self, matches: &getopts::Matches, _: &config::Options, - cfg: &ast::CrateConfig, + _: &ast::CrateConfig, descriptions: &errors::registry::Registry, output: ErrorOutputType) -> Compilation { @@ -413,7 +386,6 @@ impl<'a> CompilerCalls<'a> for RustcDefaultCalls { return Compilation::Stop; } - check_cfg(cfg, output); Compilation::Continue } @@ -640,24 +612,26 @@ impl RustcDefaultCalls { let allow_unstable_cfg = UnstableFeatures::from_environment() .is_nightly_build(); - for cfg in &sess.parse_sess.config { - if !allow_unstable_cfg && GatedCfg::gate(cfg).is_some() { + let mut cfgs = Vec::new(); + for &(name, ref value) in sess.parse_sess.config.iter() { + let gated_cfg = GatedCfg::gate(&ast::MetaItem { + node: ast::MetaItemKind::Word(name), + span: DUMMY_SP, + }); + if !allow_unstable_cfg && gated_cfg.is_some() { continue; } - if cfg.is_word() { - println!("{}", cfg.name()); - } else if let Some(s) = cfg.value_str() { - println!("{}=\"{}\"", cfg.name(), s); - } else if cfg.is_meta_item_list() { - // Right now there are not and should not be any - // MetaItemKind::List items in the configuration returned by - // `build_configuration`. - panic!("Found an unexpected list in cfg attribute '{}'!", cfg.name()) + cfgs.push(if let &Some(ref value) = value { + format!("{}=\"{}\"", name, value) } else { - // There also shouldn't be literals. - panic!("Found an unexpected literal in cfg attribute '{}'!", cfg.name()) - } + format!("{}", name) + }); + } + + cfgs.sort(); + for cfg in cfgs { + println!("{}", cfg); } } PrintRequest::TargetCPUs => { diff --git a/src/librustc_driver/target_features.rs b/src/librustc_driver/target_features.rs index 436b44d8b03..34073dfd24d 100644 --- a/src/librustc_driver/target_features.rs +++ b/src/librustc_driver/target_features.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use syntax::{ast, attr}; +use syntax::ast; use llvm::LLVMRustHasFeature; use rustc::session::Session; use rustc_trans::back::write::create_target_machine; @@ -44,7 +44,7 @@ pub fn add_configuration(cfg: &mut ast::CrateConfig, sess: &Session) { for feat in whitelist { assert_eq!(feat.chars().last(), Some('\0')); if unsafe { LLVMRustHasFeature(target_machine, feat.as_ptr() as *const c_char) } { - cfg.push(attr::mk_name_value_item_str(tf, intern(&feat[..feat.len() - 1]))) + cfg.insert((tf, Some(intern(&feat[..feat.len() - 1])))); } } @@ -73,6 +73,6 @@ pub fn add_configuration(cfg: &mut ast::CrateConfig, sess: &Session) { } if crt_static { - cfg.push(attr::mk_name_value_item_str(tf.clone(), intern("crt-static"))); + cfg.insert((tf, Some(intern("crt-static")))); } } diff --git a/src/librustc_incremental/persist/dirty_clean.rs b/src/librustc_incremental/persist/dirty_clean.rs index 0cd1c88fb87..c22416e1120 100644 --- a/src/librustc_incremental/persist/dirty_clean.rs +++ b/src/librustc_incremental/persist/dirty_clean.rs @@ -48,7 +48,7 @@ use rustc::hir::def_id::DefId; use rustc::hir::itemlikevisit::ItemLikeVisitor; use syntax::ast::{self, Attribute, NestedMetaItem}; use rustc_data_structures::fx::{FxHashSet, FxHashMap}; -use syntax::parse::token::InternedString; +use syntax::parse::token; use syntax_pos::Span; use rustc::ty::TyCtxt; use ich::Fingerprint; @@ -88,12 +88,11 @@ pub struct DirtyCleanVisitor<'a, 'tcx:'a> { } impl<'a, 'tcx> DirtyCleanVisitor<'a, 'tcx> { - fn dep_node(&self, attr: &Attribute, def_id: DefId) -> DepNode { for item in attr.meta_item_list().unwrap_or(&[]) { if item.check_name(LABEL) { let value = expect_associated_value(self.tcx, item); - match DepNode::from_label_string(&value[..], def_id) { + match DepNode::from_label_string(&value.as_str(), def_id) { Ok(def_id) => return def_id, Err(()) => { self.tcx.sess.span_fatal( @@ -276,13 +275,7 @@ fn check_config(tcx: TyCtxt, attr: &ast::Attribute) -> bool { if item.check_name(CFG) { let value = expect_associated_value(tcx, item); debug!("check_config: searching for cfg {:?}", value); - for cfg in &config[..] { - if cfg.check_name(&value[..]) { - debug!("check_config: matched {:?}", cfg); - return true; - } - } - return false; + return config.contains(&(value, None)); } } @@ -291,9 +284,9 @@ fn check_config(tcx: TyCtxt, attr: &ast::Attribute) -> bool { &format!("no cfg attribute")); } -fn expect_associated_value(tcx: TyCtxt, item: &NestedMetaItem) -> InternedString { +fn expect_associated_value(tcx: TyCtxt, item: &NestedMetaItem) -> ast::Name { if let Some(value) = item.value_str() { - value + token::intern(&value) } else { let msg = if let Some(name) = item.name() { format!("associated value expected for `{}`", name) diff --git a/src/librustc_trans/assert_module_sources.rs b/src/librustc_trans/assert_module_sources.rs index 264ed4cd12f..0bdf66e4589 100644 --- a/src/librustc_trans/assert_module_sources.rs +++ b/src/librustc_trans/assert_module_sources.rs @@ -29,7 +29,7 @@ use rustc::ty::TyCtxt; use syntax::ast; -use syntax::parse::token::InternedString; +use syntax::parse::token; use {ModuleSource, ModuleTranslation}; @@ -77,7 +77,7 @@ impl<'a, 'tcx> AssertModuleSource<'a, 'tcx> { } let mname = self.field(attr, MODULE); - let mtrans = self.modules.iter().find(|mtrans| &mtrans.name[..] == &mname[..]); + let mtrans = self.modules.iter().find(|mtrans| *mtrans.name == *mname.as_str()); let mtrans = match mtrans { Some(m) => m, None => { @@ -113,11 +113,11 @@ impl<'a, 'tcx> AssertModuleSource<'a, 'tcx> { } } - fn field(&self, attr: &ast::Attribute, name: &str) -> InternedString { + fn field(&self, attr: &ast::Attribute, name: &str) -> ast::Name { for item in attr.meta_item_list().unwrap_or(&[]) { if item.check_name(name) { if let Some(value) = item.value_str() { - return value; + return token::intern(&value); } else { self.tcx.sess.span_fatal( item.span, @@ -137,7 +137,7 @@ impl<'a, 'tcx> AssertModuleSource<'a, 'tcx> { let config = &self.tcx.sess.parse_sess.config; let value = self.field(attr, CFG); debug!("check_config(config={:?}, value={:?})", config, value); - if config.iter().any(|c| c.check_name(&value[..])) { + if config.iter().any(|&(name, _)| name == value) { debug!("check_config: matched"); return true; } diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index 8de843fdcb8..3664cc8e064 100644 --- a/src/libsyntax/ast.rs +++ b/src/libsyntax/ast.rs @@ -25,6 +25,7 @@ use print::pprust; use ptr::P; use tokenstream::{TokenTree}; +use std::collections::HashSet; use std::fmt; use std::rc::Rc; use std::u32; @@ -485,7 +486,7 @@ pub struct WhereEqPredicate { /// The set of MetaItems that define the compilation environment of the crate, /// used to drive conditional compilation -pub type CrateConfig = Vec>; +pub type CrateConfig = HashSet<(Name, Option)>; #[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)] pub struct Crate { @@ -519,7 +520,7 @@ pub type MetaItem = Spanned; /// A compile-time attribute item. /// /// E.g. `#[test]`, `#[derive(..)]` or `#[feature = "foo"]` -#[derive(Clone, Eq, RustcEncodable, RustcDecodable, Hash, Debug)] +#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)] pub enum MetaItemKind { /// Word meta item. /// @@ -535,34 +536,6 @@ pub enum MetaItemKind { NameValue(Name, Lit), } -// can't be derived because the MetaItemKind::List requires an unordered comparison -impl PartialEq for MetaItemKind { - fn eq(&self, other: &MetaItemKind) -> bool { - use self::MetaItemKind::*; - match *self { - Word(ref ns) => match *other { - Word(ref no) => (*ns) == (*no), - _ => false - }, - List(ref ns, ref miss) => match *other { - List(ref no, ref miso) => { - ns == no && - miss.iter().all(|mi| { - miso.iter().any(|x| x.node == mi.node) - }) - } - _ => false - }, - NameValue(ref ns, ref vs) => match *other { - NameValue(ref no, ref vo) => { - (*ns) == (*no) && vs.node == vo.node - } - _ => false - }, - } - } -} - /// A Block (`{ .. }`). /// /// E.g. `{ .. }` as in `fn foo() { .. }` diff --git a/src/libsyntax/attr.rs b/src/libsyntax/attr.rs index 220ecf52ae0..f84199fb29e 100644 --- a/src/libsyntax/attr.rs +++ b/src/libsyntax/attr.rs @@ -400,18 +400,6 @@ pub fn mk_sugared_doc_attr(id: AttrId, text: InternedString, lo: BytePos, hi: By } } -/* Searching */ -/// Check if `needle` occurs in `haystack` by a structural -/// comparison. This is slightly subtle, and relies on ignoring the -/// span included in the `==` comparison a plain MetaItem. -pub fn contains(haystack: &[P], needle: &MetaItem) -> bool { - debug!("attr::contains (name={})", needle.name()); - haystack.iter().any(|item| { - debug!(" testing: {}", item.name()); - item.node == needle.node - }) -} - pub fn list_contains_name(items: &[NestedMetaItem], name: &str) -> bool { debug!("attr::list_contains_name (name={})", name); items.iter().any(|item| { @@ -558,7 +546,7 @@ pub fn cfg_matches(cfg: &ast::MetaItem, sess: &ParseSess, features: Option<&Feat if let (Some(feats), Some(gated_cfg)) = (features, GatedCfg::gate(cfg)) { gated_cfg.check_and_emit(sess, feats); } - contains(&sess.config, cfg) + sess.config.contains(&(cfg.name(), cfg.value_str())) } } } diff --git a/src/libsyntax/parse/mod.rs b/src/libsyntax/parse/mod.rs index 12408c7d3c9..7feb745259c 100644 --- a/src/libsyntax/parse/mod.rs +++ b/src/libsyntax/parse/mod.rs @@ -22,6 +22,7 @@ use str::char_at; use tokenstream; use std::cell::RefCell; +use std::collections::HashSet; use std::iter; use std::path::{Path, PathBuf}; use std::rc::Rc; @@ -64,7 +65,7 @@ impl ParseSess { ParseSess { span_diagnostic: handler, unstable_features: UnstableFeatures::from_environment(), - config: Vec::new(), + config: HashSet::new(), included_mod_stack: RefCell::new(vec![]), code_map: code_map }