/// # Cloning references
///
/// Creating a new reference from an existing reference counted pointer is done using the
-/// `Clone` trait implemented for [`Arc<T>`][`arc`] and [`Weak<T>`][`weak`].
+/// `Clone` trait implemented for [`Arc<T>`][arc] and [`Weak<T>`][weak].
///
/// ```
/// use std::sync::Arc;
/// # Deref
///
/// `String`s implement [`Deref`]`<Target=str>`, and so inherit all of [`str`]'s
-/// methods. In addition, this means that you can pass a `String` to any
+/// methods. In addition, this means that you can pass a `String` to a
/// function which takes a [`&str`] by using an ampersand (`&`):
///
/// ```
///
/// This will create a [`&str`] from the `String` and pass it in. This
/// conversion is very inexpensive, and so generally, functions will accept
-/// [`&str`]s as arguments unless they need a `String` for some specific reason.
+/// [`&str`]s as arguments unless they need a `String` for some specific
+/// reason.
///
+/// In certain cases Rust doesn't have enough information to make this
+/// conversion, known as `Deref` coercion. In the following example a string
+/// slice `&'a str` implements the trait `TraitExample`, and the function
+/// `example_func` takes anything that implements the trait. In this case Rust
+/// would need to make two implicit conversions, which Rust doesn't have the
+/// means to do. For that reason, the following example will not compile.
+///
+/// ```compile_fail,E0277
+/// trait TraitExample {}
+///
+/// impl<'a> TraitExample for &'a str {}
+///
+/// fn example_func<A: TraitExample>(example_arg: A) {}
+///
+/// fn main() {
+/// let example_string = String::from("example_string");
+/// example_func(&example_string);
+/// }
+/// ```
+///
+/// There are two options that would work instead. The first would be to
+/// change the line `example_func(&example_string);` to
+/// `example_func(example_string.as_str());`, using the method `as_str()`
+/// to explicitly extract the string slice containing the string. The second
+/// way changes `example_func(&example_string);` to
+/// `example_func(&*example_string);`. In this case we are dereferencing a
+/// `String` to a `str`, then referencing the `str` back to `&str`. The
+/// second way is more idiomatic, however both work to do the conversion
+/// explicitly rather than relying on the implicit conversion.
///
/// # Representation
///
impl_stable_hash_for!(struct mir::BasicBlockData<'tcx> { statements, terminator, is_cleanup });
impl<'a, 'gcx, 'tcx> HashStable<StableHashingContext<'a, 'gcx, 'tcx>>
-for mir::Terminator<'tcx> {
+for mir::Terminator<'gcx> {
#[inline]
fn hash_stable<W: StableHasherResult>(&self,
hcx: &mut StableHashingContext<'a, 'gcx, 'tcx>,
}
impl<'a, 'gcx, 'tcx> HashStable<StableHashingContext<'a, 'gcx, 'tcx>>
-for mir::TerminatorKind<'tcx> {
+for mir::TerminatorKind<'gcx> {
fn hash_stable<W: StableHasherResult>(&self,
hcx: &mut StableHashingContext<'a, 'gcx, 'tcx>,
hasher: &mut StableHasher<W>) {
}
impl<'a, 'gcx, 'tcx> HashStable<StableHashingContext<'a, 'gcx, 'tcx>>
-for mir::AssertMessage<'tcx> {
+for mir::AssertMessage<'gcx> {
fn hash_stable<W: StableHasherResult>(&self,
hcx: &mut StableHashingContext<'a, 'gcx, 'tcx>,
hasher: &mut StableHasher<W>) {
impl_stable_hash_for!(struct mir::Statement<'tcx> { source_info, kind });
impl<'a, 'gcx, 'tcx> HashStable<StableHashingContext<'a, 'gcx, 'tcx>>
-for mir::StatementKind<'tcx> {
+for mir::StatementKind<'gcx> {
fn hash_stable<W: StableHasherResult>(&self,
hcx: &mut StableHashingContext<'a, 'gcx, 'tcx>,
hasher: &mut StableHasher<W>) {
}
impl<'a, 'gcx, 'tcx, T> HashStable<StableHashingContext<'a, 'gcx, 'tcx>>
- for mir::ValidationOperand<'tcx, T>
+ for mir::ValidationOperand<'gcx, T>
where T: HashStable<StableHashingContext<'a, 'gcx, 'tcx>>
{
fn hash_stable<W: StableHasherResult>(&self,
impl_stable_hash_for!(enum mir::ValidationOp { Acquire, Release, Suspend(extent) });
-impl<'a, 'gcx, 'tcx> HashStable<StableHashingContext<'a, 'gcx, 'tcx>> for mir::Lvalue<'tcx> {
+impl<'a, 'gcx, 'tcx> HashStable<StableHashingContext<'a, 'gcx, 'tcx>> for mir::Lvalue<'gcx> {
fn hash_stable<W: StableHasherResult>(&self,
hcx: &mut StableHashingContext<'a, 'gcx, 'tcx>,
hasher: &mut StableHasher<W>) {
}
impl<'a, 'gcx, 'tcx, B, V, T> HashStable<StableHashingContext<'a, 'gcx, 'tcx>>
-for mir::Projection<'tcx, B, V, T>
+for mir::Projection<'gcx, B, V, T>
where B: HashStable<StableHashingContext<'a, 'gcx, 'tcx>>,
V: HashStable<StableHashingContext<'a, 'gcx, 'tcx>>,
T: HashStable<StableHashingContext<'a, 'gcx, 'tcx>>
}
impl<'a, 'gcx, 'tcx, V, T> HashStable<StableHashingContext<'a, 'gcx, 'tcx>>
-for mir::ProjectionElem<'tcx, V, T>
+for mir::ProjectionElem<'gcx, V, T>
where V: HashStable<StableHashingContext<'a, 'gcx, 'tcx>>,
T: HashStable<StableHashingContext<'a, 'gcx, 'tcx>>
{
impl_stable_hash_for!(struct mir::VisibilityScopeData { span, parent_scope });
-impl<'a, 'gcx, 'tcx> HashStable<StableHashingContext<'a, 'gcx, 'tcx>> for mir::Operand<'tcx> {
+impl<'a, 'gcx, 'tcx> HashStable<StableHashingContext<'a, 'gcx, 'tcx>> for mir::Operand<'gcx> {
fn hash_stable<W: StableHasherResult>(&self,
hcx: &mut StableHashingContext<'a, 'gcx, 'tcx>,
hasher: &mut StableHasher<W>) {
}
}
-impl<'a, 'gcx, 'tcx> HashStable<StableHashingContext<'a, 'gcx, 'tcx>> for mir::Rvalue<'tcx> {
+impl<'a, 'gcx, 'tcx> HashStable<StableHashingContext<'a, 'gcx, 'tcx>> for mir::Rvalue<'gcx> {
fn hash_stable<W: StableHasherResult>(&self,
hcx: &mut StableHashingContext<'a, 'gcx, 'tcx>,
hasher: &mut StableHasher<W>) {
});
impl<'a, 'gcx, 'tcx> HashStable<StableHashingContext<'a, 'gcx, 'tcx>>
-for mir::AggregateKind<'tcx> {
+for mir::AggregateKind<'gcx> {
fn hash_stable<W: StableHasherResult>(&self,
hcx: &mut StableHashingContext<'a, 'gcx, 'tcx>,
hasher: &mut StableHasher<W>) {
impl_stable_hash_for!(struct mir::Constant<'tcx> { span, ty, literal });
-impl<'a, 'gcx, 'tcx> HashStable<StableHashingContext<'a, 'gcx, 'tcx>> for mir::Literal<'tcx> {
+impl<'a, 'gcx, 'tcx> HashStable<StableHashingContext<'a, 'gcx, 'tcx>> for mir::Literal<'gcx> {
fn hash_stable<W: StableHasherResult>(&self,
hcx: &mut StableHashingContext<'a, 'gcx, 'tcx>,
hasher: &mut StableHasher<W>) {
use ty;
impl<'a, 'gcx, 'tcx, T> HashStable<StableHashingContext<'a, 'gcx, 'tcx>>
-for &'tcx ty::Slice<T>
+for &'gcx ty::Slice<T>
where T: HashStable<StableHashingContext<'a, 'gcx, 'tcx>> {
fn hash_stable<W: StableHasherResult>(&self,
hcx: &mut StableHashingContext<'a, 'gcx, 'tcx>,
}
impl<'a, 'gcx, 'tcx> HashStable<StableHashingContext<'a, 'gcx, 'tcx>>
-for ty::subst::Kind<'tcx> {
+for ty::subst::Kind<'gcx> {
fn hash_stable<W: StableHasherResult>(&self,
hcx: &mut StableHashingContext<'a, 'gcx, 'tcx>,
hasher: &mut StableHasher<W>) {
db.depth.hash_stable(hcx, hasher);
i.hash_stable(hcx, hasher);
}
+ ty::ReLateBound(db, ty::BrNamed(def_id, name)) => {
+ db.depth.hash_stable(hcx, hasher);
+ def_id.hash_stable(hcx, hasher);
+ name.hash_stable(hcx, hasher);
+ }
ty::ReEarlyBound(ty::EarlyBoundRegion { def_id, index, name }) => {
def_id.hash_stable(hcx, hasher);
index.hash_stable(hcx, hasher);
}
impl<'a, 'gcx, 'tcx> HashStable<StableHashingContext<'a, 'gcx, 'tcx>>
-for ty::adjustment::AutoBorrow<'tcx> {
+for ty::adjustment::AutoBorrow<'gcx> {
fn hash_stable<W: StableHasherResult>(&self,
hcx: &mut StableHashingContext<'a, 'gcx, 'tcx>,
hasher: &mut StableHasher<W>) {
}
impl<'a, 'gcx, 'tcx> HashStable<StableHashingContext<'a, 'gcx, 'tcx>>
-for ty::adjustment::Adjust<'tcx> {
+for ty::adjustment::Adjust<'gcx> {
fn hash_stable<W: StableHasherResult>(&self,
hcx: &mut StableHashingContext<'a, 'gcx, 'tcx>,
hasher: &mut StableHasher<W>) {
});
impl<'a, 'gcx, 'tcx> HashStable<StableHashingContext<'a, 'gcx, 'tcx>>
-for ty::UpvarCapture<'tcx> {
+for ty::UpvarCapture<'gcx> {
fn hash_stable<W: StableHasherResult>(&self,
hcx: &mut StableHashingContext<'a, 'gcx, 'tcx>,
hasher: &mut StableHasher<W>) {
});
impl<'a, 'gcx, 'tcx, T> HashStable<StableHashingContext<'a, 'gcx, 'tcx>> for ty::Binder<T>
- where T: HashStable<StableHashingContext<'a, 'gcx, 'tcx>> + ty::fold::TypeFoldable<'tcx>
+ where T: HashStable<StableHashingContext<'a, 'gcx, 'tcx>>
{
fn hash_stable<W: StableHasherResult>(&self,
hcx: &mut StableHashingContext<'a, 'gcx, 'tcx>,
hasher: &mut StableHasher<W>) {
- hcx.tcx().anonymize_late_bound_regions(self).0.hash_stable(hcx, hasher);
+ let ty::Binder(ref inner) = *self;
+ inner.hash_stable(hcx, hasher);
}
}
impl_stable_hash_for!(struct ty::ProjectionTy<'tcx> { substs, item_def_id });
-impl<'a, 'gcx, 'tcx> HashStable<StableHashingContext<'a, 'gcx, 'tcx>> for ty::Predicate<'tcx> {
+impl<'a, 'gcx, 'tcx> HashStable<StableHashingContext<'a, 'gcx, 'tcx>> for ty::Predicate<'gcx> {
fn hash_stable<W: StableHasherResult>(&self,
hcx: &mut StableHashingContext<'a, 'gcx, 'tcx>,
hasher: &mut StableHasher<W>) {
});
impl<'a, 'gcx, 'tcx> HashStable<StableHashingContext<'a, 'gcx, 'tcx>>
-for ::middle::const_val::ConstVal<'tcx> {
+for ::middle::const_val::ConstVal<'gcx> {
fn hash_stable<W: StableHasherResult>(&self,
hcx: &mut StableHashingContext<'a, 'gcx, 'tcx>,
hasher: &mut StableHasher<W>) {
});
impl<'a, 'gcx, 'tcx> HashStable<StableHashingContext<'a, 'gcx, 'tcx>>
-for ty::TypeVariants<'tcx>
+for ty::TypeVariants<'gcx>
{
fn hash_stable<W: StableHasherResult>(&self,
hcx: &mut StableHashingContext<'a, 'gcx, 'tcx>,
});
impl<'a, 'gcx, 'tcx> HashStable<StableHashingContext<'a, 'gcx, 'tcx>>
-for ty::ExistentialPredicate<'tcx>
+for ty::ExistentialPredicate<'gcx>
{
fn hash_stable<W: StableHasherResult>(&self,
hcx: &mut StableHashingContext<'a, 'gcx, 'tcx>,
impl<'a, 'gcx, 'tcx> HashStable<StableHashingContext<'a, 'gcx, 'tcx>>
-for ty::TypeckTables<'tcx> {
+for ty::TypeckTables<'gcx> {
fn hash_stable<W: StableHasherResult>(&self,
hcx: &mut StableHashingContext<'a, 'gcx, 'tcx>,
hasher: &mut StableHasher<W>) {
substs
});
-impl<'a, 'gcx, 'tcx> HashStable<StableHashingContext<'a, 'gcx, 'tcx>> for ty::InstanceDef<'tcx> {
+impl<'a, 'gcx, 'tcx> HashStable<StableHashingContext<'a, 'gcx, 'tcx>> for ty::InstanceDef<'gcx> {
fn hash_stable<W: StableHasherResult>(&self,
hcx: &mut StableHashingContext<'a, 'gcx, 'tcx>,
hasher: &mut StableHasher<W>) {
#[macro_export]
macro_rules! impl_stable_hash_for {
(enum $enum_name:path { $( $variant:ident $( ( $($arg:ident),* ) )* ),* }) => {
- impl<'a, 'gcx, 'tcx> ::rustc_data_structures::stable_hasher::HashStable<$crate::ich::StableHashingContext<'a, 'gcx, 'tcx>> for $enum_name {
+ impl<'a, 'tcx, 'lcx> ::rustc_data_structures::stable_hasher::HashStable<$crate::ich::StableHashingContext<'a, 'tcx, 'lcx>> for $enum_name {
#[inline]
fn hash_stable<W: ::rustc_data_structures::stable_hasher::StableHasherResult>(&self,
- __ctx: &mut $crate::ich::StableHashingContext<'a, 'gcx, 'tcx>,
+ __ctx: &mut $crate::ich::StableHashingContext<'a, 'tcx, 'lcx>,
__hasher: &mut ::rustc_data_structures::stable_hasher::StableHasher<W>) {
use $enum_name::*;
::std::mem::discriminant(self).hash_stable(__ctx, __hasher);
}
};
(struct $struct_name:path { $($field:ident),* }) => {
- impl<'a, 'gcx, 'tcx> ::rustc_data_structures::stable_hasher::HashStable<$crate::ich::StableHashingContext<'a, 'gcx, 'tcx>> for $struct_name {
+ impl<'a, 'tcx, 'lcx> ::rustc_data_structures::stable_hasher::HashStable<$crate::ich::StableHashingContext<'a, 'tcx, 'lcx>> for $struct_name {
#[inline]
fn hash_stable<W: ::rustc_data_structures::stable_hasher::StableHasherResult>(&self,
- __ctx: &mut $crate::ich::StableHashingContext<'a, 'gcx, 'tcx>,
+ __ctx: &mut $crate::ich::StableHashingContext<'a, 'tcx, 'lcx>,
__hasher: &mut ::rustc_data_structures::stable_hasher::StableHasher<W>) {
let $struct_name {
$(ref $field),*
}
};
(tuple_struct $struct_name:path { $($field:ident),* }) => {
- impl<'a, 'gcx, 'tcx> ::rustc_data_structures::stable_hasher::HashStable<$crate::ich::StableHashingContext<'a, 'gcx, 'tcx>> for $struct_name {
+ impl<'a, 'tcx, 'lcx> ::rustc_data_structures::stable_hasher::HashStable<$crate::ich::StableHashingContext<'a, 'tcx, 'lcx>> for $struct_name {
#[inline]
fn hash_stable<W: ::rustc_data_structures::stable_hasher::StableHasherResult>(&self,
- __ctx: &mut $crate::ich::StableHashingContext<'a, 'gcx, 'tcx>,
+ __ctx: &mut $crate::ich::StableHashingContext<'a, 'tcx, 'lcx>,
__hasher: &mut ::rustc_data_structures::stable_hasher::StableHasher<W>) {
let $struct_name (
$(ref $field),*
macro_rules! impl_stable_hash_for_spanned {
($T:path) => (
- impl<'a, 'gcx, 'tcx> HashStable<StableHashingContext<'a, 'gcx, 'tcx>> for ::syntax::codemap::Spanned<$T>
+ impl<'a, 'tcx, 'lcx> HashStable<StableHashingContext<'a, 'tcx, 'lcx>> for ::syntax::codemap::Spanned<$T>
{
#[inline]
fn hash_stable<W: StableHasherResult>(&self,
- hcx: &mut StableHashingContext<'a, 'gcx, 'tcx>,
+ hcx: &mut StableHashingContext<'a, 'tcx, 'lcx>,
hasher: &mut StableHasher<W>) {
self.node.hash_stable(hcx, hasher);
self.span.hash_stable(hcx, hasher);
make_mir_visitor!(Visitor,);
make_mir_visitor!(MutVisitor,mut);
+#[derive(Copy, Clone, Debug)]
pub enum Lookup {
Loc(Location),
Src(SourceInfo),
let tcx = cx.tcx();
let ptr_field_type = |pointee: Ty<'tcx>| {
+ assert!(i < 2);
let slice = |element: Ty<'tcx>| {
- assert!(i < 2);
if i == 0 {
tcx.mk_mut_ptr(element)
} else {
}
}
-impl<'a, 'gcx, 'tcx> HashStable<StableHashingContext<'a, 'gcx, 'tcx>> for ty::TyS<'tcx> {
+impl<'a, 'gcx, 'tcx> HashStable<StableHashingContext<'a, 'gcx, 'tcx>> for ty::TyS<'gcx> {
fn hash_stable<W: StableHasherResult>(&self,
hcx: &mut StableHashingContext<'a, 'gcx, 'tcx>,
hasher: &mut StableHasher<W>) {
let mut hasher = StableHasher::new();
let mut hcx = StableHashingContext::new(self);
+ // We want the type_id be independent of the types free regions, so we
+ // erase them. The erase_regions() call will also anonymize bound
+ // regions, which is desirable too.
+ let ty = self.erase_regions(&ty);
+
hcx.while_hashing_spans(false, |hcx| {
hcx.with_node_id_hashing_mode(NodeIdHashingMode::HashDefPath, |hcx| {
ty.hash_stable(hcx, &mut hasher);
// These next passes must be executed together
passes.push_pass(MIR_OPTIMIZED, mir::transform::no_landing_pads::NoLandingPads);
- passes.push_pass(MIR_OPTIMIZED, mir::transform::add_call_guards::AddCallGuards);
+ passes.push_pass(MIR_OPTIMIZED, mir::transform::add_call_guards::CriticalCallEdges);
passes.push_pass(MIR_OPTIMIZED, mir::transform::elaborate_drops::ElaborateDrops);
passes.push_pass(MIR_OPTIMIZED, mir::transform::no_landing_pads::NoLandingPads);
+ // AddValidation needs to run after ElaborateDrops and before EraseRegions, and it needs
+ // an AllCallEdges pass right before it.
+ passes.push_pass(MIR_OPTIMIZED, mir::transform::add_call_guards::AllCallEdges);
+ passes.push_pass(MIR_OPTIMIZED, mir::transform::add_validation::AddValidation);
passes.push_pass(MIR_OPTIMIZED, mir::transform::simplify::SimplifyCfg::new("elaborate-drops"));
// No lifetime analysis based on borrowing can be done from here on out.
- // AddValidation needs to run after ElaborateDrops and before EraseRegions.
- passes.push_pass(MIR_OPTIMIZED, mir::transform::add_validation::AddValidation);
-
// From here on out, regions are gone.
passes.push_pass(MIR_OPTIMIZED, mir::transform::erase_regions::EraseRegions);
passes.push_pass(MIR_OPTIMIZED, mir::transform::simplify::SimplifyLocals);
passes.push_pass(MIR_OPTIMIZED, mir::transform::generator::StateTransform);
- passes.push_pass(MIR_OPTIMIZED, mir::transform::no_landing_pads::NoLandingPads);
-
- passes.push_pass(MIR_OPTIMIZED, mir::transform::add_call_guards::AddCallGuards);
+ passes.push_pass(MIR_OPTIMIZED, mir::transform::add_call_guards::CriticalCallEdges);
passes.push_pass(MIR_OPTIMIZED, mir::transform::dump_mir::Marker("PreTrans"));
TyCtxt::create_and_enter(sess,
Entry {
kind: EntryKind::Mod(self.lazy(&data)),
visibility: self.lazy(&ty::Visibility::from_hir(vis, id, tcx)),
- span: self.lazy(&md.inner),
+ span: self.lazy(&tcx.def_span(def_id)),
attributes: self.encode_attributes(attrs),
children: self.lazy_seq(md.item_ids.iter().map(|item_id| {
tcx.hir.local_def_id(item_id.id).index
debug!("make_shim({:?}) = untransformed {:?}", instance, result);
no_landing_pads::no_landing_pads(tcx, &mut result);
simplify::simplify_cfg(&mut result);
- add_call_guards::add_call_guards(&mut result);
+ add_call_guards::CriticalCallEdges.add_call_guards(&mut result);
debug!("make_shim({:?}) = {:?}", instance, result);
tcx.alloc_mir(result)
use rustc::mir::transform::{MirPass, MirSource};
use rustc_data_structures::indexed_vec::{Idx, IndexVec};
-pub struct AddCallGuards;
+#[derive(PartialEq)]
+pub enum AddCallGuards {
+ AllCallEdges,
+ CriticalCallEdges,
+}
+pub use self::AddCallGuards::*;
/**
* Breaks outgoing critical edges for call terminators in the MIR.
_tcx: TyCtxt<'a, 'tcx, 'tcx>,
_src: MirSource,
mir: &mut Mir<'tcx>) {
- add_call_guards(mir);
+ self.add_call_guards(mir);
}
}
-pub fn add_call_guards(mir: &mut Mir) {
- let pred_count: IndexVec<_, _> =
- mir.predecessors().iter().map(|ps| ps.len()).collect();
+impl AddCallGuards {
+ pub fn add_call_guards(&self, mir: &mut Mir) {
+ let pred_count: IndexVec<_, _> =
+ mir.predecessors().iter().map(|ps| ps.len()).collect();
- // We need a place to store the new blocks generated
- let mut new_blocks = Vec::new();
+ // We need a place to store the new blocks generated
+ let mut new_blocks = Vec::new();
- let cur_len = mir.basic_blocks().len();
+ let cur_len = mir.basic_blocks().len();
- for block in mir.basic_blocks_mut() {
- match block.terminator {
- Some(Terminator {
- kind: TerminatorKind::Call {
- destination: Some((_, ref mut destination)),
- cleanup: Some(_),
- ..
- }, source_info
- }) if pred_count[*destination] > 1 => {
- // It's a critical edge, break it
- let call_guard = BasicBlockData {
- statements: vec![],
- is_cleanup: block.is_cleanup,
- terminator: Some(Terminator {
- source_info: source_info,
- kind: TerminatorKind::Goto { target: *destination }
- })
- };
+ for block in mir.basic_blocks_mut() {
+ match block.terminator {
+ Some(Terminator {
+ kind: TerminatorKind::Call {
+ destination: Some((_, ref mut destination)),
+ cleanup,
+ ..
+ }, source_info
+ }) if pred_count[*destination] > 1 &&
+ (cleanup.is_some() || self == &AllCallEdges) =>
+ {
+ // It's a critical edge, break it
+ let call_guard = BasicBlockData {
+ statements: vec![],
+ is_cleanup: block.is_cleanup,
+ terminator: Some(Terminator {
+ source_info: source_info,
+ kind: TerminatorKind::Goto { target: *destination }
+ })
+ };
- // Get the index it will be when inserted into the MIR
- let idx = cur_len + new_blocks.len();
- new_blocks.push(call_guard);
- *destination = BasicBlock::new(idx);
+ // Get the index it will be when inserted into the MIR
+ let idx = cur_len + new_blocks.len();
+ new_blocks.push(call_guard);
+ *destination = BasicBlock::new(idx);
+ }
+ _ => {}
}
- _ => {}
}
- }
- debug!("Broke {} N edges", new_blocks.len());
+ debug!("Broke {} N edges", new_blocks.len());
- mir.basic_blocks_mut().extend(new_blocks);
+ mir.basic_blocks_mut().extend(new_blocks);
+ }
}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-use rustc::ty::TyCtxt;
-use rustc::mir::Mir;
-use rustc::mir::visit::MutVisitor;
+use rustc::ty::TypeFoldable;
+use rustc::ty::subst::{Kind, Substs};
+use rustc::ty::{Ty, TyCtxt, ClosureSubsts, RegionVid, RegionKind};
+use rustc::mir::{Mir, Location, Rvalue, BasicBlock, Statement, StatementKind};
+use rustc::mir::visit::{MutVisitor, Lookup};
use rustc::mir::transform::{MirPass, MirSource};
+use rustc::infer::{self, InferCtxt};
+use syntax_pos::DUMMY_SP;
+use std::collections::HashMap;
#[allow(dead_code)]
-struct NLLVisitor<'a, 'tcx: 'a> {
- tcx: TyCtxt<'a, 'tcx, 'tcx>,
+struct NLLVisitor<'a, 'gcx: 'a + 'tcx, 'tcx: 'a> {
+ lookup_map: HashMap<RegionVid, Lookup>,
+ infcx: InferCtxt<'a, 'gcx, 'tcx>,
}
-impl<'a, 'tcx> NLLVisitor<'a, 'tcx> {
- pub fn new(tcx: TyCtxt<'a, 'tcx, 'tcx>) -> Self {
+impl<'a, 'gcx, 'tcx> NLLVisitor<'a, 'gcx, 'tcx> {
+ pub fn new(infcx: InferCtxt<'a, 'gcx, 'tcx>) -> Self {
NLLVisitor {
- tcx: tcx
+ infcx: infcx,
+ lookup_map: HashMap::new(),
+ }
+ }
+
+ pub fn into_results(self) -> HashMap<RegionVid, Lookup> {
+ self.lookup_map
+ }
+
+ fn renumber_regions<T>(&self, value: &T) -> T where T: TypeFoldable<'tcx> {
+ self.infcx.tcx.fold_regions(value, &mut false, |_region, _depth| {
+ self.infcx.next_region_var(infer::MiscVariable(DUMMY_SP))
+ })
+ }
+
+ fn store_region(&mut self, region: &RegionKind, lookup: Lookup) {
+ if let RegionKind::ReVar(rid) = *region {
+ self.lookup_map.entry(rid).or_insert(lookup);
+ }
+ }
+
+ fn store_ty_regions(&mut self, ty: &Ty<'tcx>, lookup: Lookup) {
+ for region in ty.regions() {
+ self.store_region(region, lookup);
+ }
+ }
+
+ fn store_kind_regions(&mut self, kind: &'tcx Kind, lookup: Lookup) {
+ if let Some(ty) = kind.as_type() {
+ self.store_ty_regions(&ty, lookup);
+ } else if let Some(region) = kind.as_region() {
+ self.store_region(region, lookup);
}
}
}
-impl<'a, 'tcx> MutVisitor<'tcx> for NLLVisitor<'a, 'tcx> {
- // FIXME: Nashenas88: implement me!
+impl<'a, 'gcx, 'tcx> MutVisitor<'tcx> for NLLVisitor<'a, 'gcx, 'tcx> {
+ fn visit_ty(&mut self, ty: &mut Ty<'tcx>, lookup: Lookup) {
+ let old_ty = *ty;
+ *ty = self.renumber_regions(&old_ty);
+ self.store_ty_regions(ty, lookup);
+ }
+
+ fn visit_substs(&mut self, substs: &mut &'tcx Substs<'tcx>, location: Location) {
+ *substs = self.renumber_regions(&{*substs});
+ let lookup = Lookup::Loc(location);
+ for kind in *substs {
+ self.store_kind_regions(kind, lookup);
+ }
+ }
+
+ fn visit_rvalue(&mut self, rvalue: &mut Rvalue<'tcx>, location: Location) {
+ match *rvalue {
+ Rvalue::Ref(ref mut r, _, _) => {
+ let old_r = *r;
+ *r = self.renumber_regions(&old_r);
+ let lookup = Lookup::Loc(location);
+ self.store_region(r, lookup);
+ }
+ Rvalue::Use(..) |
+ Rvalue::Repeat(..) |
+ Rvalue::Len(..) |
+ Rvalue::Cast(..) |
+ Rvalue::BinaryOp(..) |
+ Rvalue::CheckedBinaryOp(..) |
+ Rvalue::UnaryOp(..) |
+ Rvalue::Discriminant(..) |
+ Rvalue::NullaryOp(..) |
+ Rvalue::Aggregate(..) => {
+ // These variants don't contain regions.
+ }
+ }
+ self.super_rvalue(rvalue, location);
+ }
+
+ fn visit_closure_substs(&mut self,
+ substs: &mut ClosureSubsts<'tcx>,
+ location: Location) {
+ *substs = self.renumber_regions(substs);
+ let lookup = Lookup::Loc(location);
+ for kind in substs.substs {
+ self.store_kind_regions(kind, lookup);
+ }
+ }
+
+ fn visit_statement(&mut self,
+ block: BasicBlock,
+ statement: &mut Statement<'tcx>,
+ location: Location) {
+ if let StatementKind::EndRegion(_) = statement.kind {
+ statement.kind = StatementKind::Nop;
+ }
+ self.super_statement(block, statement, location);
+ }
}
// MIR Pass for non-lexical lifetimes
tcx: TyCtxt<'a, 'tcx, 'tcx>,
_: MirSource,
mir: &mut Mir<'tcx>) {
- if tcx.sess.opts.debugging_opts.nll {
- // Clone mir so we can mutate it without disturbing the rest
- // of the compiler
- NLLVisitor::new(tcx).visit_mir(&mut mir.clone());
+ if !tcx.sess.opts.debugging_opts.nll {
+ return;
}
+
+ tcx.infer_ctxt().enter(|infcx| {
+ // Clone mir so we can mutate it without disturbing the rest of the compiler
+ let mut renumbered_mir = mir.clone();
+ let mut visitor = NLLVisitor::new(infcx);
+ visitor.visit_mir(&mut renumbered_mir);
+ let _results = visitor.into_results();
+ })
}
}
\ No newline at end of file
use rustc::hir::def_id::{DefId, CrateNum, LOCAL_CRATE, INVALID_CRATE, CRATE_DEF_INDEX};
use rustc::session::config;
use rustc::ty::TyCtxt;
+use rustc_allocator::ALLOCATOR_METHODS;
use syntax::attr;
/// The SymbolExportLevel of a symbols specifies from which kinds of crates
SymbolExportLevel::C));
}
+ if tcx.sess.allocator_kind.get().is_some() {
+ for method in ALLOCATOR_METHODS {
+ local_crate.push((format!("__rust_{}", method.name),
+ INVALID_DEF_ID,
+ SymbolExportLevel::Rust));
+ }
+ }
+
if let Some(id) = tcx.sess.derive_registrar_fn.get() {
let def_id = tcx.hir.local_def_id(id);
let idx = def_id.index;
// inside a loop at all, which is caught by the
// loop-checking pass.
assert!(self.tcx.sess.err_count() > 0);
+
+ // We still need to assign a type to the inner expression to
+ // prevent the ICE in #43162.
+ if let Some(ref e) = *expr_opt {
+ self.check_expr_with_hint(e, tcx.types.err);
+
+ // ... except when we try to 'break rust;'.
+ // ICE this expression in particular (see #43162).
+ if let hir::ExprPath(hir::QPath::Resolved(_, ref path)) = e.node {
+ if path.segments.len() == 1 && path.segments[0].name == "rust" {
+ fatally_break_rust(self.tcx.sess);
+ }
+ }
+ }
}
// the type of a `break` is always `!`, since it diverges
}
}
}
+
+fn fatally_break_rust(sess: &Session) {
+ let handler = sess.diagnostic();
+ handler.span_bug_no_panic(
+ MultiSpan::new(),
+ "It looks like you're trying to break rust; would you like some ICE?",
+ );
+ handler.note_without_error("the compiler expectedly panicked. this is a feature.");
+ handler.note_without_error(
+ "we would appreciate a joke overview: \
+ https://github.com/rust-lang/rust/issues/43162#issuecomment-320764675"
+ );
+ handler.note_without_error(&format!("rustc {} running on {}",
+ option_env!("CFG_VERSION").unwrap_or("unknown_version"),
+ ::session::config::host_triple(),
+ ));
+}
"##,
E0122: r##"
-An attempt was made to add a generic constraint to a type alias. While Rust will
-allow this with a warning, it will not currently enforce the constraint.
-Consider the example below:
+An attempt was made to add a generic constraint to a type alias. This constraint
+is entirely ignored. For backwards compatibility, Rust still allows this with a
+warning. Consider the example below:
```
trait Foo{}
if !types.is_empty() {
write!(w, "
- <h2 id='associated-types' class='section-header'>
- <a href='#associated-types'>Associated Types</a>
+ <h2 id='associated-types' class='small-section-header'>
+ Associated Types<a href='#associated-types' class='anchor'></a>
</h2>
<div class='methods'>
")?;
if !consts.is_empty() {
write!(w, "
- <h2 id='associated-const' class='section-header'>
- <a href='#associated-const'>Associated Constants</a>
+ <h2 id='associated-const' class='small-section-header'>
+ Associated Constants<a href='#associated-const' class='anchor'></a>
</h2>
<div class='methods'>
")?;
// Output the documentation for each function individually
if !required.is_empty() {
write!(w, "
- <h2 id='required-methods' class='section-header'>
- <a href='#required-methods'>Required Methods</a>
+ <h2 id='required-methods' class='small-section-header'>
+ Required Methods<a href='#required-methods' class='anchor'></a>
</h2>
<div class='methods'>
")?;
}
if !provided.is_empty() {
write!(w, "
- <h2 id='provided-methods' class='section-header'>
- <a href='#provided-methods'>Provided Methods</a>
+ <h2 id='provided-methods' class='small-section-header'>
+ Provided Methods<a href='#provided-methods' class='anchor'></a>
</h2>
<div class='methods'>
")?;
let cache = cache();
write!(w, "
- <h2 id='implementors' class='section-header'>
- <a href='#implementors'>Implementors</a>
+ <h2 id='implementors' class='small-section-header'>
+ Implementors<a href='#implementors' class='anchor'></a>
</h2>
<ul class='item-list' id='implementors-list'>
")?;
}).peekable();
if let doctree::Plain = s.struct_type {
if fields.peek().is_some() {
- write!(w, "<h2 id='fields' class='fields section-header'>
- <a href='#fields'>Fields</a></h2>")?;
+ write!(w, "<h2 id='fields' class='fields small-section-header'>
+ Fields<a href='#fields' class='anchor'></a></h2>")?;
for (field, ty) in fields {
let id = derive_id(format!("{}.{}",
ItemType::StructField,
}
}).peekable();
if fields.peek().is_some() {
- write!(w, "<h2 id='fields' class='fields section-header'>
- <a href='#fields'>Fields</a></h2>")?;
+ write!(w, "<h2 id='fields' class='fields small-section-header'>
+ Fields<a href='#fields' class='anchor'></a></h2>")?;
for (field, ty) in fields {
write!(w, "<span id='{shortty}.{name}' class=\"{shortty}\"><code>{name}: {ty}</code>
</span>",
document(w, cx, it)?;
if !e.variants.is_empty() {
- write!(w, "<h2 id='variants' class='variants section-header'>
- <a href='#variants'>Variants</a></h2>\n")?;
+ write!(w, "<h2 id='variants' class='variants small-section-header'>
+ Variants<a href='#variants' class='anchor'></a></h2>\n")?;
for variant in &e.variants {
let id = derive_id(format!("{}.{}",
ItemType::Variant,
let render_mode = match what {
AssocItemRender::All => {
write!(w, "
- <h2 id='methods' class='section-header'>
- <a href='#methods'>Methods</a>
+ <h2 id='methods' class='small-section-header'>
+ Methods<a href='#methods' class='anchor'></a>
</h2>
")?;
RenderMode::Normal
}
AssocItemRender::DerefFor { trait_, type_, deref_mut_ } => {
write!(w, "
- <h2 id='deref-methods' class='section-header'>
- <a href='#deref-methods'>Methods from {}<Target = {}></a>
+ <h2 id='deref-methods' class='small-section-header'>
+ Methods from {}<Target = {}><a href='#deref-methods' class='anchor'></a>
</h2>
", trait_, type_)?;
RenderMode::ForDeref { mut_: deref_mut_ }
render_deref_methods(w, cx, impl_, containing_item, has_deref_mut)?;
}
write!(w, "
- <h2 id='implementations' class='section-header'>
- <a href='#implementations'>Trait Implementations</a>
+ <h2 id='implementations' class='small-section-header'>
+ Trait Implementations<a href='#implementations' class='anchor'></a>
</h2>
")?;
for i in &traits {
background: transparent;
}
+.small-section-header:hover > .anchor {
+ display: initial;
+}
+.anchor {
+ display: none;
+}
+.anchor:after {
+ content: '\2002\00a7\2002';
+}
+
.docblock a:hover, .docblock-short a:hover, .stability a {
text-decoration: underline;
}
left: 0;
}
+.variant + .toggle-wrapper + .docblock > p {
+ margin-top: 5px;
+}
+
.variant + .toggle-wrapper > a {
margin-top: 5px;
}
margin-bottom: 25px;
}
-.enum .variant, .struct .structfield, .union .structfield {
+#main > .variant, #main > .structfield {
display: block;
}
/// A reference to an open file on the filesystem.
///
/// An instance of a `File` can be read and/or written depending on what options
-/// it was opened with. Files also implement `Seek` to alter the logical cursor
+/// it was opened with. Files also implement [`Seek`] to alter the logical cursor
/// that the file contains internally.
///
/// Files are automatically closed when they go out of scope.
/// # }
/// ```
///
-/// Read the contents of a file into a `String`:
+/// Read the contents of a file into a [`String`]:
///
/// ```no_run
/// use std::fs::File;
/// # }
/// ```
///
+/// [`Seek`]: ../io/trait.Seek.html
+/// [`String`]: ../string/struct.String.html
/// [`Read`]: ../io/trait.Read.html
/// [`BufReader<R>`]: ../io/struct.BufReader.html
#[stable(feature = "rust1", since = "1.0.0")]
/// Iterator over the entries in a directory.
///
/// This iterator is returned from the [`read_dir`] function of this module and
-/// will yield instances of `io::Result<DirEntry>`. Through a [`DirEntry`]
+/// will yield instances of [`io::Result`]`<`[`DirEntry`]`>`. Through a [`DirEntry`]
/// information like the entry's path and possibly other metadata can be
/// learned.
///
-/// [`read_dir`]: fn.read_dir.html
-/// [`DirEntry`]: struct.DirEntry.html
-///
/// # Errors
///
-/// This [`io::Result`] will be an `Err` if there's some sort of intermittent
+/// This [`io::Result`] will be an [`Err`] if there's some sort of intermittent
/// IO error during iteration.
///
+/// [`read_dir`]: fn.read_dir.html
+/// [`DirEntry`]: struct.DirEntry.html
/// [`io::Result`]: ../io/type.Result.html
+/// [`Err`]: ../result/enum.Result.html#variant.Err
#[stable(feature = "rust1", since = "1.0.0")]
#[derive(Debug)]
pub struct ReadDir(fs_imp::ReadDir);
/// A specialized [`Result`](../result/enum.Result.html) type for I/O
/// operations.
///
-/// This type is broadly used across `std::io` for any operation which may
+/// This type is broadly used across [`std::io`] for any operation which may
/// produce an error.
///
-/// This typedef is generally used to avoid writing out `io::Error` directly and
-/// is otherwise a direct mapping to `Result`.
+/// This typedef is generally used to avoid writing out [`io::Error`] directly and
+/// is otherwise a direct mapping to [`Result`].
///
-/// While usual Rust style is to import types directly, aliases of `Result`
-/// often are not, to make it easier to distinguish between them. `Result` is
-/// generally assumed to be `std::result::Result`, and so users of this alias
+/// While usual Rust style is to import types directly, aliases of [`Result`]
+/// often are not, to make it easier to distinguish between them. [`Result`] is
+/// generally assumed to be [`std::result::Result`][`Result`], and so users of this alias
/// will generally use `io::Result` instead of shadowing the prelude's import
-/// of `std::result::Result`.
+/// of [`std::result::Result`][`Result`].
+///
+/// [`std::io`]: ../io/index.html
+/// [`io::Error`]: ../io/struct.Error.html
+/// [`Result`]: ../result/enum.Result.html
///
/// # Examples
///
#[stable(feature = "rust1", since = "1.0.0")]
pub type Result<T> = result::Result<T, Error>;
-/// The error type for I/O operations of the `Read`, `Write`, `Seek`, and
+/// The error type for I/O operations of the [`Read`], [`Write`], [`Seek`], and
/// associated traits.
///
/// Errors mostly originate from the underlying OS, but custom instances of
/// `Error` can be created with crafted error messages and a particular value of
/// [`ErrorKind`].
///
+/// [`Read`]: ../io/trait.Read.html
+/// [`Write`]: ../io/trait.Write.html
+/// [`Seek`]: ../io/trait.Seek.html
/// [`ErrorKind`]: enum.ErrorKind.html
#[derive(Debug)]
#[stable(feature = "rust1", since = "1.0.0")]
//! you'll see a few different types of I/O throughout the documentation in
//! this module: [`File`]s, [`TcpStream`]s, and sometimes even [`Vec<T>`]s. For
//! example, [`Read`] adds a [`read`][`Read::read`] method, which we can use on
-//! `File`s:
+//! [`File`]s:
//!
//! ```
//! use std::io;
//! # }
//! ```
//!
-//! Note that you cannot use the `?` operator in functions that do not return
-//! a `Result<T, E>` (e.g. `main`). Instead, you can call `.unwrap()` or `match`
-//! on the return value to catch any possible errors:
+//! Note that you cannot use the [`?` operator] in functions that do not return
+//! a [`Result<T, E>`][`Result`] (e.g. `main`). Instead, you can call [`.unwrap()`]
+//! or `match` on the return value to catch any possible errors:
//!
//! ```
//! use std::io;
//! [`io::Result`]: type.Result.html
//! [`?` operator]: ../../book/first-edition/syntax-index.html
//! [`Read::read`]: trait.Read.html#tymethod.read
+//! [`Result`]: ../result/enum.Result.html
+//! [`.unwrap()`]: ../result/enum.Result.html#method.unwrap
#![stable(feature = "rust1", since = "1.0.0")]
#![default_lib_allocator]
+// Always use alloc_system during stage0 since we don't know if the alloc_*
+// crate the stage0 compiler will pick by default is enabled (e.g.
+// if the user has disabled jemalloc in `./configure`).
+// `force_alloc_system` is *only* intended as a workaround for local rebuilds
+// with a rustc without jemalloc.
+// The not(stage0+msvc) gates will only last until the next stage0 bump
+#![cfg_attr(all(
+ not(all(stage0, target_env = "msvc")),
+ any(stage0, feature = "force_alloc_system")),
+ feature(global_allocator))]
+#[cfg(all(
+ not(all(stage0, target_env = "msvc")),
+ any(stage0, feature = "force_alloc_system")))]
+#[global_allocator]
+static ALLOC: alloc_system::System = alloc_system::System;
+
// Explicitly import the prelude. The compiler uses this same unstable attribute
// to import the prelude implicitly when building crates that depend on std.
#[prelude_import]
/// - test addresses used for documentation (192.0.2.0/24, 198.51.100.0/24 and 203.0.113.0/24)
/// - the unspecified address (0.0.0.0)
///
- /// [ipv4-sr]: http://goo.gl/RaZ7lg
+ /// [ipv4-sr]: https://www.iana.org/assignments/iana-ipv4-special-registry/iana-ipv4-special-registry.xhtml
/// [`true`]: ../../std/primitive.bool.html
///
/// # Examples
/// Accepts a new incoming connection to this listener.
///
/// This function will block the calling thread until a new Unix connection
- /// is established. When established, the corersponding [`UnixStream`] and
+ /// is established. When established, the corresponding [`UnixStream`] and
/// the remote peer's address will be returned.
///
/// [`UnixStream`]: ../../../../std/os/unix/net/struct.UnixStream.html
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-pub use self::SyntaxExtension::{MultiDecorator, MultiModifier, NormalTT, IdentTT};
+pub use self::SyntaxExtension::*;
use ast::{self, Attribute, Name, PatKind, MetaItem};
use attr::HasAttrs;
let item = match self.cx.resolver.resolve_macro(
Mark::root(), path, MacroKind::Derive, false) {
Ok(ext) => match *ext {
- SyntaxExtension::BuiltinDerive(..) => item_with_markers.clone(),
+ BuiltinDerive(..) => item_with_markers.clone(),
_ => item.clone(),
},
_ => item.clone(),
items.push(item);
kind.expect_from_annotatables(items)
}
- SyntaxExtension::AttrProcMacro(ref mac) => {
+ AttrProcMacro(ref mac) => {
let item_tok = TokenTree::Token(DUMMY_SP, Token::interpolated(match item {
Annotatable::Item(item) => token::NtItem(item),
Annotatable::TraitItem(item) => token::NtTraitItem(item.unwrap()),
let tok_result = mac.expand(self.cx, attr.span, attr.tokens, item_tok);
self.parse_expansion(tok_result, kind, &attr.path, attr.span)
}
- SyntaxExtension::ProcMacroDerive(..) | SyntaxExtension::BuiltinDerive(..) => {
+ ProcMacroDerive(..) | BuiltinDerive(..) => {
self.cx.span_err(attr.span, &format!("`{}` is a derive mode", attr.path));
kind.dummy(attr.span)
}
};
let opt_expanded = match *ext {
- SyntaxExtension::DeclMacro(ref expand, def_span) => {
+ DeclMacro(ref expand, def_span) => {
if let Err(msg) = validate_and_set_expn_info(def_span.map(|(_, s)| s),
false) {
self.cx.span_err(path.span, &msg);
kind.make_from(expander.expand(self.cx, span, ident, input))
}
- MultiDecorator(..) | MultiModifier(..) | SyntaxExtension::AttrProcMacro(..) => {
+ MultiDecorator(..) | MultiModifier(..) | AttrProcMacro(..) => {
self.cx.span_err(path.span,
&format!("`{}` can only be used in attributes", path));
return kind.dummy(span);
}
- SyntaxExtension::ProcMacroDerive(..) | SyntaxExtension::BuiltinDerive(..) => {
+ ProcMacroDerive(..) | BuiltinDerive(..) => {
self.cx.span_err(path.span, &format!("`{}` is a derive mode", path));
return kind.dummy(span);
}
- SyntaxExtension::ProcMacro(ref expandfun) => {
+ ProcMacro(ref expandfun) => {
if ident.name != keywords::Invalid.name() {
let msg =
format!("macro {}! expects no ident argument, given '{}'", path, ident);
};
match *ext {
- SyntaxExtension::ProcMacroDerive(ref ext, _) => {
+ ProcMacroDerive(ref ext, _) => {
invoc.expansion_data.mark.set_expn_info(expn_info);
let span = Span { ctxt: self.cx.backtrace(), ..span };
let dummy = ast::MetaItem { // FIXME(jseyfried) avoid this
};
kind.expect_from_annotatables(ext.expand(self.cx, span, &dummy, item))
}
- SyntaxExtension::BuiltinDerive(func) => {
+ BuiltinDerive(func) => {
expn_info.callee.allow_internal_unstable = true;
invoc.expansion_data.mark.set_expn_info(expn_info);
let span = Span { ctxt: self.cx.backtrace(), ..span };
('։', "Armenian Full Stop", ':'),
('܃', "Syriac Supralinear Colon", ':'),
('܄', "Syriac Sublinear Colon", ':'),
- ('᛬', "Runic Multiple Ponctuation", ':'),
+ ('᛬', "Runic Multiple Punctuation", ':'),
('︰', "Presentation Form For Vertical Two Dot Leader", ':'),
('᠃', "Mongolian Full Stop", ':'),
('᠉', "Mongolian Manchu Full Stop", ':'),
('ꝸ', "Latin Small Letter Um", '&'),
('&', "Fullwidth Ampersand", '&'),
- ('᛭', "Runic Cros Punctuation", '+'),
+ ('᛭', "Runic Cross Punctuation", '+'),
('➕', "Heavy Plus Sign", '+'),
('𐊛', "Lycian Letter H", '+'),
('﬩', "Hebrew Letter Alternative Plus Sign", '+'),
// except according to those terms.
// aux-build:attribute-with-error.rs
+// ignore-stage1
#![feature(proc_macro)]
// except according to those terms.
// aux-build:attributes-included.rs
+// ignore-stage1
#![feature(proc_macro, rustc_attrs)]
#![warn(unused)]
// except according to those terms.
// aux-build:derive-bad.rs
+// ignore-stage1
#[macro_use]
extern crate derive_bad;
// except according to those terms.
// aux-build:derive-unstable-2.rs
+// ignore-stage1
#![allow(warnings)]
// except according to those terms.
// aux-build:derive-unstable.rs
+// ignore-stage1
#![allow(warnings)]
// except according to those terms.
// aux-build:issue_38586.rs
+// ignore-stage1
#![feature(proc_macro)]
// except according to those terms.
// aux-build:derive-b.rs
+// ignore-stage1
#![allow(warnings)]
// except according to those terms.
// aux-build:bang_proc_macro2.rs
+// ignore-stage1
#![feature(proc_macro)]
#![allow(unused_macros)]
// except according to those terms.
// aux-build:derive-b.rs
+// ignore-stage1
#![allow(warnings)]
--- /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() -> bool {
+ break true; //~ ERROR E0268
+}
+
+fn main() {
+ break {}; //~ ERROR E0268
+}
// except according to those terms.
// ignore-tidy-linelength
-// compile-flags: -Z verbose -Z mir-emit-validate=1
+// compile-flags: -Z verbose -Z mir-emit-validate=1 -Z span_free_formats
struct Test(i32);
fn main() {
let mut x = 0;
- Test(0).foo(&mut x);
+ Test(0).foo(&mut x); // just making sure we do not panic when there is a tuple struct ctor
// Also test closures
let c = |x: &mut i32| { let y = &*x; *y };
c(&mut x);
}
-// FIXME: Also test code generated inside the closure, make sure it has validation. Unfortunately,
-// the interesting lines of code also contain name of the source file, so we cannot test for it.
-
// END RUST SOURCE
// START rustc.node12.EraseRegions.after.mir
// bb0: {
// }
// }
// END rustc.node23.EraseRegions.after.mir
+// START rustc.node50.EraseRegions.after.mir
+// fn main::{{closure}}(_1: &ReErased [closure@NodeId(50)], _2: &ReErased mut i32) -> i32 {
+// bb0: {
+// Validate(Acquire, [_1: &ReFree(DefId { krate: CrateNum(0), node: DefIndex(2147483663) => validate_1/8cd878b::main[0]::{{closure}}[0] }, "BrEnv") [closure@NodeId(50)], _2: &ReFree(DefId { krate: CrateNum(0), node: DefIndex(2147483663) => validate_1/8cd878b::main[0]::{{closure}}[0] }, BrAnon(1)) mut i32]);
+// StorageLive(_3);
+// _3 = _2;
+// StorageLive(_4);
+// Validate(Suspend(ReScope(Remainder(BlockRemainder { block: NodeId(41), first_statement_index: 0 }))), [(*_3): i32]);
+// _4 = &ReErased (*_3);
+// Validate(Acquire, [(*_4): i32/ReScope(Remainder(BlockRemainder { block: NodeId(41), first_statement_index: 0 })) (imm)]);
+// StorageLive(_5);
+// _5 = (*_4);
+// _0 = _5;
+// StorageDead(_5);
+// StorageDead(_4);
+// EndRegion(ReScope(Remainder(BlockRemainder { block: NodeId(41), first_statement_index: 0 })));
+// StorageDead(_3);
+// return;
+// }
+// }
+// END rustc.node50.EraseRegions.after.mir
// except according to those terms.
// ignore-tidy-linelength
-// compile-flags: -Z verbose -Z mir-emit-validate=1
+// compile-flags: -Z verbose -Z mir-emit-validate=1 -Z span_free_formats
// Make sure unsafe fns and fns with an unsafe block only get restricted validation.
// }
// }
// END rustc.node4.EraseRegions.after.mir
+// START rustc.node22.EraseRegions.after.mir
+// fn write_42::{{closure}}(_1: &ReErased [closure@NodeId(22)], _2: *mut i32) -> () {
+// bb0: {
+// Validate(Acquire, [_1: &ReFree(DefId { krate: CrateNum(0), node: DefIndex(2147483659) => validate_4/8cd878b::write_42[0]::{{closure}}[0] }, "BrEnv") [closure@NodeId(22)], _2: *mut i32]);
+// Validate(Release, [_1: &ReFree(DefId { krate: CrateNum(0), node: DefIndex(2147483659) => validate_4/8cd878b::write_42[0]::{{closure}}[0] }, "BrEnv") [closure@NodeId(22)], _2: *mut i32]);
+// StorageLive(_3);
+// _3 = _2;
+// (*_3) = const 23i32;
+// StorageDead(_3);
+// return;
+// }
+// }
+// END rustc.node22.EraseRegions.after.mir
// START rustc.node31.EraseRegions.after.mir
// fn test(_1: &ReErased mut i32) -> () {
// bb0: {
// }
// }
// END rustc.node31.EraseRegions.after.mir
+// START rustc.node60.EraseRegions.after.mir
+// fn main::{{closure}}(_1: &ReErased [closure@NodeId(60)], _2: &ReErased mut i32) -> bool {
+// bb0: {
+// Validate(Acquire, [_1: &ReFree(DefId { krate: CrateNum(0), node: DefIndex(2147483663) => validate_4/8cd878b::main[0]::{{closure}}[0] }, "BrEnv") [closure@NodeId(60)], _2: &ReFree(DefId { krate: CrateNum(0), node: DefIndex(2147483663) => validate_4/8cd878b::main[0]::{{closure}}[0] }, BrAnon(1)) mut i32]);
+// Validate(Release, [_1: &ReFree(DefId { krate: CrateNum(0), node: DefIndex(2147483663) => validate_4/8cd878b::main[0]::{{closure}}[0] }, "BrEnv") [closure@NodeId(60)], _2: &ReFree(DefId { krate: CrateNum(0), node: DefIndex(2147483663) => validate_4/8cd878b::main[0]::{{closure}}[0] }, BrAnon(1)) mut i32]);
+// StorageLive(_3);
+// _0 = const write_42(_4) -> bb1;
+// }
+// }
+// END rustc.node60.EraseRegions.after.mir
// except according to those terms.
// ignore-tidy-linelength
-// compile-flags: -Z verbose -Z mir-emit-validate=2
+// compile-flags: -Z verbose -Z mir-emit-validate=2 -Z span_free_formats
-// Make sure unsafe fns and fns with an unsafe block only get full validation.
+// Make sure unsafe fns and fns with an unsafe block still get full validation.
unsafe fn write_42(x: *mut i32) -> bool {
*x = 42;
test(&mut 0);
let test_closure = unsafe { |x: &mut i32| write_42(x) };
+ // Note that validation will fail if this is executed: The closure keeps the lock on
+ // x, so the write in write_42 fails. This test just checks code generation,
+ // so the UB doesn't matter.
test_closure(&mut 0);
}
-// FIXME: Also test code generated inside the closure, make sure it has validation. Unfortunately,
-// the interesting lines of code also contain name of the source file, so we cannot test for it.
-
// END RUST SOURCE
// START rustc.node17.EraseRegions.after.mir
// fn test(_1: &ReErased mut i32) -> () {
// }
// }
// END rustc.node17.EraseRegions.after.mir
+// START rustc.node46.EraseRegions.after.mir
+// fn main::{{closure}}(_1: &ReErased [closure@NodeId(46)], _2: &ReErased mut i32) -> bool {
+// bb0: {
+// Validate(Acquire, [_1: &ReFree(DefId { krate: CrateNum(0), node: DefIndex(2147483660) => validate_5/8cd878b::main[0]::{{closure}}[0] }, "BrEnv") [closure@NodeId(46)], _2: &ReFree(DefId { krate: CrateNum(0), node: DefIndex(2147483660) => validate_5/8cd878b::main[0]::{{closure}}[0] }, BrAnon(1)) mut i32]);
+// StorageLive(_3);
+// _3 = _2;
+// StorageLive(_4);
+// StorageLive(_5);
+// Validate(Suspend(ReScope(Misc(NodeId(44)))), [(*_3): i32]);
+// _5 = &ReErased mut (*_3);
+// Validate(Acquire, [(*_5): i32/ReScope(Misc(NodeId(44)))]);
+// _4 = _5 as *mut i32 (Misc);
+// StorageDead(_5);
+// EndRegion(ReScope(Misc(NodeId(44))));
+// Validate(Release, [_0: bool, _4: *mut i32]);
+// _0 = const write_42(_4) -> bb1;
+// }
+// }
+// END rustc.node46.EraseRegions.after.mir
-include ../tools.mk
+ifeq ($(findstring stage1,$(RUST_BUILD_STAGE)),stage1)
+# ignore stage1
+all:
+
+else
all:
$(RUSTC) a.rs && $(RUSTC) b.rs
$(BARE_RUSTC) c.rs -L dependency=$(TMPDIR) --extern b=$(TMPDIR)/libb.rlib \
--out-dir=$(TMPDIR)
+endif
-include ../tools.mk
+ifeq ($(findstring stage1,$(RUST_BUILD_STAGE)),stage1)
+# ignore stage1
+all:
+
+else
all:
$(RUSTC) a.rs && $(RUSTC) b.rs && $(RUSTC) c.rs
+endif
-include ../tools.mk
+ifeq ($(findstring stage1,$(RUST_BUILD_STAGE)),stage1)
+# ignore stage1
+all:
+
+else
all:
$(RUSTC) foo.rs; $(RUSTC) bar.rs
$(RUSTDOC) baz.rs -L $(TMPDIR) -o $(TMPDIR)
+endif
-include ../tools.mk
+ifeq ($(findstring stage1,$(RUST_BUILD_STAGE)),stage1)
+# ignore stage1
+all:
+
+else
# Windows doesn't correctly handle include statements with escaping paths,
# so this test will not get run on Windows.
ifdef IS_WINDOWS
$(TMPDIR)/libllvm-module-pass.o:
$(CXX) $(CFLAGS) $(LLVM_CXXFLAGS) -c llvm-module-pass.so.cc -o $(TMPDIR)/libllvm-module-pass.o
endif
+
+endif
-include ../tools.mk
+ifeq ($(findstring stage1,$(RUST_BUILD_STAGE)),stage1)
+# ignore stage1
+all:
+
+else
all:
$(RUSTC) foo.rs
$(RUSTC) bar.rs --emit dep-info
grep "proc-macro source" $(TMPDIR)/bar.d && exit 1 || exit 0
+endif
// except according to those terms.
// aux-build:custom_derive_plugin.rs
+// ignore-stage1
#![feature(plugin, custom_derive)]
#![plugin(custom_derive_plugin)]
// except according to those terms.
// aux-build:add-impl.rs
+// ignore-stage1
#[macro_use]
extern crate add_impl;
// except according to those terms.
// aux-build:append-impl.rs
+// ignore-stage1
#![allow(warnings)]
// except according to those terms.
// aux-build:attr-args.rs
+// ignore-stage1
#![allow(warnings)]
#![feature(proc_macro)]
// except according to those terms.
// aux-build:bang-macro.rs
+// ignore-stage1
#![feature(proc_macro)]
// except according to those terms.
// aux-build:count_compound_ops.rs
+// ignore-stage1
#![feature(proc_macro)]
// except according to those terms.
// aux-build:double.rs
+// ignore-stage1
#![allow(unused)]
// except according to those terms.
// aux-build:derive-same-struct.rs
+// ignore-stage1
#[macro_use]
extern crate derive_same_struct;
// aux-build:hygiene_example_codegen.rs
// aux-build:hygiene_example.rs
+// ignore-stage1
#![feature(proc_macro)]
// except according to those terms.
// aux-build:issue-39889.rs
+// ignore-stage1
#![feature(proc_macro)]
#![allow(unused)]
// except according to those terms.
// aux-build:issue-40001-plugin.rs
+// ignore-stage1
#![feature(proc_macro, plugin)]
#![plugin(issue_40001_plugin)]
// aux-build:derive-atob.rs
// aux-build:derive-ctod.rs
+// ignore-stage1
#[macro_use]
extern crate derive_atob;
// aux-build:derive-a.rs
// aux-build:derive-reexport.rs
+// ignore-stage1
#[macro_use]
extern crate derive_reexport;
panic!("from outer");
};
assert_eq!(break_from_while_to_outer, 567);
+
+ let rust = true;
+ let value = loop {
+ break rust;
+ };
+ assert!(value);
}
assert!(g != h);
assert!(g != i);
assert!(h != i);
+
+ // Make sure lifetime anonymization handles nesting correctly
+ let j = TypeId::of::<fn(for<'a> fn(&'a isize) -> &'a usize)>();
+ let k = TypeId::of::<fn(for<'b> fn(&'b isize) -> &'b usize)>();
+ assert_eq!(j, k);
}
// Boxed unboxed closures
{
String::<>::from::<>("><>").chars::<>().rev::<>().collect::<String>());
}
+fn union() {
+ union union<'union> { union: &'union union<'union>, }
+}
+
pub fn main() {
strange();
funny();
dots();
you_eight();
fishy();
+ union();
}
"src/libstd/path.rs",
"src/libstd/f32.rs",
"src/libstd/f64.rs",
+ "src/libstd/lib.rs", // Until next stage0 snapshot bump
"src/libstd/sys_common/mod.rs",
"src/libstd/sys_common/net.rs",
"src/libterm", // Not sure how to make this crate portable, but test needs it
=> state = EXP_END,
(EXP_URL, w)
- if w.starts_with("http://") || w.starts_with("https://")
+ if w.starts_with("http://") || w.starts_with("https://") || w.starts_with("../")
=> state = EXP_END,
(_, _) => return false,