diff --git a/src/libcollections/fmt.rs b/src/libcollections/fmt.rs index 079541235a25e..dfd292176d2f9 100644 --- a/src/libcollections/fmt.rs +++ b/src/libcollections/fmt.rs @@ -524,6 +524,7 @@ use string; pub fn format(args: Arguments) -> string::String { let capacity = args.estimated_capacity(); let mut output = string::String::with_capacity(capacity); - let _ = output.write_fmt(args); + output.write_fmt(args) + .expect("a formatting trait implementation returned an error"); output } diff --git a/src/libcollections/macros.rs b/src/libcollections/macros.rs index 3115be00a4d72..396a917dfde26 100644 --- a/src/libcollections/macros.rs +++ b/src/libcollections/macros.rs @@ -72,6 +72,12 @@ macro_rules! vec { /// /// [fmt]: ../std/fmt/index.html /// +/// # Panics +/// +/// `format!` panics if a formatting trait implementation returns an error. +/// This indicates an incorrect implementation +/// since `fmt::Write for String` never returns an error itself. +/// /// # Examples /// /// ``` diff --git a/src/libcollections/string.rs b/src/libcollections/string.rs index 4b37aef860d72..f2e4be49684a9 100644 --- a/src/libcollections/string.rs +++ b/src/libcollections/string.rs @@ -1900,13 +1900,20 @@ pub trait ToString { fn to_string(&self) -> String; } +/// # Panics +/// +/// In this implementation, the `to_string` method panics +/// if the `Display` implementation returns an error. +/// This indicates an incorrect `Display` implementation +/// since `fmt::Write for String` never returns an error itself. #[stable(feature = "rust1", since = "1.0.0")] impl ToString for T { #[inline] default fn to_string(&self) -> String { use core::fmt::Write; let mut buf = String::new(); - let _ = buf.write_fmt(format_args!("{}", self)); + buf.write_fmt(format_args!("{}", self)) + .expect("a Display implementation return an error unexpectedly"); buf.shrink_to_fit(); buf } diff --git a/src/libproc_macro/lib.rs b/src/libproc_macro/lib.rs index b33caefbcd2ec..0516e111be3b3 100644 --- a/src/libproc_macro/lib.rs +++ b/src/libproc_macro/lib.rs @@ -125,6 +125,10 @@ pub mod __internal { fn register_attr_proc_macro(&mut self, name: &str, expand: fn(TokenStream, TokenStream) -> TokenStream); + + fn register_bang_proc_macro(&mut self, + name: &str, + expand: fn(TokenStream) -> TokenStream); } // Emulate scoped_thread_local!() here essentially diff --git a/src/librustc/mir/mod.rs b/src/librustc/mir/mod.rs index 40ebc97a78a6c..10761a03bec0c 100644 --- a/src/librustc/mir/mod.rs +++ b/src/librustc/mir/mod.rs @@ -983,7 +983,7 @@ pub enum Rvalue<'tcx> { Use(Operand<'tcx>), /// [x; 32] - Repeat(Operand<'tcx>, TypedConstVal<'tcx>), + Repeat(Operand<'tcx>, ConstUsize), /// &x or &mut x Ref(&'tcx Region, BorrowKind, Lvalue<'tcx>), @@ -1038,7 +1038,8 @@ pub enum CastKind { #[derive(Clone, Debug, PartialEq, Eq, RustcEncodable, RustcDecodable)] pub enum AggregateKind<'tcx> { - Array, + /// The type is of the element + Array(Ty<'tcx>), Tuple, /// The second field is variant number (discriminant), it's equal to 0 /// for struct and union expressions. The fourth field is active field @@ -1135,7 +1136,7 @@ impl<'tcx> Debug for Rvalue<'tcx> { } match *kind { - AggregateKind::Array => write!(fmt, "{:?}", lvs), + AggregateKind::Array(_) => write!(fmt, "{:?}", lvs), AggregateKind::Tuple => { match lvs.len() { @@ -1202,19 +1203,6 @@ pub struct Constant<'tcx> { pub literal: Literal<'tcx>, } -#[derive(Clone, RustcEncodable, RustcDecodable)] -pub struct TypedConstVal<'tcx> { - pub ty: Ty<'tcx>, - pub span: Span, - pub value: ConstUsize, -} - -impl<'tcx> Debug for TypedConstVal<'tcx> { - fn fmt(&self, fmt: &mut Formatter) -> fmt::Result { - write!(fmt, "const {}", ConstInt::Usize(self.value)) - } -} - newtype_index!(Promoted, "promoted"); #[derive(Clone, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable)] diff --git a/src/librustc/mir/tcx.rs b/src/librustc/mir/tcx.rs index 50a80305bee27..14d3876a66e55 100644 --- a/src/librustc/mir/tcx.rs +++ b/src/librustc/mir/tcx.rs @@ -134,46 +134,45 @@ impl<'tcx> Lvalue<'tcx> { } impl<'tcx> Rvalue<'tcx> { - pub fn ty<'a, 'gcx>(&self, mir: &Mir<'tcx>, tcx: TyCtxt<'a, 'gcx, 'tcx>) -> Option> + pub fn ty<'a, 'gcx>(&self, mir: &Mir<'tcx>, tcx: TyCtxt<'a, 'gcx, 'tcx>) -> Ty<'tcx> { match *self { - Rvalue::Use(ref operand) => Some(operand.ty(mir, tcx)), + Rvalue::Use(ref operand) => operand.ty(mir, tcx), Rvalue::Repeat(ref operand, ref count) => { let op_ty = operand.ty(mir, tcx); - let count = count.value.as_u64(tcx.sess.target.uint_type); + let count = count.as_u64(tcx.sess.target.uint_type); assert_eq!(count as usize as u64, count); - Some(tcx.mk_array(op_ty, count as usize)) + tcx.mk_array(op_ty, count as usize) } Rvalue::Ref(reg, bk, ref lv) => { let lv_ty = lv.ty(mir, tcx).to_ty(tcx); - Some(tcx.mk_ref(reg, + tcx.mk_ref(reg, ty::TypeAndMut { ty: lv_ty, mutbl: bk.to_mutbl_lossy() } - )) + ) } - Rvalue::Len(..) => Some(tcx.types.usize), - Rvalue::Cast(.., ty) => Some(ty), + Rvalue::Len(..) => tcx.types.usize, + Rvalue::Cast(.., ty) => ty, Rvalue::BinaryOp(op, ref lhs, ref rhs) => { let lhs_ty = lhs.ty(mir, tcx); let rhs_ty = rhs.ty(mir, tcx); - Some(op.ty(tcx, lhs_ty, rhs_ty)) + op.ty(tcx, lhs_ty, rhs_ty) } Rvalue::CheckedBinaryOp(op, ref lhs, ref rhs) => { let lhs_ty = lhs.ty(mir, tcx); let rhs_ty = rhs.ty(mir, tcx); let ty = op.ty(tcx, lhs_ty, rhs_ty); - let ty = tcx.intern_tup(&[ty, tcx.types.bool], false); - Some(ty) + tcx.intern_tup(&[ty, tcx.types.bool], false) } Rvalue::UnaryOp(_, ref operand) => { - Some(operand.ty(mir, tcx)) + operand.ty(mir, tcx) } Rvalue::Discriminant(ref lval) => { let ty = lval.ty(mir, tcx).to_ty(tcx); if let ty::TyAdt(adt_def, _) = ty.sty { - Some(adt_def.repr.discr_type().to_ty(tcx)) + adt_def.repr.discr_type().to_ty(tcx) } else { // Undefined behaviour, bug for now; may want to return something for // the `discriminant` intrinsic later. @@ -181,29 +180,24 @@ impl<'tcx> Rvalue<'tcx> { } } Rvalue::Box(t) => { - Some(tcx.mk_box(t)) + tcx.mk_box(t) } Rvalue::Aggregate(ref ak, ref ops) => { match *ak { - AggregateKind::Array => { - if let Some(operand) = ops.get(0) { - let ty = operand.ty(mir, tcx); - Some(tcx.mk_array(ty, ops.len())) - } else { - None - } + AggregateKind::Array(ty) => { + tcx.mk_array(ty, ops.len()) } AggregateKind::Tuple => { - Some(tcx.mk_tup( + tcx.mk_tup( ops.iter().map(|op| op.ty(mir, tcx)), false - )) + ) } AggregateKind::Adt(def, _, substs, _) => { - Some(tcx.item_type(def.did).subst(tcx, substs)) + tcx.item_type(def.did).subst(tcx, substs) } AggregateKind::Closure(did, substs) => { - Some(tcx.mk_closure_from_closure_substs(did, substs)) + tcx.mk_closure_from_closure_substs(did, substs) } } } diff --git a/src/librustc/mir/visit.rs b/src/librustc/mir/visit.rs index 7cdbd5cae061f..980d1806e78f8 100644 --- a/src/librustc/mir/visit.rs +++ b/src/librustc/mir/visit.rs @@ -235,12 +235,6 @@ macro_rules! make_mir_visitor { self.super_const_usize(const_usize); } - fn visit_typed_const_val(&mut self, - val: & $($mutability)* TypedConstVal<'tcx>, - location: Location) { - self.super_typed_const_val(val, location); - } - fn visit_local_decl(&mut self, local_decl: & $($mutability)* LocalDecl<'tcx>) { self.super_local_decl(local_decl); @@ -467,9 +461,9 @@ macro_rules! make_mir_visitor { } Rvalue::Repeat(ref $($mutability)* value, - ref $($mutability)* typed_const_val) => { + ref $($mutability)* length) => { self.visit_operand(value, location); - self.visit_typed_const_val(typed_const_val, location); + self.visit_const_usize(length, location); } Rvalue::Ref(r, bk, ref $($mutability)* path) => { @@ -515,7 +509,8 @@ macro_rules! make_mir_visitor { Rvalue::Aggregate(ref $($mutability)* kind, ref $($mutability)* operands) => { match *kind { - AggregateKind::Array => { + AggregateKind::Array(ref $($mutability)* ty) => { + self.visit_ty(ty); } AggregateKind::Tuple => { } @@ -647,20 +642,6 @@ macro_rules! make_mir_visitor { self.visit_literal(literal, location); } - fn super_typed_const_val(&mut self, - constant: & $($mutability)* TypedConstVal<'tcx>, - location: Location) { - let TypedConstVal { - ref $($mutability)* span, - ref $($mutability)* ty, - ref $($mutability)* value, - } = *constant; - - self.visit_span(span); - self.visit_ty(ty); - self.visit_const_usize(value, location); - } - fn super_literal(&mut self, literal: & $($mutability)* Literal<'tcx>, location: Location) { diff --git a/src/librustc/traits/error_reporting.rs b/src/librustc/traits/error_reporting.rs index f850fd9772781..99db5f9b62435 100644 --- a/src/librustc/traits/error_reporting.rs +++ b/src/librustc/traits/error_reporting.rs @@ -986,7 +986,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { fn suggest_new_overflow_limit(&self, err: &mut DiagnosticBuilder) { let current_limit = self.tcx.sess.recursion_limit.get(); let suggested_limit = current_limit * 2; - err.note(&format!( + err.help(&format!( "consider adding a `#![recursion_limit=\"{}\"]` attribute to your crate", suggested_limit)); } diff --git a/src/librustc_borrowck/borrowck/mir/elaborate_drops.rs b/src/librustc_borrowck/borrowck/mir/elaborate_drops.rs index 13f898219bc12..a71d23e7e1e7e 100644 --- a/src/librustc_borrowck/borrowck/mir/elaborate_drops.rs +++ b/src/librustc_borrowck/borrowck/mir/elaborate_drops.rs @@ -161,6 +161,7 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> { fn create_drop_flag(&mut self, index: MovePathIndex) { let tcx = self.tcx; let patch = &mut self.patch; + debug!("create_drop_flag({:?})", self.mir.span); self.drop_flags.entry(index).or_insert_with(|| { patch.new_temp(tcx.types.bool) }); diff --git a/src/librustc_metadata/creader.rs b/src/librustc_metadata/creader.rs index 4477488f6cb38..49dcffb4830a1 100644 --- a/src/librustc_metadata/creader.rs +++ b/src/librustc_metadata/creader.rs @@ -586,7 +586,7 @@ impl<'a> CrateLoader<'a> { use proc_macro::__internal::Registry; use rustc_back::dynamic_lib::DynamicLibrary; use syntax_ext::deriving::custom::ProcMacroDerive; - use syntax_ext::proc_macro_impl::AttrProcMacro; + use syntax_ext::proc_macro_impl::{AttrProcMacro, BangProcMacro}; let path = match dylib { Some(dylib) => dylib, @@ -630,6 +630,15 @@ impl<'a> CrateLoader<'a> { ); self.0.push((Symbol::intern(name), Rc::new(expand))); } + + fn register_bang_proc_macro(&mut self, + name: &str, + expand: fn(TokenStream) -> TokenStream) { + let expand = SyntaxExtension::ProcMacro( + Box::new(BangProcMacro { inner: expand }) + ); + self.0.push((Symbol::intern(name), Rc::new(expand))); + } } let mut my_registrar = MyRegistrar(Vec::new()); diff --git a/src/librustc_mir/build/block.rs b/src/librustc_mir/build/block.rs index 121d592da0316..3305cfc0dfe1a 100644 --- a/src/librustc_mir/build/block.rs +++ b/src/librustc_mir/build/block.rs @@ -67,7 +67,10 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { this.expr_into_pattern(block, pattern, init) })); } else { - this.storage_live_for_bindings(block, &pattern); + this.visit_bindings(&pattern, &mut |this, _, _, node, span, _| { + this.storage_live_binding(block, node, span); + this.schedule_drop_for_binding(node, span); + }) } // Enter the visibility scope, after evaluating the initializer. diff --git a/src/librustc_mir/build/expr/as_lvalue.rs b/src/librustc_mir/build/expr/as_lvalue.rs index 5abfe084f2258..8886a310429ea 100644 --- a/src/librustc_mir/build/expr/as_lvalue.rs +++ b/src/librustc_mir/build/expr/as_lvalue.rs @@ -56,8 +56,10 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { let (usize_ty, bool_ty) = (this.hir.usize_ty(), this.hir.bool_ty()); let slice = unpack!(block = this.as_lvalue(block, lhs)); - - let idx = unpack!(block = this.as_operand(block, index)); + // extent=None so lvalue indexes live forever. They are scalars so they + // do not need storage annotations, and they are often copied between + // places. + let idx = unpack!(block = this.as_operand(block, None, index)); // bounds check: let (len, lt) = (this.temp(usize_ty.clone()), this.temp(bool_ty)); @@ -121,7 +123,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { Some(Category::Lvalue) => false, _ => true, }); - this.as_temp(block, expr) + this.as_temp(block, expr.temp_lifetime, expr) } } } diff --git a/src/librustc_mir/build/expr/as_operand.rs b/src/librustc_mir/build/expr/as_operand.rs index 09cdcc74ef63e..8d79e755685d0 100644 --- a/src/librustc_mir/build/expr/as_operand.rs +++ b/src/librustc_mir/build/expr/as_operand.rs @@ -13,29 +13,52 @@ use build::{BlockAnd, BlockAndExtension, Builder}; use build::expr::category::Category; use hair::*; +use rustc::middle::region::CodeExtent; use rustc::mir::*; impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { + /// Returns an operand suitable for use until the end of the current + /// scope expression. + /// + /// The operand returned from this function will *not be valid* after + /// an ExprKind::Scope is passed, so please do *not* return it from + /// functions to avoid bad miscompiles. + pub fn as_local_operand(&mut self, block: BasicBlock, expr: M) + -> BlockAnd> + where M: Mirror<'tcx, Output = Expr<'tcx>> + { + let topmost_scope = self.topmost_scope(); // FIXME(#6393) + self.as_operand(block, Some(topmost_scope), expr) + } + /// Compile `expr` into a value that can be used as an operand. /// If `expr` is an lvalue like `x`, this will introduce a /// temporary `tmp = x`, so that we capture the value of `x` at /// this time. - pub fn as_operand(&mut self, block: BasicBlock, expr: M) -> BlockAnd> + /// + /// The operand is known to be live until the end of `scope`. + pub fn as_operand(&mut self, + block: BasicBlock, + scope: Option, + expr: M) -> BlockAnd> where M: Mirror<'tcx, Output = Expr<'tcx>> { let expr = self.hir.mirror(expr); - self.expr_as_operand(block, expr) + self.expr_as_operand(block, scope, expr) } fn expr_as_operand(&mut self, mut block: BasicBlock, + scope: Option, expr: Expr<'tcx>) -> BlockAnd> { debug!("expr_as_operand(block={:?}, expr={:?})", block, expr); let this = self; if let ExprKind::Scope { extent, value } = expr.kind { - return this.in_scope(extent, block, |this| this.as_operand(block, value)); + return this.in_scope(extent, block, |this| { + this.as_operand(block, scope, value) + }); } let category = Category::of(&expr.kind).unwrap(); @@ -47,7 +70,8 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { } Category::Lvalue | Category::Rvalue(..) => { - let operand = unpack!(block = this.as_temp(block, expr)); + let operand = + unpack!(block = this.as_temp(block, scope, expr)); block.and(Operand::Consume(operand)) } } diff --git a/src/librustc_mir/build/expr/as_rvalue.rs b/src/librustc_mir/build/expr/as_rvalue.rs index 7f5d9c36ecedf..6694107a8d485 100644 --- a/src/librustc_mir/build/expr/as_rvalue.rs +++ b/src/librustc_mir/build/expr/as_rvalue.rs @@ -21,22 +21,34 @@ use build::expr::category::{Category, RvalueFunc}; use hair::*; use rustc_const_math::{ConstInt, ConstIsize}; use rustc::middle::const_val::ConstVal; +use rustc::middle::region::CodeExtent; use rustc::ty; use rustc::mir::*; use syntax::ast; use syntax_pos::Span; impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { + /// See comment on `as_local_operand` + pub fn as_local_rvalue(&mut self, block: BasicBlock, expr: M) + -> BlockAnd> + where M: Mirror<'tcx, Output = Expr<'tcx>> + { + let topmost_scope = self.topmost_scope(); // FIXME(#6393) + self.as_rvalue(block, Some(topmost_scope), expr) + } + /// Compile `expr`, yielding an rvalue. - pub fn as_rvalue(&mut self, block: BasicBlock, expr: M) -> BlockAnd> + pub fn as_rvalue(&mut self, block: BasicBlock, scope: Option, expr: M) + -> BlockAnd> where M: Mirror<'tcx, Output = Expr<'tcx>> { let expr = self.hir.mirror(expr); - self.expr_as_rvalue(block, expr) + self.expr_as_rvalue(block, scope, expr) } fn expr_as_rvalue(&mut self, mut block: BasicBlock, + scope: Option, expr: Expr<'tcx>) -> BlockAnd> { debug!("expr_as_rvalue(block={:?}, expr={:?})", block, expr); @@ -47,10 +59,10 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { match expr.kind { ExprKind::Scope { extent, value } => { - this.in_scope(extent, block, |this| this.as_rvalue(block, value)) + this.in_scope(extent, block, |this| this.as_rvalue(block, scope, value)) } ExprKind::Repeat { value, count } => { - let value_operand = unpack!(block = this.as_operand(block, value)); + let value_operand = unpack!(block = this.as_operand(block, scope, value)); block.and(Rvalue::Repeat(value_operand, count)) } ExprKind::Borrow { region, borrow_kind, arg } => { @@ -58,13 +70,13 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { block.and(Rvalue::Ref(region, borrow_kind, arg_lvalue)) } ExprKind::Binary { op, lhs, rhs } => { - let lhs = unpack!(block = this.as_operand(block, lhs)); - let rhs = unpack!(block = this.as_operand(block, rhs)); + let lhs = unpack!(block = this.as_operand(block, scope, lhs)); + let rhs = unpack!(block = this.as_operand(block, scope, rhs)); this.build_binary_op(block, op, expr_span, expr.ty, lhs, rhs) } ExprKind::Unary { op, arg } => { - let arg = unpack!(block = this.as_operand(block, arg)); + let arg = unpack!(block = this.as_operand(block, scope, arg)); // Check for -MIN on signed integers if this.hir.check_overflow() && op == UnOp::Neg && expr.ty.is_signed() { let bool_ty = this.hir.bool_ty(); @@ -97,27 +109,27 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { ExprKind::Cast { source } => { let source = this.hir.mirror(source); - let source = unpack!(block = this.as_operand(block, source)); + let source = unpack!(block = this.as_operand(block, scope, source)); block.and(Rvalue::Cast(CastKind::Misc, source, expr.ty)) } ExprKind::Use { source } => { - let source = unpack!(block = this.as_operand(block, source)); + let source = unpack!(block = this.as_operand(block, scope, source)); block.and(Rvalue::Use(source)) } ExprKind::ReifyFnPointer { source } => { - let source = unpack!(block = this.as_operand(block, source)); + let source = unpack!(block = this.as_operand(block, scope, source)); block.and(Rvalue::Cast(CastKind::ReifyFnPointer, source, expr.ty)) } ExprKind::UnsafeFnPointer { source } => { - let source = unpack!(block = this.as_operand(block, source)); + let source = unpack!(block = this.as_operand(block, scope, source)); block.and(Rvalue::Cast(CastKind::UnsafeFnPointer, source, expr.ty)) } ExprKind::ClosureFnPointer { source } => { - let source = unpack!(block = this.as_operand(block, source)); + let source = unpack!(block = this.as_operand(block, scope, source)); block.and(Rvalue::Cast(CastKind::ClosureFnPointer, source, expr.ty)) } ExprKind::Unsize { source } => { - let source = unpack!(block = this.as_operand(block, source)); + let source = unpack!(block = this.as_operand(block, scope, source)); block.and(Rvalue::Cast(CastKind::Unsize, source, expr.ty)) } ExprKind::Array { fields } => { @@ -148,18 +160,19 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { // to the same MIR as `let x = ();`. // first process the set of fields + let el_ty = expr.ty.sequence_element_type(this.hir.tcx()); let fields: Vec<_> = fields.into_iter() - .map(|f| unpack!(block = this.as_operand(block, f))) + .map(|f| unpack!(block = this.as_operand(block, scope, f))) .collect(); - block.and(Rvalue::Aggregate(AggregateKind::Array, fields)) + block.and(Rvalue::Aggregate(AggregateKind::Array(el_ty), fields)) } ExprKind::Tuple { fields } => { // see (*) above // first process the set of fields let fields: Vec<_> = fields.into_iter() - .map(|f| unpack!(block = this.as_operand(block, f))) + .map(|f| unpack!(block = this.as_operand(block, scope, f))) .collect(); block.and(Rvalue::Aggregate(AggregateKind::Tuple, fields)) @@ -167,7 +180,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { ExprKind::Closure { closure_id, substs, upvars } => { // see (*) above let upvars = upvars.into_iter() - .map(|upvar| unpack!(block = this.as_operand(block, upvar))) + .map(|upvar| unpack!(block = this.as_operand(block, scope, upvar))) .collect(); block.and(Rvalue::Aggregate(AggregateKind::Closure(closure_id, substs), upvars)) } @@ -179,10 +192,9 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { // first process the set of fields that were provided // (evaluating them in order given by user) - let fields_map: FxHashMap<_, _> = - fields.into_iter() - .map(|f| (f.name, unpack!(block = this.as_operand(block, f.expr)))) - .collect(); + let fields_map: FxHashMap<_, _> = fields.into_iter() + .map(|f| (f.name, unpack!(block = this.as_operand(block, scope, f.expr)))) + .collect(); let field_names = this.hir.all_fields(adt_def, variant_index); @@ -235,7 +247,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { Some(Category::Rvalue(RvalueFunc::AsRvalue)) => false, _ => true, }); - let operand = unpack!(block = this.as_operand(block, expr)); + let operand = unpack!(block = this.as_operand(block, scope, expr)); block.and(Rvalue::Use(operand)) } } diff --git a/src/librustc_mir/build/expr/as_temp.rs b/src/librustc_mir/build/expr/as_temp.rs index 0ae4bcc4205d4..69b9570200921 100644 --- a/src/librustc_mir/build/expr/as_temp.rs +++ b/src/librustc_mir/build/expr/as_temp.rs @@ -13,29 +13,38 @@ use build::{BlockAnd, BlockAndExtension, Builder}; use build::expr::category::Category; use hair::*; +use rustc::middle::region::CodeExtent; use rustc::mir::*; impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { /// Compile `expr` into a fresh temporary. This is used when building /// up rvalues so as to freeze the value that will be consumed. - pub fn as_temp(&mut self, block: BasicBlock, expr: M) -> BlockAnd> + pub fn as_temp(&mut self, + block: BasicBlock, + temp_lifetime: Option, + expr: M) + -> BlockAnd> where M: Mirror<'tcx, Output = Expr<'tcx>> { let expr = self.hir.mirror(expr); - self.expr_as_temp(block, expr) + self.expr_as_temp(block, temp_lifetime, expr) } - fn expr_as_temp(&mut self, mut block: BasicBlock, expr: Expr<'tcx>) -> BlockAnd> { + fn expr_as_temp(&mut self, + mut block: BasicBlock, + temp_lifetime: Option, + expr: Expr<'tcx>) + -> BlockAnd> { debug!("expr_as_temp(block={:?}, expr={:?})", block, expr); let this = self; - if let ExprKind::Scope { extent, value } = expr.kind { - return this.in_scope(extent, block, |this| this.as_temp(block, value)); + if let ExprKind::Scope { .. } = expr.kind { + span_bug!(expr.span, "unexpected scope expression in as_temp: {:?}", + expr); } let expr_ty = expr.ty.clone(); let temp = this.temp(expr_ty.clone()); - let temp_lifetime = expr.temp_lifetime; let expr_span = expr.span; let source_info = this.source_info(expr_span); diff --git a/src/librustc_mir/build/expr/into.rs b/src/librustc_mir/build/expr/into.rs index ae51951b519bd..dab8510687329 100644 --- a/src/librustc_mir/build/expr/into.rs +++ b/src/librustc_mir/build/expr/into.rs @@ -52,7 +52,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { _ => false, }; - unpack!(block = this.as_rvalue(block, source)); + unpack!(block = this.as_local_rvalue(block, source)); // This is an optimization. If the expression was a call then we already have an // unreachable block. Don't bother to terminate it and create a new one. @@ -65,7 +65,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { } } ExprKind::If { condition: cond_expr, then: then_expr, otherwise: else_expr } => { - let operand = unpack!(block = this.as_operand(block, cond_expr)); + let operand = unpack!(block = this.as_local_operand(block, cond_expr)); let mut then_block = this.cfg.start_new_block(); let mut else_block = this.cfg.start_new_block(); @@ -107,7 +107,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { (this.cfg.start_new_block(), this.cfg.start_new_block(), this.cfg.start_new_block(), this.cfg.start_new_block()); - let lhs = unpack!(block = this.as_operand(block, lhs)); + let lhs = unpack!(block = this.as_local_operand(block, lhs)); let blocks = match op { LogicalOp::And => (else_block, false_block), LogicalOp::Or => (true_block, else_block), @@ -115,7 +115,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { let term = TerminatorKind::if_(this.hir.tcx(), lhs, blocks.0, blocks.1); this.cfg.terminate(block, source_info, term); - let rhs = unpack!(else_block = this.as_operand(else_block, rhs)); + let rhs = unpack!(else_block = this.as_local_operand(else_block, rhs)); let term = TerminatorKind::if_(this.hir.tcx(), rhs, true_block, false_block); this.cfg.terminate(else_block, source_info, term); @@ -173,7 +173,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { if let Some(cond_expr) = opt_cond_expr { let loop_block_end; let cond = unpack!( - loop_block_end = this.as_operand(loop_block, cond_expr)); + loop_block_end = this.as_local_operand(loop_block, cond_expr)); body_block = this.cfg.start_new_block(); let term = TerminatorKind::if_(this.hir.tcx(), cond, body_block, exit_block); @@ -206,10 +206,10 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { } _ => false }; - let fun = unpack!(block = this.as_operand(block, fun)); + let fun = unpack!(block = this.as_local_operand(block, fun)); let args: Vec<_> = args.into_iter() - .map(|arg| unpack!(block = this.as_operand(block, arg))) + .map(|arg| unpack!(block = this.as_local_operand(block, arg))) .collect(); let success = this.cfg.start_new_block(); @@ -265,7 +265,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { _ => true, }); - let rvalue = unpack!(block = this.as_rvalue(block, expr)); + let rvalue = unpack!(block = this.as_local_rvalue(block, expr)); this.cfg.push_assign(block, source_info, destination, rvalue); block.unit() } diff --git a/src/librustc_mir/build/expr/stmt.rs b/src/librustc_mir/build/expr/stmt.rs index c577aab40dbeb..be39dcbf6d08d 100644 --- a/src/librustc_mir/build/expr/stmt.rs +++ b/src/librustc_mir/build/expr/stmt.rs @@ -38,14 +38,14 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { // Generate better code for things that don't need to be // dropped. if this.hir.needs_drop(lhs.ty) { - let rhs = unpack!(block = this.as_operand(block, rhs)); + let rhs = unpack!(block = this.as_local_operand(block, rhs)); let lhs = unpack!(block = this.as_lvalue(block, lhs)); unpack!(block = this.build_drop_and_replace( block, lhs_span, lhs, rhs )); block.unit() } else { - let rhs = unpack!(block = this.as_rvalue(block, rhs)); + let rhs = unpack!(block = this.as_local_rvalue(block, rhs)); let lhs = unpack!(block = this.as_lvalue(block, lhs)); this.cfg.push_assign(block, source_info, &lhs, rhs); block.unit() @@ -64,7 +64,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { let lhs_ty = lhs.ty; // As above, RTL. - let rhs = unpack!(block = this.as_operand(block, rhs)); + let rhs = unpack!(block = this.as_local_operand(block, rhs)); let lhs = unpack!(block = this.as_lvalue(block, lhs)); // we don't have to drop prior contents or anything @@ -122,7 +122,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { unpack!(block = this.as_lvalue(block, output)) }).collect(); let inputs = inputs.into_iter().map(|input| { - unpack!(block = this.as_operand(block, input)) + unpack!(block = this.as_local_operand(block, input)) }).collect(); this.cfg.push(block, Statement { source_info: source_info, diff --git a/src/librustc_mir/build/matches/mod.rs b/src/librustc_mir/build/matches/mod.rs index 6b6acb054b1b0..705eb1f56608e 100644 --- a/src/librustc_mir/build/matches/mod.rs +++ b/src/librustc_mir/build/matches/mod.rs @@ -123,16 +123,16 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { PatternKind::Binding { mode: BindingMode::ByValue, var, subpattern: None, .. } => { - self.storage_live_for_bindings(block, &irrefutable_pat); - let lvalue = Lvalue::Local(self.var_indices[&var]); - return self.into(&lvalue, block, initializer); + let lvalue = self.storage_live_binding(block, var, irrefutable_pat.span); + unpack!(block = self.into(&lvalue, block, initializer)); + self.schedule_drop_for_binding(var, irrefutable_pat.span); + block.unit() + } + _ => { + let lvalue = unpack!(block = self.as_lvalue(block, initializer)); + self.lvalue_into_pattern(block, irrefutable_pat, &lvalue) } - _ => {} } - let lvalue = unpack!(block = self.as_lvalue(block, initializer)); - self.lvalue_into_pattern(block, - irrefutable_pat, - &lvalue) } pub fn lvalue_into_pattern(&mut self, @@ -174,79 +174,70 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { scope_span: Span, pattern: &Pattern<'tcx>) -> Option { - match *pattern.kind { - PatternKind::Binding { mutability, name, mode: _, var, ty, ref subpattern } => { - if var_scope.is_none() { - var_scope = Some(self.new_visibility_scope(scope_span)); - } - let source_info = SourceInfo { - span: pattern.span, - scope: var_scope.unwrap() - }; - self.declare_binding(source_info, mutability, name, var, ty); - if let Some(subpattern) = subpattern.as_ref() { - var_scope = self.declare_bindings(var_scope, scope_span, subpattern); - } - } - PatternKind::Array { ref prefix, ref slice, ref suffix } | - PatternKind::Slice { ref prefix, ref slice, ref suffix } => { - for subpattern in prefix.iter().chain(slice).chain(suffix) { - var_scope = self.declare_bindings(var_scope, scope_span, subpattern); - } - } - PatternKind::Constant { .. } | PatternKind::Range { .. } | PatternKind::Wild => { - } - PatternKind::Deref { ref subpattern } => { - var_scope = self.declare_bindings(var_scope, scope_span, subpattern); - } - PatternKind::Leaf { ref subpatterns } | - PatternKind::Variant { ref subpatterns, .. } => { - for subpattern in subpatterns { - var_scope = self.declare_bindings(var_scope, scope_span, &subpattern.pattern); - } + self.visit_bindings(pattern, &mut |this, mutability, name, var, span, ty| { + if var_scope.is_none() { + var_scope = Some(this.new_visibility_scope(scope_span)); } - } + let source_info = SourceInfo { + span: span, + scope: var_scope.unwrap() + }; + this.declare_binding(source_info, mutability, name, var, ty); + }); var_scope } - /// Emit `StorageLive` for every binding in the pattern. - pub fn storage_live_for_bindings(&mut self, - block: BasicBlock, - pattern: &Pattern<'tcx>) { - match *pattern.kind { - PatternKind::Binding { var, ref subpattern, .. } => { - let lvalue = Lvalue::Local(self.var_indices[&var]); - let source_info = self.source_info(pattern.span); - self.cfg.push(block, Statement { - source_info: source_info, - kind: StatementKind::StorageLive(lvalue) - }); + pub fn storage_live_binding(&mut self, block: BasicBlock, var: NodeId, span: Span) + -> Lvalue<'tcx> + { + let local_id = self.var_indices[&var]; + let source_info = self.source_info(span); + self.cfg.push(block, Statement { + source_info: source_info, + kind: StatementKind::StorageLive(Lvalue::Local(local_id)) + }); + Lvalue::Local(local_id) + } + pub fn schedule_drop_for_binding(&mut self, var: NodeId, span: Span) { + let local_id = self.var_indices[&var]; + let var_ty = self.local_decls[local_id].ty; + let extent = self.hir.tcx().region_maps.var_scope(var); + self.schedule_drop(span, extent, &Lvalue::Local(local_id), var_ty); + } + + pub fn visit_bindings(&mut self, pattern: &Pattern<'tcx>, mut f: &mut F) + where F: FnMut(&mut Self, Mutability, Name, NodeId, Span, Ty<'tcx>) + { + match *pattern.kind { + PatternKind::Binding { mutability, name, var, ty, ref subpattern, .. } => { + f(self, mutability, name, var, pattern.span, ty); if let Some(subpattern) = subpattern.as_ref() { - self.storage_live_for_bindings(block, subpattern); + self.visit_bindings(subpattern, f); } } PatternKind::Array { ref prefix, ref slice, ref suffix } | PatternKind::Slice { ref prefix, ref slice, ref suffix } => { for subpattern in prefix.iter().chain(slice).chain(suffix) { - self.storage_live_for_bindings(block, subpattern); + self.visit_bindings(subpattern, f); } } PatternKind::Constant { .. } | PatternKind::Range { .. } | PatternKind::Wild => { } PatternKind::Deref { ref subpattern } => { - self.storage_live_for_bindings(block, subpattern); + self.visit_bindings(subpattern, f); } PatternKind::Leaf { ref subpatterns } | PatternKind::Variant { ref subpatterns, .. } => { for subpattern in subpatterns { - self.storage_live_for_bindings(block, &subpattern.pattern); + self.visit_bindings(&subpattern.pattern, f); } } } } } + /// List of blocks for each arm (and potentially other metadata in the /// future). struct ArmBlocks { @@ -670,7 +661,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { // guard, this block is simply unreachable let guard = self.hir.mirror(guard); let source_info = self.source_info(guard.span); - let cond = unpack!(block = self.as_operand(block, guard)); + let cond = unpack!(block = self.as_local_operand(block, guard)); let otherwise = self.cfg.start_new_block(); self.cfg.terminate(block, source_info, TerminatorKind::if_(self.hir.tcx(), cond, arm_block, otherwise)); @@ -691,25 +682,16 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { // Assign each of the bindings. This may trigger moves out of the candidate. for binding in bindings { - // Find the variable for the `var_id` being bound. It - // should have been created by a previous call to - // `declare_bindings`. - let var_index = self.var_indices[&binding.var_id]; - + let source_info = self.source_info(binding.span); + let local = self.storage_live_binding(block, binding.var_id, binding.span); + self.schedule_drop_for_binding(binding.var_id, binding.span); let rvalue = match binding.binding_mode { BindingMode::ByValue => Rvalue::Use(Operand::Consume(binding.source)), BindingMode::ByRef(region, borrow_kind) => Rvalue::Ref(region, borrow_kind, binding.source), }; - - let source_info = self.source_info(binding.span); - self.cfg.push(block, Statement { - source_info: source_info, - kind: StatementKind::StorageLive(Lvalue::Local(var_index)) - }); - self.cfg.push_assign(block, source_info, - &Lvalue::Local(var_index), rvalue); + self.cfg.push_assign(block, source_info, &local, rvalue); } } @@ -730,8 +712,6 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { name: Some(name), source_info: Some(source_info), }); - let extent = self.hir.tcx().region_maps.var_scope(var_id); - self.schedule_drop(source_info.span, extent, &Lvalue::Local(var), var_ty); self.var_indices.insert(var_id, var); debug!("declare_binding: var={:?}", var); diff --git a/src/librustc_mir/build/scope.rs b/src/librustc_mir/build/scope.rs index 282361fc13e27..3dab1717f6b2e 100644 --- a/src/librustc_mir/build/scope.rs +++ b/src/librustc_mir/build/scope.rs @@ -253,9 +253,9 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { f: F) where F: FnOnce(&mut Builder<'a, 'gcx, 'tcx>) { - let extent = self.scopes.last().map(|scope| scope.extent).unwrap(); + let extent = self.topmost_scope(); let loop_scope = LoopScope { - extent: extent.clone(), + extent: extent, continue_block: loop_block, break_block: break_block, break_destination: break_destination, @@ -416,6 +416,12 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { self.scopes[1].extent } + /// Returns the topmost active scope, which is known to be alive until + /// the next scope expression. + pub fn topmost_scope(&self) -> CodeExtent { + self.scopes.last().expect("topmost_scope: no scopes present").extent + } + // Scheduling drops // ================ /// Indicates that `lvalue` should be dropped on exit from diff --git a/src/librustc_mir/hair/cx/expr.rs b/src/librustc_mir/hair/cx/expr.rs index f2b89309e4ab1..c67bb8ec6c585 100644 --- a/src/librustc_mir/hair/cx/expr.rs +++ b/src/librustc_mir/hair/cx/expr.rs @@ -602,11 +602,7 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, ExprKind::Repeat { value: v.to_ref(), - count: TypedConstVal { - ty: cx.tcx.types.usize, - span: c.span, - value: count - } + count: count, } } hir::ExprRet(ref v) => ExprKind::Return { value: v.to_ref() }, diff --git a/src/librustc_mir/hair/mod.rs b/src/librustc_mir/hair/mod.rs index 9c7ee6a9ce883..2ee375dee08ac 100644 --- a/src/librustc_mir/hair/mod.rs +++ b/src/librustc_mir/hair/mod.rs @@ -14,7 +14,8 @@ //! unit-tested and separated from the Rust source and compiler data //! structures. -use rustc::mir::{BinOp, BorrowKind, Field, Literal, UnOp, TypedConstVal}; +use rustc_const_math::ConstUsize; +use rustc::mir::{BinOp, BorrowKind, Field, Literal, UnOp}; use rustc::hir::def_id::DefId; use rustc::middle::region::CodeExtent; use rustc::ty::subst::Substs; @@ -219,7 +220,7 @@ pub enum ExprKind<'tcx> { }, Repeat { value: ExprRef<'tcx>, - count: TypedConstVal<'tcx>, + count: ConstUsize, }, Array { fields: Vec>, diff --git a/src/librustc_mir/transform/qualify_consts.rs b/src/librustc_mir/transform/qualify_consts.rs index 441a9add883dd..e998665e03536 100644 --- a/src/librustc_mir/transform/qualify_consts.rs +++ b/src/librustc_mir/transform/qualify_consts.rs @@ -752,7 +752,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Qualifier<'a, 'tcx, 'tcx> { } if Some(def.did) == self.tcx.lang_items.unsafe_cell_type() { - let ty = rvalue.ty(self.mir, self.tcx).unwrap(); + let ty = rvalue.ty(self.mir, self.tcx); self.add_type(ty); assert!(self.qualif.intersects(Qualif::MUTABLE_INTERIOR)); // Even if the value inside may not need dropping, diff --git a/src/librustc_mir/transform/type_check.rs b/src/librustc_mir/transform/type_check.rs index af4a4a53905eb..c99c4323bb8a1 100644 --- a/src/librustc_mir/transform/type_check.rs +++ b/src/librustc_mir/transform/type_check.rs @@ -83,9 +83,8 @@ impl<'a, 'b, 'gcx, 'tcx> Visitor<'tcx> for TypeVerifier<'a, 'b, 'gcx, 'tcx> { fn visit_rvalue(&mut self, rvalue: &Rvalue<'tcx>, location: Location) { self.super_rvalue(rvalue, location); - if let Some(ty) = rvalue.ty(self.mir, self.tcx()) { - self.sanitize_type(rvalue, ty); - } + let rval_ty = rvalue.ty(self.mir, self.tcx()); + self.sanitize_type(rvalue, rval_ty); } fn visit_mir(&mut self, mir: &Mir<'tcx>) { @@ -356,14 +355,10 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { StatementKind::Assign(ref lv, ref rv) => { let lv_ty = lv.ty(mir, tcx).to_ty(tcx); let rv_ty = rv.ty(mir, tcx); - if let Some(rv_ty) = rv_ty { - if let Err(terr) = self.sub_types(rv_ty, lv_ty) { - span_mirbug!(self, stmt, "bad assignment ({:?} = {:?}): {:?}", - lv_ty, rv_ty, terr); - } + if let Err(terr) = self.sub_types(rv_ty, lv_ty) { + span_mirbug!(self, stmt, "bad assignment ({:?} = {:?}): {:?}", + lv_ty, rv_ty, terr); } - // FIXME: rvalue with undeterminable type - e.g. AggregateKind::Array branch that - // returns `None`. } StatementKind::SetDiscriminant{ ref lvalue, variant_index } => { let lvalue_type = lvalue.ty(mir, tcx).to_ty(tcx); diff --git a/src/librustc_passes/mir_stats.rs b/src/librustc_passes/mir_stats.rs index ad20c535decbb..ce02cb0e83643 100644 --- a/src/librustc_passes/mir_stats.rs +++ b/src/librustc_passes/mir_stats.rs @@ -19,7 +19,7 @@ use rustc::mir::{Constant, Literal, Location, LocalDecl}; use rustc::mir::{Lvalue, LvalueElem, LvalueProjection}; use rustc::mir::{Mir, Operand, ProjectionElem}; use rustc::mir::{Rvalue, SourceInfo, Statement, StatementKind}; -use rustc::mir::{Terminator, TerminatorKind, TypedConstVal, VisibilityScope, VisibilityScopeData}; +use rustc::mir::{Terminator, TerminatorKind, VisibilityScope, VisibilityScopeData}; use rustc::mir::visit as mir_visit; use rustc::mir::visit::Visitor; use rustc::ty::{ClosureSubsts, TyCtxt}; @@ -191,7 +191,7 @@ impl<'a, 'tcx> mir_visit::Visitor<'tcx> for StatCollector<'a, 'tcx> { // AggregateKind is not distinguished by visit API, so // record it. (`super_rvalue` handles `_operands`.) self.record(match *kind { - AggregateKind::Array => "AggregateKind::Array", + AggregateKind::Array(_) => "AggregateKind::Array", AggregateKind::Tuple => "AggregateKind::Tuple", AggregateKind::Adt(..) => "AggregateKind::Adt", AggregateKind::Closure(..) => "AggregateKind::Closure", @@ -297,13 +297,6 @@ impl<'a, 'tcx> mir_visit::Visitor<'tcx> for StatCollector<'a, 'tcx> { self.super_const_usize(const_usize); } - fn visit_typed_const_val(&mut self, - val: &TypedConstVal<'tcx>, - location: Location) { - self.record("TypedConstVal", val); - self.super_typed_const_val(val, location); - } - fn visit_local_decl(&mut self, local_decl: &LocalDecl<'tcx>) { self.record("LocalDecl", local_decl); diff --git a/src/librustc_trans/mir/constant.rs b/src/librustc_trans/mir/constant.rs index 771a5b7f366a1..c524d8351e003 100644 --- a/src/librustc_trans/mir/constant.rs +++ b/src/librustc_trans/mir/constant.rs @@ -529,7 +529,7 @@ impl<'a, 'tcx> MirConstContext<'a, 'tcx> { mir::Rvalue::Repeat(ref elem, ref count) => { let elem = self.const_operand(elem, span)?; - let size = count.value.as_u64(tcx.sess.target.uint_type); + let size = count.as_u64(tcx.sess.target.uint_type); let fields = vec![elem.llval; size as usize]; self.const_array(dest_ty, &fields) } @@ -548,7 +548,7 @@ impl<'a, 'tcx> MirConstContext<'a, 'tcx> { failure?; match *kind { - mir::AggregateKind::Array => { + mir::AggregateKind::Array(_) => { self.const_array(dest_ty, &fields) } mir::AggregateKind::Adt(..) | diff --git a/src/librustc_trans/mir/rvalue.rs b/src/librustc_trans/mir/rvalue.rs index 037c771c97b06..b6af4e52e820b 100644 --- a/src/librustc_trans/mir/rvalue.rs +++ b/src/librustc_trans/mir/rvalue.rs @@ -95,7 +95,7 @@ impl<'a, 'tcx> MirContext<'a, 'tcx> { mir::Rvalue::Repeat(ref elem, ref count) => { let tr_elem = self.trans_operand(&bcx, elem); - let size = count.value.as_u64(bcx.tcx().sess.target.uint_type); + let size = count.as_u64(bcx.tcx().sess.target.uint_type); let size = C_uint(bcx.ccx, size); let base = base::get_dataptr(&bcx, dest.llval); tvec::slice_for_each(&bcx, base, tr_elem.ty, size, |bcx, llslot| { @@ -435,7 +435,7 @@ impl<'a, 'tcx> MirContext<'a, 'tcx> { mir::Rvalue::Discriminant(ref lvalue) => { let discr_lvalue = self.trans_lvalue(&bcx, lvalue); let enum_ty = discr_lvalue.ty.to_ty(bcx.tcx()); - let discr_ty = rvalue.ty(&*self.mir, bcx.tcx()).unwrap(); + let discr_ty = rvalue.ty(&*self.mir, bcx.tcx()); let discr_type = type_of::immediate_type_of(bcx.ccx, discr_ty); let discr = adt::trans_get_discr(&bcx, enum_ty, discr_lvalue.llval, discr_lvalue.alignment, Some(discr_type), true); diff --git a/src/librustc_typeck/check/autoderef.rs b/src/librustc_typeck/check/autoderef.rs index b4647df3f4f0a..ca0ab8f1e8c77 100644 --- a/src/librustc_typeck/check/autoderef.rs +++ b/src/librustc_typeck/check/autoderef.rs @@ -54,12 +54,16 @@ impl<'a, 'gcx, 'tcx> Iterator for Autoderef<'a, 'gcx, 'tcx> { if self.steps.len() == tcx.sess.recursion_limit.get() { // We've reached the recursion limit, error gracefully. + let suggested_limit = tcx.sess.recursion_limit.get() * 2; struct_span_err!(tcx.sess, self.span, E0055, "reached the recursion limit while auto-dereferencing {:?}", self.cur_ty) .span_label(self.span, &format!("deref recursion limit reached")) + .help(&format!( + "consider adding a `#[recursion_limit=\"{}\"]` attribute to your crate", + suggested_limit)) .emit(); return None; } diff --git a/src/libsyntax/ext/base.rs b/src/libsyntax/ext/base.rs index 666e2205b4a26..c7d2f0cd31dc6 100644 --- a/src/libsyntax/ext/base.rs +++ b/src/libsyntax/ext/base.rs @@ -14,7 +14,7 @@ use ast::{self, Attribute, Name, PatKind, MetaItem}; use attr::HasAttrs; use codemap::{self, CodeMap, ExpnInfo, Spanned, respan}; use syntax_pos::{Span, ExpnId, NO_EXPANSION}; -use errors::DiagnosticBuilder; +use errors::{DiagnosticBuilder, FatalError}; use ext::expand::{self, Expansion}; use ext::hygiene::Mark; use fold::{self, Folder}; @@ -695,9 +695,15 @@ impl<'a> ExtCtxt<'a> { pub fn bt_push(&mut self, ei: ExpnInfo) { if self.current_expansion.depth > self.ecfg.recursion_limit { - self.span_fatal(ei.call_site, - &format!("recursion limit reached while expanding the macro `{}`", - ei.callee.name())); + let suggested_limit = self.ecfg.recursion_limit * 2; + let mut err = self.struct_span_fatal(ei.call_site, + &format!("recursion limit reached while expanding the macro `{}`", + ei.callee.name())); + err.help(&format!( + "consider adding a `#![recursion_limit=\"{}\"]` attribute to your crate", + suggested_limit)); + err.emit(); + panic!(FatalError); } let mut call_site = ei.call_site; diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index c2b72edb66c6c..7de50430184f6 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -763,6 +763,11 @@ pub const BUILTIN_ATTRIBUTES: &'static [(&'static str, AttributeType, AttributeG "attribute proc macros are currently unstable", cfg_fn!(proc_macro))), + ("proc_macro", Normal, Gated(Stability::Unstable, + "proc_macro", + "function-like proc macros are currently unstable", + cfg_fn!(proc_macro))), + ("rustc_derive_registrar", Normal, Gated(Stability::Unstable, "rustc_derive_registrar", "used internally by rustc", diff --git a/src/libsyntax_ext/proc_macro_impl.rs b/src/libsyntax_ext/proc_macro_impl.rs index b454628acb1c0..f60e5824db962 100644 --- a/src/libsyntax_ext/proc_macro_impl.rs +++ b/src/libsyntax_ext/proc_macro_impl.rs @@ -56,3 +56,38 @@ impl base::AttrProcMacro for AttrProcMacro { } } } + +pub struct BangProcMacro { + pub inner: fn(TsShim) -> TsShim, +} + +impl base::ProcMacro for BangProcMacro { + fn expand<'cx>(&self, + ecx: &'cx mut ExtCtxt, + span: Span, + input: TokenStream) + -> TokenStream { + let input = __internal::token_stream_wrap(input); + + let res = __internal::set_parse_sess(&ecx.parse_sess, || { + panic::catch_unwind(panic::AssertUnwindSafe(|| (self.inner)(input))) + }); + + match res { + Ok(stream) => __internal::token_stream_inner(stream), + Err(e) => { + let msg = "proc macro panicked"; + let mut err = ecx.struct_span_fatal(span, msg); + if let Some(s) = e.downcast_ref::() { + err.help(&format!("message: {}", s)); + } + if let Some(s) = e.downcast_ref::<&'static str>() { + err.help(&format!("message: {}", s)); + } + + err.emit(); + panic!(FatalError); + } + } + } +} diff --git a/src/libsyntax_ext/proc_macro_registrar.rs b/src/libsyntax_ext/proc_macro_registrar.rs index 325f09a83ddab..9c96ad547e1ae 100644 --- a/src/libsyntax_ext/proc_macro_registrar.rs +++ b/src/libsyntax_ext/proc_macro_registrar.rs @@ -27,6 +27,9 @@ use syntax_pos::{Span, DUMMY_SP}; use deriving; +const PROC_MACRO_KINDS: [&'static str; 3] = + ["proc_macro_derive", "proc_macro_attribute", "proc_macro"]; + struct ProcMacroDerive { trait_name: ast::Name, function_name: Ident, @@ -34,14 +37,15 @@ struct ProcMacroDerive { attrs: Vec, } -struct AttrProcMacro { +struct ProcMacroDef { function_name: Ident, span: Span, } struct CollectProcMacros<'a> { derives: Vec, - attr_macros: Vec, + attr_macros: Vec, + bang_macros: Vec, in_root: bool, handler: &'a errors::Handler, is_proc_macro_crate: bool, @@ -58,17 +62,18 @@ pub fn modify(sess: &ParseSess, let ecfg = ExpansionConfig::default("proc_macro".to_string()); let mut cx = ExtCtxt::new(sess, ecfg, resolver); - let (derives, attr_macros) = { + let (derives, attr_macros, bang_macros) = { let mut collect = CollectProcMacros { derives: Vec::new(), attr_macros: Vec::new(), + bang_macros: Vec::new(), in_root: true, handler: handler, is_proc_macro_crate: is_proc_macro_crate, is_test_crate: is_test_crate, }; visit::walk_crate(&mut collect, &krate); - (collect.derives, collect.attr_macros) + (collect.derives, collect.attr_macros, collect.bang_macros) }; if !is_proc_macro_crate { @@ -83,7 +88,7 @@ pub fn modify(sess: &ParseSess, return krate; } - krate.module.items.push(mk_registrar(&mut cx, &derives, &attr_macros)); + krate.module.items.push(mk_registrar(&mut cx, &derives, &attr_macros, &bang_macros)); if krate.exported_macros.len() > 0 { handler.err("cannot export macro_rules! macros from a `proc-macro` \ @@ -93,6 +98,10 @@ pub fn modify(sess: &ParseSess, return krate } +fn is_proc_macro_attr(attr: &ast::Attribute) -> bool { + PROC_MACRO_KINDS.iter().any(|kind| attr.check_name(kind)) +} + impl<'a> CollectProcMacros<'a> { fn check_not_pub_in_root(&self, vis: &ast::Visibility, sp: Span) { if self.is_proc_macro_crate && @@ -196,12 +205,12 @@ impl<'a> CollectProcMacros<'a> { fn collect_attr_proc_macro(&mut self, item: &'a ast::Item, attr: &'a ast::Attribute) { if let Some(_) = attr.meta_item_list() { self.handler.span_err(attr.span, "`#[proc_macro_attribute]` attribute - cannot contain any meta items"); + does not take any arguments"); return; } if self.in_root && item.vis == ast::Visibility::Public { - self.attr_macros.push(AttrProcMacro { + self.attr_macros.push(ProcMacroDef { span: item.span, function_name: item.ident, }); @@ -215,6 +224,29 @@ impl<'a> CollectProcMacros<'a> { self.handler.span_err(item.span, msg); } } + + fn collect_bang_proc_macro(&mut self, item: &'a ast::Item, attr: &'a ast::Attribute) { + if let Some(_) = attr.meta_item_list() { + self.handler.span_err(attr.span, "`#[proc_macro]` attribute + does not take any arguments"); + return; + } + + if self.in_root && item.vis == ast::Visibility::Public { + self.bang_macros.push(ProcMacroDef { + span: item.span, + function_name: item.ident, + }); + } else { + let msg = if !self.in_root { + "functions tagged with `#[proc_macro]` must \ + currently reside in the root of the crate" + } else { + "functions tagged with `#[proc_macro]` must be `pub`" + }; + self.handler.span_err(item.span, msg); + } + } } impl<'a> Visitor<'a> for CollectProcMacros<'a> { @@ -232,7 +264,7 @@ impl<'a> Visitor<'a> for CollectProcMacros<'a> { let mut found_attr: Option<&'a ast::Attribute> = None; for attr in &item.attrs { - if attr.check_name("proc_macro_derive") || attr.check_name("proc_macro_attribute") { + if is_proc_macro_attr(&attr) { if let Some(prev_attr) = found_attr { let msg = if attr.name() == prev_attr.name() { format!("Only one `#[{}]` attribute is allowed on any given function", @@ -285,6 +317,8 @@ impl<'a> Visitor<'a> for CollectProcMacros<'a> { self.collect_custom_derive(item, attr); } else if attr.check_name("proc_macro_attribute") { self.collect_attr_proc_macro(item, attr); + } else if attr.check_name("proc_macro") { + self.collect_bang_proc_macro(item, attr); }; visit::walk_item(self, item); @@ -320,7 +354,8 @@ impl<'a> Visitor<'a> for CollectProcMacros<'a> { // } fn mk_registrar(cx: &mut ExtCtxt, custom_derives: &[ProcMacroDerive], - custom_attrs: &[AttrProcMacro]) -> P { + custom_attrs: &[ProcMacroDef], + custom_macros: &[ProcMacroDef]) -> P { let eid = cx.codemap().record_expansion(ExpnInfo { call_site: DUMMY_SP, callee: NameAndSpan { @@ -342,6 +377,7 @@ fn mk_registrar(cx: &mut ExtCtxt, let registrar = Ident::from_str("registrar"); let register_custom_derive = Ident::from_str("register_custom_derive"); let register_attr_proc_macro = Ident::from_str("register_attr_proc_macro"); + let register_bang_proc_macro = Ident::from_str("register_bang_proc_macro"); let mut stmts = custom_derives.iter().map(|cd| { let path = cx.path_global(cd.span, vec![cd.function_name]); @@ -371,6 +407,18 @@ fn mk_registrar(cx: &mut ExtCtxt, vec![registrar, name, cx.expr_path(path)])) })); + stmts.extend(custom_macros.iter().map(|cm| { + let name = cx.expr_str(cm.span, cm.function_name.name); + let path = cx.path_global(cm.span, vec![cm.function_name]); + let registrar = cx.expr_ident(cm.span, registrar); + + let ufcs_path = cx.path(span, + vec![proc_macro, __internal, registry, register_bang_proc_macro]); + + cx.stmt_expr(cx.expr_call(span, cx.expr_path(ufcs_path), + vec![registrar, name, cx.expr_path(path)])) + })); + let path = cx.path(span, vec![proc_macro, __internal, registry]); let registrar_path = cx.ty_path(path); let arg_ty = cx.ty_rptr(span, registrar_path, None, ast::Mutability::Mutable); diff --git a/src/llvm b/src/llvm index ceb177eeefa7d..50ab09fb43f03 160000 --- a/src/llvm +++ b/src/llvm @@ -1 +1 @@ -Subproject commit ceb177eeefa7d67ca29230d2e7e8584f97d4fdad +Subproject commit 50ab09fb43f038e4f824eea6cb278f560d3e8621 diff --git a/src/rustllvm/llvm-auto-clean-trigger b/src/rustllvm/llvm-auto-clean-trigger index ab36e9a2c2b20..57f37ea050c1b 100644 --- a/src/rustllvm/llvm-auto-clean-trigger +++ b/src/rustllvm/llvm-auto-clean-trigger @@ -1,4 +1,4 @@ # If this file is modified, then llvm will be forcibly cleaned and then rebuilt. # The actual contents of this file do not matter, but to trigger a change on the # build bots then the contents should be changed so git updates the mtime. -2017-02-15 +2017-03-02 diff --git a/src/test/codegen/lifetime_start_end.rs b/src/test/codegen/lifetime_start_end.rs index e3b35cf355250..5c1f1f8f2bb20 100644 --- a/src/test/codegen/lifetime_start_end.rs +++ b/src/test/codegen/lifetime_start_end.rs @@ -11,11 +11,9 @@ // compile-flags: -O -C no-prepopulate-passes #![crate_type = "lib"] -#![feature(rustc_attrs)] // CHECK-LABEL: @test #[no_mangle] -#[rustc_mir] // FIXME #27840 MIR has different codegen. pub fn test() { let a = 0; &a; // keep variable in an alloca @@ -33,11 +31,11 @@ pub fn test() { // CHECK: [[S__5:%[0-9]+]] = bitcast %"core::option::Option"* %_5 to i8* // CHECK: call void @llvm.lifetime.start(i{{[0-9 ]+}}, i8* [[S__5]]) -// CHECK: [[E__5:%[0-9]+]] = bitcast %"core::option::Option"* %_5 to i8* -// CHECK: call void @llvm.lifetime.end(i{{[0-9 ]+}}, i8* [[E__5]]) - // CHECK: [[E_b:%[0-9]+]] = bitcast %"core::option::Option"** %b to i8* // CHECK: call void @llvm.lifetime.end(i{{[0-9 ]+}}, i8* [[E_b]]) + +// CHECK: [[E__5:%[0-9]+]] = bitcast %"core::option::Option"* %_5 to i8* +// CHECK: call void @llvm.lifetime.end(i{{[0-9 ]+}}, i8* [[E__5]]) } let c = 1; diff --git a/src/test/compile-fail-fulldeps/proc-macro/auxiliary/bang_proc_macro.rs b/src/test/compile-fail-fulldeps/proc-macro/auxiliary/bang_proc_macro.rs new file mode 100644 index 0000000000000..89ac11b309d75 --- /dev/null +++ b/src/test/compile-fail-fulldeps/proc-macro/auxiliary/bang_proc_macro.rs @@ -0,0 +1,23 @@ +// Copyright 2016 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// force-host +// no-prefer-dynamic +#![feature(proc_macro)] +#![crate_type = "proc-macro"] + +extern crate proc_macro; + +use proc_macro::TokenStream; + +#[proc_macro] +pub fn bang_proc_macro(input: TokenStream) -> TokenStream { + input +} diff --git a/src/test/compile-fail-fulldeps/proc-macro/macro-use-bang.rs b/src/test/compile-fail-fulldeps/proc-macro/macro-use-bang.rs new file mode 100644 index 0000000000000..7ecc685357ee6 --- /dev/null +++ b/src/test/compile-fail-fulldeps/proc-macro/macro-use-bang.rs @@ -0,0 +1,21 @@ +// Copyright 2016 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// aux-build:bang_proc_macro.rs + +#![feature(proc_macro)] + +#[macro_use] +extern crate bang_proc_macro; + +fn main() { + bang_proc_macro!(println!("Hello, world!")); + //~^ ERROR: procedural macros cannot be imported with `#[macro_use]` +} diff --git a/src/test/compile-fail-fulldeps/proc-macro/resolve-error.rs b/src/test/compile-fail-fulldeps/proc-macro/resolve-error.rs index eac0be6f84874..e0066dd43be89 100644 --- a/src/test/compile-fail-fulldeps/proc-macro/resolve-error.rs +++ b/src/test/compile-fail-fulldeps/proc-macro/resolve-error.rs @@ -11,6 +11,7 @@ // aux-build:derive-foo.rs // aux-build:derive-clona.rs // aux-build:attr_proc_macro.rs +// aux-build:bang_proc_macro.rs #![feature(proc_macro)] @@ -19,13 +20,19 @@ extern crate derive_foo; #[macro_use] extern crate derive_clona; extern crate attr_proc_macro; +extern crate bang_proc_macro; use attr_proc_macro::attr_proc_macro; +use bang_proc_macro::bang_proc_macro; macro_rules! FooWithLongNam { () => {} } +macro_rules! attr_proc_mac { + () => {} +} + #[derive(FooWithLongNan)] //~^ ERROR cannot find derive macro `FooWithLongNan` in this scope //~^^ HELP did you mean `FooWithLongName`? @@ -61,7 +68,12 @@ fn main() { attr_proc_macra!(); //~^ ERROR cannot find macro `attr_proc_macra!` in this scope + //~^^ HELP did you mean `attr_proc_mac!`? Dlona!(); //~^ ERROR cannot find macro `Dlona!` in this scope + + bang_proc_macrp!(); + //~^ ERROR cannot find macro `bang_proc_macrp!` in this scope + //~^^ HELP did you mean `bang_proc_macro!`? } diff --git a/src/test/compile-fail/recursion_limit.rs b/src/test/compile-fail/recursion_limit.rs deleted file mode 100644 index 226a6d57ddbf0..0000000000000 --- a/src/test/compile-fail/recursion_limit.rs +++ /dev/null @@ -1,57 +0,0 @@ -// 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 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -// Test that the recursion limit can be changed. In this case, we have -// deeply nested types that will fail the `Send` check by overflow -// when the recursion limit is set very low. - -#![allow(dead_code)] -#![recursion_limit="10"] - -macro_rules! link { - ($id:ident, $t:ty) => { - enum $id { $id($t) } - } -} - -link! { A, B } -link! { B, C } -link! { C, D } -link! { D, E } -link! { E, F } -link! { F, G } -link! { G, H } -link! { H, I } -link! { I, J } -link! { J, K } -link! { K, L } -link! { L, M } -link! { M, N } - -enum N { N(usize) } - -fn is_send() { } - -fn main() { - is_send::(); - //~^ ERROR overflow evaluating - //~| NOTE consider adding a `#![recursion_limit="20"]` attribute to your crate - //~| NOTE required because it appears within the type `A` - //~| NOTE required because it appears within the type `B` - //~| NOTE required because it appears within the type `C` - //~| NOTE required because it appears within the type `D` - //~| NOTE required because it appears within the type `E` - //~| NOTE required because it appears within the type `F` - //~| NOTE required because it appears within the type `G` - //~| NOTE required because it appears within the type `H` - //~| NOTE required because it appears within the type `I` - //~| NOTE required because it appears within the type `J` - //~| NOTE required by `is_send` -} diff --git a/src/test/mir-opt/basic_assignment.rs b/src/test/mir-opt/basic_assignment.rs new file mode 100644 index 0000000000000..9c924a23903f9 --- /dev/null +++ b/src/test/mir-opt/basic_assignment.rs @@ -0,0 +1,85 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// this tests move up progration, which is not yet implemented +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// check that codegen of assignment expressions is sane. Assignments +// tend to be absent in simple code, so subtle breakage in them can +// leave a quite hard-to-find trail of destruction. + +fn main() { + let nodrop_x = false; + let nodrop_y; + + nodrop_y = nodrop_x; + + let drop_x : Option> = None; + let drop_y; + + drop_y = drop_x; +} + +// END RUST SOURCE +// START rustc.node4.SimplifyCfg.initial-after.mir +// bb0: { +// StorageLive(_1); +// _1 = const false; +// StorageLive(_2); +// StorageLive(_3); +// _3 = _1; +// _2 = _3; +// StorageDead(_3); +// StorageLive(_4); +// _4 = std::option::Option>::None; +// StorageLive(_6); +// StorageLive(_7); +// _7 = _4; +// replace(_6 <- _7) -> [return: bb5, unwind: bb4]; +// } +// bb1: { +// resume; +// } +// bb2: { +// drop(_4) -> bb1; +// } +// bb3: { +// drop(_6) -> bb2; +// } +// bb4: { +// drop(_7) -> bb3; +// } +// bb5: { +// drop(_7) -> [return: bb6, unwind: bb3]; +// } +// bb6: { +// StorageDead(_7); +// _0 = (); +// drop(_6) -> [return: bb7, unwind: bb2]; +// } +// bb7: { +// StorageDead(_6); +// drop(_4) -> bb8; +// } +// bb8: { +// StorageDead(_4); +// StorageDead(_2); +// StorageDead(_1); +// return; +// } +// END rustc.node4.SimplifyCfg.initial-after.mir diff --git a/src/test/mir-opt/issue-38669.rs b/src/test/mir-opt/issue-38669.rs new file mode 100644 index 0000000000000..d1e515c4f2b15 --- /dev/null +++ b/src/test/mir-opt/issue-38669.rs @@ -0,0 +1,52 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// check that we don't StorageDead booleans before they are used + +fn main() { + let mut should_break = false; + loop { + if should_break { + break; + } + should_break = true; + } +} + +// END RUST SOURCE +// START rustc.node4.SimplifyCfg.initial-after.mir +// bb0: { +// StorageLive(_1); +// _1 = const false; +// goto -> bb1; +// } +// +// bb1: { +// StorageLive(_4); +// _4 = _1; +// switchInt(_4) -> [0: bb3, otherwise: bb2]; +// } +// +// bb2: { +// StorageLive(_6); +// _0 = (); +// StorageDead(_4); +// StorageDead(_1); +// return; +// } +// +// bb3: { +// _3 = (); +// StorageDead(_4); +// _1 = const true; +// _2 = (); +// goto -> bb1; +// } +// END rustc.node4.SimplifyCfg.initial-after.mir diff --git a/src/test/mir-opt/storage_ranges.rs b/src/test/mir-opt/storage_ranges.rs index 933bfa8df2ec2..3fbd1a36f2f16 100644 --- a/src/test/mir-opt/storage_ranges.rs +++ b/src/test/mir-opt/storage_ranges.rs @@ -28,16 +28,15 @@ fn main() { // StorageLive(_5); // _5 = _1; // _4 = std::option::Option::Some(_5,); -// _3 = &_4; // StorageDead(_5); +// _3 = &_4; // _2 = (); -// StorageDead(_4); // StorageDead(_3); +// StorageDead(_4); // StorageLive(_6); // _6 = const 1i32; // _0 = (); // StorageDead(_6); // StorageDead(_1); -// return; -// } +// } // END rustc.node4.TypeckMir.before.mir diff --git a/src/test/run-pass-fulldeps/proc-macro/auxiliary/bang-macro.rs b/src/test/run-pass-fulldeps/proc-macro/auxiliary/bang-macro.rs new file mode 100644 index 0000000000000..122a47aff7198 --- /dev/null +++ b/src/test/run-pass-fulldeps/proc-macro/auxiliary/bang-macro.rs @@ -0,0 +1,26 @@ +// Copyright 2016 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// no-prefer-dynamic +#![feature(proc_macro)] +#![crate_type = "proc-macro"] + +extern crate proc_macro; + +use proc_macro::TokenStream; + +#[proc_macro] +pub fn rewrite(input: TokenStream) -> TokenStream { + let input = input.to_string(); + + assert_eq!(input, r#""Hello, world!""#); + + r#""NOT Hello, world!""#.parse().unwrap() +} diff --git a/src/test/run-pass-fulldeps/proc-macro/bang-macro.rs b/src/test/run-pass-fulldeps/proc-macro/bang-macro.rs new file mode 100644 index 0000000000000..531bd0dd3569d --- /dev/null +++ b/src/test/run-pass-fulldeps/proc-macro/bang-macro.rs @@ -0,0 +1,20 @@ +// Copyright 2016 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// aux-build:bang-macro.rs + +#![feature(proc_macro)] + +extern crate bang_macro; +use bang_macro::rewrite; + +fn main() { + assert_eq!(rewrite!("Hello, world!"), "NOT Hello, world!"); +} diff --git a/src/test/run-pass/mir_drop_order.rs b/src/test/run-pass/mir_drop_order.rs new file mode 100644 index 0000000000000..e7da43597f169 --- /dev/null +++ b/src/test/run-pass/mir_drop_order.rs @@ -0,0 +1,55 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use std::cell::RefCell; +use std::panic; + +pub struct DropLogger<'a> { + id: usize, + log: &'a panic::AssertUnwindSafe>> +} + +impl<'a> Drop for DropLogger<'a> { + fn drop(&mut self) { + self.log.0.borrow_mut().push(self.id); + } +} + +struct InjectedFailure; + +#[allow(unreachable_code)] +fn main() { + let log = panic::AssertUnwindSafe(RefCell::new(vec![])); + let d = |id| DropLogger { id: id, log: &log }; + let get = || -> Vec<_> { + let mut m = log.0.borrow_mut(); + let n = m.drain(..); + n.collect() + }; + + { + let _x = (d(0), &d(1), d(2), &d(3)); + // all borrows are extended - nothing has been dropped yet + assert_eq!(get(), vec![]); + } + // in a let-statement, extended lvalues are dropped + // *after* the let result (tho they have the same scope + // as far as scope-based borrowck goes). + assert_eq!(get(), vec![0, 2, 3, 1]); + + let _ = std::panic::catch_unwind(|| { + (d(4), &d(5), d(6), &d(7), panic!(InjectedFailure)); + }); + + // here, the temporaries (5/7) live until the end of the + // containing statement, which is destroyed after the operands + // (4/6) on a panic. + assert_eq!(get(), vec![6, 4, 7, 5]); +} diff --git a/src/test/ui/did_you_mean/recursion_limit.rs b/src/test/ui/did_you_mean/recursion_limit.rs new file mode 100644 index 0000000000000..becb81b1fff7e --- /dev/null +++ b/src/test/ui/did_you_mean/recursion_limit.rs @@ -0,0 +1,45 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Test that the recursion limit can be changed and that the compiler +// suggests a fix. In this case, we have deeply nested types that will +// fail the `Send` check by overflow when the recursion limit is set +// very low. + +#![allow(dead_code)] +#![recursion_limit="10"] + +macro_rules! link { + ($id:ident, $t:ty) => { + enum $id { $id($t) } + } +} + +link! { A, B } +link! { B, C } +link! { C, D } +link! { D, E } +link! { E, F } +link! { F, G } +link! { G, H } +link! { H, I } +link! { I, J } +link! { J, K } +link! { K, L } +link! { L, M } +link! { M, N } + +enum N { N(usize) } + +fn is_send() { } + +fn main() { + is_send::(); +} diff --git a/src/test/ui/did_you_mean/recursion_limit.stderr b/src/test/ui/did_you_mean/recursion_limit.stderr new file mode 100644 index 0000000000000..d157c5de6c7f5 --- /dev/null +++ b/src/test/ui/did_you_mean/recursion_limit.stderr @@ -0,0 +1,21 @@ +error[E0275]: overflow evaluating the requirement `K: std::marker::Send` + --> $DIR/recursion_limit.rs:44:5 + | +44 | is_send::(); + | ^^^^^^^^^^^^ + | + = help: consider adding a `#![recursion_limit="20"]` attribute to your crate + = note: required because it appears within the type `J` + = note: required because it appears within the type `I` + = note: required because it appears within the type `H` + = note: required because it appears within the type `G` + = note: required because it appears within the type `F` + = note: required because it appears within the type `E` + = note: required because it appears within the type `D` + = note: required because it appears within the type `C` + = note: required because it appears within the type `B` + = note: required because it appears within the type `A` + = note: required by `is_send` + +error: aborting due to previous error + diff --git a/src/test/ui/did_you_mean/recursion_limit_deref.rs b/src/test/ui/did_you_mean/recursion_limit_deref.rs new file mode 100644 index 0000000000000..ebc56c94adf84 --- /dev/null +++ b/src/test/ui/did_you_mean/recursion_limit_deref.rs @@ -0,0 +1,62 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Test that the recursion limit can be changed and that the compiler +// suggests a fix. In this case, we have a long chain of Deref impls +// which will cause an overflow during the autoderef loop. + +#![allow(dead_code)] +#![recursion_limit="10"] + +macro_rules! link { + ($outer:ident, $inner:ident) => { + struct $outer($inner); + + impl $outer { + fn new() -> $outer { + $outer($inner::new()) + } + } + + impl std::ops::Deref for $outer { + type Target = $inner; + + fn deref(&self) -> &$inner { + &self.0 + } + } + } +} + +struct Bottom; +impl Bottom { + fn new() -> Bottom { + Bottom + } +} + +link!(Top, A); +link!(A, B); +link!(B, C); +link!(C, D); +link!(D, E); +link!(E, F); +link!(F, G); +link!(G, H); +link!(H, I); +link!(I, J); +link!(J, K); +link!(K, Bottom); + +fn main() { + let t = Top::new(); + let x: &Bottom = &t; +} + diff --git a/src/test/ui/did_you_mean/recursion_limit_deref.stderr b/src/test/ui/did_you_mean/recursion_limit_deref.stderr new file mode 100644 index 0000000000000..57b28d0373622 --- /dev/null +++ b/src/test/ui/did_you_mean/recursion_limit_deref.stderr @@ -0,0 +1,23 @@ +error[E0055]: reached the recursion limit while auto-dereferencing I + --> $DIR/recursion_limit_deref.rs:60:22 + | +60 | let x: &Bottom = &t; + | ^^ deref recursion limit reached + | + = help: consider adding a `#[recursion_limit="20"]` attribute to your crate + +error[E0055]: reached the recursion limit while auto-dereferencing I + | + = help: consider adding a `#[recursion_limit="20"]` attribute to your crate + +error[E0308]: mismatched types + --> $DIR/recursion_limit_deref.rs:60:22 + | +60 | let x: &Bottom = &t; + | ^^ expected struct `Bottom`, found struct `Top` + | + = note: expected type `&Bottom` + found type `&Top` + +error: aborting due to 3 previous errors + diff --git a/src/test/ui/did_you_mean/recursion_limit_macro.rs b/src/test/ui/did_you_mean/recursion_limit_macro.rs new file mode 100644 index 0000000000000..9fb82b730c9b3 --- /dev/null +++ b/src/test/ui/did_you_mean/recursion_limit_macro.rs @@ -0,0 +1,26 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Test that the recursion limit can be changed and that the compiler +// suggests a fix. In this case, we have a recursing macro that will +// overflow if the number of arguments surpasses the recursion limit. + +#![allow(dead_code)] +#![recursion_limit="10"] + +macro_rules! recurse { + () => { }; + ($t:tt $($tail:tt)*) => { recurse!($($tail)*) }; +} + +fn main() { + recurse!(0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9); +} + diff --git a/src/test/ui/did_you_mean/recursion_limit_macro.stderr b/src/test/ui/did_you_mean/recursion_limit_macro.stderr new file mode 100644 index 0000000000000..19aac1f77e7c1 --- /dev/null +++ b/src/test/ui/did_you_mean/recursion_limit_macro.stderr @@ -0,0 +1,11 @@ +error: recursion limit reached while expanding the macro `recurse` + --> $DIR/recursion_limit_macro.rs:20:31 + | +20 | ($t:tt $($tail:tt)*) => { recurse!($($tail)*) }; + | ^^^^^^^^^^^^^^^^^^^ +... +24 | recurse!(0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9); + | -------------------------------------------------- in this macro invocation + | + = help: consider adding a `#![recursion_limit="20"]` attribute to your crate +