diff --git a/src/lib.rs b/src/lib.rs index de50135..58c5db1 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -59,6 +59,7 @@ macro_rules! try { }; } +use std::collections::HashSet; use std::env; use std::ffi::OsString; use std::fs; @@ -86,6 +87,7 @@ pub struct AutoCfg { rustc_version: Version, target: Option, no_std: bool, + features: HashSet, rustflags: Option>, } @@ -196,6 +198,7 @@ impl AutoCfg { rustc_version: rustc_version, target: target, no_std: false, + features: HashSet::new(), rustflags: rustflags, }; @@ -255,6 +258,11 @@ impl AutoCfg { if self.no_std { try!(stdin.write_all(b"#![no_std]\n").map_err(error::from_io)); } + for feature in &self.features { + try!(stdin + .write_all(format!("#![feature({})]", feature).as_bytes()) + .map_err(error::from_io)); + } try!(stdin.write_all(code.as_ref()).map_err(error::from_io)); drop(stdin); @@ -404,6 +412,22 @@ impl AutoCfg { emit(cfg); } } + + /// Enables `feature` for all subsequent probes. + /// + /// This adds `#![feature()]` to the start of all probes. Multiple features may be + /// enabled at once. + pub fn enable_feature(&mut self, feature: &str) { + self.features.insert(feature.to_owned()); + } + + /// Disables `feature` for all subsequent probes. + /// + /// This removes `#![feature()]` from the start of all probes. If `feature` was not + /// previously enabled, this has no effect. + pub fn disable_feature(&mut self, feature: &str) { + self.features.remove(feature); + } } fn mangle(s: &str) -> String { diff --git a/src/tests.rs b/src/tests.rs index 4c67462..8d22c13 100644 --- a/src/tests.rs +++ b/src/tests.rs @@ -1,5 +1,7 @@ use super::AutoCfg; use std::env; +use std::process::Command; +use std::str; impl AutoCfg { fn core_std(&self, path: &str) -> String { @@ -15,6 +17,28 @@ impl AutoCfg { assert_eq!(self.probe_rustc_version(major, minor), probe_result); } + fn assert_nightly(&self, probe_result: bool) { + let output = match Command::new(&self.rustc) + .args(&["--version", "--verbose"]) + .output() + { + Ok(value) => value, + Err(error) => panic!(error), + }; + if !output.status.success() { + panic!("could not execute rustc"); + } + let output = match str::from_utf8(&output.stdout) { + Ok(value) => value, + Err(error) => panic!(error), + }; + let release = match output.lines().find(|line| line.starts_with("release: ")) { + Some(line) => &line["release: ".len()..], + None => panic!("could not find rustc release"), + }; + assert_eq!(release.ends_with("nightly"), probe_result); + } + fn for_test() -> Result { match env::var_os("TESTS_TARGET_DIR") { Some(d) => Self::with_dir(d), @@ -132,6 +156,17 @@ fn probe_constant() { ac.assert_min(1, 39, ac.probe_constant(r#""test".len()"#)); } +#[test] +fn features() { + let mut ac = AutoCfg::for_test().unwrap(); + // Enabling features should work only on the nightly channel. + ac.enable_feature("step_trait"); + ac.assert_nightly(ac.probe_trait("std::iter::Step")); + // With the feature disabled, probes should again work as normal. + ac.disable_feature("step_trait"); + assert!(ac.probe_type("usize")); +} + #[test] fn dir_does_not_contain_target() { assert!(!super::dir_contains_target(