* Magenta, **B**-prefixed labels identify bugs which are **blockers**.
+* Dark blue, **beta-** labels track changes which need to be backported into
+ the beta branches.
+
+* Light purple, **C**-prefixed labels represent the **category** of an issue.
+
* Green, **E**-prefixed labels explain the level of **experience** necessary
to fix the issue.
+* The dark blue **final-comment-period** label marks bugs that are using the
+ RFC signoff functionality of [rfcbot][rfcbot] and are currenty in the final
+ comment period.
+
* Red, **I**-prefixed labels indicate the **importance** of the issue. The
[I-nominated][inom] label indicates that an issue has been nominated for
prioritizing at the next triage meeting.
+* The purple **metabug** label marks lists of bugs collected by other
+ categories.
+
+* Purple gray, **O**-prefixed labels are the **operating system** or platform
+ that this issue is specific to.
+
* Orange, **P**-prefixed labels indicate a bug's **priority**. These labels
are only assigned during triage meetings, and replace the [I-nominated][inom]
label.
-* Blue, **T**-prefixed bugs denote which **team** the issue belongs to.
+* The gray **proposed-final-comment-period** label marks bugs that are using
+ the RFC signoff functionality of [rfcbot][rfcbot] and are currently awaiting
+ signoff of all team members in order to enter the final comment period.
-* Dark blue, **beta-** labels track changes which need to be backported into
- the beta branches.
+* Pink, **regression**-prefixed labels track regressions from stable to the
+ release channels.
-* The purple **metabug** label marks lists of bugs collected by other
- categories.
+* The light orange **relnotes** label marks issues that should be documented in
+ the release notes of the next release.
+
+* Gray, **S**-prefixed labels are used for tracking the **status** of pull
+ requests.
+
+* Blue, **T**-prefixed bugs denote which **team** the issue belongs to.
If you're looking for somewhere to start, check out the [E-easy][eeasy] tag.
[inom]: https://github.com/rust-lang/rust/issues?q=is%3Aopen+is%3Aissue+label%3AI-nominated
[eeasy]: https://github.com/rust-lang/rust/issues?q=is%3Aopen+is%3Aissue+label%3AE-easy
[lru]: https://github.com/rust-lang/rust/issues?q=is%3Aissue+is%3Aopen+sort%3Aupdated-asc
+[rfcbot]: https://github.com/dikaiosune/rust-dashboard/blob/master/RFCBOT.md
## Out-of-tree Contributions
--- /dev/null
+
+fn foo(x: fn(&u8, &u8), y: Vec<&u8>, z: &u8) {
+// Debruijn 1 1 1 1
+// Anon-Index 0 1 0 1
+// ------
+// debruijn indices are shifted by 1 in here
+ y.push(z); // index will be zero or one
+}
"regex 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
]
+[[package]]
+name = "error-chain"
+version = "0.10.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "backtrace 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
[[package]]
name = "error-chain"
version = "0.11.0"
[[package]]
name = "handlebars"
-version = "0.26.2"
+version = "0.27.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"lazy_static 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
[[package]]
name = "mdbook"
-version = "0.0.22"
+version = "0.0.25"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"clap 2.26.0 (registry+https://github.com/rust-lang/crates.io-index)",
"env_logger 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)",
- "handlebars 0.26.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "error-chain 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "handlebars 0.27.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "lazy_static 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
"open 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
"pulldown-cmark 0.0.14 (registry+https://github.com/rust-lang/crates.io-index)",
"regex 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
"serde 1.0.11 (registry+https://github.com/rust-lang/crates.io-index)",
+ "serde_derive 1.0.11 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_json 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "tempdir 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)",
"toml 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)",
]
version = "0.1.0"
dependencies = [
"clap 2.26.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "mdbook 0.0.22 (registry+https://github.com/rust-lang/crates.io-index)",
+ "mdbook 0.0.25 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
"checksum enum_primitive 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "be4551092f4d519593039259a9ed8daedf0da12e5109c5280338073eaeb81180"
"checksum env_logger 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "15abd780e45b3ea4f76b4e9a26ff4843258dd8a3eed2775a0e7368c2e7936c2f"
"checksum env_logger 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)" = "3ddf21e73e016298f5cb37d6ef8e8da8e39f91f9ec8b0df44b7deb16a9f8cd5b"
+"checksum error-chain 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d9435d864e017c3c6afeac1654189b06cdb491cf2ff73dbf0d73b0f292f42ff8"
"checksum error-chain 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ff511d5dc435d703f4971bc399647c9bc38e20cb41452e3b9feb4765419ed3f3"
"checksum filetime 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "5363ab8e4139b8568a6237db5248646e5a8a2f89bd5ccb02092182b11fd3e922"
"checksum flate2 0.2.19 (registry+https://github.com/rust-lang/crates.io-index)" = "36df0166e856739905cd3d7e0b210fe818592211a008862599845e012d8d304c"
"checksum glob 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "8be18de09a56b60ed0edf84bc9df007e30040691af7acd1c41874faac5895bfb"
"checksum globset 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "feeb1b6840809ef5efcf7a4a990bc4e1b7ee3df8cf9e2379a75aeb2ba42ac9c3"
"checksum hamcrest 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "bf088f042a467089e9baa4972f57f9247e42a0cc549ba264c7a04fbb8ecb89d4"
-"checksum handlebars 0.26.2 (registry+https://github.com/rust-lang/crates.io-index)" = "fbba80e74e9591a5f6a4ffff6b7f9d645759a896e431cfbdc853e9184370294a"
+"checksum handlebars 0.27.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ef7567daf271a32e60301e4821fcb5b51a5b535167115d1ce04f46c3f0a15f0b"
"checksum hex 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d6a22814455d41612f41161581c2883c0c6a1c41852729b17d5ed88f01e153aa"
"checksum home 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "9f25ae61099d8f3fee8b483df0bd4ecccf4b2731897aad40d50eca1b641fe6db"
"checksum html-diff 0.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "5298d63081a642508fce965740ddb03a386c5d81bf1fef0579a815cf49cb8c68"
"checksum magenta-sys 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "40d014c7011ac470ae28e2f76a02bfea4a8480f73e701353b49ad7a8d75f4699"
"checksum markup5ever 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "ff834ac7123c6a37826747e5ca09db41fd7a83126792021c2e636ad174bb77d3"
"checksum matches 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "100aabe6b8ff4e4a7e32c1c13523379802df0772b82466207ac25b013f193376"
-"checksum mdbook 0.0.22 (registry+https://github.com/rust-lang/crates.io-index)" = "22911d86cde6f80fa9f0fb2a68bbbde85d97af4fe0ce267141c83a4187d28700"
+"checksum mdbook 0.0.25 (registry+https://github.com/rust-lang/crates.io-index)" = "146eadfc6d141452a364c351f07bb19208d1401e931f40b8532f87bba3ecc40f"
"checksum memchr 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)" = "d8b629fb514376c675b98c1421e80b151d3817ac42d7c667717d282761418d20"
"checksum memchr 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "1dbccc0e46f1ea47b9f17e6d67c5a96bd27030519c519c9c91327e31275a47b4"
"checksum miniz-sys 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "28eaee17666671fa872e567547e8428e83308ebe5808cdf6a0e28397dbe2c726"
drop(fs::remove_dir_all(&dst));
build.run(Command::new("tar").arg("xf").arg(&tarball).current_dir(&out));
- let mut configure = Command::new(obj.join("Configure"));
+ let mut configure = Command::new("perl");
+ configure.arg(obj.join("Configure"));
configure.arg(format!("--prefix={}", dst.display()));
configure.arg("no-dso");
configure.arg("no-ssl2");
}
/// Returns an iterator of `u16` over the string encoded as UTF-16.
+ ///
+ /// # Examples
+ ///
+ /// Basic usage:
+ ///
+ /// ```
+ /// let text = "Zażółć gęślą jaźń";
+ ///
+ /// let utf8_len = text.len();
+ /// let utf16_len = text.encode_utf16().count();
+ ///
+ /// assert!(utf16_len <= utf8_len);
+ /// ```
#[stable(feature = "encode_utf16", since = "1.8.0")]
pub fn encode_utf16(&self) -> EncodeUtf16 {
EncodeUtf16 { encoder: Utf16Encoder::new(self[..].chars()) }
}
/// Converts a `Box<str>` into a `Box<[u8]>` without copying or allocating.
+ ///
+ /// # Examples
+ ///
+ /// Basic usage:
+ ///
+ /// ```
+ /// let s = "this is a string";
+ /// let boxed_str = s.to_owned().into_boxed_str();
+ /// let boxed_bytes = boxed_str.into_boxed_bytes();
+ /// assert_eq!(*boxed_bytes, *s.as_bytes());
+ /// ```
#[stable(feature = "str_box_extras", since = "1.20.0")]
pub fn into_boxed_bytes(self: Box<str>) -> Box<[u8]> {
self.into()
/// Converts a boxed slice of bytes to a boxed string slice without checking
/// that the string contains valid UTF-8.
+///
+/// # Examples
+///
+/// Basic usage:
+///
+/// ```
+/// let smile_utf8 = Box::new([226, 152, 186]);
+/// let smile = unsafe { std::str::from_boxed_utf8_unchecked(smile_utf8) };
+///
+/// assert_eq!("☺", &*smile);
+/// ```
#[stable(feature = "str_box_extras", since = "1.20.0")]
pub unsafe fn from_boxed_utf8_unchecked(v: Box<[u8]>) -> Box<str> {
mem::transmute(v)
self
}
- /// Extracts a string slice containing the entire string.
+ /// Converts a `String` into a mutable string slice.
+ ///
+ /// # Examples
+ ///
+ /// Basic usage:
+ ///
+ /// ```
+ /// use std::ascii::AsciiExt;
+ ///
+ /// let mut s = String::from("foobar");
+ /// let s_mut_str = s.as_mut_str();
+ ///
+ /// s_mut_str.make_ascii_uppercase();
+ ///
+ /// assert_eq!("FOOBAR", s_mut_str);
+ /// ```
#[inline]
#[stable(feature = "string_as_str", since = "1.7.0")]
pub fn as_mut_str(&mut self) -> &mut str {
///
/// * `ptr` needs to have been previously allocated via [`String`]/`Vec<T>`
/// (at least, it's highly likely to be incorrect if it wasn't).
+ /// * `ptr`'s `T` needs to have the same size and alignment as it was allocated with.
/// * `length` needs to be less than or equal to `capacity`.
/// * `capacity` needs to be the capacity that the pointer was allocated with.
///
/// Using this method is equivalent to the following code:
///
/// ```
- /// # let some_predicate = |x: &mut i32| { *x == 2 };
- /// # let mut vec = vec![1, 2, 3, 4, 5];
+ /// # let some_predicate = |x: &mut i32| { *x == 2 || *x == 3 || *x == 6 };
+ /// # let mut vec = vec![1, 2, 3, 4, 5, 6];
/// let mut i = 0;
/// while i != vec.len() {
/// if some_predicate(&mut vec[i]) {
/// let val = vec.remove(i);
/// // your code here
+ /// } else {
+ /// i += 1;
/// }
- /// i += 1;
/// }
+ ///
+ /// # assert_eq!(vec, vec![1, 4, 5]);
/// ```
///
/// But `drain_filter` is easier to use. `drain_filter` is also more efficient,
/// // The no-copy, unsafe way, still using transmute, but not UB.
/// // This is equivalent to the original, but safer, and reuses the
/// // same Vec internals. Therefore the new inner type must have the
- /// // exact same size, and the same or lesser alignment, as the old
- /// // type. The same caveats exist for this method as transmute, for
+ /// // exact same size, and the same alignment, as the old type.
+ /// // The same caveats exist for this method as transmute, for
/// // the original inner type (`&i32`) to the converted inner type
/// // (`Option<&i32>`), so read the nomicon pages linked above.
/// let v_from_raw = unsafe {
- /// Vec::from_raw_parts(v_orig.as_mut_ptr(),
+ /// Vec::from_raw_parts(v_orig.as_mut_ptr() as *mut Option<&i32>,
/// v_orig.len(),
/// v_orig.capacity())
/// };
}
/// Converts a mutable slice of bytes to a mutable string slice.
+///
+/// # Examples
+///
+/// Basic usage:
+///
+/// ```
+/// use std::str;
+///
+/// // "Hello, Rust!" as a mutable vector
+/// let mut hellorust = vec![72, 101, 108, 108, 111, 44, 32, 82, 117, 115, 116, 33];
+///
+/// // As we know these bytes are valid, we can use `unwrap()`
+/// let outstr = str::from_utf8_mut(&mut hellorust).unwrap();
+///
+/// assert_eq!("Hello, Rust!", outstr);
+/// ```
+///
+/// Incorrect bytes:
+///
+/// ```
+/// use std::str;
+///
+/// // Some invalid bytes in a mutable vector
+/// let mut invalid = vec![128, 223];
+///
+/// assert!(str::from_utf8_mut(&mut invalid).is_err());
+/// ```
+/// See the docs for [`Utf8Error`][error] for more details on the kinds of
+/// errors that can be returned.
+///
+/// [error]: struct.Utf8Error.html
#[stable(feature = "str_mut_extras", since = "1.20.0")]
pub fn from_utf8_mut(v: &mut [u8]) -> Result<&mut str, Utf8Error> {
run_utf8_validation(v)?;
/// See the immutable version, [`from_utf8_unchecked()`][fromutf8], for more information.
///
/// [fromutf8]: fn.from_utf8_unchecked.html
+///
+/// # Examples
+///
+/// Basic usage:
+///
+/// ```
+/// use std::str;
+///
+/// let mut heart = vec![240, 159, 146, 150];
+/// let heart = unsafe { str::from_utf8_unchecked_mut(&mut heart) };
+///
+/// assert_eq!("💖", heart);
+/// ```
#[inline]
#[stable(feature = "str_mut_extras", since = "1.20.0")]
pub unsafe fn from_utf8_unchecked_mut(v: &mut [u8]) -> &mut str {
-Subproject commit 04a5e75c99dc92afab490c38fcbbeac9b4bc8104
+Subproject commit 95848f9622deccc9cbadcd5d3a4faef01a90ead4
//! get confused if the spans from leaf AST nodes occur in multiple places
//! in the HIR, especially for multiple identifiers.
+use dep_graph::DepGraph;
use hir;
use hir::map::{Definitions, DefKey};
use hir::def_id::{DefIndex, DefId, CRATE_DEF_INDEX};
pub fn lower_crate(sess: &Session,
cstore: &CrateStore,
+ dep_graph: &DepGraph,
krate: &Crate,
resolver: &mut Resolver)
-> hir::Crate {
// We're constructing the HIR here; we don't care what we will
// read, since we haven't even constructed the *input* to
// incr. comp. yet.
- let _ignore = sess.dep_graph.in_ignore();
+ let _ignore = dep_graph.in_ignore();
LoweringContext {
crate_root: std_inject::injected_crate_name(krate),
hir_map: &self.tcx.hir,
bound_region: *br,
found_type: None,
+ depth: 1,
};
nested_visitor.visit_ty(arg);
nested_visitor.found_type
// The type where the anonymous lifetime appears
// for e.g. Vec<`&u8`> and <`&u8`>
found_type: Option<&'gcx hir::Ty>,
+ depth: u32,
}
impl<'a, 'gcx, 'tcx> Visitor<'gcx> for FindNestedTypeVisitor<'a, 'gcx, 'tcx> {
fn visit_ty(&mut self, arg: &'gcx hir::Ty) {
match arg.node {
+ hir::TyBareFn(_) => {
+ self.depth += 1;
+ intravisit::walk_ty(self, arg);
+ self.depth -= 1;
+ return;
+ }
+
+ hir::TyTraitObject(ref bounds, _) => {
+ for bound in bounds {
+ self.depth += 1;
+ self.visit_poly_trait_ref(bound, hir::TraitBoundModifier::None);
+ self.depth -= 1;
+ }
+ }
+
hir::TyRptr(ref lifetime, _) => {
// the lifetime of the TyRptr
let hir_id = self.infcx.tcx.hir.node_to_hir_id(lifetime.id);
debruijn_index.depth,
anon_index,
br_index);
- if debruijn_index.depth == 1 && anon_index == br_index {
+ if debruijn_index.depth == self.depth && anon_index == br_index {
self.found_type = Some(arg);
return; // we can stop visiting now
}
debug!("self.infcx.tcx.hir.local_def_id(id)={:?}",
self.infcx.tcx.hir.local_def_id(id));
debug!("def_id={:?}", def_id);
- if debruijn_index.depth == 1 &&
+ if debruijn_index.depth == self.depth &&
self.infcx.tcx.hir.local_def_id(id) == def_id {
self.found_type = Some(arg);
return; // we can stop visiting now
}
}
+impl LangItem {
+ fn name(self) -> &'static str {
+ match self {
+ $( $variant => $name, )*
+ }
+ }
+}
+
pub struct LanguageItems {
pub items: Vec<Option<DefId>>,
pub missing: Vec<LangItem>,
&*self.items
}
- pub fn item_name(index: usize) -> &'static str {
- let item: Option<LangItem> = LangItem::from_u32(index as u32);
- match item {
- $( Some($variant) => $name, )*
- None => "???"
- }
- }
-
pub fn require(&self, it: LangItem) -> Result<DefId, String> {
- match self.items[it as usize] {
- Some(id) => Ok(id),
- None => {
- Err(format!("requires `{}` lang_item",
- LanguageItems::item_name(it as usize)))
- }
- }
- }
-
- pub fn require_owned_box(&self) -> Result<DefId, String> {
- self.require(OwnedBoxLangItem)
+ self.items[it as usize].ok_or_else(|| format!("requires `{}` lang_item", it.name()))
}
pub fn fn_trait_kind(&self, id: DefId) -> Option<ty::ClosureKind> {
- let def_id_kinds = [
- (self.fn_trait(), ty::ClosureKind::Fn),
- (self.fn_mut_trait(), ty::ClosureKind::FnMut),
- (self.fn_once_trait(), ty::ClosureKind::FnOnce),
- ];
-
- for &(opt_def_id, kind) in &def_id_kinds {
- if Some(id) == opt_def_id {
- return Some(kind);
- }
+ match Some(id) {
+ x if x == self.fn_trait() => Some(ty::ClosureKind::Fn),
+ x if x == self.fn_mut_trait() => Some(ty::ClosureKind::FnMut),
+ x if x == self.fn_once_trait() => Some(ty::ClosureKind::FnOnce),
+ _ => None
}
-
- None
}
$(
// Check for duplicates.
match self.items.items[item_index] {
Some(original_def_id) if original_def_id != item_def_id => {
- let name = LanguageItems::item_name(item_index);
+ let name = LangItem::from_u32(item_index as u32).unwrap().name();
let mut err = match self.tcx.hir.span_if_local(item_def_id) {
Some(span) => struct_span_err!(
self.tcx.sess,
PhantomDataItem, "phantom_data", phantom_data;
- // Deprecated:
- CovariantTypeItem, "covariant_type", covariant_type;
- ContravariantTypeItem, "contravariant_type", contravariant_type;
- InvariantTypeItem, "invariant_type", invariant_type;
- CovariantLifetimeItem, "covariant_lifetime", covariant_lifetime;
- ContravariantLifetimeItem, "contravariant_lifetime", contravariant_lifetime;
- InvariantLifetimeItem, "invariant_lifetime", invariant_lifetime;
-
NonZeroItem, "non_zero", non_zero;
DebugTraitLangItem, "debug_trait", debug_trait;
#[cfg(test)]
mod tests {
- use dep_graph::DepGraph;
use errors;
use getopts;
use lint;
// When the user supplies --test we should implicitly supply --cfg test
#[test]
fn test_switch_implies_cfg_test() {
- let dep_graph = DepGraph::new(false);
let matches =
&match optgroups().parse(&["--test".to_string()]) {
Ok(m) => m,
};
let registry = errors::registry::Registry::new(&[]);
let (sessopts, cfg) = build_session_options_and_crate_config(matches);
- let sess = build_session(sessopts, &dep_graph, None, registry);
+ let sess = build_session(sessopts, None, registry);
let cfg = build_configuration(&sess, cfg);
assert!(cfg.contains(&(Symbol::intern("test"), None)));
}
// another --cfg test
#[test]
fn test_switch_implies_cfg_test_unless_cfg_test() {
- let dep_graph = DepGraph::new(false);
let matches =
&match optgroups().parse(&["--test".to_string(), "--cfg=test".to_string()]) {
Ok(m) => m,
};
let registry = errors::registry::Registry::new(&[]);
let (sessopts, cfg) = build_session_options_and_crate_config(matches);
- let sess = build_session(sessopts, &dep_graph, None, registry);
+ let sess = build_session(sessopts, None, registry);
let cfg = build_configuration(&sess, cfg);
let mut test_items = cfg.iter().filter(|&&(name, _)| name == "test");
assert!(test_items.next().is_some());
#[test]
fn test_can_print_warnings() {
- let dep_graph = DepGraph::new(false);
{
let matches = optgroups().parse(&[
"-Awarnings".to_string()
]).unwrap();
let registry = errors::registry::Registry::new(&[]);
let (sessopts, _) = build_session_options_and_crate_config(&matches);
- let sess = build_session(sessopts, &dep_graph, None, registry);
+ let sess = build_session(sessopts, None, registry);
assert!(!sess.diagnostic().can_emit_warnings);
}
]).unwrap();
let registry = errors::registry::Registry::new(&[]);
let (sessopts, _) = build_session_options_and_crate_config(&matches);
- let sess = build_session(sessopts, &dep_graph, None, registry);
+ let sess = build_session(sessopts, None, registry);
assert!(sess.diagnostic().can_emit_warnings);
}
]).unwrap();
let registry = errors::registry::Registry::new(&[]);
let (sessopts, _) = build_session_options_and_crate_config(&matches);
- let sess = build_session(sessopts, &dep_graph, None, registry);
+ let sess = build_session(sessopts, None, registry);
assert!(sess.diagnostic().can_emit_warnings);
}
}
pub use self::code_stats::{CodeStats, DataTypeKind, FieldInfo};
pub use self::code_stats::{SizeKind, TypeSizeInfo, VariantInfo};
-use dep_graph::DepGraph;
use hir::def_id::{CrateNum, DefIndex};
use lint;
// Represents the data associated with a compilation
// session for a single crate.
pub struct Session {
- pub dep_graph: DepGraph,
pub target: config::Config,
pub host: Target,
pub opts: config::Options,
// forms a unique global identifier for the crate. It is used to allow
// multiple crates with the same name to coexist. See the
// trans::back::symbol_names module for more information.
- pub crate_disambiguator: RefCell<Symbol>,
+ pub crate_disambiguator: RefCell<Option<Symbol>>,
pub features: RefCell<feature_gate::Features>,
/// The maximum recursion limit for potentially infinitely recursive
impl Session {
pub fn local_crate_disambiguator(&self) -> Symbol {
- *self.crate_disambiguator.borrow()
+ match *self.crate_disambiguator.borrow() {
+ Some(sym) => sym,
+ None => bug!("accessing disambiguator before initialization"),
+ }
}
pub fn struct_span_warn<'a, S: Into<MultiSpan>>(&'a self,
sp: S,
kind)
}
+ pub fn set_incr_session_load_dep_graph(&self, load: bool) {
+ let mut incr_comp_session = self.incr_comp_session.borrow_mut();
+
+ match *incr_comp_session {
+ IncrCompSession::Active { ref mut load_dep_graph, .. } => {
+ *load_dep_graph = load;
+ }
+ _ => {}
+ }
+ }
+
+ pub fn incr_session_load_dep_graph(&self) -> bool {
+ let incr_comp_session = self.incr_comp_session.borrow();
+ match *incr_comp_session {
+ IncrCompSession::Active { load_dep_graph, .. } => load_dep_graph,
+ _ => false,
+ }
+ }
+
pub fn init_incr_comp_session(&self,
session_dir: PathBuf,
- lock_file: flock::Lock) {
+ lock_file: flock::Lock,
+ load_dep_graph: bool) {
let mut incr_comp_session = self.incr_comp_session.borrow_mut();
if let IncrCompSession::NotInitialized = *incr_comp_session { } else {
*incr_comp_session = IncrCompSession::Active {
session_directory: session_dir,
lock_file,
+ load_dep_graph,
};
}
}
pub fn build_session(sopts: config::Options,
- dep_graph: &DepGraph,
local_crate_source_file: Option<PathBuf>,
registry: errors::registry::Registry)
-> Session {
let file_path_mapping = sopts.file_path_mapping();
build_session_with_codemap(sopts,
- dep_graph,
local_crate_source_file,
registry,
Rc::new(codemap::CodeMap::new(file_path_mapping)),
}
pub fn build_session_with_codemap(sopts: config::Options,
- dep_graph: &DepGraph,
local_crate_source_file: Option<PathBuf>,
registry: errors::registry::Registry,
codemap: Rc<codemap::CodeMap>,
emitter);
build_session_(sopts,
- dep_graph,
local_crate_source_file,
diagnostic_handler,
codemap)
}
pub fn build_session_(sopts: config::Options,
- dep_graph: &DepGraph,
local_crate_source_file: Option<PathBuf>,
span_diagnostic: errors::Handler,
codemap: Rc<codemap::CodeMap>)
let working_dir = file_path_mapping.map_prefix(working_dir);
let sess = Session {
- dep_graph: dep_graph.clone(),
target: target_cfg,
host,
opts: sopts,
plugin_attributes: RefCell::new(Vec::new()),
crate_types: RefCell::new(Vec::new()),
dependency_formats: RefCell::new(FxHashMap()),
- crate_disambiguator: RefCell::new(Symbol::intern("")),
+ crate_disambiguator: RefCell::new(None),
features: RefCell::new(feature_gate::Features::new()),
recursion_limit: Cell::new(64),
type_length_limit: Cell::new(1048576),
Active {
session_directory: PathBuf,
lock_file: flock::Lock,
+ load_dep_graph: bool,
},
// This is the state after the session directory has been finalized. In this
// state, the contents of the directory must not be modified any more.
fn join(&self, pred1: usize, pred2: usize) -> usize;
}
+pub struct Intersect;
+impl BitwiseOperator for Intersect {
+ #[inline]
+ fn join(&self, a: usize, b: usize) -> usize { a & b }
+}
pub struct Union;
impl BitwiseOperator for Union {
#[inline]
use std::ops::{Deref, DerefMut, Range};
use std::slice;
use bitslice::{BitSlice, Word};
-use bitslice::{bitwise, Union, Subtract};
+use bitslice::{bitwise, Union, Subtract, Intersect};
use indexed_vec::Idx;
/// Represents a set (or packed family of sets), of some element type
bitwise(self.words_mut(), other.words(), &Subtract)
}
+ pub fn intersect(&mut self, other: &IdxSet<T>) -> bool {
+ bitwise(self.words_mut(), other.words(), &Intersect)
+ }
+
pub fn iter(&self) -> Iter<T> {
Iter {
cur: None,
#![cfg_attr(not(feature="llvm"), allow(dead_code))]
+use rustc::dep_graph::DepGraph;
use rustc::hir::{self, map as hir_map};
use rustc::hir::lowering::lower_crate;
use rustc::ich::Fingerprint;
// We need nested scopes here, because the intermediate results can keep
// large chunks of memory alive and we want to free them as soon as
// possible to keep the peak memory usage low
- let (outputs, trans): (OutputFilenames, OngoingCrateTranslation) = {
+ let (outputs, trans, dep_graph): (OutputFilenames, OngoingCrateTranslation, DepGraph) = {
let krate = match phase_1_parse_input(control, sess, input) {
Ok(krate) => krate,
Err(mut parse_error) => {
::rustc_trans_utils::link::find_crate_name(Some(sess), &krate.attrs, input);
let ExpansionResult { expanded_crate, defs, analysis, resolutions, mut hir_forest } = {
phase_2_configure_and_expand(
- sess, &cstore, krate, registry, &crate_name, addl_plugins, control.make_glob_map,
+ sess,
+ &cstore,
+ krate,
+ registry,
+ &crate_name,
+ addl_plugins,
+ control.make_glob_map,
|expanded_crate| {
let mut state = CompileState::state_after_expand(
input, sess, outdir, output, &cstore, expanded_crate, &crate_name,
}
}
- Ok((outputs, trans))
+ Ok((outputs, trans, tcx.dep_graph.clone()))
})??
};
sess.code_stats.borrow().print_type_sizes();
}
- let (phase5_result, trans) = phase_5_run_llvm_passes(sess, trans);
+ let (phase5_result, trans) = phase_5_run_llvm_passes(sess, &dep_graph, trans);
controller_entry_point!(after_llvm,
sess,
*sess.features.borrow_mut() = features;
*sess.crate_types.borrow_mut() = collect_crate_types(sess, &krate.attrs);
- *sess.crate_disambiguator.borrow_mut() = Symbol::intern(&compute_crate_disambiguator(sess));
+
+ let disambiguator = Symbol::intern(&compute_crate_disambiguator(sess));
+ *sess.crate_disambiguator.borrow_mut() = Some(disambiguator);
+ rustc_incremental::prepare_session_directory(
+ sess,
+ &crate_name,
+ &disambiguator.as_str(),
+ );
+ let dep_graph = DepGraph::new(sess.opts.build_dep_graph());
time(time_passes, "recursion limit", || {
middle::recursion_limit::update_limits(sess, &krate);
// item, much like we do for macro expansion. In other words, the hash reflects not just
// its contents but the results of name resolution on those contents. Hopefully we'll push
// this back at some point.
- let _ignore = sess.dep_graph.in_ignore();
+ let _ignore = dep_graph.in_ignore();
let mut crate_loader = CrateLoader::new(sess, &cstore, crate_name);
let resolver_arenas = Resolver::arenas();
let mut resolver = Resolver::new(sess,
// Lower ast -> hir.
let hir_forest = time(time_passes, "lowering ast -> hir", || {
- let hir_crate = lower_crate(sess, cstore, &krate, &mut resolver);
+ let hir_crate = lower_crate(sess, cstore, &dep_graph, &krate, &mut resolver);
if sess.opts.debugging_opts.hir_stats {
hir_stats::print_hir_stats(&hir_crate);
}
- hir_map::Forest::new(hir_crate, &sess.dep_graph)
+ hir_map::Forest::new(hir_crate, &dep_graph)
});
time(time_passes,
/// as a side effect.
#[cfg(feature="llvm")]
pub fn phase_5_run_llvm_passes(sess: &Session,
+ dep_graph: &DepGraph,
trans: write::OngoingCrateTranslation)
-> (CompileResult, trans::CrateTranslation) {
- let trans = trans.join(sess);
+ let trans = trans.join(sess, dep_graph);
if sess.opts.debugging_opts.incremental_info {
write::dump_incremental_data(&trans);
time(sess.time_passes(),
"serialize work products",
- move || rustc_incremental::save_work_products(sess));
+ move || rustc_incremental::save_work_products(sess, dep_graph));
(sess.compile_status(), trans)
}
use rustc_resolve as resolve;
use rustc_save_analysis as save;
use rustc_save_analysis::DumpHandler;
-use rustc::dep_graph::DepGraph;
use rustc::session::{self, config, Session, build_session, CompileResult};
use rustc::session::CompileIncomplete;
use rustc::session::config::{Input, PrintRequest, OutputType, ErrorOutputType};
},
};
- let dep_graph = DepGraph::new(sopts.build_dep_graph());
let cstore = Rc::new(CStore::new(box ::MetadataLoader));
let loader = file_loader.unwrap_or(box RealFileLoader);
let codemap = Rc::new(CodeMap::with_file_loader(loader, sopts.file_path_mapping()));
let mut sess = session::build_session_with_codemap(
- sopts, &dep_graph, input_file_path, descriptions, codemap, emitter_dest,
+ sopts, input_file_path, descriptions, codemap, emitter_dest,
);
rustc_trans::init(&sess);
rustc_lint::register_builtins(&mut sess.lint_store.borrow_mut(), Some(&sess));
let plugins = sess.opts.debugging_opts.extra_plugins.clone();
let control = callbacks.build_controller(&sess, &matches);
- (driver::compile_input(&sess, &cstore, &input, &odir, &ofile, Some(plugins), &control),
+ (driver::compile_input(&sess,
+ &cstore,
+ &input,
+ &odir,
+ &ofile,
+ Some(plugins),
+ &control),
Some(sess))
}
describe_lints(&ls, false);
return None;
}
- let dep_graph = DepGraph::new(sopts.build_dep_graph());
let mut sess = build_session(sopts.clone(),
- &dep_graph,
None,
descriptions.clone());
rustc_trans::init(&sess);
//! # Standalone Tests for the Inference Module
use driver;
-use rustc::dep_graph::DepGraph;
use rustc_lint;
use rustc_resolve::MakeGlobMap;
use rustc_trans;
options.unstable_features = UnstableFeatures::Allow;
let diagnostic_handler = errors::Handler::with_emitter(true, false, emitter);
- let dep_graph = DepGraph::new(false);
- let _ignore = dep_graph.in_ignore();
let cstore = Rc::new(CStore::new(box ::MetadataLoader));
let sess = session::build_session_(options,
- &dep_graph,
None,
diagnostic_handler,
Rc::new(CodeMap::new(FilePathMapping::empty())));
|_| Ok(()))
.expect("phase 2 aborted")
};
- let _ignore = dep_graph.in_ignore();
let arena = DroplessArena::new();
let arenas = ty::GlobalArenas::new();
pub use persist::save_trans_partition;
pub use persist::save_work_products;
pub use persist::in_incr_comp_dir;
+pub use persist::prepare_session_directory;
pub use persist::finalize_session_directory;
//! unsupported file system and emit a warning in that case. This is not yet
//! implemented.
-use rustc::hir::def_id::{CrateNum, LOCAL_CRATE};
+use rustc::hir::def_id::CrateNum;
use rustc::hir::svh::Svh;
use rustc::session::Session;
use rustc::ty::TyCtxt;
/// a dep-graph and work products from a previous session.
/// If the call fails, the fn may leave behind an invalid session directory.
/// The garbage collection will take care of it.
-pub fn prepare_session_directory(tcx: TyCtxt) -> Result<bool, ()> {
+pub fn prepare_session_directory(sess: &Session,
+ crate_name: &str,
+ crate_disambiguator: &str) {
+ if sess.opts.incremental.is_none() {
+ return
+ }
+
debug!("prepare_session_directory");
// {incr-comp-dir}/{crate-name-and-disambiguator}
- let crate_dir = crate_path_tcx(tcx, LOCAL_CRATE);
+ let crate_dir = crate_path(sess, crate_name, crate_disambiguator);
debug!("crate-dir: {}", crate_dir.display());
- try!(create_dir(tcx.sess, &crate_dir, "crate"));
+ if create_dir(sess, &crate_dir, "crate").is_err() {
+ return
+ }
// Hack: canonicalize the path *after creating the directory*
// because, on windows, long paths can cause problems;
let crate_dir = match crate_dir.canonicalize() {
Ok(v) => v,
Err(err) => {
- tcx.sess.err(&format!("incremental compilation: error canonicalizing path `{}`: {}",
- crate_dir.display(), err));
- return Err(());
+ sess.err(&format!("incremental compilation: error canonicalizing path `{}`: {}",
+ crate_dir.display(), err));
+ return
}
};
// Lock the new session directory. If this fails, return an
// error without retrying
- let (directory_lock, lock_file_path) = try!(lock_directory(tcx.sess, &session_dir));
+ let (directory_lock, lock_file_path) = match lock_directory(sess, &session_dir) {
+ Ok(e) => e,
+ Err(_) => return,
+ };
// Now that we have the lock, we can actually create the session
// directory
- try!(create_dir(tcx.sess, &session_dir, "session"));
+ if create_dir(sess, &session_dir, "session").is_err() {
+ return
+ }
// Find a suitable source directory to copy from. Ignore those that we
// have already tried before.
debug!("no source directory found. Continuing with empty session \
directory.");
- tcx.sess.init_incr_comp_session(session_dir, directory_lock);
- return Ok(false)
+ sess.init_incr_comp_session(session_dir, directory_lock, false);
+ return
};
debug!("attempting to copy data from source: {}",
source_directory.display());
- let print_file_copy_stats = tcx.sess.opts.debugging_opts.incremental_info;
+ let print_file_copy_stats = sess.opts.debugging_opts.incremental_info;
// Try copying over all files from the source directory
if let Ok(allows_links) = copy_files(&session_dir, &source_directory,
source_directory.display());
if !allows_links {
- tcx.sess.warn(&format!("Hard linking files in the incremental \
+ sess.warn(&format!("Hard linking files in the incremental \
compilation cache failed. Copying files \
instead. Consider moving the cache \
directory to a file system which supports \
);
}
- tcx.sess.init_incr_comp_session(session_dir, directory_lock);
- return Ok(true)
+ sess.init_incr_comp_session(session_dir, directory_lock, true);
+ return
} else {
debug!("copying failed - trying next directory");
// Try to remove the session directory we just allocated. We don't
// know if there's any garbage in it from the failed copy action.
if let Err(err) = safe_remove_dir_all(&session_dir) {
- tcx.sess.warn(&format!("Failed to delete partly initialized \
- session dir `{}`: {}",
- session_dir.display(),
- err));
+ sess.warn(&format!("Failed to delete partly initialized \
+ session dir `{}`: {}",
+ session_dir.display(),
+ err));
}
- delete_session_dir_lock_file(tcx.sess, &lock_file_path);
+ delete_session_dir_lock_file(sess, &lock_file_path);
mem::drop(directory_lock);
}
}
/// more general overview.
pub fn load_dep_graph<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
incremental_hashes_map: &IncrementalHashesMap) {
- if tcx.sess.opts.incremental.is_none() {
- return;
+ if tcx.sess.incr_session_load_dep_graph() {
+ let _ignore = tcx.dep_graph.in_ignore();
+ load_dep_graph_if_exists(tcx, incremental_hashes_map);
}
-
- match prepare_session_directory(tcx) {
- Ok(true) => {
- // We successfully allocated a session directory and there is
- // something in it to load, so continue
- }
- Ok(false) => {
- // We successfully allocated a session directory, but there is no
- // dep-graph data in it to load (because this is the first
- // compilation session with this incr. comp. dir.)
- return
- }
- Err(()) => {
- // Something went wrong while trying to allocate the session
- // directory. Don't try to use it any further.
- return
- }
- }
-
- let _ignore = tcx.dep_graph.in_ignore();
- load_dep_graph_if_exists(tcx, incremental_hashes_map);
}
fn load_dep_graph_if_exists<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
mod work_product;
mod file_format;
+pub use self::fs::prepare_session_directory;
pub use self::fs::finalize_session_directory;
pub use self::fs::in_incr_comp_dir;
pub use self::load::load_dep_graph;
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-use rustc::dep_graph::DepNode;
+use rustc::dep_graph::{DepGraph, DepNode};
use rustc::hir::def_id::DefId;
use rustc::hir::svh::Svh;
use rustc::ich::Fingerprint;
¤t_metadata_hashes);
}
-pub fn save_work_products(sess: &Session) {
+pub fn save_work_products(sess: &Session, dep_graph: &DepGraph) {
if sess.opts.incremental.is_none() {
return;
}
debug!("save_work_products()");
- let _ignore = sess.dep_graph.in_ignore();
+ let _ignore = dep_graph.in_ignore();
let path = work_products_path(sess);
- save_in(sess, path, |e| encode_work_products(sess, e));
+ save_in(sess, path, |e| encode_work_products(dep_graph, e));
// We also need to clean out old work-products, as not all of them are
// deleted during invalidation. Some object files don't change their
// content, they are just not needed anymore.
- let new_work_products = sess.dep_graph.work_products();
- let previous_work_products = sess.dep_graph.previous_work_products();
+ let new_work_products = dep_graph.work_products();
+ let previous_work_products = dep_graph.previous_work_products();
for (id, wp) in previous_work_products.iter() {
if !new_work_products.contains_key(id) {
Ok(())
}
-pub fn encode_work_products(sess: &Session, encoder: &mut Encoder) -> io::Result<()> {
- let work_products: Vec<_> = sess.dep_graph
+pub fn encode_work_products(dep_graph: &DepGraph,
+ encoder: &mut Encoder) -> io::Result<()> {
+ let work_products: Vec<_> = dep_graph
.work_products()
.iter()
.map(|(id, work_product)| {
//! This module contains files for saving intermediate work-products.
use persist::fs::*;
-use rustc::dep_graph::{WorkProduct, WorkProductId};
+use rustc::dep_graph::{WorkProduct, WorkProductId, DepGraph};
use rustc::session::Session;
use rustc::session::config::OutputType;
use rustc::util::fs::link_or_copy;
use std::fs as std_fs;
pub fn save_trans_partition(sess: &Session,
+ dep_graph: &DepGraph,
cgu_name: &str,
partition_hash: u64,
files: &[(OutputType, PathBuf)]) {
saved_files,
};
- sess.dep_graph.insert_work_product(&work_product_id, work_product);
+ dep_graph.insert_work_product(&work_product_id, work_product);
}
pub fn delete_workproduct_files(sess: &Session, work_product: &WorkProduct) {
use super::drop_flag_effects_for_location;
use super::on_lookup_result_bits;
+mod storage_liveness;
+
+pub use self::storage_liveness::*;
+
#[allow(dead_code)]
pub(super) mod borrows;
--- /dev/null
+// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+pub use super::*;
+
+use rustc::mir::*;
+use dataflow::BitDenotation;
+
+#[derive(Copy, Clone)]
+pub struct MaybeStorageLive<'a, 'tcx: 'a> {
+ mir: &'a Mir<'tcx>,
+}
+
+impl<'a, 'tcx: 'a> MaybeStorageLive<'a, 'tcx> {
+ pub fn new(mir: &'a Mir<'tcx>)
+ -> Self {
+ MaybeStorageLive { mir: mir }
+ }
+
+ pub fn mir(&self) -> &Mir<'tcx> {
+ self.mir
+ }
+}
+
+impl<'a, 'tcx> BitDenotation for MaybeStorageLive<'a, 'tcx> {
+ type Idx = Local;
+ fn name() -> &'static str { "maybe_storage_live" }
+ fn bits_per_block(&self) -> usize {
+ self.mir.local_decls.len()
+ }
+
+ fn start_block_effect(&self, _sets: &mut BlockSets<Local>) {
+ // Nothing is live on function entry
+ }
+
+ fn statement_effect(&self,
+ sets: &mut BlockSets<Local>,
+ loc: Location) {
+ let stmt = &self.mir[loc.block].statements[loc.statement_index];
+
+ match stmt.kind {
+ StatementKind::StorageLive(l) => sets.gen(&l),
+ StatementKind::StorageDead(l) => sets.kill(&l),
+ _ => (),
+ }
+ }
+
+ fn terminator_effect(&self,
+ _sets: &mut BlockSets<Local>,
+ _loc: Location) {
+ // Terminators have no effect
+ }
+
+ fn propagate_call_return(&self,
+ _in_out: &mut IdxSet<Local>,
+ _call_bb: mir::BasicBlock,
+ _dest_bb: mir::BasicBlock,
+ _dest_lval: &mir::Lvalue) {
+ // Nothing to do when a call returns successfully
+ }
+}
+
+impl<'a, 'tcx> BitwiseOperator for MaybeStorageLive<'a, 'tcx> {
+ #[inline]
+ fn join(&self, pred1: usize, pred2: usize) -> usize {
+ pred1 | pred2 // "maybe" means we union effects of both preds
+ }
+}
+
+impl<'a, 'tcx> DataflowOperator for MaybeStorageLive<'a, 'tcx> {
+ #[inline]
+ fn bottom_value() -> bool {
+ false // bottom = dead
+ }
+}
use std::path::PathBuf;
use std::usize;
+pub use self::impls::{MaybeStorageLive};
pub use self::impls::{MaybeInitializedLvals, MaybeUninitializedLvals};
pub use self::impls::{DefinitelyInitializedLvals};
pub use self::impls::borrows::{Borrows, BorrowData, BorrowIndex};
flow_state: &mut Self::FlowState);
}
+pub fn state_for_location<T: BitDenotation>(loc: Location,
+ analysis: &T,
+ result: &DataflowResults<T>)
+ -> IdxSetBuf<T::Idx> {
+ let mut entry = result.sets().on_entry_set_for(loc.block.index()).to_owned();
+
+ {
+ let mut sets = BlockSets {
+ on_entry: &mut entry.clone(),
+ kill_set: &mut entry.clone(),
+ gen_set: &mut entry,
+ };
+
+ for stmt in 0..loc.statement_index {
+ let mut stmt_loc = loc;
+ stmt_loc.statement_index = stmt;
+ analysis.statement_effect(&mut sets, stmt_loc);
+ }
+ }
+
+ entry
+}
+
pub struct DataflowAnalysis<'a, 'tcx: 'a, O> where O: BitDenotation
{
flow_state: DataflowState<O>,
//! This pass computes the meaning of the state field and the MIR locals which are live
//! across a suspension point. There are however two hardcoded generator states:
//! 0 - Generator have not been resumed yet
-//! 1 - Generator has been poisoned
+//! 1 - Generator has returned / is completed
+//! 2 - Generator has been poisoned
//!
//! It also rewrites `return x` and `yield y` as setting a new generator state and returning
//! GeneratorState::Complete(x) and GeneratorState::Yielded(y) respectively.
//! the action to take.
//!
//! One of them is the implementation of Generator::resume.
-//! For generators which have already returned it panics.
//! For generators with state 0 (unresumed) it starts the execution of the generator.
-//! For generators with state 1 (poisoned) it panics.
+//! For generators with state 1 (returned) and state 2 (poisoned) it panics.
//! Otherwise it continues the execution from the last suspension point.
//!
//! The other function is the drop glue for the generator.
-//! For generators which have already returned it does nothing.
//! For generators with state 0 (unresumed) it drops the upvars of the generator.
-//! For generators with state 1 (poisoned) it does nothing.
+//! For generators with state 1 (returned) and state 2 (poisoned) it does nothing.
//! Otherwise it drops all the values in scope at the last suspension point.
use rustc::hir;
use rustc::middle::const_val::ConstVal;
use rustc::mir::*;
use rustc::mir::transform::{MirPass, MirSource};
-use rustc::mir::visit::{LvalueContext, MutVisitor};
+use rustc::mir::visit::{LvalueContext, Visitor, MutVisitor};
use rustc::ty::{self, TyCtxt, AdtDef, Ty, GeneratorInterior};
use rustc::ty::subst::{Kind, Substs};
use util::dump_mir;
use util::liveness;
use rustc_const_math::ConstInt;
use rustc_data_structures::indexed_vec::Idx;
+use rustc_data_structures::indexed_set::IdxSetBuf;
use std::collections::HashMap;
use std::borrow::Cow;
use std::iter::once;
use std::mem;
use transform::simplify;
use transform::no_landing_pads::no_landing_pads;
+use dataflow::{self, MaybeStorageLive, state_for_location};
pub struct StateTransform;
Local::new(1)
}
+struct SuspensionPoint {
+ state: u32,
+ resume: BasicBlock,
+ drop: Option<BasicBlock>,
+ storage_liveness: liveness::LocalSet,
+}
+
struct TransformVisitor<'a, 'tcx: 'a> {
tcx: TyCtxt<'a, 'tcx, 'tcx>,
state_adt_ref: &'tcx AdtDef,
// Mapping from Local to (type of local, generator struct index)
remap: HashMap<Local, (Ty<'tcx>, usize)>,
- // The number of generator states. 0 is unresumed, 1 is poisoned. So this is initialized to 2
- bb_target_count: u32,
+ // A map from a suspension point in a block to the locals which have live storage at that point
+ storage_liveness: HashMap<BasicBlock, liveness::LocalSet>,
- // Map from a (which block to resume execution at, which block to use to drop the generator)
- // to a generator state
- bb_targets: HashMap<(BasicBlock, Option<BasicBlock>), u32>,
+ // A list of suspension points, generated during the transform
+ suspension_points: Vec<SuspensionPoint>,
// The original RETURN_POINTER local
new_ret_local: Local,
-
- // The block to resume execution when for Return
- return_block: BasicBlock,
}
impl<'a, 'tcx> TransformVisitor<'a, 'tcx> {
let ret_val = match data.terminator().kind {
TerminatorKind::Return => Some((1,
- self.return_block,
+ None,
Operand::Consume(Lvalue::Local(self.new_ret_local)),
None)),
TerminatorKind::Yield { ref value, resume, drop } => Some((0,
- resume,
+ Some(resume),
value.clone(),
drop)),
_ => None
};
if let Some((state_idx, resume, v, drop)) = ret_val {
- let bb_idx = {
- let bb_targets = &mut self.bb_targets;
- let bb_target = &mut self.bb_target_count;
- *bb_targets.entry((resume, drop)).or_insert_with(|| {
- let target = *bb_target;
- *bb_target = target.checked_add(1).unwrap();
- target
- })
- };
let source_info = data.terminator().source_info;
- data.statements.push(self.set_state(bb_idx, source_info));
+ // We must assign the value first in case it gets declared dead below
data.statements.push(Statement {
source_info,
kind: StatementKind::Assign(Lvalue::Local(RETURN_POINTER),
self.make_state(state_idx, v)),
});
+ let state = if let Some(resume) = resume { // Yield
+ let state = 3 + self.suspension_points.len() as u32;
+
+ self.suspension_points.push(SuspensionPoint {
+ state,
+ resume,
+ drop,
+ storage_liveness: self.storage_liveness.get(&block).unwrap().clone(),
+ });
+
+ state
+ } else { // Return
+ 1 // state for returned
+ };
+ data.statements.push(self.set_state(state, source_info));
data.terminator.as_mut().unwrap().kind = TerminatorKind::Return;
}
fn replace_result_variable<'tcx>(ret_ty: Ty<'tcx>,
mir: &mut Mir<'tcx>) -> Local {
- let source_info = SourceInfo {
- span: mir.span,
- scope: ARGUMENT_VISIBILITY_SCOPE,
- };
-
let new_ret = LocalDecl {
mutability: Mutability::Mut,
ty: ret_ty,
name: None,
- source_info,
+ source_info: source_info(mir),
internal: false,
is_user_variable: false,
};
new_ret_local
}
+struct StorageIgnored(liveness::LocalSet);
+
+impl<'tcx> Visitor<'tcx> for StorageIgnored {
+ fn visit_statement(&mut self,
+ _block: BasicBlock,
+ statement: &Statement<'tcx>,
+ _location: Location) {
+ match statement.kind {
+ StatementKind::StorageLive(l) |
+ StatementKind::StorageDead(l) => { self.0.remove(&l); }
+ _ => (),
+ }
+ }
+}
+
fn locals_live_across_suspend_points<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
mir: &Mir<'tcx>,
- source: MirSource) -> liveness::LocalSet {
+ source: MirSource) ->
+ (liveness::LocalSet,
+ HashMap<BasicBlock, liveness::LocalSet>) {
+ let dead_unwinds = IdxSetBuf::new_empty(mir.basic_blocks().len());
+ let node_id = source.item_id();
+ let analysis = MaybeStorageLive::new(mir);
+ let storage_live =
+ dataflow::do_dataflow(tcx, mir, node_id, &[], &dead_unwinds, analysis,
+ |bd, p| &bd.mir().local_decls[p]);
+
+ let mut ignored = StorageIgnored(IdxSetBuf::new_filled(mir.local_decls.len()));
+ ignored.visit_mir(mir);
+
let mut set = liveness::LocalSet::new_empty(mir.local_decls.len());
- let result = liveness::liveness_of_locals(mir);
- liveness::dump_mir(tcx, "generator_liveness", source, mir, &result);
+ let liveness = liveness::liveness_of_locals(mir);
+ liveness::dump_mir(tcx, "generator_liveness", source, mir, &liveness);
+
+ let mut storage_liveness_map = HashMap::new();
for (block, data) in mir.basic_blocks().iter_enumerated() {
if let TerminatorKind::Yield { .. } = data.terminator().kind {
- set.union(&result.outs[block]);
+ let loc = Location {
+ block: block,
+ statement_index: data.statements.len(),
+ };
+
+ let storage_liveness = state_for_location(loc, &analysis, &storage_live);
+
+ storage_liveness_map.insert(block, storage_liveness.clone());
+
+ let mut live_locals = storage_liveness;
+
+ // Mark locals without storage statements as always having live storage
+ live_locals.union(&ignored.0);
+
+ // Locals live are live at this point only if they are used across suspension points
+ // and their storage is live
+ live_locals.intersect(&liveness.outs[block]);
+
+ // Add the locals life at this suspension point to the set of locals which live across
+ // any suspension points
+ set.union(&live_locals);
}
}
// The generator argument is ignored
set.remove(&self_arg());
- set
+ (set, storage_liveness_map)
}
fn compute_layout<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
source: MirSource,
interior: GeneratorInterior<'tcx>,
mir: &mut Mir<'tcx>)
- -> (HashMap<Local, (Ty<'tcx>, usize)>, GeneratorLayout<'tcx>)
+ -> (HashMap<Local, (Ty<'tcx>, usize)>,
+ GeneratorLayout<'tcx>,
+ HashMap<BasicBlock, liveness::LocalSet>)
{
// Use a liveness analysis to compute locals which are live across a suspension point
- let live_locals = locals_live_across_suspend_points(tcx, mir, source);
+ let (live_locals, storage_liveness) = locals_live_across_suspend_points(tcx, mir, source);
// Erase regions from the types passed in from typeck so we can compare them with
// MIR types
fields: vars
};
- (remap, layout)
+ (remap, layout, storage_liveness)
}
-fn insert_entry_point<'tcx>(mir: &mut Mir<'tcx>,
- block: BasicBlockData<'tcx>) {
- mir.basic_blocks_mut().raw.insert(0, block);
+fn insert_switch<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
+ mir: &mut Mir<'tcx>,
+ cases: Vec<(u32, BasicBlock)>,
+ transform: &TransformVisitor<'a, 'tcx>) {
+ let return_block = insert_return_block(mir);
+
+ let switch = TerminatorKind::SwitchInt {
+ discr: Operand::Consume(transform.make_field(transform.state_field, tcx.types.u32)),
+ switch_ty: tcx.types.u32,
+ values: Cow::from(cases.iter().map(|&(i, _)| ConstInt::U32(i)).collect::<Vec<_>>()),
+ targets: cases.iter().map(|&(_, d)| d).chain(once(return_block)).collect(),
+ };
+
+ let source_info = source_info(mir);
+ mir.basic_blocks_mut().raw.insert(0, BasicBlockData {
+ statements: Vec::new(),
+ terminator: Some(Terminator {
+ source_info,
+ kind: switch,
+ }),
+ is_cleanup: false,
+ });
let blocks = mir.basic_blocks_mut().iter_mut();
drop_clean: BasicBlock) -> Mir<'tcx> {
let mut mir = mir.clone();
- let source_info = SourceInfo {
- span: mir.span,
- scope: ARGUMENT_VISIBILITY_SCOPE,
- };
+ let source_info = source_info(&mir);
- let return_block = BasicBlock::new(mir.basic_blocks().len());
- mir.basic_blocks_mut().push(BasicBlockData {
- statements: Vec::new(),
- terminator: Some(Terminator {
- source_info,
- kind: TerminatorKind::Return,
- }),
- is_cleanup: false,
- });
-
- let mut cases: Vec<_> = transform.bb_targets.iter().filter_map(|(&(_, u), &s)| {
- u.map(|d| (s, d))
- }).collect();
+ let mut cases = create_cases(&mut mir, transform, |point| point.drop);
cases.insert(0, (0, drop_clean));
- // The poisoned state 1 falls through to the default case which is just to return
+ // The returned state (1) and the poisoned state (2) falls through to
+ // the default case which is just to return
- let switch = TerminatorKind::SwitchInt {
- discr: Operand::Consume(transform.make_field(transform.state_field, tcx.types.u32)),
- switch_ty: tcx.types.u32,
- values: Cow::from(cases.iter().map(|&(i, _)| {
- ConstInt::U32(i)
- }).collect::<Vec<_>>()),
- targets: cases.iter().map(|&(_, d)| d).chain(once(return_block)).collect(),
- };
-
- insert_entry_point(&mut mir, BasicBlockData {
- statements: Vec::new(),
- terminator: Some(Terminator {
- source_info,
- kind: switch,
- }),
- is_cleanup: false,
- });
+ insert_switch(tcx, &mut mir, cases, &transform);
for block in mir.basic_blocks_mut() {
let kind = &mut block.terminator_mut().kind;
}
// Replace the return variable
- let source_info = SourceInfo {
- span: mir.span,
- scope: ARGUMENT_VISIBILITY_SCOPE,
- };
-
mir.return_ty = tcx.mk_nil();
mir.local_decls[RETURN_POINTER] = LocalDecl {
mutability: Mutability::Mut,
mir
}
-fn insert_panic_on_resume_after_return<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
- mir: &mut Mir<'tcx>) {
+fn insert_return_block<'tcx>(mir: &mut Mir<'tcx>) -> BasicBlock {
+ let return_block = BasicBlock::new(mir.basic_blocks().len());
+ let source_info = source_info(mir);
+ mir.basic_blocks_mut().push(BasicBlockData {
+ statements: Vec::new(),
+ terminator: Some(Terminator {
+ source_info,
+ kind: TerminatorKind::Return,
+ }),
+ is_cleanup: false,
+ });
+ return_block
+}
+
+fn insert_panic_block<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
+ mir: &mut Mir<'tcx>,
+ message: AssertMessage<'tcx>) -> BasicBlock {
let assert_block = BasicBlock::new(mir.basic_blocks().len());
let term = TerminatorKind::Assert {
cond: Operand::Constant(box Constant {
},
}),
expected: true,
- msg: AssertMessage::GeneratorResumedAfterReturn,
+ msg: message,
target: assert_block,
cleanup: None,
};
- let source_info = SourceInfo {
- span: mir.span,
- scope: ARGUMENT_VISIBILITY_SCOPE,
- };
-
+ let source_info = source_info(mir);
mir.basic_blocks_mut().push(BasicBlockData {
statements: Vec::new(),
terminator: Some(Terminator {
}),
is_cleanup: false,
});
+
+ assert_block
}
fn create_generator_resume_function<'a, 'tcx>(
tcx: TyCtxt<'a, 'tcx, 'tcx>,
- mut transform: TransformVisitor<'a, 'tcx>,
+ transform: TransformVisitor<'a, 'tcx>,
def_id: DefId,
source: MirSource,
mir: &mut Mir<'tcx>) {
}
}
- let source_info = SourceInfo {
- span: mir.span,
- scope: ARGUMENT_VISIBILITY_SCOPE,
- };
-
- let poisoned_block = BasicBlock::new(mir.basic_blocks().len());
-
- let term = TerminatorKind::Assert {
- cond: Operand::Constant(box Constant {
- span: mir.span,
- ty: tcx.types.bool,
- literal: Literal::Value {
- value: tcx.mk_const(ty::Const {
- val: ConstVal::Bool(false),
- ty: tcx.types.bool
- }),
- },
- }),
- expected: true,
- msg: AssertMessage::GeneratorResumedAfterPanic,
- target: transform.return_block,
- cleanup: None,
- };
-
- mir.basic_blocks_mut().push(BasicBlockData {
- statements: Vec::new(),
- terminator: Some(Terminator {
- source_info,
- kind: term,
- }),
- is_cleanup: false,
- });
-
- transform.bb_targets.insert((poisoned_block, None), 1);
+ let mut cases = create_cases(mir, &transform, |point| Some(point.resume));
- let switch = TerminatorKind::SwitchInt {
- discr: Operand::Consume(transform.make_field(transform.state_field, tcx.types.u32)),
- switch_ty: tcx.types.u32,
- values: Cow::from(transform.bb_targets.values().map(|&i| {
- ConstInt::U32(i)
- }).collect::<Vec<_>>()),
- targets: transform.bb_targets.keys()
- .map(|&(k, _)| k)
- .chain(once(transform.return_block))
- .collect(),
- };
+ // Jump to the entry point on the 0 state
+ cases.insert(0, (0, BasicBlock::new(0)));
+ // Panic when resumed on the returned (1) state
+ cases.insert(1, (1, insert_panic_block(tcx, mir, AssertMessage::GeneratorResumedAfterReturn)));
+ // Panic when resumed on the poisoned (2) state
+ cases.insert(2, (2, insert_panic_block(tcx, mir, AssertMessage::GeneratorResumedAfterPanic)));
- insert_entry_point(mir, BasicBlockData {
- statements: Vec::new(),
- terminator: Some(Terminator {
- source_info,
- kind: switch,
- }),
- is_cleanup: false,
- });
+ insert_switch(tcx, mir, cases, &transform);
make_generator_state_argument_indirect(tcx, def_id, mir);
dump_mir(tcx, None, "generator_resume", &0, source, mir);
}
-fn insert_clean_drop<'a, 'tcx>(mir: &mut Mir<'tcx>) -> BasicBlock {
- let source_info = SourceInfo {
+fn source_info<'a, 'tcx>(mir: &Mir<'tcx>) -> SourceInfo {
+ SourceInfo {
span: mir.span,
scope: ARGUMENT_VISIBILITY_SCOPE,
- };
+ }
+}
- let return_block = BasicBlock::new(mir.basic_blocks().len());
- mir.basic_blocks_mut().push(BasicBlockData {
- statements: Vec::new(),
- terminator: Some(Terminator {
- source_info,
- kind: TerminatorKind::Return,
- }),
- is_cleanup: false,
- });
+fn insert_clean_drop<'a, 'tcx>(mir: &mut Mir<'tcx>) -> BasicBlock {
+ let return_block = insert_return_block(mir);
// Create a block to destroy an unresumed generators. This can only destroy upvars.
let drop_clean = BasicBlock::new(mir.basic_blocks().len());
target: return_block,
unwind: None,
};
+ let source_info = source_info(mir);
mir.basic_blocks_mut().push(BasicBlockData {
statements: Vec::new(),
terminator: Some(Terminator {
drop_clean
}
+fn create_cases<'a, 'tcx, F>(mir: &mut Mir<'tcx>,
+ transform: &TransformVisitor<'a, 'tcx>,
+ target: F) -> Vec<(u32, BasicBlock)>
+ where F: Fn(&SuspensionPoint) -> Option<BasicBlock> {
+ let source_info = source_info(mir);
+
+ transform.suspension_points.iter().filter_map(|point| {
+ // Find the target for this suspension point, if applicable
+ target(point).map(|target| {
+ let block = BasicBlock::new(mir.basic_blocks().len());
+ let mut statements = Vec::new();
+
+ // Create StorageLive instructions for locals with live storage
+ for i in 0..(mir.local_decls.len()) {
+ let l = Local::new(i);
+ if point.storage_liveness.contains(&l) && !transform.remap.contains_key(&l) {
+ statements.push(Statement {
+ source_info,
+ kind: StatementKind::StorageLive(l),
+ });
+ }
+ }
+
+ // Then jump to the real target
+ mir.basic_blocks_mut().push(BasicBlockData {
+ statements,
+ terminator: Some(Terminator {
+ source_info,
+ kind: TerminatorKind::Goto {
+ target,
+ },
+ }),
+ is_cleanup: false,
+ });
+
+ (point.state, block)
+ })
+ }).collect()
+}
+
impl MirPass for StateTransform {
fn run_pass<'a, 'tcx>(&self,
tcx: TyCtxt<'a, 'tcx, 'tcx>,
// Extract locals which are live across suspension point into `layout`
// `remap` gives a mapping from local indices onto generator struct indices
- let (remap, layout) = compute_layout(tcx, source, interior, mir);
+ // `storage_liveness` tells us which locals have live storage at suspension points
+ let (remap, layout, storage_liveness) = compute_layout(tcx, source, interior, mir);
let state_field = mir.upvar_decls.len();
- let mut bb_targets = HashMap::new();
-
- // If we jump to the entry point, we should go to the initial 0 generator state.
- // FIXME: Could this result in the need for destruction for state 0?
- bb_targets.insert((BasicBlock::new(0), None), 0);
-
// Run the transformation which converts Lvalues from Local to generator struct
// accesses for locals in `remap`.
// It also rewrites `return x` and `yield y` as writing a new generator state and returning
state_adt_ref,
state_substs,
remap,
- bb_target_count: 2,
- bb_targets,
+ storage_liveness,
+ suspension_points: Vec::new(),
new_ret_local,
state_field,
-
- // For returns we will resume execution at the next added basic block.
- // This happens in `insert_panic_on_resume_after_return`
- return_block: BasicBlock::new(mir.basic_blocks().len()),
};
transform.visit_mir(mir);
mir.spread_arg = None;
mir.generator_layout = Some(layout);
- // Panic if we resumed after returning
- insert_panic_on_resume_after_return(tcx, mir);
-
// Insert `drop(generator_struct)` which is used to drop upvars for generators in
// the unresumed (0) state.
// This is expanded to a drop ladder in `elaborate_generator_drops`.
use back::linker::LinkerInfo;
use back::symbol_export::ExportedSymbols;
use rustc_incremental::{save_trans_partition, in_incr_comp_dir};
+use rustc::dep_graph::DepGraph;
use rustc::middle::cstore::{LinkMeta, EncodedMetadata};
use rustc::session::config::{self, OutputFilenames, OutputType, OutputTypes, Passes, SomePasses,
AllPasses, Sanitizer};
}
fn copy_module_artifacts_into_incr_comp_cache(sess: &Session,
+ dep_graph: &DepGraph,
compiled_modules: &CompiledModules,
crate_output: &OutputFilenames) {
if sess.opts.incremental.is_none() {
files.push((OutputType::Bitcode, path));
}
- save_trans_partition(sess, &module.name, module.symbol_name_hash, &files);
+ save_trans_partition(sess,
+ dep_graph,
+ &module.name,
+ module.symbol_name_hash,
+ &files);
}
}
}
impl OngoingCrateTranslation {
- pub fn join(self, sess: &Session) -> CrateTranslation {
+ pub fn join(self, sess: &Session, dep_graph: &DepGraph) -> CrateTranslation {
self.shared_emitter_main.check(sess, true);
let compiled_modules = match self.future.join() {
Ok(compiled_modules) => compiled_modules,
}
copy_module_artifacts_into_incr_comp_cache(sess,
+ dep_graph,
&compiled_modules,
&self.output_filenames);
produce_final_output_artifacts(sess,
let all = vec![
(lang_items.phantom_data(), vec![ty::Covariant]),
(lang_items.unsafe_cell_type(), vec![ty::Invariant]),
-
- // Deprecated:
- (lang_items.covariant_type(), vec![ty::Covariant]),
- (lang_items.contravariant_type(), vec![ty::Contravariant]),
- (lang_items.invariant_type(), vec![ty::Invariant]),
- (lang_items.covariant_lifetime(), vec![ty::Covariant]),
- (lang_items.contravariant_lifetime(), vec![ty::Contravariant]),
- (lang_items.invariant_lifetime(), vec![ty::Invariant]),
-
];
all.into_iter() // iterating over (Option<DefId>, Variance)
use rustc_lint;
use rustc_driver::{driver, target_features, abort_on_err};
use rustc_driver::pretty::ReplaceBodyWithLoop;
-use rustc::dep_graph::DepGraph;
use rustc::session::{self, config};
use rustc::hir::def_id::DefId;
use rustc::hir::def::Def;
false,
Some(codemap.clone()));
- let dep_graph = DepGraph::new(false);
- let _ignore = dep_graph.in_ignore();
let cstore = Rc::new(CStore::new(box rustc_trans::LlvmMetadataLoader));
let mut sess = session::build_session_(
- sessopts, &dep_graph, cpath, diagnostic_handler, codemap
+ sessopts, cpath, diagnostic_handler, codemap,
);
rustc_trans::init(&sess);
rustc_lint::register_builtins(&mut sess.lint_store.borrow_mut(), Some(&sess));
use serialize::json::{ToJson, Json, as_json};
use syntax::{abi, ast};
-use syntax::feature_gate::UnstableFeatures;
use rustc::hir::def_id::{CrateNum, CRATE_DEF_INDEX, DefId};
use rustc::middle::privacy::AccessLevels;
use rustc::middle::stability;
use rustc::hir;
use rustc::util::nodemap::{FxHashMap, FxHashSet};
-use rustc::session::config::nightly_options::is_nightly_build;
use rustc_data_structures::flock;
use clean::{self, AttributesExt, GetDefId, SelfTy, Mutability, Span};
prefix: &str,
scx: &SharedContext)
-> fmt::Result {
- let hoedown_output = format!("{}", Markdown(md_text, RenderType::Hoedown));
// We only emit warnings if the user has opted-in to Pulldown rendering.
let output = if render_type == RenderType::Pulldown {
+ // Save the state of USED_ID_MAP so it only gets updated once even
+ // though we're rendering twice.
+ let orig_used_id_map = USED_ID_MAP.with(|map| map.borrow().clone());
+ let hoedown_output = format!("{}", Markdown(md_text, RenderType::Hoedown));
+ USED_ID_MAP.with(|map| *map.borrow_mut() = orig_used_id_map);
let pulldown_output = format!("{}", Markdown(md_text, RenderType::Pulldown));
let mut differences = html_diff::get_differences(&pulldown_output, &hoedown_output);
differences.retain(|s| {
pulldown_output
} else {
- hoedown_output
+ format!("{}", Markdown(md_text, RenderType::Hoedown))
};
write!(w, "<div class='docblock'>{}{}</div>", prefix, output)
fn item_function(w: &mut fmt::Formatter, cx: &Context, it: &clean::Item,
f: &clean::Function) -> fmt::Result {
- // FIXME(#24111): remove when `const_fn` is stabilized
- let vis_constness = match UnstableFeatures::from_environment() {
- UnstableFeatures::Allow => f.constness,
- _ => hir::Constness::NotConst
- };
let name_len = format!("{}{}{}{:#}fn {}{:#}",
VisSpace(&it.visibility),
- ConstnessSpace(vis_constness),
+ ConstnessSpace(f.constness),
UnsafetySpace(f.unsafety),
AbiSpace(f.abi),
it.name.as_ref().unwrap(),
write!(w, "{vis}{constness}{unsafety}{abi}fn \
{name}{generics}{decl}{where_clause}</pre>",
vis = VisSpace(&it.visibility),
- constness = ConstnessSpace(vis_constness),
+ constness = ConstnessSpace(f.constness),
unsafety = UnsafetySpace(f.unsafety),
abi = AbiSpace(f.abi),
name = it.name.as_ref().unwrap(),
href(did).map(|p| format!("{}#{}.{}", p.0, ty, name)).unwrap_or(anchor)
}
};
- // FIXME(#24111): remove when `const_fn` is stabilized
- let vis_constness = if is_nightly_build() {
- constness
- } else {
- hir::Constness::NotConst
- };
let mut head_len = format!("{}{}{:#}fn {}{:#}",
- ConstnessSpace(vis_constness),
+ ConstnessSpace(constness),
UnsafetySpace(unsafety),
AbiSpace(abi),
name,
};
write!(w, "{}{}{}fn <a href='{href}' class='fnname'>{name}</a>\
{generics}{decl}{where_clause}",
- ConstnessSpace(vis_constness),
+ ConstnessSpace(constness),
UnsafetySpace(unsafety),
AbiSpace(abi),
href = href,
use testing;
use rustc_lint;
-use rustc::dep_graph::DepGraph;
use rustc::hir;
use rustc::hir::intravisit;
use rustc::session::{self, CompileIncomplete, config};
let handler =
errors::Handler::with_tty_emitter(ColorConfig::Auto, true, false, Some(codemap.clone()));
- let dep_graph = DepGraph::new(false);
- let _ignore = dep_graph.in_ignore();
let cstore = Rc::new(CStore::new(box rustc_trans::LlvmMetadataLoader));
let mut sess = session::build_session_(
- sessopts, &dep_graph, Some(input_path.clone()), handler, codemap.clone()
+ sessopts, Some(input_path.clone()), handler, codemap.clone(),
);
rustc_trans::init(&sess);
rustc_lint::register_builtins(&mut sess.lint_store.borrow_mut(), Some(&sess));
let krate = ReplaceBodyWithLoop::new().fold_crate(krate);
let driver::ExpansionResult { defs, mut hir_forest, .. } = {
phase_2_configure_and_expand(
- &sess, &cstore, krate, None, "rustdoc-test", None, MakeGlobMap::No, |_| Ok(())
+ &sess,
+ &cstore,
+ krate,
+ None,
+ "rustdoc-test",
+ None,
+ MakeGlobMap::No,
+ |_| Ok(()),
).expect("phase_2_configure_and_expand aborted in rustdoc!")
};
render_type);
{
- let dep_graph = DepGraph::new(false);
- let _ignore = dep_graph.in_ignore();
let map = hir::map::map_crate(&mut hir_forest, defs);
let krate = map.krate();
let mut hir_collector = HirCollector {
// Compile the code
let diagnostic_handler = errors::Handler::with_emitter(true, false, box emitter);
- let dep_graph = DepGraph::new(false);
let cstore = Rc::new(CStore::new(box rustc_trans::LlvmMetadataLoader));
let mut sess = session::build_session_(
- sessopts, &dep_graph, None, diagnostic_handler, codemap
+ sessopts, None, diagnostic_handler, codemap,
);
rustc_trans::init(&sess);
rustc_lint::register_builtins(&mut sess.lint_store.borrow_mut(), Some(&sess));
///
/// One maybe obvious note when using append-mode: make sure that all data
/// that belongs together is written to the file in one operation. This
- /// can be done by concatenating strings before passing them to `write()`,
+ /// can be done by concatenating strings before passing them to [`write()`],
/// or using a buffered writer (with a buffer of adequate size),
- /// and calling `flush()` when the message is complete.
+ /// and calling [`flush()`] when the message is complete.
///
/// If a file is opened with both read and append access, beware that after
/// opening, and after every write, the position for reading may be set at the
/// end of the file. So, before writing, save the current position (using
- /// `seek(SeekFrom::Current(0))`, and restore it before the next read.
+ /// [`seek`]`(`[`SeekFrom`]`::`[`Current`]`(0))`, and restore it before the next read.
+ ///
+ /// ## Note
+ ///
+ /// This function doesn't create the file if it doesn't exist. Use the [`create`]
+ /// method to do so.
+ ///
+ /// [`write()`]: ../../std/fs/struct.File.html#method.write
+ /// [`flush()`]: ../../std/fs/struct.File.html#method.flush
+ /// [`seek`]: ../../std/fs/struct.File.html#method.seek
+ /// [`SeekFrom`]: ../../std/io/enum.SeekFrom.html
+ /// [`Current`]: ../../std/io/enum.SeekFrom.html#variant.Current
+ /// [`create`]: #method.create
///
/// # Examples
///
/// This option indicates whether a new file will be created if the file
/// does not yet already exist.
///
- /// In order for the file to be created, `write` or `append` access must
+ /// In order for the file to be created, [`write`] or [`append`] access must
/// be used.
///
+ /// [`write`]: #method.write
+ /// [`append`]: #method.append
+ ///
/// # Examples
///
/// ```no_run
/// whether a file exists and creating a new one, the file may have been
/// created by another process (a TOCTOU race condition / attack).
///
- /// If `.create_new(true)` is set, `.create()` and `.truncate()` are
+ /// If `.create_new(true)` is set, [`.create()`] and [`.truncate()`] are
/// ignored.
///
/// The file must be opened with write or append access in order to create
/// a new file.
///
+ /// [`.create()`]: #method.create
+ /// [`.truncate()`]: #method.truncate
+ ///
/// # Examples
///
/// ```no_run
/// {
/// let mut socket = UdpSocket::bind("127.0.0.1:34254")?;
///
-/// // read from the socket
+/// // Receives a single datagram message on the socket. If `buf` is too small to hold
+/// // the message, it will be cut off.
/// let mut buf = [0; 10];
/// let (amt, src) = socket.recv_from(&mut buf)?;
///
-/// // send a reply to the socket we received data from
+/// // Redeclare `buf` as slice of the received data and send reverse data back to origin.
/// let buf = &mut buf[..amt];
/// buf.reverse();
/// socket.send_to(buf, &src)?;
super::each_addr(addr, net_imp::UdpSocket::bind).map(UdpSocket)
}
- /// Receives data from the socket. On success, returns the number of bytes
- /// read and the address from whence the data came.
+ /// Receives a single datagram message on the socket. On success, returns the number
+ /// of bytes read and the origin.
+ ///
+ /// The function must be called with valid byte array `buf` of sufficient size to
+ /// hold the message bytes. If a message is too long to fit in the supplied buffer,
+ /// excess bytes may be discarded.
///
/// # Examples
///
/// let mut buf = [0; 10];
/// let (number_of_bytes, src_addr) = socket.recv_from(&mut buf)
/// .expect("Didn't receive data");
+ /// let filled_buf = &mut buf[..number_of_bytes];
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
pub fn recv_from(&self, buf: &mut [u8]) -> io::Result<(usize, SocketAddr)> {
self.0.recv_from(buf)
}
- /// Receives data from the socket, without removing it from the queue.
+ /// Receives a single datagram message on the socket, without removing it from the
+ /// queue. On success, returns the number of bytes read and the origin.
+ ///
+ /// The function must be called with valid byte array `buf` of sufficient size to
+ /// hold the message bytes. If a message is too long to fit in the supplied buffer,
+ /// excess bytes may be discarded.
///
/// Successive calls return the same data. This is accomplished by passing
/// `MSG_PEEK` as a flag to the underlying `recvfrom` system call.
///
- /// On success, returns the number of bytes peeked and the address from
- /// whence the data came.
+ /// Do not use this function to implement busy waiting, instead use `libc::poll` to
+ /// synchronize IO events on one or more sockets.
///
/// # Examples
///
/// let mut buf = [0; 10];
/// let (number_of_bytes, src_addr) = socket.peek_from(&mut buf)
/// .expect("Didn't receive data");
+ /// let filled_buf = &mut buf[..number_of_bytes];
/// ```
#[stable(feature = "peek", since = "1.18.0")]
pub fn peek_from(&self, buf: &mut [u8]) -> io::Result<(usize, SocketAddr)> {
/// receive data from the specified address.
///
/// If `addr` yields multiple addresses, `connect` will be attempted with
- /// each of the addresses until a connection is successful. If none of
- /// the addresses are able to be connected, the error returned from the
+ /// each of the addresses until the underlying OS function returns no
+ /// error. Note that usually, a successful `connect` call does not specify
+ /// that there is a remote server listening on the port, rather, such an
+ /// error would only be detected after the first send. If the OS returns an
+ /// error for each of the specified addresses, the error returned from the
/// last connection attempt (the last address) is returned.
///
/// # Examples
/// socket.connect("127.0.0.1:8080").expect("connect function failed");
/// ```
///
- /// Create a UDP socket bound to `127.0.0.1:3400` and connect the socket to
- /// `127.0.0.1:8080`. If that connection fails, then the UDP socket will
- /// connect to `127.0.0.1:8081`:
- ///
- /// ```no_run
- /// use std::net::{SocketAddr, UdpSocket};
- ///
- /// let socket = UdpSocket::bind("127.0.0.1:3400").expect("couldn't bind to address");
- /// let connect_addrs = [
- /// SocketAddr::from(([127, 0, 0, 1], 8080)),
- /// SocketAddr::from(([127, 0, 0, 1], 8081)),
- /// ];
- /// socket.connect(&connect_addrs[..]).expect("connect function failed");
- /// ```
+ /// Unlike in the TCP case, passing an array of addresses to the `connect`
+ /// function of a UDP socket is not a useful thing to do: The OS will be
+ /// unable to determine whether something is listening on the remote
+ /// address without the application sending data.
#[stable(feature = "net2_mutators", since = "1.9.0")]
pub fn connect<A: ToSocketAddrs>(&self, addr: A) -> io::Result<()> {
super::each_addr(addr, |addr| self.0.connect(addr))
self.0.send(buf)
}
- /// Receives data on the socket from the remote address to which it is
- /// connected.
+ /// Receives a single datagram message on the socket from the remote address to
+ /// which it is connected. On success, returns the number of bytes read.
+ ///
+ /// The function must be called with valid byte array `buf` of sufficient size to
+ /// hold the message bytes. If a message is too long to fit in the supplied buffer,
+ /// excess bytes may be discarded.
///
/// The [`connect`] method will connect this socket to a remote address. This
/// method will fail if the socket is not connected.
/// socket.connect("127.0.0.1:8080").expect("connect function failed");
/// let mut buf = [0; 10];
/// match socket.recv(&mut buf) {
- /// Ok(received) => println!("received {} bytes", received),
+ /// Ok(received) => println!("received {} bytes {:?}", received, &buf[..received]),
/// Err(e) => println!("recv function failed: {:?}", e),
/// }
/// ```
self.0.recv(buf)
}
- /// Receives data on the socket from the remote address to which it is
- /// connected, without removing that data from the queue. On success,
- /// returns the number of bytes peeked.
+ /// Receives single datagram on the socket from the remote address to which it is
+ /// connected, without removing the message from input queue. On success, returns
+ /// the number of bytes peeked.
+ ///
+ /// The function must be called with valid byte array `buf` of sufficient size to
+ /// hold the message bytes. If a message is too long to fit in the supplied buffer,
+ /// excess bytes may be discarded.
///
/// Successive calls return the same data. This is accomplished by passing
/// `MSG_PEEK` as a flag to the underlying `recv` system call.
///
+ /// Do not use this function to implement busy waiting, instead use `libc::poll` to
+ /// synchronize IO events on one or more sockets.
+ ///
+ /// The [`connect`] method will connect this socket to a remote address. This
+ /// method will fail if the socket is not connected.
+ ///
+ /// [`connect`]: #method.connect
+ ///
/// # Errors
///
/// This method will fail if the socket is not connected. The `connect` method
#[stable(feature = "rust1", since = "1.0.0")]
pub use sys::windows_ext as windows;
-#[cfg(any(dox, target_os = "linux"))]
+#[cfg(any(dox, target_os = "linux", target_os = "l4re"))]
#[doc(cfg(target_os = "linux"))]
pub mod linux;
target_arch = "s390x")),
all(target_os = "android", any(target_arch = "aarch64",
target_arch = "arm")),
+ all(target_os = "l4re", target_arch = "x86_64"),
all(target_os = "fuchsia", target_arch = "aarch64")))]
#[stable(feature = "raw_os", since = "1.1.0")] pub type c_char = u8;
#[cfg(not(any(all(target_os = "linux", any(target_arch = "aarch64",
target_arch = "s390x")),
all(target_os = "android", any(target_arch = "aarch64",
target_arch = "arm")),
+ all(target_os = "l4re", target_arch = "x86_64"),
all(target_os = "fuchsia", target_arch = "aarch64"))))]
#[stable(feature = "raw_os", since = "1.1.0")] pub type c_char = i8;
#[stable(feature = "raw_os", since = "1.1.0")] pub type c_schar = i8;
use sys::{cvt, syscall};
use time::Duration;
+pub const DEFAULT_MIN_STACK_SIZE: usize = 2 * 1024 * 1024;
+
pub struct Thread {
id: usize,
}
target_os = "solaris",
target_os = "emscripten",
target_os = "haiku",
+ target_os = "l4re",
target_os = "fuchsia"))]
mod imp {
use os::unix::prelude::*;
Condvar { inner: UnsafeCell::new(libc::PTHREAD_COND_INITIALIZER) }
}
- #[cfg(any(target_os = "macos", target_os = "ios", target_os = "android"))]
+ #[cfg(any(target_os = "macos",
+ target_os = "ios",
+ target_os = "l4re",
+ target_os = "android"))]
pub unsafe fn init(&mut self) {}
- #[cfg(not(any(target_os = "macos", target_os = "ios", target_os = "android")))]
+ #[cfg(not(any(target_os = "macos",
+ target_os = "ios",
+ target_os = "l4re",
+ target_os = "android")))]
pub unsafe fn init(&mut self) {
use mem;
let mut attr: libc::pthread_condattr_t = mem::uninitialized();
pub const EXE_SUFFIX: &'static str = "";
pub const EXE_EXTENSION: &'static str = "";
}
+
+#[cfg(target_os = "l4re")]
+pub mod os {
+ pub const FAMILY: &'static str = "unix";
+ pub const OS: &'static str = "l4re";
+ pub const DLL_PREFIX: &'static str = "lib";
+ pub const DLL_SUFFIX: &'static str = ".so";
+ pub const DLL_EXTENSION: &'static str = "so";
+ pub const EXE_SUFFIX: &'static str = "";
+ pub const EXE_EXTENSION: &'static str = "";
+}
target_os = "solaris",
target_os = "emscripten",
target_os = "fuchsia",
+ target_os = "l4re",
target_os = "haiku")))]
pub fn set_cloexec(&self) -> io::Result<()> {
unsafe {
target_os = "solaris",
target_os = "emscripten",
target_os = "fuchsia",
+ target_os = "l4re",
target_os = "haiku"))]
pub fn set_cloexec(&self) -> io::Result<()> {
unsafe {
use sys::{cvt, cvt_r};
use sys_common::{AsInner, FromInner};
-#[cfg(any(target_os = "linux", target_os = "emscripten"))]
+#[cfg(any(target_os = "linux", target_os = "emscripten", target_os = "l4re"))]
use libc::{stat64, fstat64, lstat64, off64_t, ftruncate64, lseek64, dirent64, readdir64_r, open64};
#[cfg(target_os = "android")]
use libc::{stat as stat64, fstat as fstat64, lstat as lstat64, lseek64,
dirent as dirent64, open as open64};
#[cfg(not(any(target_os = "linux",
target_os = "emscripten",
+ target_os = "l4re",
target_os = "android")))]
use libc::{stat as stat64, fstat as fstat64, lstat as lstat64, off_t as off64_t,
ftruncate as ftruncate64, lseek as lseek64, dirent as dirent64, open as open64};
#[cfg(not(any(target_os = "linux",
target_os = "emscripten",
target_os = "solaris",
+ target_os = "l4re",
target_os = "fuchsia")))]
use libc::{readdir_r as readdir64_r};
target_os = "android",
target_os = "solaris",
target_os = "haiku",
+ target_os = "l4re",
target_os = "fuchsia"))]
pub fn ino(&self) -> u64 {
self.entry.d_ino as u64
#[cfg(any(target_os = "android",
target_os = "linux",
target_os = "emscripten",
+ target_os = "l4re",
target_os = "haiku"))]
fn name_bytes(&self) -> &[u8] {
unsafe {
--- /dev/null
+// Copyright 2016-2017 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+macro_rules! unimpl {
+ () => (return Err(io::Error::new(io::ErrorKind::Other, "No networking available on L4Re."));)
+}
+
+pub mod net {
+ #![allow(warnings)]
+ use fmt;
+ use io;
+ use libc;
+ use net::{SocketAddr, Shutdown, Ipv4Addr, Ipv6Addr};
+ use sys_common::{AsInner, FromInner, IntoInner};
+ use sys::fd::FileDesc;
+ use time::Duration;
+
+
+ pub extern crate libc as netc;
+
+ pub struct Socket(FileDesc);
+ impl Socket {
+ pub fn new(_: &SocketAddr, _: libc::c_int) -> io::Result<Socket> {
+ unimpl!();
+ }
+
+ pub fn new_raw(_: libc::c_int, _: libc::c_int) -> io::Result<Socket> {
+ unimpl!();
+ }
+
+ pub fn new_pair(_: libc::c_int, _: libc::c_int) -> io::Result<(Socket, Socket)> {
+ unimpl!();
+ }
+
+ pub fn connect_timeout(&self, _: &SocketAddr, _: Duration) -> io::Result<()> {
+ unimpl!();
+ }
+
+ pub fn accept(&self, _: *mut libc::sockaddr, _: *mut libc::socklen_t)
+ -> io::Result<Socket> {
+ unimpl!();
+ }
+
+ pub fn duplicate(&self) -> io::Result<Socket> {
+ unimpl!();
+ }
+
+ pub fn read(&self, _: &mut [u8]) -> io::Result<usize> {
+ unimpl!();
+ }
+
+ pub fn peek(&self, _: &mut [u8]) -> io::Result<usize> {
+ unimpl!();
+ }
+
+ pub fn recv_from(&self, _: &mut [u8]) -> io::Result<(usize, SocketAddr)> {
+ unimpl!();
+ }
+
+ pub fn peek_from(&self, _: &mut [u8]) -> io::Result<(usize, SocketAddr)> {
+ unimpl!();
+ }
+
+ pub fn write(&self, _: &[u8]) -> io::Result<usize> {
+ unimpl!();
+ }
+
+ pub fn set_timeout(&self, _: Option<Duration>, _: libc::c_int) -> io::Result<()> {
+ unimpl!();
+ }
+
+ pub fn timeout(&self, _: libc::c_int) -> io::Result<Option<Duration>> {
+ unimpl!();
+ }
+
+ pub fn shutdown(&self, _: Shutdown) -> io::Result<()> {
+ unimpl!();
+ }
+
+ pub fn set_nodelay(&self, _: bool) -> io::Result<()> {
+ unimpl!();
+ }
+
+ pub fn nodelay(&self) -> io::Result<bool> {
+ unimpl!();
+ }
+
+ pub fn set_nonblocking(&self, _: bool) -> io::Result<()> {
+ unimpl!();
+ }
+
+ pub fn take_error(&self) -> io::Result<Option<io::Error>> {
+ unimpl!();
+ }
+ }
+
+ impl AsInner<libc::c_int> for Socket {
+ fn as_inner(&self) -> &libc::c_int { self.0.as_inner() }
+ }
+
+ impl FromInner<libc::c_int> for Socket {
+ fn from_inner(fd: libc::c_int) -> Socket { Socket(FileDesc::new(fd)) }
+ }
+
+ impl IntoInner<libc::c_int> for Socket {
+ fn into_inner(self) -> libc::c_int { self.0.into_raw() }
+ }
+
+ pub struct TcpStream {
+ inner: Socket,
+ }
+
+ impl TcpStream {
+ pub fn connect(_: &SocketAddr) -> io::Result<TcpStream> {
+ unimpl!();
+ }
+
+ pub fn connect_timeout(_: &SocketAddr, _: Duration) -> io::Result<TcpStream> {
+ unimpl!();
+ }
+
+ pub fn socket(&self) -> &Socket { &self.inner }
+
+ pub fn into_socket(self) -> Socket { self.inner }
+
+ pub fn set_read_timeout(&self, _: Option<Duration>) -> io::Result<()> {
+ unimpl!();
+ }
+
+ pub fn set_write_timeout(&self, _: Option<Duration>) -> io::Result<()> {
+ unimpl!();
+ }
+
+ pub fn read_timeout(&self) -> io::Result<Option<Duration>> {
+ unimpl!();
+ }
+
+ pub fn write_timeout(&self) -> io::Result<Option<Duration>> {
+ unimpl!();
+ }
+
+ pub fn peek(&self, _: &mut [u8]) -> io::Result<usize> {
+ unimpl!();
+ }
+
+ pub fn read(&self, _: &mut [u8]) -> io::Result<usize> {
+ unimpl!();
+ }
+
+ pub fn write(&self, _: &[u8]) -> io::Result<usize> {
+ unimpl!();
+ }
+
+ pub fn peer_addr(&self) -> io::Result<SocketAddr> {
+ unimpl!();
+ }
+
+ pub fn socket_addr(&self) -> io::Result<SocketAddr> {
+ unimpl!();
+ }
+
+ pub fn shutdown(&self, _: Shutdown) -> io::Result<()> {
+ unimpl!();
+ }
+
+ pub fn duplicate(&self) -> io::Result<TcpStream> {
+ unimpl!();
+ }
+
+ pub fn set_nodelay(&self, _: bool) -> io::Result<()> {
+ unimpl!();
+ }
+
+ pub fn nodelay(&self) -> io::Result<bool> {
+ unimpl!();
+ }
+
+ pub fn set_ttl(&self, _: u32) -> io::Result<()> {
+ unimpl!();
+ }
+
+ pub fn ttl(&self) -> io::Result<u32> {
+ unimpl!();
+ }
+
+ pub fn take_error(&self) -> io::Result<Option<io::Error>> {
+ unimpl!();
+ }
+
+ pub fn set_nonblocking(&self, _: bool) -> io::Result<()> {
+ unimpl!();
+ }
+ }
+
+ impl FromInner<Socket> for TcpStream {
+ fn from_inner(socket: Socket) -> TcpStream {
+ TcpStream { inner: socket }
+ }
+ }
+
+ impl fmt::Debug for TcpStream {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ write!(f, "No networking support available on L4Re")
+ }
+ }
+
+ pub struct TcpListener {
+ inner: Socket,
+ }
+
+ impl TcpListener {
+ pub fn bind(_: &SocketAddr) -> io::Result<TcpListener> {
+ unimpl!();
+ }
+
+ pub fn socket(&self) -> &Socket { &self.inner }
+
+ pub fn into_socket(self) -> Socket { self.inner }
+
+ pub fn socket_addr(&self) -> io::Result<SocketAddr> {
+ unimpl!();
+ }
+
+ pub fn accept(&self) -> io::Result<(TcpStream, SocketAddr)> {
+ unimpl!();
+ }
+
+ pub fn duplicate(&self) -> io::Result<TcpListener> {
+ unimpl!();
+ }
+
+ pub fn set_ttl(&self, _: u32) -> io::Result<()> {
+ unimpl!();
+ }
+
+ pub fn ttl(&self) -> io::Result<u32> {
+ unimpl!();
+ }
+
+ pub fn set_only_v6(&self, _: bool) -> io::Result<()> {
+ unimpl!();
+ }
+
+ pub fn only_v6(&self) -> io::Result<bool> {
+ unimpl!();
+ }
+
+ pub fn take_error(&self) -> io::Result<Option<io::Error>> {
+ unimpl!();
+ }
+
+ pub fn set_nonblocking(&self, _: bool) -> io::Result<()> {
+ unimpl!();
+ }
+ }
+
+ impl FromInner<Socket> for TcpListener {
+ fn from_inner(socket: Socket) -> TcpListener {
+ TcpListener { inner: socket }
+ }
+ }
+
+ impl fmt::Debug for TcpListener {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ write!(f, "No networking support available on L4Re.")
+ }
+ }
+
+ pub struct UdpSocket {
+ inner: Socket,
+ }
+
+ impl UdpSocket {
+ pub fn bind(_: &SocketAddr) -> io::Result<UdpSocket> {
+ unimpl!();
+ }
+
+ pub fn socket(&self) -> &Socket { &self.inner }
+
+ pub fn into_socket(self) -> Socket { self.inner }
+
+ pub fn socket_addr(&self) -> io::Result<SocketAddr> {
+ unimpl!();
+ }
+
+ pub fn recv_from(&self, _: &mut [u8]) -> io::Result<(usize, SocketAddr)> {
+ unimpl!();
+ }
+
+ pub fn peek_from(&self, _: &mut [u8]) -> io::Result<(usize, SocketAddr)> {
+ unimpl!();
+ }
+
+ pub fn send_to(&self, _: &[u8], _: &SocketAddr) -> io::Result<usize> {
+ unimpl!();
+ }
+
+ pub fn duplicate(&self) -> io::Result<UdpSocket> {
+ unimpl!();
+ }
+
+ pub fn set_read_timeout(&self, _: Option<Duration>) -> io::Result<()> {
+ unimpl!();
+ }
+
+ pub fn set_write_timeout(&self, _: Option<Duration>) -> io::Result<()> {
+ unimpl!();
+ }
+
+ pub fn read_timeout(&self) -> io::Result<Option<Duration>> {
+ unimpl!();
+ }
+
+ pub fn write_timeout(&self) -> io::Result<Option<Duration>> {
+ unimpl!();
+ }
+
+ pub fn set_broadcast(&self, _: bool) -> io::Result<()> {
+ unimpl!();
+ }
+
+ pub fn broadcast(&self) -> io::Result<bool> {
+ unimpl!();
+ }
+
+ pub fn set_multicast_loop_v4(&self, _: bool) -> io::Result<()> {
+ unimpl!();
+ }
+
+ pub fn multicast_loop_v4(&self) -> io::Result<bool> {
+ unimpl!();
+ }
+
+ pub fn set_multicast_ttl_v4(&self, _: u32) -> io::Result<()> {
+ unimpl!();
+ }
+
+ pub fn multicast_ttl_v4(&self) -> io::Result<u32> {
+ unimpl!();
+ }
+
+ pub fn set_multicast_loop_v6(&self, _: bool) -> io::Result<()> {
+ unimpl!();
+ }
+
+ pub fn multicast_loop_v6(&self) -> io::Result<bool> {
+ unimpl!();
+ }
+
+ pub fn join_multicast_v4(&self, _: &Ipv4Addr, _: &Ipv4Addr)
+ -> io::Result<()> {
+ unimpl!();
+ }
+
+ pub fn join_multicast_v6(&self, _: &Ipv6Addr, _: u32)
+ -> io::Result<()> {
+ unimpl!();
+ }
+
+ pub fn leave_multicast_v4(&self, _: &Ipv4Addr, _: &Ipv4Addr)
+ -> io::Result<()> {
+ unimpl!();
+ }
+
+ pub fn leave_multicast_v6(&self, _: &Ipv6Addr, _: u32)
+ -> io::Result<()> {
+ unimpl!();
+ }
+
+ pub fn set_ttl(&self, _: u32) -> io::Result<()> {
+ unimpl!();
+ }
+
+ pub fn ttl(&self) -> io::Result<u32> {
+ unimpl!();
+ }
+
+ pub fn take_error(&self) -> io::Result<Option<io::Error>> {
+ unimpl!();
+ }
+
+ pub fn set_nonblocking(&self, _: bool) -> io::Result<()> {
+ unimpl!();
+ }
+
+ pub fn recv(&self, _: &mut [u8]) -> io::Result<usize> {
+ unimpl!();
+ }
+
+ pub fn peek(&self, _: &mut [u8]) -> io::Result<usize> {
+ unimpl!();
+ }
+
+ pub fn send(&self, _: &[u8]) -> io::Result<usize> {
+ unimpl!();
+ }
+
+ pub fn connect(&self, _: &SocketAddr) -> io::Result<()> {
+ unimpl!();
+ }
+ }
+
+ impl FromInner<Socket> for UdpSocket {
+ fn from_inner(socket: Socket) -> UdpSocket {
+ UdpSocket { inner: socket }
+ }
+ }
+
+ impl fmt::Debug for UdpSocket {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ write!(f, "No networking support on L4Re available.")
+ }
+ }
+
+ pub struct LookupHost {
+ original: *mut libc::addrinfo,
+ cur: *mut libc::addrinfo,
+ }
+
+ impl Iterator for LookupHost {
+ type Item = SocketAddr;
+ fn next(&mut self) -> Option<SocketAddr> {
+ None
+ }
+ }
+
+ unsafe impl Sync for LookupHost {}
+ unsafe impl Send for LookupHost {}
+
+ pub fn lookup_host(_: &str) -> io::Result<LookupHost> {
+ unimpl!();
+ }
+}
+
#[cfg(all(not(dox), target_os = "solaris"))] pub use os::solaris as platform;
#[cfg(all(not(dox), target_os = "emscripten"))] pub use os::emscripten as platform;
#[cfg(all(not(dox), target_os = "fuchsia"))] pub use os::fuchsia as platform;
+#[cfg(all(not(dox), target_os = "l4re"))] pub use os::linux as platform;
#[macro_use]
pub mod weak;
pub mod fs;
pub mod memchr;
pub mod mutex;
+#[cfg(not(target_os = "l4re"))]
pub mod net;
+#[cfg(target_os = "l4re")]
+mod l4re;
+#[cfg(target_os = "l4re")]
+pub use self::l4re::net;
pub mod os;
pub mod os_str;
pub mod path;
extern {
#[cfg(not(target_os = "dragonfly"))]
- #[cfg_attr(any(target_os = "linux", target_os = "emscripten", target_os = "fuchsia"),
+ #[cfg_attr(any(target_os = "linux",
+ target_os = "emscripten",
+ target_os = "fuchsia",
+ target_os = "l4re"),
link_name = "__errno_location")]
#[cfg_attr(any(target_os = "bitrig",
target_os = "netbsd",
}
}
-#[cfg(target_os = "fuchsia")]
+#[cfg(any(target_os = "fuchsia", target_os = "l4re"))]
pub fn current_exe() -> io::Result<PathBuf> {
use io::ErrorKind;
- Err(io::Error::new(ErrorKind::Other, "Not yet implemented on fuchsia"))
+ Err(io::Error::new(ErrorKind::Other, "Not yet implemented!"))
}
pub struct Env {
t!(cvt_r(|| libc::dup2(fd, libc::STDERR_FILENO)));
}
- if let Some(u) = self.get_gid() {
- t!(cvt(libc::setgid(u as gid_t)));
- }
- if let Some(u) = self.get_uid() {
- // When dropping privileges from root, the `setgroups` call
- // will remove any extraneous groups. If we don't call this,
- // then even though our uid has dropped, we may still have
- // groups that enable us to do super-user things. This will
- // fail if we aren't root, so don't bother checking the
- // return value, this is just done as an optimistic
- // privilege dropping function.
- let _ = libc::setgroups(0, ptr::null());
+ if cfg!(not(any(target_os = "l4re"))) {
+ if let Some(u) = self.get_gid() {
+ t!(cvt(libc::setgid(u as gid_t)));
+ }
+ if let Some(u) = self.get_uid() {
+ // When dropping privileges from root, the `setgroups` call
+ // will remove any extraneous groups. If we don't call this,
+ // then even though our uid has dropped, we may still have
+ // groups that enable us to do super-user things. This will
+ // fail if we aren't root, so don't bother checking the
+ // return value, this is just done as an optimistic
+ // privilege dropping function.
+ let _ = libc::setgroups(0, ptr::null());
- t!(cvt(libc::setuid(u as uid_t)));
+ t!(cvt(libc::setuid(u as uid_t)));
+ }
}
if let Some(ref cwd) = *self.get_cwd() {
t!(cvt(libc::chdir(cwd.as_ptr())));
use sys_common::thread::*;
+#[cfg(not(target_os = "l4re"))]
+pub const DEFAULT_MIN_STACK_SIZE: usize = 2 * 1024 * 1024;
+#[cfg(target_os = "l4re")]
+pub const DEFAULT_MIN_STACK_SIZE: usize = 1024 * 1024;
+
pub struct Thread {
id: libc::pthread_t,
}
assert_eq!(libc::pthread_attr_init(&mut attr), 0);
let stack_size = cmp::max(stack, min_stack_size(&attr));
+
match pthread_attr_setstacksize(&mut attr,
stack_size) {
0 => {}
#[cfg(any(target_env = "newlib",
target_os = "solaris",
target_os = "haiku",
+ target_os = "l4re",
target_os = "emscripten"))]
pub fn set_name(_name: &CStr) {
// Newlib, Illumos, Haiku, and Emscripten have no way to set a thread name.
}
#[cfg(any(target_os = "android", target_os = "freebsd",
- target_os = "linux", target_os = "netbsd"))]
+ target_os = "linux", target_os = "netbsd", target_os = "l4re"))]
unsafe fn get_stack_start() -> Option<*mut libc::c_void> {
let mut ret = None;
let mut attr: libc::pthread_attr_t = ::mem::zeroed();
}
#[cfg(any(target_os = "android", target_os = "freebsd",
- target_os = "linux", target_os = "netbsd"))]
+ target_os = "linux", target_os = "netbsd", target_os = "l4re"))]
pub unsafe fn current() -> Option<usize> {
let mut ret = None;
let mut attr: libc::pthread_attr_t = ::mem::zeroed();
pub type HANDLE = LPVOID;
pub type HINSTANCE = HANDLE;
pub type HMODULE = HINSTANCE;
+pub type HRESULT = LONG;
pub type BOOL = c_int;
pub type BYTE = u8;
pub type BOOLEAN = BYTE;
pub const ERROR_IO_PENDING: DWORD = 997;
pub const ERROR_TIMEOUT: DWORD = 0x5B4;
+pub const E_NOTIMPL: HRESULT = 0x80004001u32 as HRESULT;
+
pub const INVALID_HANDLE_VALUE: HANDLE = !0 as HANDLE;
pub const FACILITY_NT_BIT: DWORD = 0x1000_0000;
timeout: *const timeval) -> c_int;
}
-// Functions that aren't available on Windows XP, but we still use them and just
-// provide some form of a fallback implementation.
+// Functions that aren't available on every version of Windows that we support,
+// but we still use them and just provide some form of a fallback implementation.
compat_fn! {
kernel32:
pub fn SetThreadStackGuarantee(_size: *mut c_ulong) -> BOOL {
SetLastError(ERROR_CALL_NOT_IMPLEMENTED as DWORD); 0
}
+ pub fn SetThreadDescription(hThread: HANDLE,
+ lpThreadDescription: LPCWSTR) -> HRESULT {
+ SetLastError(ERROR_CALL_NOT_IMPLEMENTED as DWORD); E_NOTIMPL
+ }
pub fn SetFileInformationByHandle(_hFile: HANDLE,
_FileInformationClass: FILE_INFO_BY_HANDLE_CLASS,
_lpFileInformation: LPVOID,
use sys_common::thread::*;
use time::Duration;
+use super::to_u16s;
+
+pub const DEFAULT_MIN_STACK_SIZE: usize = 2 * 1024 * 1024;
+
pub struct Thread {
handle: Handle
}
}
}
- pub fn set_name(_name: &CStr) {
- // Windows threads are nameless
- // The names in MSVC debugger are obtained using a "magic" exception,
- // which requires a use of MS C++ extensions.
- // See https://msdn.microsoft.com/en-us/library/xcb2z8hs.aspx
+ pub fn set_name(name: &CStr) {
+ if let Ok(utf8) = name.to_str() {
+ if let Ok(utf16) = to_u16s(utf8) {
+ unsafe { c::SetThreadDescription(c::GetCurrentThread(), utf16.as_ptr()); };
+ };
+ };
}
pub fn join(self) {
pub mod util;
pub mod wtf8;
-#[cfg(target_os = "redox")]
+#[cfg(any(target_os = "redox", target_os = "l4re"))]
pub use sys::net;
-#[cfg(not(target_os = "redox"))]
+#[cfg(not(any(target_os = "redox", target_os = "l4re")))]
pub mod net;
#[cfg(feature = "backtrace")]
#[cfg(any(target_os = "dragonfly", target_os = "freebsd",
target_os = "ios", target_os = "macos",
target_os = "openbsd", target_os = "netbsd",
- target_os = "solaris", target_os = "haiku"))]
+ target_os = "solaris", target_os = "haiku", target_os = "l4re"))]
use sys::net::netc::IPV6_JOIN_GROUP as IPV6_ADD_MEMBERSHIP;
#[cfg(not(any(target_os = "dragonfly", target_os = "freebsd",
target_os = "ios", target_os = "macos",
target_os = "openbsd", target_os = "netbsd",
- target_os = "solaris", target_os = "haiku")))]
+ target_os = "solaris", target_os = "haiku", target_os = "l4re")))]
use sys::net::netc::IPV6_ADD_MEMBERSHIP;
#[cfg(any(target_os = "dragonfly", target_os = "freebsd",
target_os = "ios", target_os = "macos",
target_os = "openbsd", target_os = "netbsd",
- target_os = "solaris", target_os = "haiku"))]
+ target_os = "solaris", target_os = "haiku", target_os = "l4re"))]
use sys::net::netc::IPV6_LEAVE_GROUP as IPV6_DROP_MEMBERSHIP;
#[cfg(not(any(target_os = "dragonfly", target_os = "freebsd",
target_os = "ios", target_os = "macos",
target_os = "openbsd", target_os = "netbsd",
- target_os = "solaris", target_os = "haiku")))]
+ target_os = "solaris", target_os = "haiku", target_os = "l4re")))]
use sys::net::netc::IPV6_DROP_MEMBERSHIP;
#[cfg(any(target_os = "linux", target_os = "android",
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+use env;
use alloc::boxed::FnBox;
use libc;
+use sync::atomic::{self, Ordering};
use sys::stack_overflow;
+use sys::thread as imp;
pub unsafe fn start_thread(main: *mut libc::c_void) {
// Next, set up our stack overflow handler which may get triggered if we run
// Finally, let's run some code.
Box::from_raw(main as *mut Box<FnBox()>)()
}
+
+pub fn min_stack() -> usize {
+ static MIN: atomic::AtomicUsize = atomic::AtomicUsize::new(0);
+ match MIN.load(Ordering::SeqCst) {
+ 0 => {}
+ n => return n - 1,
+ }
+ let amt = env::var("RUST_MIN_STACK").ok().and_then(|s| s.parse().ok());
+ let amt = amt.unwrap_or(imp::DEFAULT_MIN_STACK_SIZE);
+
+ // 0 is our sentinel value, so ensure that we'll never see 0 after
+ // initialization has run
+ MIN.store(amt + 1, Ordering::SeqCst);
+ amt
+}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-use env;
use fmt;
use io::prelude::*;
-use sync::atomic::{self, Ordering};
use sys::stdio::Stderr;
use thread;
-pub fn min_stack() -> usize {
- static MIN: atomic::AtomicUsize = atomic::AtomicUsize::new(0);
- match MIN.load(Ordering::SeqCst) {
- 0 => {}
- n => return n - 1,
- }
- let amt = env::var("RUST_MIN_STACK").ok().and_then(|s| s.parse().ok());
- let amt = amt.unwrap_or(2 * 1024 * 1024);
- // 0 is our sentinel value, so ensure that we'll never see 0 after
- // initialization has run
- MIN.store(amt + 1, Ordering::SeqCst);
- amt
-}
-
pub fn dumb_print(args: fmt::Arguments) {
let _ = Stderr::new().map(|mut stderr| stderr.write_fmt(args));
}
use sys::thread as imp;
use sys_common::mutex;
use sys_common::thread_info;
-use sys_common::util;
+use sys_common::thread;
use sys_common::{AsInner, IntoInner};
use time::Duration;
{
let Builder { name, stack_size } = self;
- let stack_size = stack_size.unwrap_or_else(util::min_stack);
+ let stack_size = stack_size.unwrap_or_else(thread::min_stack);
let my_thread = Thread::new(name);
let their_thread = my_thread.clone();
Arg { ty: P(ty), pat: pat, id: ast::DUMMY_NODE_ID }
}
+#[derive(Copy, Clone, Debug, PartialEq, Eq)]
+enum TokenExpectType {
+ Expect,
+ NoExpect,
+}
+
impl<'a> Parser<'a> {
pub fn new(sess: &'a ParseSess,
tokens: TokenStream,
}
}
+ /// Expect and consume an `|`. If `||` is seen, replace it with a single
+ /// `|` and continue. If an `|` is not seen, signal an error.
+ fn expect_or(&mut self) -> PResult<'a, ()> {
+ self.expected_tokens.push(TokenType::Token(token::BinOp(token::Or)));
+ match self.token {
+ token::BinOp(token::Or) => {
+ self.bump();
+ Ok(())
+ }
+ token::OrOr => {
+ let span = self.span.with_lo(self.span.lo() + BytePos(1));
+ Ok(self.bump_with(token::BinOp(token::Or), span))
+ }
+ _ => self.unexpected()
+ }
+ }
+
pub fn expect_no_suffix(&self, sp: Span, kind: &str, suffix: Option<ast::Name>) {
match suffix {
None => {/* everything ok */}
self.parse_seq_to_before_tokens(kets,
SeqSep::none(),
+ TokenExpectType::Expect,
|p| Ok(p.parse_token_tree()),
|mut e| handler.cancel(&mut e));
}
-> Vec<T>
where F: FnMut(&mut Parser<'a>) -> PResult<'a, T>
{
- self.parse_seq_to_before_tokens(&[ket], sep, f, |mut e| e.emit())
+ self.parse_seq_to_before_tokens(&[ket], sep, TokenExpectType::Expect, f, |mut e| e.emit())
}
// `fe` is an error handler.
fn parse_seq_to_before_tokens<T, F, Fe>(&mut self,
kets: &[&token::Token],
sep: SeqSep,
+ expect: TokenExpectType,
mut f: F,
mut fe: Fe)
-> Vec<T>
}
}
}
- if sep.trailing_sep_allowed && kets.iter().any(|k| self.check(k)) {
+ if sep.trailing_sep_allowed && kets.iter().any(|k| {
+ match expect {
+ TokenExpectType::Expect => self.check(k),
+ TokenExpectType::NoExpect => self.token == **k,
+ }
+ }) {
break;
}
Vec::new()
} else {
self.expect(&token::BinOp(token::Or))?;
- let args = self.parse_seq_to_before_end(
- &token::BinOp(token::Or),
+ let args = self.parse_seq_to_before_tokens(
+ &[&token::BinOp(token::Or), &token::OrOr],
SeqSep::trailing_allowed(token::Comma),
- |p| p.parse_fn_block_arg()
+ TokenExpectType::NoExpect,
+ |p| p.parse_fn_block_arg(),
+ |mut e| e.emit()
);
- self.expect(&token::BinOp(token::Or))?;
+ self.expect_or()?;
args
}
};
}
}
+impl From<Vec<Span>> for MultiSpan {
+ fn from(spans: Vec<Span>) -> MultiSpan {
+ MultiSpan::from_spans(spans)
+ }
+}
+
pub const NO_EXPANSION: SyntaxContext = SyntaxContext::empty();
/// Identifies an offset of a multi-byte character in a FileMap
opts.maybe_sysroot = Some(sysroot);
let descriptions = Registry::new(&rustc::DIAGNOSTICS);
- let dep_graph = DepGraph::new(opts.build_dep_graph());
let cstore = Rc::new(CStore::new(Box::new(rustc_trans::LlvmMetadataLoader)));
- let sess = build_session(opts, &dep_graph, None, descriptions);
+ let sess = build_session(opts, None, descriptions);
rustc_trans::init(&sess);
rustc_lint::register_builtins(&mut sess.lint_store.borrow_mut(), Some(&sess));
(sess, cstore)
--- /dev/null
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+fn main() {
+ let f = |_||x, y| x+y;
+ assert_eq!(f(())(1, 2), 3);
+}
--- /dev/null
+// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![feature(generators)]
+
+enum Enum {
+ A(String),
+ B
+}
+
+fn main() {
+ || {
+ loop {
+ if let true = true {
+ match Enum::A(String::new()) {
+ Enum::A(_var) => {}
+ Enum::B => {}
+ }
+ }
+ yield;
+ }
+ };
+}
\ No newline at end of file
--- /dev/null
+// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![feature(const_fn)]
+#![crate_name = "foo"]
+
+// @has foo/fn.bar.html
+// @has - '//*[@class="rust fn"]' 'pub const fn bar() -> '
+/// foo
+pub const fn bar() -> usize {
+ 2
+}
+
+// @has foo/struct.Foo.html
+// @has - '//*[@class="method"]' 'const fn new()'
+pub struct Foo(usize);
+
+impl Foo {
+ pub const fn new() -> Foo { Foo(0) }
+}
--- /dev/null
+error[E0623]: lifetime mismatch
+ --> $DIR/ex3-both-anon-regions-4.rs:12:13
+ |
+11 | fn foo(z: &mut Vec<(&u8,&u8)>, (x, y): (&u8, &u8)) {
+ | --- --- these references are declared with different lifetimes...
+12 | z.push((x,y));
+ | ^ ...but data flows into `z` here
+
+error[E0623]: lifetime mismatch
+ --> $DIR/ex3-both-anon-regions-4.rs:12:15
+ |
+11 | fn foo(z: &mut Vec<(&u8,&u8)>, (x, y): (&u8, &u8)) {
+ | --- --- these references are declared with different lifetimes...
+12 | z.push((x,y));
+ | ^ ...but data flows into `z` here
+
+error: aborting due to 2 previous errors
+
--- /dev/null
+// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+struct Ref<'a, 'b> {
+ a: &'a u32,
+ b: &'b u32,
+}
+
+fn foo(mut x: Ref) {
+ x.a = x.b;
+}
+
+fn main() {}
--- /dev/null
+error[E0623]: lifetime mismatch
+ --> $DIR/ex3-both-anon-regions-both-are-structs-4.rs:16:11
+ |
+15 | fn foo(mut x: Ref) {
+ | ---
+ | |
+ | this type was declared with multiple lifetimes...
+16 | x.a = x.b;
+ | ^^^ ...but data with one lifetime flows into the other here
+
+error: aborting due to previous error
+
--- /dev/null
+// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+struct Ref<'a, 'b> { a: &'a u32, b: &'b u32 }
+
+fn foo(mut y: Ref, x: &u32) {
+ y.b = x;
+}
+
+fn main() { }
--- /dev/null
+error[E0623]: lifetime mismatch
+ --> $DIR/ex3-both-anon-regions-one-is-struct-4.rs:14:11
+ |
+13 | fn foo(mut y: Ref, x: &u32) {
+ | --- ---- these two types are declared with different lifetimes...
+14 | y.b = x;
+ | ^ ...but data from `x` flows into `y` here
+
+error: aborting due to previous error
+
--- /dev/null
+// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+fn foo(x:fn(&u8, &u8), y: Vec<&u8>, z: &u8) {
+ y.push(z);
+}
+
+fn main() { }
--- /dev/null
+error[E0623]: lifetime mismatch
+ --> $DIR/ex3-both-anon-regions-using-fn-items.rs:11:10
+ |
+10 | fn foo(x:fn(&u8, &u8), y: Vec<&u8>, z: &u8) {
+ | --- --- these two types are declared with different lifetimes...
+11 | y.push(z);
+ | ^ ...but data from `z` flows into `y` here
+
+error: aborting due to previous error
+
--- /dev/null
+// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+fn foo(x:Box<Fn(&u8, &u8)> , y: Vec<&u8>, z: &u8) {
+ y.push(z);
+}
+
+fn main() { }
--- /dev/null
+error[E0623]: lifetime mismatch
+ --> $DIR/ex3-both-anon-regions-using-trait-objects.rs:11:10
+ |
+10 | fn foo(x:Box<Fn(&u8, &u8)> , y: Vec<&u8>, z: &u8) {
+ | --- --- these two types are declared with different lifetimes...
+11 | y.push(z);
+ | ^ ...but data from `z` flows into `y` here
+
+error: aborting due to previous error
+
clap = "2.25.0"
[dependencies.mdbook]
-version = "0.0.22"
+version = "0.0.25"
default-features = false
extern crate clap;
use std::env;
-use std::error::Error;
use std::io::{self, Write};
use std::path::{Path, PathBuf};
use clap::{App, ArgMatches, SubCommand, AppSettings};
use mdbook::MDBook;
+use mdbook::errors::Result;
fn main() {
let d_message = "-d, --dest-dir=[dest-dir]
::std::process::exit(101);
}
}
-
// Build command implementation
-fn build(args: &ArgMatches) -> Result<(), Box<Error>> {
- let book = build_mdbook_struct(args);
+pub fn build(args: &ArgMatches) -> Result<()> {
+ let book_dir = get_book_dir(args);
+ let book = MDBook::new(&book_dir).read_config()?;
let mut book = match args.value_of("dest-dir") {
- Some(dest_dir) => book.set_dest(Path::new(dest_dir)),
- None => book
+ Some(dest_dir) => book.with_destination(dest_dir),
+ None => book,
};
- try!(book.build());
+ book.build()?;
Ok(())
}
-fn build_mdbook_struct(args: &ArgMatches) -> mdbook::MDBook {
- let book_dir = get_book_dir(args);
- let mut book = MDBook::new(&book_dir).read_config();
-
- // By default mdbook will attempt to create non-existent files referenced
- // from SUMMARY.md files. This is problematic on CI where we mount the
- // source directory as readonly. To avoid any issues, we'll disabled
- // mdbook's implicit file creation feature.
- book.create_missing = false;
-
- book
-}
-
fn get_book_dir(args: &ArgMatches) -> PathBuf {
if let Some(dir) = args.value_of("dir") {
// Check if path is relative from current dir, or absolute...