From e753d2105159397eff162aa3f1f7715f96b5772d Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 4 Nov 2018 11:23:34 +0100 Subject: [PATCH 01/41] miri: accept extern types in structs if they are the only field --- src/librustc_mir/interpret/eval_context.rs | 15 ++++++++++++-- src/librustc_mir/interpret/place.rs | 3 ++- src/test/ui/consts/const-eval/issue-55541.rs | 21 ++++++++++++++++++++ 3 files changed, 36 insertions(+), 3 deletions(-) create mode 100644 src/test/ui/consts/const-eval/issue-55541.rs diff --git a/src/librustc_mir/interpret/eval_context.rs b/src/librustc_mir/interpret/eval_context.rs index bc7ad16dc97b..48a8d0bbe56d 100644 --- a/src/librustc_mir/interpret/eval_context.rs +++ b/src/librustc_mir/interpret/eval_context.rs @@ -371,8 +371,19 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tc // the last field). Can't have foreign types here, how would we // adjust alignment and size for them? let field = layout.field(self, layout.fields.count() - 1)?; - let (unsized_size, unsized_align) = self.size_and_align_of(metadata, field)? - .expect("Fields cannot be extern types"); + let (unsized_size, unsized_align) = match self.size_and_align_of(metadata, field)? { + Some(size_and_align) => size_and_align, + None => { + // A field with extern type. If this is the only field, + // we treat this struct just the same. Else, this is an error + // (for now). + if layout.fields.count() == 1 { + return Ok(None) + } else { + bug!("Fields cannot be extern types, unless they are the only field") + } + } + }; // FIXME (#26403, #27023): We should be adding padding // to `sized_size` (to accommodate the `unsized_align` diff --git a/src/librustc_mir/interpret/place.rs b/src/librustc_mir/interpret/place.rs index 3b104e2284fe..8bd29aff841c 100644 --- a/src/librustc_mir/interpret/place.rs +++ b/src/librustc_mir/interpret/place.rs @@ -354,7 +354,8 @@ where let (meta, offset) = if field_layout.is_unsized() { // re-use parent metadata to determine dynamic field layout let (_, align) = self.size_and_align_of(base.meta, field_layout)? - .expect("Fields cannot be extern types"); + // If this is an extern type, we fall back to its static size and alignment. + .unwrap_or_else(|| base.layout.size_and_align()); (base.meta, offset.abi_align(align)) } else { // base.meta could be present; we might be accessing a sized field of an unsized diff --git a/src/test/ui/consts/const-eval/issue-55541.rs b/src/test/ui/consts/const-eval/issue-55541.rs new file mode 100644 index 000000000000..bf8965e83618 --- /dev/null +++ b/src/test/ui/consts/const-eval/issue-55541.rs @@ -0,0 +1,21 @@ +// compile-pass + +// Test that we can handle newtypes wrapping extern types + +#![feature(extern_types, const_transmute)] + +extern "C" { + pub type ExternType; +} +unsafe impl Sync for ExternType {} + +#[repr(transparent)] +pub struct Wrapper(ExternType); + +static MAGIC_FFI_STATIC: u8 = 42; + +pub static MAGIC_FFI_REF: &'static Wrapper = unsafe { + std::mem::transmute(&MAGIC_FFI_STATIC) +}; + +fn main() {} From aca76d42a05c419a539d9b34fa30b88d4cdcadcc Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 4 Nov 2018 11:55:39 +0100 Subject: [PATCH 02/41] test for offset and alignment of the sized part, instead of field count --- src/librustc_mir/interpret/eval_context.rs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/librustc_mir/interpret/eval_context.rs b/src/librustc_mir/interpret/eval_context.rs index 48a8d0bbe56d..c1c2efdae751 100644 --- a/src/librustc_mir/interpret/eval_context.rs +++ b/src/librustc_mir/interpret/eval_context.rs @@ -374,13 +374,13 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tc let (unsized_size, unsized_align) = match self.size_and_align_of(metadata, field)? { Some(size_and_align) => size_and_align, None => { - // A field with extern type. If this is the only field, - // we treat this struct just the same. Else, this is an error - // (for now). - if layout.fields.count() == 1 { + // A field with extern type. If this field is at offset 0 and the sized + // part makes no alignment constraints, we behave like the underlying + // extern type. + if sized_size == Size::ZERO && sized_align.abi() == 1 { return Ok(None) } else { - bug!("Fields cannot be extern types, unless they are the only field") + bug!("Fields cannot be extern types, unless they are at offset 0") } } }; From bb17f717499132a23e1b54bf3fdd0727c09715ff Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 4 Nov 2018 14:43:05 +0100 Subject: [PATCH 03/41] also test with PhantomData --- src/test/ui/consts/const-eval/issue-55541.rs | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/src/test/ui/consts/const-eval/issue-55541.rs b/src/test/ui/consts/const-eval/issue-55541.rs index bf8965e83618..611fb89341de 100644 --- a/src/test/ui/consts/const-eval/issue-55541.rs +++ b/src/test/ui/consts/const-eval/issue-55541.rs @@ -4,18 +4,24 @@ #![feature(extern_types, const_transmute)] +use std::marker::PhantomData; + extern "C" { pub type ExternType; } unsafe impl Sync for ExternType {} +static MAGIC_FFI_STATIC: u8 = 42; #[repr(transparent)] pub struct Wrapper(ExternType); - -static MAGIC_FFI_STATIC: u8 = 42; - pub static MAGIC_FFI_REF: &'static Wrapper = unsafe { std::mem::transmute(&MAGIC_FFI_STATIC) }; +#[repr(transparent)] +pub struct Wrapper2(PhantomData>, ExternType); +pub static MAGIC_FFI_REF2: &'static Wrapper2 = unsafe { + std::mem::transmute(&MAGIC_FFI_STATIC) +}; + fn main() {} From 5ebd077f54c735aeb634d18080c9f127016f1c87 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 5 Nov 2018 11:14:21 +0100 Subject: [PATCH 04/41] make it more obvious that the size is not relevant --- src/librustc_mir/interpret/place.rs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/librustc_mir/interpret/place.rs b/src/librustc_mir/interpret/place.rs index 8bd29aff841c..3dcd081edf9d 100644 --- a/src/librustc_mir/interpret/place.rs +++ b/src/librustc_mir/interpret/place.rs @@ -353,9 +353,10 @@ where // Offset may need adjustment for unsized fields let (meta, offset) = if field_layout.is_unsized() { // re-use parent metadata to determine dynamic field layout - let (_, align) = self.size_and_align_of(base.meta, field_layout)? - // If this is an extern type, we fall back to its static size and alignment. - .unwrap_or_else(|| base.layout.size_and_align()); + let align = self.size_and_align_of(base.meta, field_layout)? + .map(|(_, align)| align) + // If this is an extern type, we fall back to its static alignment. + .unwrap_or_else(|| base.layout.align); (base.meta, offset.abi_align(align)) } else { // base.meta could be present; we might be accessing a sized field of an unsized From a6622c265c9a359c277af576c4849a74d476f597 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 5 Nov 2018 11:20:01 +0100 Subject: [PATCH 05/41] note some FIXMEs --- src/librustc_mir/interpret/eval_context.rs | 3 +++ src/librustc_mir/interpret/place.rs | 3 +++ 2 files changed, 6 insertions(+) diff --git a/src/librustc_mir/interpret/eval_context.rs b/src/librustc_mir/interpret/eval_context.rs index c1c2efdae751..797e0458e531 100644 --- a/src/librustc_mir/interpret/eval_context.rs +++ b/src/librustc_mir/interpret/eval_context.rs @@ -377,6 +377,9 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tc // A field with extern type. If this field is at offset 0 and the sized // part makes no alignment constraints, we behave like the underlying // extern type. + // FIXME: Once we have made decisions for how to handle size and alignment + // of `extern type`, this should be adapted. It is just a temporary hack + // to get some code to work that probably ought to work. if sized_size == Size::ZERO && sized_align.abi() == 1 { return Ok(None) } else { diff --git a/src/librustc_mir/interpret/place.rs b/src/librustc_mir/interpret/place.rs index 3dcd081edf9d..c60ae7b4a00c 100644 --- a/src/librustc_mir/interpret/place.rs +++ b/src/librustc_mir/interpret/place.rs @@ -356,6 +356,9 @@ where let align = self.size_and_align_of(base.meta, field_layout)? .map(|(_, align)| align) // If this is an extern type, we fall back to its static alignment. + // FIXME: Once we have made decisions for how to handle size and alignment + // of `extern type`, this should be adapted. It is just a temporary hack + // to get some code to work that probably ought to work. .unwrap_or_else(|| base.layout.align); (base.meta, offset.abi_align(align)) } else { From 1224e0197a21a048385a663ffc548bcc777099f4 Mon Sep 17 00:00:00 2001 From: kngwyu Date: Tue, 6 Nov 2018 15:34:03 +0900 Subject: [PATCH 06/41] Format BtreeMap::range_mut example --- src/liballoc/collections/btree/map.rs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/liballoc/collections/btree/map.rs b/src/liballoc/collections/btree/map.rs index 24c8fd3a969c..49e488702b4b 100644 --- a/src/liballoc/collections/btree/map.rs +++ b/src/liballoc/collections/btree/map.rs @@ -853,9 +853,10 @@ impl BTreeMap { /// ``` /// use std::collections::BTreeMap; /// - /// let mut map: BTreeMap<&str, i32> = ["Alice", "Bob", "Carol", "Cheryl"].iter() - /// .map(|&s| (s, 0)) - /// .collect(); + /// let mut map: BTreeMap<&str, i32> = ["Alice", "Bob", "Carol", "Cheryl"] + /// .iter() + /// .map(|&s| (s, 0)) + /// .collect(); /// for (_, balance) in map.range_mut("B".."Cheryl") { /// *balance += 100; /// } From ba0bab39e04a13ad996e41a2ef2ca9b83fbb2cf4 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 6 Nov 2018 08:41:56 +0100 Subject: [PATCH 07/41] make sure we only guess field alignment at offset 0 --- src/librustc_mir/interpret/eval_context.rs | 7 +++---- src/librustc_mir/interpret/place.rs | 18 +++++++++++------- 2 files changed, 14 insertions(+), 11 deletions(-) diff --git a/src/librustc_mir/interpret/eval_context.rs b/src/librustc_mir/interpret/eval_context.rs index 797e0458e531..cca4e8a3ce31 100644 --- a/src/librustc_mir/interpret/eval_context.rs +++ b/src/librustc_mir/interpret/eval_context.rs @@ -374,13 +374,12 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tc let (unsized_size, unsized_align) = match self.size_and_align_of(metadata, field)? { Some(size_and_align) => size_and_align, None => { - // A field with extern type. If this field is at offset 0 and the sized - // part makes no alignment constraints, we behave like the underlying - // extern type. + // A field with extern type. If this field is at offset 0, we behave + // like the underlying extern type. // FIXME: Once we have made decisions for how to handle size and alignment // of `extern type`, this should be adapted. It is just a temporary hack // to get some code to work that probably ought to work. - if sized_size == Size::ZERO && sized_align.abi() == 1 { + if sized_size == Size::ZERO { return Ok(None) } else { bug!("Fields cannot be extern types, unless they are at offset 0") diff --git a/src/librustc_mir/interpret/place.rs b/src/librustc_mir/interpret/place.rs index c60ae7b4a00c..a836a199f768 100644 --- a/src/librustc_mir/interpret/place.rs +++ b/src/librustc_mir/interpret/place.rs @@ -353,13 +353,17 @@ where // Offset may need adjustment for unsized fields let (meta, offset) = if field_layout.is_unsized() { // re-use parent metadata to determine dynamic field layout - let align = self.size_and_align_of(base.meta, field_layout)? - .map(|(_, align)| align) - // If this is an extern type, we fall back to its static alignment. - // FIXME: Once we have made decisions for how to handle size and alignment - // of `extern type`, this should be adapted. It is just a temporary hack - // to get some code to work that probably ought to work. - .unwrap_or_else(|| base.layout.align); + let align = match self.size_and_align_of(base.meta, field_layout)? { + Some((_, align)) => align, + None if offset == Size::ZERO => + // An extern type at offset 0, we fall back to its static alignment. + // FIXME: Once we have made decisions for how to handle size and alignment + // of `extern type`, this should be adapted. It is just a temporary hack + // to get some code to work that probably ought to work. + field_layout.align, + None => + bug!("Cannot compute offset for extern type field at non-0 offset"), + }; (base.meta, offset.abi_align(align)) } else { // base.meta could be present; we might be accessing a sized field of an unsized From ece4f472c923d72faf50efaaba60a8f51c143bec Mon Sep 17 00:00:00 2001 From: "Felix S. Klock II" Date: Thu, 8 Nov 2018 11:37:27 +0100 Subject: [PATCH 08/41] For diagnostics, set spans of drops of temps to be that of the statement's terminating semicolon. --- src/librustc_mir/build/block.rs | 4 ++-- src/librustc_mir/build/expr/as_rvalue.rs | 2 +- src/librustc_mir/build/expr/into.rs | 2 +- src/librustc_mir/build/expr/stmt.rs | 25 +++++++++++++++++++++--- src/librustc_mir/hair/cx/block.rs | 3 +++ src/librustc_mir/hair/mod.rs | 4 ++++ 6 files changed, 33 insertions(+), 7 deletions(-) diff --git a/src/librustc_mir/build/block.rs b/src/librustc_mir/build/block.rs index aa383a123b69..83e132054a9a 100644 --- a/src/librustc_mir/build/block.rs +++ b/src/librustc_mir/build/block.rs @@ -90,7 +90,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { let source_info = this.source_info(span); for stmt in stmts { - let Stmt { kind, opt_destruction_scope } = this.hir.mirror(stmt); + let Stmt { kind, opt_destruction_scope, span: stmt_span } = this.hir.mirror(stmt); match kind { StmtKind::Expr { scope, expr } => { this.block_context.push(BlockFrame::Statement { ignores_expr_result: true }); @@ -99,7 +99,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { let si = (scope, source_info); this.in_scope(si, LintLevel::Inherited, block, |this| { let expr = this.hir.mirror(expr); - this.stmt_expr(block, expr) + this.stmt_expr(block, expr, Some(stmt_span)) }) })); } diff --git a/src/librustc_mir/build/expr/as_rvalue.rs b/src/librustc_mir/build/expr/as_rvalue.rs index 8fee74390cc6..18ce7ae49070 100644 --- a/src/librustc_mir/build/expr/as_rvalue.rs +++ b/src/librustc_mir/build/expr/as_rvalue.rs @@ -351,7 +351,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { block.and(Rvalue::Aggregate(adt, fields)) } ExprKind::Assign { .. } | ExprKind::AssignOp { .. } => { - block = unpack!(this.stmt_expr(block, expr)); + block = unpack!(this.stmt_expr(block, expr, None)); block.and(this.unit_rvalue()) } ExprKind::Yield { value } => { diff --git a/src/librustc_mir/build/expr/into.rs b/src/librustc_mir/build/expr/into.rs index d2913872fca4..8eb46a048391 100644 --- a/src/librustc_mir/build/expr/into.rs +++ b/src/librustc_mir/build/expr/into.rs @@ -351,7 +351,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { | ExprKind::Break { .. } | ExprKind::InlineAsm { .. } | ExprKind::Return { .. } => { - unpack!(block = this.stmt_expr(block, expr)); + unpack!(block = this.stmt_expr(block, expr, None)); this.cfg.push_assign_unit(block, source_info, destination); block.unit() } diff --git a/src/librustc_mir/build/expr/stmt.rs b/src/librustc_mir/build/expr/stmt.rs index 8f52499124ab..3b9fb7237b0c 100644 --- a/src/librustc_mir/build/expr/stmt.rs +++ b/src/librustc_mir/build/expr/stmt.rs @@ -14,7 +14,18 @@ use hair::*; use rustc::mir::*; impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { - pub fn stmt_expr(&mut self, mut block: BasicBlock, expr: Expr<'tcx>) -> BlockAnd<()> { + /// Builds a block of MIR statements to evaluate the HAIR `expr`. + /// If the original expression was an AST statement, + /// (e.g. `some().code(&here());`) then `opt_stmt_span` is the + /// span of that statement (including its semicolon, if any). + /// Diagnostics use this span (which may be larger than that of + /// `expr`) to identify when statement temporaries are dropped. + pub fn stmt_expr(&mut self, + mut block: BasicBlock, + expr: Expr<'tcx>, + opt_stmt_span: Option) + -> BlockAnd<()> + { let this = self; let expr_span = expr.span; let source_info = this.source_info(expr.span); @@ -29,7 +40,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { } => { let value = this.hir.mirror(value); this.in_scope((region_scope, source_info), lint_level, block, |this| { - this.stmt_expr(block, value) + this.stmt_expr(block, value, opt_stmt_span) }) } ExprKind::Assign { lhs, rhs } => { @@ -192,7 +203,15 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { let expr_ty = expr.ty; let temp = this.temp(expr.ty.clone(), expr_span); unpack!(block = this.into(&temp, block, expr)); - unpack!(block = this.build_drop(block, expr_span, temp, expr_ty)); + + // Attribute drops of the statement's temps to the + // semicolon at the statement's end. + let drop_point = this.hir.tcx().sess.source_map().end_point(match opt_stmt_span { + None => expr_span, + Some(StatementSpan(span)) => span, + }); + + unpack!(block = this.build_drop(block, drop_point, temp, expr_ty)); block.unit() } } diff --git a/src/librustc_mir/hair/cx/block.rs b/src/librustc_mir/hair/cx/block.rs index 586d6d87fa0d..d56ddcb49440 100644 --- a/src/librustc_mir/hair/cx/block.rs +++ b/src/librustc_mir/hair/cx/block.rs @@ -57,6 +57,7 @@ fn mirror_stmts<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, for (index, stmt) in stmts.iter().enumerate() { let hir_id = cx.tcx.hir.node_to_hir_id(stmt.node.id()); let opt_dxn_ext = cx.region_scope_tree.opt_destruction_scope(hir_id.local_id); + let stmt_span = StatementSpan(cx.tcx.hir.span(stmt.node.id())); match stmt.node { hir::StmtKind::Expr(ref expr, _) | hir::StmtKind::Semi(ref expr, _) => { @@ -69,6 +70,7 @@ fn mirror_stmts<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, expr: expr.to_ref(), }, opt_destruction_scope: opt_dxn_ext, + span: stmt_span, }))) } hir::StmtKind::Decl(ref decl, _) => { @@ -111,6 +113,7 @@ fn mirror_stmts<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, lint_level: cx.lint_level_of(local.id), }, opt_destruction_scope: opt_dxn_ext, + span: stmt_span, }))); } } diff --git a/src/librustc_mir/hair/mod.rs b/src/librustc_mir/hair/mod.rs index 8a24851de814..fd1ddcc1cc6c 100644 --- a/src/librustc_mir/hair/mod.rs +++ b/src/librustc_mir/hair/mod.rs @@ -71,10 +71,14 @@ pub enum StmtRef<'tcx> { Mirror(Box>), } +#[derive(Clone, Debug)] +pub struct StatementSpan(pub Span); + #[derive(Clone, Debug)] pub struct Stmt<'tcx> { pub kind: StmtKind<'tcx>, pub opt_destruction_scope: Option, + pub span: StatementSpan, } #[derive(Clone, Debug)] From 3011ecdeac214aeb99714abbefffbf6a1fe1e0c8 Mon Sep 17 00:00:00 2001 From: "Felix S. Klock II" Date: Thu, 8 Nov 2018 12:39:54 +0100 Subject: [PATCH 09/41] Narrow span of temp holding the value of a Block expression to the block's tail (if present). --- src/librustc_mir/build/expr/stmt.rs | 25 ++++++++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) diff --git a/src/librustc_mir/build/expr/stmt.rs b/src/librustc_mir/build/expr/stmt.rs index 3b9fb7237b0c..708ddd3842d8 100644 --- a/src/librustc_mir/build/expr/stmt.rs +++ b/src/librustc_mir/build/expr/stmt.rs @@ -201,7 +201,30 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { } _ => { let expr_ty = expr.ty; - let temp = this.temp(expr.ty.clone(), expr_span); + + // Issue #54382: When creating temp for the value of + // expression like: + // + // `{ side_effects(); { let l = stuff(); the_value } }` + // + // it is usually better to focus on `the_value` rather + // than the entirety of block(s) surrounding it. + let mut temp_span = expr_span; + if let ExprKind::Block { body } = expr.kind { + if let Some(tail_expr) = &body.expr { + let mut expr = tail_expr; + while let rustc::hir::ExprKind::Block(subblock, _label) = &expr.node { + if let Some(subtail_expr) = &subblock.expr { + expr = subtail_expr + } else { + break; + } + } + temp_span = expr.span; + } + } + + let temp = this.temp(expr.ty.clone(), temp_span); unpack!(block = this.into(&temp, block, expr)); // Attribute drops of the statement's temps to the From 556f583587ce87bfaa5e1fd27bc89d8fdfe84339 Mon Sep 17 00:00:00 2001 From: "Felix S. Klock II" Date: Thu, 8 Nov 2018 12:52:53 +0100 Subject: [PATCH 10/41] Regression test for issue #54382 (I opted to rely on compare-mode=nll rather than opt into `#![feature(nll)]`, mostly to make it easy to observe the interesting differences between the AST-borrwock diagnostic and the NLL one.) --- ...54382-use-span-of-tail-of-block.nll.stderr | 18 ++++++++++++ .../issue-54382-use-span-of-tail-of-block.rs | 28 +++++++++++++++++++ ...sue-54382-use-span-of-tail-of-block.stderr | 15 ++++++++++ 3 files changed, 61 insertions(+) create mode 100644 src/test/ui/nll/issue-54382-use-span-of-tail-of-block.nll.stderr create mode 100644 src/test/ui/nll/issue-54382-use-span-of-tail-of-block.rs create mode 100644 src/test/ui/nll/issue-54382-use-span-of-tail-of-block.stderr diff --git a/src/test/ui/nll/issue-54382-use-span-of-tail-of-block.nll.stderr b/src/test/ui/nll/issue-54382-use-span-of-tail-of-block.nll.stderr new file mode 100644 index 000000000000..31f49b2836e9 --- /dev/null +++ b/src/test/ui/nll/issue-54382-use-span-of-tail-of-block.nll.stderr @@ -0,0 +1,18 @@ +error[E0597]: `_thing1` does not live long enough + --> $DIR/issue-54382-use-span-of-tail-of-block.rs:7:29 + | +LL | D("other").next(&_thing1) + | ----------------^^^^^^^^- + | | | + | | borrowed value does not live long enough + | a temporary with access to the borrow is created here ... +LL | } +LL | } + | - `_thing1` dropped here while still borrowed +LL | +LL | ; + | - ... and the borrow might be used here, when that temporary is dropped and runs the `Drop` code for type `D` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0597`. diff --git a/src/test/ui/nll/issue-54382-use-span-of-tail-of-block.rs b/src/test/ui/nll/issue-54382-use-span-of-tail-of-block.rs new file mode 100644 index 000000000000..99eafe0e9d18 --- /dev/null +++ b/src/test/ui/nll/issue-54382-use-span-of-tail-of-block.rs @@ -0,0 +1,28 @@ +fn main() { + { + let mut _thing1 = D(Box::new("thing1")); + { + let _thing2 = D("thing2"); + side_effects(); + D("other").next(&_thing1) + } + } + + ; +} + +#[derive(Debug)] +struct D(T); + +impl Drop for D { + fn drop(&mut self) { + println!("dropping {:?})", self); + } +} + +impl D { + fn next(&self, _other: U) -> D { D(_other) } + fn end(&self) { } +} + +fn side_effects() { } diff --git a/src/test/ui/nll/issue-54382-use-span-of-tail-of-block.stderr b/src/test/ui/nll/issue-54382-use-span-of-tail-of-block.stderr new file mode 100644 index 000000000000..eeba7d6bb445 --- /dev/null +++ b/src/test/ui/nll/issue-54382-use-span-of-tail-of-block.stderr @@ -0,0 +1,15 @@ +error[E0597]: `_thing1` does not live long enough + --> $DIR/issue-54382-use-span-of-tail-of-block.rs:7:30 + | +LL | D("other").next(&_thing1) + | ^^^^^^^ borrowed value does not live long enough +LL | } +LL | } + | - `_thing1` dropped here while still borrowed +LL | +LL | ; + | - borrowed value needs to live until here + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0597`. From e7e1a52f63433c4e5d37836104b8080b3ad4e8c7 Mon Sep 17 00:00:00 2001 From: "Felix S. Klock II" Date: Thu, 8 Nov 2018 14:31:12 +0100 Subject: [PATCH 11/41] Refactor code so that block_context observations has nicely named (and documented) methods. --- src/librustc_mir/build/block.rs | 12 +----- src/librustc_mir/build/expr/as_temp.rs | 16 ++------ src/librustc_mir/build/mod.rs | 56 +++++++++++++++++++++++++- 3 files changed, 58 insertions(+), 26 deletions(-) diff --git a/src/librustc_mir/build/block.rs b/src/librustc_mir/build/block.rs index 83e132054a9a..2ef71617b7cb 100644 --- a/src/librustc_mir/build/block.rs +++ b/src/librustc_mir/build/block.rs @@ -177,17 +177,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { let destination_ty = destination.ty(&this.local_decls, tcx).to_ty(tcx); if let Some(expr) = expr { let tail_result_is_ignored = destination_ty.is_unit() || - match this.block_context.last() { - // no context: conservatively assume result is read - None => false, - - // sub-expression: block result feeds into some computation - Some(BlockFrame::SubExpr) => false, - - // otherwise: use accumualated is_ignored state. - Some(BlockFrame::TailExpr { tail_result_is_ignored: ignored }) | - Some(BlockFrame::Statement { ignores_expr_result: ignored }) => *ignored, - }; + this.block_context.currently_ignores_tail_results(); this.block_context.push(BlockFrame::TailExpr { tail_result_is_ignored }); unpack!(block = this.into(destination, block, expr)); diff --git a/src/librustc_mir/build/expr/as_temp.rs b/src/librustc_mir/build/expr/as_temp.rs index e0bf02c6739e..8f50a1e9a21b 100644 --- a/src/librustc_mir/build/expr/as_temp.rs +++ b/src/librustc_mir/build/expr/as_temp.rs @@ -10,7 +10,7 @@ //! See docs in build/expr/mod.rs -use build::{BlockAnd, BlockAndExtension, BlockFrame, Builder}; +use build::{BlockAnd, BlockAndExtension, Builder}; use hair::*; use rustc::middle::region; use rustc::mir::*; @@ -68,19 +68,9 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { debug!("creating temp {:?} with block_context: {:?}", local_decl, this.block_context); // Find out whether this temp is being created within the // tail expression of a block whose result is ignored. - for bf in this.block_context.iter().rev() { - match bf { - BlockFrame::SubExpr => continue, - BlockFrame::Statement { .. } => break, - &BlockFrame::TailExpr { tail_result_is_ignored } => { - local_decl = local_decl.block_tail(BlockTailInfo { - tail_result_is_ignored - }); - break; - } - } + if let Some(tail_info) = this.block_context.currently_in_block_tail() { + local_decl = local_decl.block_tail(tail_info); } - this.local_decls.push(local_decl) }; if !expr_ty.is_never() { diff --git a/src/librustc_mir/build/mod.rs b/src/librustc_mir/build/mod.rs index 5b4001f0652a..a01f8940a948 100644 --- a/src/librustc_mir/build/mod.rs +++ b/src/librustc_mir/build/mod.rs @@ -336,6 +336,9 @@ impl BlockFrame { } } +#[derive(Debug)] +struct BlockContext(Vec); + struct Builder<'a, 'gcx: 'a+'tcx, 'tcx: 'a> { hir: Cx<'a, 'gcx, 'tcx>, cfg: CFG<'tcx>, @@ -359,7 +362,7 @@ struct Builder<'a, 'gcx: 'a+'tcx, 'tcx: 'a> { /// start just throwing new entries onto that vector in order to /// distinguish the context of EXPR1 from the context of EXPR2 in /// `{ STMTS; EXPR1 } + EXPR2` - block_context: Vec, + block_context: BlockContext, /// The current unsafe block in scope, even if it is hidden by /// a PushUnsafeBlock @@ -409,6 +412,55 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { } } +impl BlockContext { + fn new() -> Self { BlockContext(vec![]) } + fn push(&mut self, bf: BlockFrame) { self.0.push(bf); } + fn pop(&mut self) -> Option { self.0.pop() } + + /// Traverses the frames on the BlockContext, searching for either + /// the first block-tail expression frame with no intervening + /// statement frame. + /// + /// Notably, this skips over `SubExpr` frames; this method is + /// meant to be used in the context of understanding the + /// relationship of a temp (created within some complicated + /// expression) with its containing expression, and whether the + /// value of that *containing expression* (not the temp!) is + /// ignored. + fn currently_in_block_tail(&self) -> Option { + for bf in self.0.iter().rev() { + match bf { + BlockFrame::SubExpr => continue, + BlockFrame::Statement { .. } => break, + &BlockFrame::TailExpr { tail_result_is_ignored } => + return Some(BlockTailInfo { tail_result_is_ignored }) + } + } + + return None; + } + + /// Looks at the topmost frame on the BlockContext and reports + /// whether its one that would discard a block tail result. + /// + /// Unlike `currently_within_ignored_tail_expression`, this does + /// *not* skip over `SubExpr` frames: here, we want to know + /// whether the block result itself is discarded. + fn currently_ignores_tail_results(&self) -> bool { + match self.0.last() { + // no context: conservatively assume result is read + None => false, + + // sub-expression: block result feeds into some computation + Some(BlockFrame::SubExpr) => false, + + // otherwise: use accumulated is_ignored state. + Some(BlockFrame::TailExpr { tail_result_is_ignored: ignored }) | + Some(BlockFrame::Statement { ignores_expr_result: ignored }) => *ignored, + } + } +} + #[derive(Debug)] enum LocalsForNode { /// In the usual case, a node-id for an identifier maps to at most @@ -764,7 +816,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { fn_span: span, arg_count, scopes: vec![], - block_context: vec![], + block_context: BlockContext::new(), source_scopes: IndexVec::new(), source_scope: OUTERMOST_SOURCE_SCOPE, source_scope_local_data: IndexVec::new(), From dd6398256ec0bde52722831d6b6cf604c9cdf1ed Mon Sep 17 00:00:00 2001 From: "Felix S. Klock II" Date: Thu, 8 Nov 2018 14:32:17 +0100 Subject: [PATCH 12/41] Revise the temp creation for blocks in `stmt_expr` to setup `BlockTailInfo`. --- src/librustc_mir/build/expr/stmt.rs | 18 +++++++++++++++++- ...-54382-use-span-of-tail-of-block.nll.stderr | 2 ++ 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/src/librustc_mir/build/expr/stmt.rs b/src/librustc_mir/build/expr/stmt.rs index 708ddd3842d8..45235b315393 100644 --- a/src/librustc_mir/build/expr/stmt.rs +++ b/src/librustc_mir/build/expr/stmt.rs @@ -210,6 +210,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { // it is usually better to focus on `the_value` rather // than the entirety of block(s) surrounding it. let mut temp_span = expr_span; + let mut temp_in_tail_of_block = false; if let ExprKind::Block { body } = expr.kind { if let Some(tail_expr) = &body.expr { let mut expr = tail_expr; @@ -221,10 +222,25 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { } } temp_span = expr.span; + temp_in_tail_of_block = true; } } - let temp = this.temp(expr.ty.clone(), temp_span); + let temp = { + let mut local_decl = LocalDecl::new_temp(expr.ty.clone(), temp_span); + if temp_in_tail_of_block { + if this.block_context.currently_ignores_tail_results() { + local_decl = local_decl.block_tail(BlockTailInfo { + tail_result_is_ignored: true + }); + } + } + let temp = this.local_decls.push(local_decl); + let place = Place::Local(temp); + debug!("created temp {:?} for expr {:?} in block_context: {:?}", + temp, expr, this.block_context); + place + }; unpack!(block = this.into(&temp, block, expr)); // Attribute drops of the statement's temps to the diff --git a/src/test/ui/nll/issue-54382-use-span-of-tail-of-block.nll.stderr b/src/test/ui/nll/issue-54382-use-span-of-tail-of-block.nll.stderr index 31f49b2836e9..c308562c0cc7 100644 --- a/src/test/ui/nll/issue-54382-use-span-of-tail-of-block.nll.stderr +++ b/src/test/ui/nll/issue-54382-use-span-of-tail-of-block.nll.stderr @@ -12,6 +12,8 @@ LL | } LL | LL | ; | - ... and the borrow might be used here, when that temporary is dropped and runs the `Drop` code for type `D` + | + = note: The temporary is part of an expression at the end of a block. Consider adding semicolon after the expression so its temporaries are dropped sooner, before the local variables declared by the block are dropped. error: aborting due to previous error From 39771339fd4f62d4c35676bd7cd1ddb4c5d9b84c Mon Sep 17 00:00:00 2001 From: Stjepan Glavina Date: Thu, 8 Nov 2018 15:28:06 +0100 Subject: [PATCH 13/41] Allow unsized types in mem::drop and mem::forget --- src/libcore/intrinsics.rs | 4 + src/libcore/lib.rs | 1 + src/libcore/mem.rs | 120 ++++++++++++++++++++++++- src/librustc_codegen_llvm/intrinsic.rs | 2 +- src/librustc_typeck/check/intrinsic.rs | 1 + 5 files changed, 126 insertions(+), 2 deletions(-) diff --git a/src/libcore/intrinsics.rs b/src/libcore/intrinsics.rs index cceae9249e45..4fcce7096b4b 100644 --- a/src/libcore/intrinsics.rs +++ b/src/libcore/intrinsics.rs @@ -714,6 +714,10 @@ extern "rust-intrinsic" { /// initialize memory previous set to the result of `uninit`. pub fn uninit() -> T; + /// Moves a value out of scope without running drop glue. + #[cfg(not(stage0))] + pub fn forget(_: T); + /// Reinterprets the bits of a value of one type as another type. /// /// Both types must have the same size. Neither the original, nor the result, diff --git a/src/libcore/lib.rs b/src/libcore/lib.rs index 1bbc7892c6be..b7d0742877ee 100644 --- a/src/libcore/lib.rs +++ b/src/libcore/lib.rs @@ -107,6 +107,7 @@ #![feature(staged_api)] #![feature(stmt_expr_attributes)] #![feature(unboxed_closures)] +#![feature(unsized_locals)] #![feature(untagged_unions)] #![feature(unwind_attributes)] #![feature(doc_alias)] diff --git a/src/libcore/mem.rs b/src/libcore/mem.rs index 1d0b194487e6..cff605489ed3 100644 --- a/src/libcore/mem.rs +++ b/src/libcore/mem.rs @@ -139,6 +139,124 @@ pub use intrinsics::transmute; /// [ub]: ../../reference/behavior-considered-undefined.html #[inline] #[stable(feature = "rust1", since = "1.0.0")] +#[cfg(not(stage0))] +pub fn forget(t: T) { + unsafe { intrinsics::forget(t) } +} + +/// Takes ownership and "forgets" about the value **without running its destructor**. +/// +/// Any resources the value manages, such as heap memory or a file handle, will linger +/// forever in an unreachable state. However, it does not guarantee that pointers +/// to this memory will remain valid. +/// +/// * If you want to leak memory, see [`Box::leak`][leak]. +/// * If you want to obtain a raw pointer to the memory, see [`Box::into_raw`][into_raw]. +/// * If you want to dispose of a value properly, running its destructor, see +/// [`mem::drop`][drop]. +/// +/// # Safety +/// +/// `forget` is not marked as `unsafe`, because Rust's safety guarantees +/// do not include a guarantee that destructors will always run. For example, +/// a program can create a reference cycle using [`Rc`][rc], or call +/// [`process::exit`][exit] to exit without running destructors. Thus, allowing +/// `mem::forget` from safe code does not fundamentally change Rust's safety +/// guarantees. +/// +/// That said, leaking resources such as memory or I/O objects is usually undesirable, +/// so `forget` is only recommended for specialized use cases like those shown below. +/// +/// Because forgetting a value is allowed, any `unsafe` code you write must +/// allow for this possibility. You cannot return a value and expect that the +/// caller will necessarily run the value's destructor. +/// +/// [rc]: ../../std/rc/struct.Rc.html +/// [exit]: ../../std/process/fn.exit.html +/// +/// # Examples +/// +/// Leak an I/O object, never closing the file: +/// +/// ```no_run +/// use std::mem; +/// use std::fs::File; +/// +/// let file = File::open("foo.txt").unwrap(); +/// mem::forget(file); +/// ``` +/// +/// The practical use cases for `forget` are rather specialized and mainly come +/// up in unsafe or FFI code. +/// +/// ## Use case 1 +/// +/// You have created an uninitialized value using [`mem::uninitialized`][uninit]. +/// You must either initialize or `forget` it on every computation path before +/// Rust drops it automatically, like at the end of a scope or after a panic. +/// Running the destructor on an uninitialized value would be [undefined behavior][ub]. +/// +/// ``` +/// use std::mem; +/// use std::ptr; +/// +/// # let some_condition = false; +/// unsafe { +/// let mut uninit_vec: Vec = mem::uninitialized(); +/// +/// if some_condition { +/// // Initialize the variable. +/// ptr::write(&mut uninit_vec, Vec::new()); +/// } else { +/// // Forget the uninitialized value so its destructor doesn't run. +/// mem::forget(uninit_vec); +/// } +/// } +/// ``` +/// +/// ## Use case 2 +/// +/// You have duplicated the bytes making up a value, without doing a proper +/// [`Clone`][clone]. You need the value's destructor to run only once, +/// because a double `free` is undefined behavior. +/// +/// An example is a possible implementation of [`mem::swap`][swap]: +/// +/// ``` +/// use std::mem; +/// use std::ptr; +/// +/// # #[allow(dead_code)] +/// fn swap(x: &mut T, y: &mut T) { +/// unsafe { +/// // Give ourselves some scratch space to work with +/// let mut t: T = mem::uninitialized(); +/// +/// // Perform the swap, `&mut` pointers never alias +/// ptr::copy_nonoverlapping(&*x, &mut t, 1); +/// ptr::copy_nonoverlapping(&*y, x, 1); +/// ptr::copy_nonoverlapping(&t, y, 1); +/// +/// // y and t now point to the same thing, but we need to completely +/// // forget `t` because we do not want to run the destructor for `T` +/// // on its value, which is still owned somewhere outside this function. +/// mem::forget(t); +/// } +/// } +/// ``` +/// +/// [drop]: fn.drop.html +/// [uninit]: fn.uninitialized.html +/// [clone]: ../clone/trait.Clone.html +/// [swap]: fn.swap.html +/// [FFI]: ../../book/first-edition/ffi.html +/// [box]: ../../std/boxed/struct.Box.html +/// [leak]: ../../std/boxed/struct.Box.html#method.leak +/// [into_raw]: ../../std/boxed/struct.Box.html#method.into_raw +/// [ub]: ../../reference/behavior-considered-undefined.html +#[inline] +#[cfg(stage0)] +#[stable(feature = "rust1", since = "1.0.0")] pub fn forget(t: T) { ManuallyDrop::new(t); } @@ -763,7 +881,7 @@ pub fn replace(dest: &mut T, mut src: T) -> T { /// [`Copy`]: ../../std/marker/trait.Copy.html #[inline] #[stable(feature = "rust1", since = "1.0.0")] -pub fn drop(_x: T) { } +pub fn drop(_x: T) { } /// Interprets `src` as having type `&U`, and then reads `src` without moving /// the contained value. diff --git a/src/librustc_codegen_llvm/intrinsic.rs b/src/librustc_codegen_llvm/intrinsic.rs index 03244c18ac3e..1681e0137bd6 100644 --- a/src/librustc_codegen_llvm/intrinsic.rs +++ b/src/librustc_codegen_llvm/intrinsic.rs @@ -193,7 +193,7 @@ pub fn codegen_intrinsic_call( return; } // Effectively no-ops - "uninit" => { + "uninit" | "forget" => { return; } "needs_drop" => { diff --git a/src/librustc_typeck/check/intrinsic.rs b/src/librustc_typeck/check/intrinsic.rs index 3156458b4aa4..0279105473f2 100644 --- a/src/librustc_typeck/check/intrinsic.rs +++ b/src/librustc_typeck/check/intrinsic.rs @@ -134,6 +134,7 @@ pub fn check_intrinsic_type<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, "rustc_peek" => (1, vec![param(0)], param(0)), "init" => (1, Vec::new(), param(0)), "uninit" => (1, Vec::new(), param(0)), + "forget" => (1, vec![param(0)], param(0)), "transmute" => (2, vec![ param(0) ], param(1)), "move_val_init" => { (1, From 06cf9ae7f98f06cde8424ce569efe72c0728c252 Mon Sep 17 00:00:00 2001 From: Stjepan Glavina Date: Thu, 8 Nov 2018 17:12:14 +0100 Subject: [PATCH 14/41] Fix return type of forget intrinsic --- src/librustc_typeck/check/intrinsic.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/librustc_typeck/check/intrinsic.rs b/src/librustc_typeck/check/intrinsic.rs index 0279105473f2..f34cd53e4c9f 100644 --- a/src/librustc_typeck/check/intrinsic.rs +++ b/src/librustc_typeck/check/intrinsic.rs @@ -134,7 +134,7 @@ pub fn check_intrinsic_type<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, "rustc_peek" => (1, vec![param(0)], param(0)), "init" => (1, Vec::new(), param(0)), "uninit" => (1, Vec::new(), param(0)), - "forget" => (1, vec![param(0)], param(0)), + "forget" => (1, vec![param(0)], tcx.mk_unit()), "transmute" => (2, vec![ param(0) ], param(1)), "move_val_init" => { (1, From f211581330399945802a227c4405fd92f983a2b8 Mon Sep 17 00:00:00 2001 From: Stjepan Glavina Date: Thu, 8 Nov 2018 17:58:12 +0100 Subject: [PATCH 15/41] Use T: ?Sized in intrinsics::forget --- src/libcore/intrinsics.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libcore/intrinsics.rs b/src/libcore/intrinsics.rs index 4fcce7096b4b..f795e41f7c5f 100644 --- a/src/libcore/intrinsics.rs +++ b/src/libcore/intrinsics.rs @@ -716,7 +716,7 @@ extern "rust-intrinsic" { /// Moves a value out of scope without running drop glue. #[cfg(not(stage0))] - pub fn forget(_: T); + pub fn forget(_: T); /// Reinterprets the bits of a value of one type as another type. /// From 401cb6bb539e95733290d1b0487f682f48b3f9cd Mon Sep 17 00:00:00 2001 From: QuietMisdreavus Date: Thu, 8 Nov 2018 19:06:16 -0600 Subject: [PATCH 16/41] don't inline `pub use some_crate` unless directly asked to --- src/doc/rustdoc/src/the-doc-attribute.md | 3 ++ src/librustdoc/clean/mod.rs | 15 +++++++- .../inline_cross/auxiliary/use_crate.rs | 15 ++++++++ .../inline_cross/auxiliary/use_crate_2.rs | 11 ++++++ src/test/rustdoc/inline_cross/use_crate.rs | 37 +++++++++++++++++++ src/test/rustdoc/src-links-external.rs | 1 + 6 files changed, 81 insertions(+), 1 deletion(-) create mode 100644 src/test/rustdoc/inline_cross/auxiliary/use_crate.rs create mode 100644 src/test/rustdoc/inline_cross/auxiliary/use_crate_2.rs create mode 100644 src/test/rustdoc/inline_cross/use_crate.rs diff --git a/src/doc/rustdoc/src/the-doc-attribute.md b/src/doc/rustdoc/src/the-doc-attribute.md index 296422744fa4..61e5b3d0133f 100644 --- a/src/doc/rustdoc/src/the-doc-attribute.md +++ b/src/doc/rustdoc/src/the-doc-attribute.md @@ -186,6 +186,9 @@ mod bar { Now we'll have a `Re-exports` line, and `Bar` will not link to anywhere. +One special case: In Rust 2018 and later, if you `pub use` one of your dependencies, `rustdoc` will +not eagerly inline it as a module unless you add `#[doc(inline)}`. + ## `#[doc(hidden)]` Any item annotated with `#[doc(hidden)]` will not appear in the documentation, unless diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index c39b71e33ca0..5a020749f357 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -3499,13 +3499,16 @@ impl Clean> for doctree::Import { // forcefully don't inline if this is not public or if the // #[doc(no_inline)] attribute is present. // Don't inline doc(hidden) imports so they can be stripped at a later stage. - let denied = !self.vis.node.is_pub() || self.attrs.iter().any(|a| { + let mut denied = !self.vis.node.is_pub() || self.attrs.iter().any(|a| { a.name() == "doc" && match a.meta_item_list() { Some(l) => attr::list_contains_name(&l, "no_inline") || attr::list_contains_name(&l, "hidden"), None => false, } }); + // Also check whether imports were asked to be inlined, in case we're trying to re-export a + // crate in Rust 2018+ + let please_inline = self.attrs.lists("doc").has_word("inline"); let path = self.path.clean(cx); let inner = if self.glob { if !denied { @@ -3518,6 +3521,16 @@ impl Clean> for doctree::Import { Import::Glob(resolve_use_source(cx, path)) } else { let name = self.name; + if !please_inline { + match path.def { + Def::Mod(did) => if !did.is_local() && did.index == CRATE_DEF_INDEX { + // if we're `pub use`ing an extern crate root, don't inline it unless we + // were specifically asked for it + denied = true; + } + _ => {} + } + } if !denied { let mut visited = FxHashSet::default(); if let Some(items) = inline::try_inline(cx, path.def, name, &mut visited) { diff --git a/src/test/rustdoc/inline_cross/auxiliary/use_crate.rs b/src/test/rustdoc/inline_cross/auxiliary/use_crate.rs new file mode 100644 index 000000000000..55202de1981b --- /dev/null +++ b/src/test/rustdoc/inline_cross/auxiliary/use_crate.rs @@ -0,0 +1,15 @@ +// Copyright 2018 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. + +pub mod asdf { + pub struct SomeStruct; +} + +pub trait SomeTrait {} diff --git a/src/test/rustdoc/inline_cross/auxiliary/use_crate_2.rs b/src/test/rustdoc/inline_cross/auxiliary/use_crate_2.rs new file mode 100644 index 000000000000..1f11cbc4da71 --- /dev/null +++ b/src/test/rustdoc/inline_cross/auxiliary/use_crate_2.rs @@ -0,0 +1,11 @@ +// Copyright 2018 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. + +pub struct SomethingElse; diff --git a/src/test/rustdoc/inline_cross/use_crate.rs b/src/test/rustdoc/inline_cross/use_crate.rs new file mode 100644 index 000000000000..a98704446ee7 --- /dev/null +++ b/src/test/rustdoc/inline_cross/use_crate.rs @@ -0,0 +1,37 @@ +// Copyright 2018 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:use_crate.rs +// aux-build:use_crate_2.rs +// build-aux-docs +// edition:2018 +// compile-flags:--extern use_crate --extern use_crate_2 -Z unstable-options + +// During the buildup to Rust 2018, rustdoc would eagerly inline `pub use some_crate;` as if it +// were a module, so we changed it to make `pub use`ing crate roots remain as a `pub use` statement +// in docs... unless you added `#[doc(inline)]`. + +#![crate_name = "local"] + +// @!has-dir local/use_crate +// @has local/index.html +// @has - '//code' 'pub use use_crate' +pub use use_crate; + +// @has-dir local/asdf +// @has local/asdf/index.html +// @has local/index.html '//a/@href' 'asdf/index.html' +pub use use_crate::asdf; + +// @has-dir local/use_crate_2 +// @has local/use_crate_2/index.html +// @has local/index.html '//a/@href' 'use_crate_2/index.html' +#[doc(inline)] +pub use use_crate_2; diff --git a/src/test/rustdoc/src-links-external.rs b/src/test/rustdoc/src-links-external.rs index d3307bb4d42c..6cc7f1743ad0 100644 --- a/src/test/rustdoc/src-links-external.rs +++ b/src/test/rustdoc/src-links-external.rs @@ -18,6 +18,7 @@ extern crate src_links_external; // @has foo/bar/index.html '//a/@href' '../../src/src_links_external/src-links-external.rs.html#11' +#[doc(inline)] pub use src_links_external as bar; // @has foo/bar/struct.Foo.html '//a/@href' '../../src/src_links_external/src-links-external.rs.html#11' From 893f539394fe34ee34f9aa404a4f8cce0a992866 Mon Sep 17 00:00:00 2001 From: Alex Gaynor Date: Thu, 8 Nov 2018 14:18:17 -0500 Subject: [PATCH 17/41] Fixes #55775 -- fixed regression in Command::exec's handling of PATH. This restores the previous behavior where if env_clear() or env_remove("PATH") was used we fall back to a default PATH of "/bin:/usr/bin" --- src/libstd/sys/unix/process/process_unix.rs | 5 +++-- src/test/run-pass/command-exec.rs | 20 ++++++++++++++++++++ 2 files changed, 23 insertions(+), 2 deletions(-) diff --git a/src/libstd/sys/unix/process/process_unix.rs b/src/libstd/sys/unix/process/process_unix.rs index f41bd2c20720..a5a93908b494 100644 --- a/src/libstd/sys/unix/process/process_unix.rs +++ b/src/libstd/sys/unix/process/process_unix.rs @@ -135,14 +135,15 @@ impl Command { Some(envp) => { match envp.get_items().iter().find(|var| var.as_bytes().starts_with(b"PATH=")) { Some(p) => &p.as_bytes()[5..], - None => return None, + // Chosen to match what glibc does if there's no PATH variable + None => b"/bin:/usr/bin", } }, // maybe_envp is None if the process isn't changing the parent's env at all. None => { match parent_path.as_ref() { Some(p) => p.as_bytes(), - None => return None, + None => b"/bin:/usr/bin", } }, }; diff --git a/src/test/run-pass/command-exec.rs b/src/test/run-pass/command-exec.rs index 96f9da67790f..0352161d7ddf 100644 --- a/src/test/run-pass/command-exec.rs +++ b/src/test/run-pass/command-exec.rs @@ -55,6 +55,16 @@ fn main() { println!("passed"); } + "exec-test6" => { + let err = Command::new("echo").arg("passed").env_clear().exec(); + panic!("failed to spawn: {}", err); + } + + "exec-test7" => { + let err = Command::new("echo").arg("passed").env_remove("PATH").exec(); + panic!("failed to spawn: {}", err); + } + _ => panic!("unknown argument: {}", arg), } return @@ -84,4 +94,14 @@ fn main() { assert!(output.status.success()); assert!(output.stderr.is_empty()); assert_eq!(output.stdout, b"passed\n"); + + let output = Command::new(&me).arg("exec-test6").output().unwrap(); + assert!(output.status.success()); + assert!(output.stderr.is_empty()); + assert_eq!(output.stdout, b"passed\n"); + + let output = Command::new(&me).arg("exec-test7").output().unwrap(); + assert!(output.status.success()); + assert!(output.stderr.is_empty()); + assert_eq!(output.stdout, b"passed\n"); } From 5e7b7f2ae6f29e66c99b6c38d7041fb71e8a36fd Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Sat, 10 Nov 2018 03:39:42 +0100 Subject: [PATCH 18/41] make PhantomData #[structural_match]. --- src/libcore/lib.rs | 1 + src/libcore/marker.rs | 1 + .../phantom-data-is-structurally-matchable.rs | 53 +++++++++++++++++++ 3 files changed, 55 insertions(+) create mode 100644 src/test/ui/rfc1445/phantom-data-is-structurally-matchable.rs diff --git a/src/libcore/lib.rs b/src/libcore/lib.rs index 1bbc7892c6be..b55ec67b0cca 100644 --- a/src/libcore/lib.rs +++ b/src/libcore/lib.rs @@ -129,6 +129,7 @@ #![feature(const_transmute)] #![feature(reverse_bits)] #![feature(non_exhaustive)] +#![feature(structural_match)] #[prelude_import] #[allow(unused)] diff --git a/src/libcore/marker.rs b/src/libcore/marker.rs index 662a8ddd9686..3bcdfabbb245 100644 --- a/src/libcore/marker.rs +++ b/src/libcore/marker.rs @@ -578,6 +578,7 @@ macro_rules! impls{ /// /// [drop check]: ../../nomicon/dropck.html #[lang = "phantom_data"] +#[structural_match] #[stable(feature = "rust1", since = "1.0.0")] pub struct PhantomData; diff --git a/src/test/ui/rfc1445/phantom-data-is-structurally-matchable.rs b/src/test/ui/rfc1445/phantom-data-is-structurally-matchable.rs new file mode 100644 index 000000000000..af025b9bbbf7 --- /dev/null +++ b/src/test/ui/rfc1445/phantom-data-is-structurally-matchable.rs @@ -0,0 +1,53 @@ +// run-pass + +// This file checks that `PhantomData` is considered structurally matchable. + +use std::marker::PhantomData; + +fn main() { + let mut count = 0; + + // A type which is not structurally matchable: + struct NotSM; + + // And one that is: + #[derive(PartialEq, Eq)] + struct SM; + + // Check that SM is #[structural_match]: + const CSM: SM = SM; + match SM { + CSM => count += 1, + }; + + // Check that PhantomData is #[structural_match] even if T is not. + const CPD1: PhantomData = PhantomData; + match PhantomData { + CPD1 => count += 1, + }; + + // Check that PhantomData is #[structural_match] when T is. + const CPD2: PhantomData = PhantomData; + match PhantomData { + CPD2 => count += 1, + }; + + // Check that a type which has a PhantomData is `#[structural_match]`. + #[derive(PartialEq, Eq, Default)] + struct Foo { + alpha: PhantomData, + beta: PhantomData, + } + + const CFOO: Foo = Foo { + alpha: PhantomData, + beta: PhantomData, + }; + + match Foo::default() { + CFOO => count += 1, + }; + + // Final count must be 4 now if all + assert_eq!(count, 4); +} From 852ff1fc7d74a7668441e0f354f8c477c95b676d Mon Sep 17 00:00:00 2001 From: Axary Date: Sat, 10 Nov 2018 11:43:39 +0100 Subject: [PATCH 19/41] add FromIterator to Box<[A]> --- src/liballoc/boxed.rs | 10 +++++++++- src/liballoc/boxed_test.rs | 8 ++++++++ 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/src/liballoc/boxed.rs b/src/liballoc/boxed.rs index 74354f605e53..e1e9617b4917 100644 --- a/src/liballoc/boxed.rs +++ b/src/liballoc/boxed.rs @@ -73,7 +73,7 @@ use core::convert::From; use core::fmt; use core::future::Future; use core::hash::{Hash, Hasher}; -use core::iter::FusedIterator; +use core::iter::{Iterator, FromIterator, FusedIterator}; use core::marker::{Unpin, Unsize}; use core::mem; use core::pin::Pin; @@ -81,6 +81,7 @@ use core::ops::{CoerceUnsized, DispatchFromDyn, Deref, DerefMut, Generator, Gene use core::ptr::{self, NonNull, Unique}; use core::task::{LocalWaker, Poll}; +use vec::Vec; use raw_vec::RawVec; use str::from_boxed_utf8_unchecked; @@ -699,6 +700,13 @@ impl, U: ?Sized> CoerceUnsized> for Box {} #[unstable(feature = "dispatch_from_dyn", issue = "0")] impl, U: ?Sized> DispatchFromDyn> for Box {} +#[unstable(feature = "boxed_slice_from_iter", issue = "0")] +impl FromIterator for Box<[A]> { + fn from_iter>(iter: T) -> Self { + iter.into_iter().collect::>().into_boxed_slice() + } +} + #[stable(feature = "box_slice_clone", since = "1.3.0")] impl Clone for Box<[T]> { fn clone(&self) -> Self { diff --git a/src/liballoc/boxed_test.rs b/src/liballoc/boxed_test.rs index 55995742a4a7..f340ea01c5f0 100644 --- a/src/liballoc/boxed_test.rs +++ b/src/liballoc/boxed_test.rs @@ -140,3 +140,11 @@ fn str_slice() { let boxed: Box = Box::from(s); assert_eq!(&*boxed, s) } + +#[test] +fn boxed_slice_from_iter() { + let iter = 0..100; + let boxed: Box<[u32]> = iter.collect(); + assert_eq!(boxed.len(), 100); + assert_eq!(boxed[7], 7); +} From 3b3b60ce6e095a62351c70e19cd922e1b2357d81 Mon Sep 17 00:00:00 2001 From: Santiago Pastorino Date: Sat, 10 Nov 2018 14:16:04 -0300 Subject: [PATCH 20/41] Avoid converting bytes to UTF-8 strings to print, just pass bytes to stdout/err --- src/libstd/process.rs | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/libstd/process.rs b/src/libstd/process.rs index 58ac4e944087..487df095f18e 100644 --- a/src/libstd/process.rs +++ b/src/libstd/process.rs @@ -764,14 +764,15 @@ impl Command { /// /// ```should_panic /// use std::process::Command; + /// use std::io::{self, Write}; /// let output = Command::new("/bin/cat") /// .arg("file.txt") /// .output() /// .expect("failed to execute process"); /// /// println!("status: {}", output.status); - /// println!("stdout: {}", String::from_utf8_lossy(&output.stdout)); - /// println!("stderr: {}", String::from_utf8_lossy(&output.stderr)); + /// io::stdout().write_all(&output.stdout).unwrap(); + /// io::stderr().write_all(&output.stderr).unwrap(); /// /// assert!(output.status.success()); /// ``` @@ -951,6 +952,7 @@ impl Stdio { /// /// ```no_run /// use std::process::{Command, Stdio}; + /// use std::io::{self, Write}; /// /// let output = Command::new("rev") /// .stdin(Stdio::inherit()) @@ -958,7 +960,8 @@ impl Stdio { /// .output() /// .expect("Failed to execute command"); /// - /// println!("You piped in the reverse of: {}", String::from_utf8_lossy(&output.stdout)); + /// print!("You piped in the reverse of: "); + /// io::stdout().write_all(&output.stdout).unwrap(); /// ``` #[stable(feature = "process", since = "1.0.0")] pub fn inherit() -> Stdio { Stdio(imp::Stdio::Inherit) } From c1487145493c54b41df16eb7ffe6fdd3b82e6a78 Mon Sep 17 00:00:00 2001 From: varkor Date: Sat, 10 Nov 2018 18:08:50 +0000 Subject: [PATCH 21/41] Rewrite `...` as `..=` as a MachineApplicable 2018 idiom lint --- src/librustc/lint/context.rs | 7 ++- src/librustc/lint/mod.rs | 2 +- src/librustc_lint/builtin.rs | 44 ++++++++++++++----- src/librustc_lint/unused.rs | 4 +- .../lint/inclusive-range-pattern-syntax.fixed | 6 +++ .../ui/lint/inclusive-range-pattern-syntax.rs | 6 +++ .../inclusive-range-pattern-syntax.stderr | 6 +++ .../range-inclusive-pattern-precedence.stderr | 4 +- 8 files changed, 62 insertions(+), 17 deletions(-) diff --git a/src/librustc/lint/context.rs b/src/librustc/lint/context.rs index 5470aff77f8a..8acbaaa844d7 100644 --- a/src/librustc/lint/context.rs +++ b/src/librustc/lint/context.rs @@ -1020,9 +1020,12 @@ impl<'a> ast_visit::Visitor<'a> for EarlyContext<'a> { } fn visit_pat(&mut self, p: &'a ast::Pat) { - run_lints!(self, check_pat, p); + let mut visit_subpats = true; + run_lints!(self, check_pat, p, &mut visit_subpats); self.check_id(p.id); - ast_visit::walk_pat(self, p); + if visit_subpats { + ast_visit::walk_pat(self, p); + } } fn visit_expr(&mut self, e: &'a ast::Expr) { diff --git a/src/librustc/lint/mod.rs b/src/librustc/lint/mod.rs index afd780081098..18922ec5d173 100644 --- a/src/librustc/lint/mod.rs +++ b/src/librustc/lint/mod.rs @@ -341,7 +341,7 @@ pub trait EarlyLintPass: LintPass { fn check_block_post(&mut self, _: &EarlyContext<'_>, _: &ast::Block) { } fn check_stmt(&mut self, _: &EarlyContext<'_>, _: &ast::Stmt) { } fn check_arm(&mut self, _: &EarlyContext<'_>, _: &ast::Arm) { } - fn check_pat(&mut self, _: &EarlyContext<'_>, _: &ast::Pat) { } + fn check_pat(&mut self, _: &EarlyContext<'_>, _: &ast::Pat, _: &mut bool) { } fn check_expr(&mut self, _: &EarlyContext<'_>, _: &ast::Expr) { } fn check_expr_post(&mut self, _: &EarlyContext<'_>, _: &ast::Expr) { } fn check_ty(&mut self, _: &EarlyContext<'_>, _: &ast::Ty) { } diff --git a/src/librustc_lint/builtin.rs b/src/librustc_lint/builtin.rs index 2a9b58200e5d..652de5dd1205 100644 --- a/src/librustc_lint/builtin.rs +++ b/src/librustc_lint/builtin.rs @@ -40,6 +40,8 @@ use rustc::util::nodemap::FxHashSet; use syntax::tokenstream::{TokenTree, TokenStream}; use syntax::ast; +use syntax::ptr::P; +use syntax::ast::Expr; use syntax::attr; use syntax::source_map::Spanned; use syntax::edition::Edition; @@ -47,6 +49,7 @@ use syntax::feature_gate::{AttributeGate, AttributeType, Stability, deprecated_a use syntax_pos::{BytePos, Span, SyntaxContext}; use syntax::symbol::keywords; use syntax::errors::{Applicability, DiagnosticBuilder}; +use syntax::print::pprust::expr_to_string; use rustc::hir::{self, GenericParamKind, PatKind}; use rustc::hir::intravisit::FnKind; @@ -1407,21 +1410,42 @@ impl LintPass for EllipsisInclusiveRangePatterns { } impl EarlyLintPass for EllipsisInclusiveRangePatterns { - fn check_pat(&mut self, cx: &EarlyContext, pat: &ast::Pat) { - use self::ast::{PatKind, RangeEnd, RangeSyntax}; + fn check_pat(&mut self, cx: &EarlyContext, pat: &ast::Pat, visit_subpats: &mut bool) { + use self::ast::{PatKind, RangeEnd, RangeSyntax::DotDotDot}; + + /// If `pat` is a `...` pattern, return the start and end of the range, as well as the span + /// corresponding to the ellipsis. + fn matches_ellipsis_pat(pat: &ast::Pat) -> Option<(&P, &P, Span)> { + match &pat.node { + PatKind::Range(a, b, Spanned { span, node: RangeEnd::Included(DotDotDot), .. }) => { + Some((a, b, *span)) + } + _ => None, + } + } + + let (parenthesise, endpoints) = match &pat.node { + PatKind::Ref(subpat, _) => (true, matches_ellipsis_pat(&subpat)), + _ => (false, matches_ellipsis_pat(pat)), + }; - if let PatKind::Range( - _, _, Spanned { span, node: RangeEnd::Included(RangeSyntax::DotDotDot) } - ) = pat.node { + if let Some((start, end, join)) = endpoints { let msg = "`...` range patterns are deprecated"; + let suggestion = "use `..=` for an inclusive range"; + let (span, replacement) = if parenthesise { + *visit_subpats = false; + (pat.span, format!("&({}..={})", expr_to_string(&start), expr_to_string(&end))) + } else { + (join, "..=".to_owned()) + }; let mut err = cx.struct_span_lint(ELLIPSIS_INCLUSIVE_RANGE_PATTERNS, span, msg); err.span_suggestion_short_with_applicability( - span, "use `..=` for an inclusive range", "..=".to_owned(), - // FIXME: outstanding problem with precedence in ref patterns: - // https://github.com/rust-lang/rust/issues/51043#issuecomment-392252285 - Applicability::MaybeIncorrect + span, + suggestion, + replacement, + Applicability::MachineApplicable, ); - err.emit() + err.emit(); } } } diff --git a/src/librustc_lint/unused.rs b/src/librustc_lint/unused.rs index 6d365e6d1ecb..7eab7d210029 100644 --- a/src/librustc_lint/unused.rs +++ b/src/librustc_lint/unused.rs @@ -396,12 +396,12 @@ impl EarlyLintPass for UnusedParens { self.check_unused_parens_expr(cx, &value, msg, followed_by_block); } - fn check_pat(&mut self, cx: &EarlyContext, p: &ast::Pat) { + fn check_pat(&mut self, cx: &EarlyContext, p: &ast::Pat, _: &mut bool) { use ast::PatKind::{Paren, Range}; // The lint visitor will visit each subpattern of `p`. We do not want to lint any range // pattern no matter where it occurs in the pattern. For something like `&(a..=b)`, there // is a recursive `check_pat` on `a` and `b`, but we will assume that if there are - // unnecessry parens they serve a purpose of readability. + // unnecessary parens they serve a purpose of readability. if let Paren(ref pat) = p.node { match pat.node { Range(..) => {} diff --git a/src/test/ui/lint/inclusive-range-pattern-syntax.fixed b/src/test/ui/lint/inclusive-range-pattern-syntax.fixed index d16859df79e2..f0aee8a51f18 100644 --- a/src/test/ui/lint/inclusive-range-pattern-syntax.fixed +++ b/src/test/ui/lint/inclusive-range-pattern-syntax.fixed @@ -20,4 +20,10 @@ fn main() { //~^ WARN `...` range patterns are deprecated _ => {} } + + match &despondency { + &(1..=2) => {} + //~^ WARN `...` range patterns are deprecated + _ => {} + } } diff --git a/src/test/ui/lint/inclusive-range-pattern-syntax.rs b/src/test/ui/lint/inclusive-range-pattern-syntax.rs index 9d418aec0858..97bc04faa774 100644 --- a/src/test/ui/lint/inclusive-range-pattern-syntax.rs +++ b/src/test/ui/lint/inclusive-range-pattern-syntax.rs @@ -20,4 +20,10 @@ fn main() { //~^ WARN `...` range patterns are deprecated _ => {} } + + match &despondency { + &1...2 => {} + //~^ WARN `...` range patterns are deprecated + _ => {} + } } diff --git a/src/test/ui/lint/inclusive-range-pattern-syntax.stderr b/src/test/ui/lint/inclusive-range-pattern-syntax.stderr index de04fed589b2..9226137f1152 100644 --- a/src/test/ui/lint/inclusive-range-pattern-syntax.stderr +++ b/src/test/ui/lint/inclusive-range-pattern-syntax.stderr @@ -10,3 +10,9 @@ note: lint level defined here LL | #![warn(ellipsis_inclusive_range_patterns)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +warning: `...` range patterns are deprecated + --> $DIR/inclusive-range-pattern-syntax.rs:25:9 + | +LL | &1...2 => {} + | ^^^^^^ help: use `..=` for an inclusive range + diff --git a/src/test/ui/range/range-inclusive-pattern-precedence.stderr b/src/test/ui/range/range-inclusive-pattern-precedence.stderr index cd5ce3035c68..3ac6be2b8ea6 100644 --- a/src/test/ui/range/range-inclusive-pattern-precedence.stderr +++ b/src/test/ui/range/range-inclusive-pattern-precedence.stderr @@ -11,10 +11,10 @@ LL | box 10..=15 => {} | ^^^^^^^ help: add parentheses to clarify the precedence: `(10 ..=15)` warning: `...` range patterns are deprecated - --> $DIR/range-inclusive-pattern-precedence.rs:24:11 + --> $DIR/range-inclusive-pattern-precedence.rs:24:9 | LL | &0...9 => {} - | ^^^ help: use `..=` for an inclusive range + | ^^^^^^ help: use `..=` for an inclusive range | note: lint level defined here --> $DIR/range-inclusive-pattern-precedence.rs:19:9 From c63df7c64fbb1cd010e24ac4eb66b87aab8e650f Mon Sep 17 00:00:00 2001 From: varkor Date: Sat, 10 Nov 2018 21:27:40 +0000 Subject: [PATCH 22/41] Use non-short suggestion for parenthesised ..= --- src/librustc_lint/builtin.rs | 28 +++++++++++-------- .../inclusive-range-pattern-syntax.stderr | 2 +- .../range-inclusive-pattern-precedence.stderr | 2 +- 3 files changed, 19 insertions(+), 13 deletions(-) diff --git a/src/librustc_lint/builtin.rs b/src/librustc_lint/builtin.rs index 652de5dd1205..696fee04273f 100644 --- a/src/librustc_lint/builtin.rs +++ b/src/librustc_lint/builtin.rs @@ -1432,20 +1432,26 @@ impl EarlyLintPass for EllipsisInclusiveRangePatterns { if let Some((start, end, join)) = endpoints { let msg = "`...` range patterns are deprecated"; let suggestion = "use `..=` for an inclusive range"; - let (span, replacement) = if parenthesise { + if parenthesise { *visit_subpats = false; - (pat.span, format!("&({}..={})", expr_to_string(&start), expr_to_string(&end))) + let mut err = cx.struct_span_lint(ELLIPSIS_INCLUSIVE_RANGE_PATTERNS, pat.span, msg); + err.span_suggestion_with_applicability( + pat.span, + suggestion, + format!("&({}..={})", expr_to_string(&start), expr_to_string(&end)), + Applicability::MachineApplicable, + ); + err.emit(); } else { - (join, "..=".to_owned()) + let mut err = cx.struct_span_lint(ELLIPSIS_INCLUSIVE_RANGE_PATTERNS, join, msg); + err.span_suggestion_short_with_applicability( + join, + suggestion, + "..=".to_owned(), + Applicability::MachineApplicable, + ); + err.emit(); }; - let mut err = cx.struct_span_lint(ELLIPSIS_INCLUSIVE_RANGE_PATTERNS, span, msg); - err.span_suggestion_short_with_applicability( - span, - suggestion, - replacement, - Applicability::MachineApplicable, - ); - err.emit(); } } } diff --git a/src/test/ui/lint/inclusive-range-pattern-syntax.stderr b/src/test/ui/lint/inclusive-range-pattern-syntax.stderr index 9226137f1152..b13afdbc023d 100644 --- a/src/test/ui/lint/inclusive-range-pattern-syntax.stderr +++ b/src/test/ui/lint/inclusive-range-pattern-syntax.stderr @@ -14,5 +14,5 @@ warning: `...` range patterns are deprecated --> $DIR/inclusive-range-pattern-syntax.rs:25:9 | LL | &1...2 => {} - | ^^^^^^ help: use `..=` for an inclusive range + | ^^^^^^ help: use `..=` for an inclusive range: `&(1..=2)` diff --git a/src/test/ui/range/range-inclusive-pattern-precedence.stderr b/src/test/ui/range/range-inclusive-pattern-precedence.stderr index 3ac6be2b8ea6..6fa67a5d4fa3 100644 --- a/src/test/ui/range/range-inclusive-pattern-precedence.stderr +++ b/src/test/ui/range/range-inclusive-pattern-precedence.stderr @@ -14,7 +14,7 @@ warning: `...` range patterns are deprecated --> $DIR/range-inclusive-pattern-precedence.rs:24:9 | LL | &0...9 => {} - | ^^^^^^ help: use `..=` for an inclusive range + | ^^^^^^ help: use `..=` for an inclusive range: `&(0..=9)` | note: lint level defined here --> $DIR/range-inclusive-pattern-precedence.rs:19:9 From 20ef40ae50f021beef40458fc1011651aed31ede Mon Sep 17 00:00:00 2001 From: Dale Wijnand <344610+dwijnand@users.noreply.github.com> Date: Sun, 11 Nov 2018 07:36:10 +0000 Subject: [PATCH 23/41] Fix a typo in std::panic --- src/libstd/macros.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libstd/macros.rs b/src/libstd/macros.rs index 96c92ceb5bb4..15fbb1059213 100644 --- a/src/libstd/macros.rs +++ b/src/libstd/macros.rs @@ -16,7 +16,7 @@ /// The entry point for panic of Rust threads. /// -/// This allows a program to to terminate immediately and provide feedback +/// This allows a program to terminate immediately and provide feedback /// to the caller of the program. `panic!` should be used when a program reaches /// an unrecoverable problem. /// From ab55d9b5d33f324495509ab45c8386b97b74d04f Mon Sep 17 00:00:00 2001 From: Axary Date: Sun, 11 Nov 2018 10:45:16 +0100 Subject: [PATCH 24/41] change attribute to stable --- src/liballoc/boxed.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/liballoc/boxed.rs b/src/liballoc/boxed.rs index e1e9617b4917..63b262d1f3d9 100644 --- a/src/liballoc/boxed.rs +++ b/src/liballoc/boxed.rs @@ -700,7 +700,7 @@ impl, U: ?Sized> CoerceUnsized> for Box {} #[unstable(feature = "dispatch_from_dyn", issue = "0")] impl, U: ?Sized> DispatchFromDyn> for Box {} -#[unstable(feature = "boxed_slice_from_iter", issue = "0")] +#[stable(feature = "boxed_slice_from_iter", since = "1.32.0")] impl FromIterator for Box<[A]> { fn from_iter>(iter: T) -> Self { iter.into_iter().collect::>().into_boxed_slice() From a62af858e003e4077f5f4554c3235a4c82636b7e Mon Sep 17 00:00:00 2001 From: Bruce Mitchener Date: Sun, 11 Nov 2018 20:52:36 +0700 Subject: [PATCH 25/41] Fix typos. --- src/bootstrap/compile.rs | 2 +- src/etc/lldb_batchmode.py | 2 +- src/libcore/str/mod.rs | 2 +- src/librustc/infer/outlives/obligations.rs | 2 +- src/librustc/mir/mod.rs | 2 +- src/librustc/mir/traversal.rs | 4 ++-- src/librustc/ty/query/plumbing.rs | 4 ++-- src/librustc_apfloat/ieee.rs | 4 ++-- src/librustc_codegen_llvm/llvm_util.rs | 2 +- src/librustc_codegen_utils/linker.rs | 2 +- src/librustc_incremental/persist/fs.rs | 2 +- src/librustc_mir/borrow_check/location.rs | 2 +- src/librustc_mir/borrow_check/nll/region_infer/values.rs | 2 +- src/librustc_typeck/check/mod.rs | 2 +- src/libsyntax/ext/tt/macro_parser.rs | 2 +- src/libsyntax/ext/tt/quoted.rs | 2 +- src/test/run-pass-fulldeps/dropck_tarena_sound_drop.rs | 2 +- .../feature-gate/issue-43106-gating-of-proc_macro_derive.rs | 2 +- src/tools/compiletest/src/header.rs | 2 +- 19 files changed, 22 insertions(+), 22 deletions(-) diff --git a/src/bootstrap/compile.rs b/src/bootstrap/compile.rs index cef0849937bf..c8689f781408 100644 --- a/src/bootstrap/compile.rs +++ b/src/bootstrap/compile.rs @@ -203,7 +203,7 @@ impl Step for StdLink { /// Link all libstd rlibs/dylibs into the sysroot location. /// - /// Links those artifacts generated by `compiler` to a the `stage` compiler's + /// Links those artifacts generated by `compiler` to the `stage` compiler's /// sysroot for the specified `host` and `target`. /// /// Note that this assumes that `compiler` has already generated the libstd diff --git a/src/etc/lldb_batchmode.py b/src/etc/lldb_batchmode.py index 24a0ce0ac361..b0220c84ef2f 100644 --- a/src/etc/lldb_batchmode.py +++ b/src/etc/lldb_batchmode.py @@ -12,7 +12,7 @@ # containing LLDB commands (one command per line), this script will execute the commands one after # the other. # LLDB also has the -s and -S commandline options which also execute a list of commands from a text -# file. However, this command are execute `immediately`: a the command of a `run` or `continue` +# file. However, this command are execute `immediately`: the command of a `run` or `continue` # command will be executed immediately after the `run` or `continue`, without waiting for the next # breakpoint to be hit. This a command sequence like the following will not yield reliable results: # diff --git a/src/libcore/str/mod.rs b/src/libcore/str/mod.rs index a2782dd8e2e4..fe383712f64c 100644 --- a/src/libcore/str/mod.rs +++ b/src/libcore/str/mod.rs @@ -1896,7 +1896,7 @@ mod traits { #[inline] fn index_mut(self, slice: &mut str) -> &mut Self::Output { // is_char_boundary checks that the index is in [0, .len()] - // canot reuse `get` as above, because of NLL trouble + // cannot reuse `get` as above, because of NLL trouble if self.start <= self.end && slice.is_char_boundary(self.start) && slice.is_char_boundary(self.end) { diff --git a/src/librustc/infer/outlives/obligations.rs b/src/librustc/infer/outlives/obligations.rs index f2825887f36e..0114f9e9321e 100644 --- a/src/librustc/infer/outlives/obligations.rs +++ b/src/librustc/infer/outlives/obligations.rs @@ -132,7 +132,7 @@ impl<'cx, 'gcx, 'tcx> InferCtxt<'cx, 'gcx, 'tcx> { /// /// See the `region_obligations` field of `InferCtxt` for some /// comments about how this function fits into the overall expected - /// flow of the the inferencer. The key point is that it is + /// flow of the inferencer. The key point is that it is /// invoked after all type-inference variables have been bound -- /// towards the end of regionck. This also ensures that the /// region-bound-pairs are available (see comments above regarding diff --git a/src/librustc/mir/mod.rs b/src/librustc/mir/mod.rs index a84226bf665d..a6fa7b1de794 100644 --- a/src/librustc/mir/mod.rs +++ b/src/librustc/mir/mod.rs @@ -2610,7 +2610,7 @@ pub fn fmt_const_val(f: &mut impl Write, const_val: &ty::Const<'_>) -> fmt::Resu _ => {} } } - // print function definitons + // print function definitions if let FnDef(did, _) = ty.sty { return write!(f, "{}", item_path_str(did)); } diff --git a/src/librustc/mir/traversal.rs b/src/librustc/mir/traversal.rs index a1e2b7a06468..f3a0b7de9037 100644 --- a/src/librustc/mir/traversal.rs +++ b/src/librustc/mir/traversal.rs @@ -142,7 +142,7 @@ impl<'a, 'tcx> Postorder<'a, 'tcx> { // // It does the actual traversal of the graph, while the `next` method on the iterator // just pops off of the stack. `visit_stack` is a stack containing pairs of nodes and - // iterators over the sucessors of those nodes. Each iteration attempts to get the next + // iterators over the successors of those nodes. Each iteration attempts to get the next // node from the top of the stack, then pushes that node and an iterator over the // successors to the top of the stack. This loop only grows `visit_stack`, stopping when // we reach a child that has no children that we haven't already visited. @@ -163,7 +163,7 @@ impl<'a, 'tcx> Postorder<'a, 'tcx> { // The state of the stack starts out with just the root node (`A` in this case); // [(A, [B, C])] // - // When the first call to `traverse_sucessor` happens, the following happens: + // When the first call to `traverse_successor` happens, the following happens: // // [(B, [D]), // `B` taken from the successors of `A`, pushed to the // // top of the stack along with the successors of `B` diff --git a/src/librustc/ty/query/plumbing.rs b/src/librustc/ty/query/plumbing.rs index 8bbfd92d688e..efee39a1d63f 100644 --- a/src/librustc/ty/query/plumbing.rs +++ b/src/librustc/ty/query/plumbing.rs @@ -100,7 +100,7 @@ pub(super) struct JobOwner<'a, 'tcx: 'a, Q: QueryDescription<'tcx> + 'a> { } impl<'a, 'tcx, Q: QueryDescription<'tcx>> JobOwner<'a, 'tcx, Q> { - /// Either gets a JobOwner corresponding the the query, allowing us to + /// Either gets a JobOwner corresponding the query, allowing us to /// start executing the query, or it returns with the result of the query. /// If the query is executing elsewhere, this will wait for it. /// If the query panicked, this will silently panic. @@ -314,7 +314,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { /// Try to read a node index for the node dep_node. /// A node will have an index, when it's already been marked green, or when we can mark it /// green. This function will mark the current task as a reader of the specified node, when - /// the a node index can be found for that node. + /// a node index can be found for that node. pub(super) fn try_mark_green_and_read(self, dep_node: &DepNode) -> Option { match self.dep_graph.node_color(dep_node) { Some(DepNodeColor::Green(dep_node_index)) => { diff --git a/src/librustc_apfloat/ieee.rs b/src/librustc_apfloat/ieee.rs index 4f405858e350..adcb9857ee3c 100644 --- a/src/librustc_apfloat/ieee.rs +++ b/src/librustc_apfloat/ieee.rs @@ -895,7 +895,7 @@ impl Float for IeeeFloat { } // The intermediate result of the multiplication has "2 * S::PRECISION" - // signicant bit; adjust the addend to be consistent with mul result. + // significant bit; adjust the addend to be consistent with mul result. let mut ext_addend_sig = [addend.sig[0], 0]; // Extend the addend significand to ext_precision - 1. This guarantees @@ -920,7 +920,7 @@ impl Float for IeeeFloat { // Convert the result having "2 * S::PRECISION" significant-bits back to the one // having "S::PRECISION" significant-bits. First, move the radix point from - // poision "2*S::PRECISION - 1" to "S::PRECISION - 1". The exponent need to be + // position "2*S::PRECISION - 1" to "S::PRECISION - 1". The exponent need to be // adjusted by "2*S::PRECISION - 1" - "S::PRECISION - 1" = "S::PRECISION". self.exp -= S::PRECISION as ExpInt + 1; diff --git a/src/librustc_codegen_llvm/llvm_util.rs b/src/librustc_codegen_llvm/llvm_util.rs index eaa599e0cd0f..267d7e0d54b6 100644 --- a/src/librustc_codegen_llvm/llvm_util.rs +++ b/src/librustc_codegen_llvm/llvm_util.rs @@ -184,7 +184,7 @@ const WASM_WHITELIST: &[(&str, Option<&str>)] = &[ ]; /// When rustdoc is running, provide a list of all known features so that all their respective -/// primtives may be documented. +/// primitives may be documented. /// /// IMPORTANT: If you're adding another whitelist to the above lists, make sure to add it to this /// iterator! diff --git a/src/librustc_codegen_utils/linker.rs b/src/librustc_codegen_utils/linker.rs index ae1d77f15218..e9ac92da6843 100644 --- a/src/librustc_codegen_utils/linker.rs +++ b/src/librustc_codegen_utils/linker.rs @@ -613,7 +613,7 @@ impl<'a> Linker for MsvcLinker<'a> { // from the CodeView line tables in the object files. self.cmd.arg("/DEBUG"); - // This will cause the Microsoft linker to embed .natvis info into the the PDB file + // This will cause the Microsoft linker to embed .natvis info into the PDB file let sysroot = self.sess.sysroot(); let natvis_dir_path = sysroot.join("lib\\rustlib\\etc"); if let Ok(natvis_dir) = fs::read_dir(&natvis_dir_path) { diff --git a/src/librustc_incremental/persist/fs.rs b/src/librustc_incremental/persist/fs.rs index dee50f5ab267..2a8a0baf571b 100644 --- a/src/librustc_incremental/persist/fs.rs +++ b/src/librustc_incremental/persist/fs.rs @@ -490,7 +490,7 @@ fn create_dir(sess: &Session, path: &Path, dir_tag: &str) -> Result<(),()> { } } -/// Allocate a the lock-file and lock it. +/// Allocate the lock-file and lock it. fn lock_directory(sess: &Session, session_dir: &Path) -> Result<(flock::Lock, PathBuf), ()> { diff --git a/src/librustc_mir/borrow_check/location.rs b/src/librustc_mir/borrow_check/location.rs index 91008e8f9690..b3e159dd8445 100644 --- a/src/librustc_mir/borrow_check/location.rs +++ b/src/librustc_mir/borrow_check/location.rs @@ -11,7 +11,7 @@ use rustc::mir::{BasicBlock, Location, Mir}; use rustc_data_structures::indexed_vec::{Idx, IndexVec}; -/// Maps between a MIR Location, which identifies the a particular +/// Maps between a MIR Location, which identifies a particular /// statement within a basic block, to a "rich location", which /// identifies at a finer granularity. In particular, we distinguish /// the *start* of a statement and the *mid-point*. The mid-point is diff --git a/src/librustc_mir/borrow_check/nll/region_infer/values.rs b/src/librustc_mir/borrow_check/nll/region_infer/values.rs index 3607ae4f5088..2b7ef38d3edf 100644 --- a/src/librustc_mir/borrow_check/nll/region_infer/values.rs +++ b/src/librustc_mir/borrow_check/nll/region_infer/values.rs @@ -112,7 +112,7 @@ impl RegionValueElements { } = self.to_location(index); if statement_index == 0 { // If this is a basic block head, then the predecessors are - // the the terminators of other basic blocks + // the terminators of other basic blocks stack.extend( mir.predecessors_for(block) .iter() diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 7dfdb926c60e..091af449095a 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -548,7 +548,7 @@ pub struct FnCtxt<'a, 'gcx: 'a+'tcx, 'tcx: 'a> { /// current expression. As each subpart is processed, they may set /// the flag to `Always` etc. Finally, at the end, we take the /// result and "union" it with the original value, so that when we - /// return the flag indicates if any subpart of the the parent + /// return the flag indicates if any subpart of the parent /// expression (up to and including this part) has diverged. So, /// if you read it after evaluating a subexpression `X`, the value /// you get indicates whether any subexpression that was diff --git a/src/libsyntax/ext/tt/macro_parser.rs b/src/libsyntax/ext/tt/macro_parser.rs index 06c1d58070e2..f2b1c359c0ea 100644 --- a/src/libsyntax/ext/tt/macro_parser.rs +++ b/src/libsyntax/ext/tt/macro_parser.rs @@ -122,7 +122,7 @@ impl<'a> TokenTreeOrTokenTreeSlice<'a> { } } - /// The the `index`-th token tree of `self`. + /// The `index`-th token tree of `self`. fn get_tt(&self, index: usize) -> TokenTree { match *self { TtSeq(ref v) => v[index].clone(), diff --git a/src/libsyntax/ext/tt/quoted.rs b/src/libsyntax/ext/tt/quoted.rs index 74363f3e5f7d..218486748315 100644 --- a/src/libsyntax/ext/tt/quoted.rs +++ b/src/libsyntax/ext/tt/quoted.rs @@ -496,7 +496,7 @@ where return (None, KleeneOp::ZeroOrMore); } - // #2 is a Kleene op, which is the the only valid option + // #2 is a Kleene op, which is the only valid option Ok(Ok((op, _))) => { // Warn that `?` as a separator will be deprecated sess.buffer_lint( diff --git a/src/test/run-pass-fulldeps/dropck_tarena_sound_drop.rs b/src/test/run-pass-fulldeps/dropck_tarena_sound_drop.rs index 9fa0b40d49c2..e519d48ac1d4 100644 --- a/src/test/run-pass-fulldeps/dropck_tarena_sound_drop.rs +++ b/src/test/run-pass-fulldeps/dropck_tarena_sound_drop.rs @@ -31,7 +31,7 @@ struct CheckId { v: T } // In the code below, the impl of HasId for `&'a usize` does not // actually access the borrowed data, but the point is that the // interface to CheckId does not (and cannot) know that, and therefore -// when encountering the a value V of type CheckId, we must +// when encountering a value V of type CheckId, we must // conservatively force the type S to strictly outlive V. impl Drop for CheckId { fn drop(&mut self) { diff --git a/src/test/ui/feature-gate/issue-43106-gating-of-proc_macro_derive.rs b/src/test/ui/feature-gate/issue-43106-gating-of-proc_macro_derive.rs index 5bb8bb024ed5..c23b43dfff70 100644 --- a/src/test/ui/feature-gate/issue-43106-gating-of-proc_macro_derive.rs +++ b/src/test/ui/feature-gate/issue-43106-gating-of-proc_macro_derive.rs @@ -13,7 +13,7 @@ // not descend further into the mod for other occurrences of the same // error. // -// This file sits on its own because the the "weird" occurrences here +// This file sits on its own because the "weird" occurrences here // signal errors, making it incompatible with the "warnings only" // nature of issue-43106-gating-of-builtin-attrs.rs diff --git a/src/tools/compiletest/src/header.rs b/src/tools/compiletest/src/header.rs index f12dd31c402d..ed2114b65301 100644 --- a/src/tools/compiletest/src/header.rs +++ b/src/tools/compiletest/src/header.rs @@ -490,7 +490,7 @@ impl TestProps { } if !self.compile_pass { - // run-pass implies must_compile_sucessfully + // run-pass implies must_compile_successfully self.compile_pass = config.parse_compile_pass(ln) || self.run_pass; } From 93b5112c16ec79d545826b8af1c7c27535330e77 Mon Sep 17 00:00:00 2001 From: Denis Vasilik Date: Sat, 10 Nov 2018 10:23:11 +0100 Subject: [PATCH 26/41] Added comment for From trait implementation: boxed string slice to String --- src/liballoc/string.rs | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/src/liballoc/string.rs b/src/liballoc/string.rs index 5c776292f53d..50d2c04657a3 100644 --- a/src/liballoc/string.rs +++ b/src/liballoc/string.rs @@ -2206,6 +2206,20 @@ impl<'a> From<&'a str> for String { #[cfg(not(test))] #[stable(feature = "string_from_box", since = "1.18.0")] impl From> for String { + /// Converts the given boxed `str` slice to a `String`. + /// It is notable that the `str` slice must be owned. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// let s1 : String = String::from("hello world"); + /// let s2 : Box = s1.into_boxed_str(); + /// let s3 : String = String::from(s2); + /// + /// assert_eq!("hello world", s3) + /// ``` fn from(s: Box) -> String { s.into_string() } From f0bfbd3e7201c59b5e155298fc4bdd0acece8992 Mon Sep 17 00:00:00 2001 From: Denis Vasilik Date: Sun, 11 Nov 2018 15:08:28 +0100 Subject: [PATCH 27/41] Added comments for trait implementations. --- src/liballoc/string.rs | 29 ++++++++++++++++++++++++++++- 1 file changed, 28 insertions(+), 1 deletion(-) diff --git a/src/liballoc/string.rs b/src/liballoc/string.rs index 50d2c04657a3..27a14bd6b8cb 100644 --- a/src/liballoc/string.rs +++ b/src/liballoc/string.rs @@ -2207,7 +2207,7 @@ impl<'a> From<&'a str> for String { #[stable(feature = "string_from_box", since = "1.18.0")] impl From> for String { /// Converts the given boxed `str` slice to a `String`. - /// It is notable that the `str` slice must be owned. + /// It is notable that the `str` slice is owned. /// /// # Examples /// @@ -2227,6 +2227,19 @@ impl From> for String { #[stable(feature = "box_from_str", since = "1.20.0")] impl From for Box { + /// Converts the given `String` to a boxed `str` slice that is owned. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// let s1 = String::from("hello world"); + /// let s2 : Box = Box::from(s1); + /// let s3 : String = String::from(s2); + /// + /// assert_eq!("hello world", s3) + /// ``` fn from(s: String) -> Box { s.into_boxed_str() } @@ -2286,6 +2299,20 @@ impl<'a> FromIterator for Cow<'a, str> { #[stable(feature = "from_string_for_vec_u8", since = "1.14.0")] impl From for Vec { + /// Converts the given `String` to a vector `Vec` that holds values of type `u8`. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// let s1 = String::from("hello world"); + /// let v1 = Vec::from(s1); + /// + /// for b in v1 { + /// println!("{}", b); + /// } + /// ``` fn from(string: String) -> Vec { string.into_bytes() } From dc0fd65af23bec1de6ae0608c40f0bbcb52d4747 Mon Sep 17 00:00:00 2001 From: Denis Vasilik Date: Sun, 11 Nov 2018 16:58:00 +0100 Subject: [PATCH 28/41] Whitespace cleanup according to Rust's style guidelines. --- src/liballoc/string.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/liballoc/string.rs b/src/liballoc/string.rs index 27a14bd6b8cb..e401951694cd 100644 --- a/src/liballoc/string.rs +++ b/src/liballoc/string.rs @@ -2206,7 +2206,7 @@ impl<'a> From<&'a str> for String { #[cfg(not(test))] #[stable(feature = "string_from_box", since = "1.18.0")] impl From> for String { - /// Converts the given boxed `str` slice to a `String`. + /// Converts the given boxed `str` slice to a `String`. /// It is notable that the `str` slice is owned. /// /// # Examples @@ -2216,7 +2216,7 @@ impl From> for String { /// ``` /// let s1 : String = String::from("hello world"); /// let s2 : Box = s1.into_boxed_str(); - /// let s3 : String = String::from(s2); + /// let s3 : String = String::from(s2); /// /// assert_eq!("hello world", s3) /// ``` @@ -2308,7 +2308,7 @@ impl From for Vec { /// ``` /// let s1 = String::from("hello world"); /// let v1 = Vec::from(s1); - /// + /// /// for b in v1 { /// println!("{}", b); /// } From 6f3add34ca18cf6fbe5374d3e519b0c8838b1dfe Mon Sep 17 00:00:00 2001 From: Denis Vasilik Date: Sun, 11 Nov 2018 20:11:25 +0100 Subject: [PATCH 29/41] Minor style guide corrections. --- src/liballoc/string.rs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/liballoc/string.rs b/src/liballoc/string.rs index e401951694cd..2beb3240aaca 100644 --- a/src/liballoc/string.rs +++ b/src/liballoc/string.rs @@ -2214,9 +2214,9 @@ impl From> for String { /// Basic usage: /// /// ``` - /// let s1 : String = String::from("hello world"); - /// let s2 : Box = s1.into_boxed_str(); - /// let s3 : String = String::from(s2); + /// let s1: String = String::from("hello world"); + /// let s2: Box = s1.into_boxed_str(); + /// let s3: String = String::from(s2); /// /// assert_eq!("hello world", s3) /// ``` @@ -2234,9 +2234,9 @@ impl From for Box { /// Basic usage: /// /// ``` - /// let s1 = String::from("hello world"); - /// let s2 : Box = Box::from(s1); - /// let s3 : String = String::from(s2); + /// let s1: String = String::from("hello world"); + /// let s2: Box = Box::from(s1); + /// let s3: String = String::from(s2); /// /// assert_eq!("hello world", s3) /// ``` From 04cc0d651e8b40dffbcd3865c1e2c2cfc1663911 Mon Sep 17 00:00:00 2001 From: Igor Matuszewski Date: Sun, 11 Nov 2018 21:05:09 +0100 Subject: [PATCH 30/41] save-analysis: Don't panic for macro-generated use globs Follow-up to https://github.com/rust-lang/rust/commit/c2bb7cadf24e82b80f403c09e800fe5fad504caf. --- src/librustc_save_analysis/dump_visitor.rs | 34 ++++++++++++---------- 1 file changed, 19 insertions(+), 15 deletions(-) diff --git a/src/librustc_save_analysis/dump_visitor.rs b/src/librustc_save_analysis/dump_visitor.rs index 9bc3fbe7c245..0c0f50c1fd70 100644 --- a/src/librustc_save_analysis/dump_visitor.rs +++ b/src/librustc_save_analysis/dump_visitor.rs @@ -1254,21 +1254,25 @@ impl<'l, 'tcx: 'l, 'll, O: DumpOutput + 'll> DumpVisitor<'l, 'tcx, 'll, O> { Vec::new() }; - let sub_span = - self.span.sub_span_of_token(use_tree.span, token::BinOp(token::Star)); - if !self.span.filter_generated(use_tree.span) { - let span = - self.span_from_span(sub_span.expect("No span found for use glob")); - self.dumper.import(&access, Import { - kind: ImportKind::GlobUse, - ref_id: None, - span, - alias_span: None, - name: "*".to_owned(), - value: names.join(", "), - parent, - }); - self.write_sub_paths(&path); + // Otherwise it's a span with wrong macro expansion info, which + // we don't want to track anyway, since it's probably macro-internal `use` + if let Some(sub_span) = + self.span.sub_span_of_token(use_tree.span, token::BinOp(token::Star)) + { + if !self.span.filter_generated(use_tree.span) { + let span = self.span_from_span(sub_span); + + self.dumper.import(&access, Import { + kind: ImportKind::GlobUse, + ref_id: None, + span, + alias_span: None, + name: "*".to_owned(), + value: names.join(", "), + parent, + }); + self.write_sub_paths(&path); + } } } ast::UseTreeKind::Nested(ref nested_items) => { From 4fdae853f70d9bbdf4dbc365743f6545cfd4a9ac Mon Sep 17 00:00:00 2001 From: Hugo van der Wijst Date: Sun, 11 Nov 2018 16:25:00 -0800 Subject: [PATCH 31/41] Reference count `crate_inherent_impls`s return value. The repeated cloning of the result in `inherent_impls` queries has quite an impact on crates with many inherent trait implementations. --- src/librustc/ty/query/mod.rs | 3 ++- src/librustc_typeck/coherence/inherent_impls.rs | 4 ++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/librustc/ty/query/mod.rs b/src/librustc/ty/query/mod.rs index ed7b2cffc46f..27eafa7ab580 100644 --- a/src/librustc/ty/query/mod.rs +++ b/src/librustc/ty/query/mod.rs @@ -291,7 +291,8 @@ define_queries! { <'tcx> /// Gets a complete map from all types to their inherent impls. /// Not meant to be used directly outside of coherence. /// (Defined only for LOCAL_CRATE) - [] fn crate_inherent_impls: crate_inherent_impls_dep_node(CrateNum) -> CrateInherentImpls, + [] fn crate_inherent_impls: crate_inherent_impls_dep_node(CrateNum) + -> Lrc, /// Checks all types in the krate for overlap in their inherent impls. Reports errors. /// Not meant to be used directly outside of coherence. diff --git a/src/librustc_typeck/coherence/inherent_impls.rs b/src/librustc_typeck/coherence/inherent_impls.rs index ec979dea4fd0..370f8857f140 100644 --- a/src/librustc_typeck/coherence/inherent_impls.rs +++ b/src/librustc_typeck/coherence/inherent_impls.rs @@ -31,7 +31,7 @@ use syntax_pos::Span; /// On-demand query: yields a map containing all types mapped to their inherent impls. pub fn crate_inherent_impls<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, crate_num: CrateNum) - -> CrateInherentImpls { + -> Lrc { assert_eq!(crate_num, LOCAL_CRATE); let krate = tcx.hir.krate(); @@ -42,7 +42,7 @@ pub fn crate_inherent_impls<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, } }; krate.visit_all_item_likes(&mut collect); - collect.impls_map + Lrc::new(collect.impls_map) } /// On-demand query: yields a vector of the inherent impls for a specific type. From c21123818096f599a9f394cd8a1072228d1f1a54 Mon Sep 17 00:00:00 2001 From: Dan Robertson Date: Mon, 12 Nov 2018 02:32:21 -0800 Subject: [PATCH 32/41] Fix TLS errors when downloading stage0 --- src/bootstrap/bootstrap.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/bootstrap/bootstrap.py b/src/bootstrap/bootstrap.py index fdd8784453bd..cd48e6aa4c4b 100644 --- a/src/bootstrap/bootstrap.py +++ b/src/bootstrap/bootstrap.py @@ -79,8 +79,8 @@ def _download(path, url, probably_big, verbose, exception): # see http://serverfault.com/questions/301128/how-to-download if sys.platform == 'win32': run(["PowerShell.exe", "/nologo", "-Command", - "(New-Object System.Net.WebClient)" - ".DownloadFile('{}', '{}')".format(url, path)], + "[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12;", + "(New-Object System.Net.WebClient).DownloadFile('{}', '{}')".format(url, path)], verbose=verbose, exception=exception) else: From ace20b964651e5f61f8233ae826f3a904ef5a8cb Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 12 Nov 2018 08:39:13 +0100 Subject: [PATCH 33/41] for uniformity, also move memory_deallocated to AllocationExtra --- src/librustc/mir/interpret/allocation.rs | 11 +++++++++++ src/librustc_mir/interpret/machine.rs | 10 ---------- src/librustc_mir/interpret/memory.rs | 2 +- 3 files changed, 12 insertions(+), 11 deletions(-) diff --git a/src/librustc/mir/interpret/allocation.rs b/src/librustc/mir/interpret/allocation.rs index e55997099c82..cc92b63256c1 100644 --- a/src/librustc/mir/interpret/allocation.rs +++ b/src/librustc/mir/interpret/allocation.rs @@ -65,6 +65,17 @@ pub trait AllocationExtra: ::std::fmt::Debug + Default + Clone { ) -> EvalResult<'tcx> { Ok(()) } + + /// Hook for performing extra checks on a memory deallocation. + /// `size` will be the size of the allocation. + #[inline] + fn memory_deallocated( + _alloc: &mut Allocation, + _ptr: Pointer, + _size: Size, + ) -> EvalResult<'tcx> { + Ok(()) + } } impl AllocationExtra<()> for () {} diff --git a/src/librustc_mir/interpret/machine.rs b/src/librustc_mir/interpret/machine.rs index 047996777ea9..4f677b086d42 100644 --- a/src/librustc_mir/interpret/machine.rs +++ b/src/librustc_mir/interpret/machine.rs @@ -174,16 +174,6 @@ pub trait Machine<'a, 'mir, 'tcx>: Sized { dest: PlaceTy<'tcx, Self::PointerTag>, ) -> EvalResult<'tcx>; - /// Hook for performing extra checks when memory gets deallocated. - #[inline] - fn memory_deallocated( - _alloc: &mut Allocation, - _ptr: Pointer, - _size: Size, - ) -> EvalResult<'tcx> { - Ok(()) - } - /// Add the tag for a newly allocated pointer. fn tag_new_allocation( ecx: &mut EvalContext<'a, 'mir, 'tcx, Self>, diff --git a/src/librustc_mir/interpret/memory.rs b/src/librustc_mir/interpret/memory.rs index 10bc984a447a..e125927e7d27 100644 --- a/src/librustc_mir/interpret/memory.rs +++ b/src/librustc_mir/interpret/memory.rs @@ -225,7 +225,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> Memory<'a, 'mir, 'tcx, M> { // Let the machine take some extra action let size = Size::from_bytes(alloc.bytes.len() as u64); - M::memory_deallocated(&mut alloc, ptr, size)?; + AllocationExtra::memory_deallocated(&mut alloc, ptr, size)?; // Don't forget to remember size and align of this now-dead allocation let old = self.dead_alloc_map.insert( From 075983c70ba20f31fc1279dacae6d6fcb8bc9cad Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 12 Nov 2018 09:00:39 +0100 Subject: [PATCH 34/41] global allocators: add a few comments --- src/liballoc/alloc.rs | 4 ++++ src/libstd/alloc.rs | 5 +++++ 2 files changed, 9 insertions(+) diff --git a/src/liballoc/alloc.rs b/src/liballoc/alloc.rs index 3bd0c243b39a..1a8a081e16fa 100644 --- a/src/liballoc/alloc.rs +++ b/src/liballoc/alloc.rs @@ -21,6 +21,10 @@ use core::usize; pub use core::alloc::*; extern "Rust" { + // These are the magic symbols to call the global allocator. rustc generates + // them from the `#[global_allocator]` attribute if there is one, or uses the + // default implementations in libstd (`__rdl_alloc` etc in `src/libstd/alloc.rs`) + // otherwise. #[allocator] #[rustc_allocator_nounwind] fn __rust_alloc(size: usize, align: usize) -> *mut u8; diff --git a/src/libstd/alloc.rs b/src/libstd/alloc.rs index 485b2ffe1975..9c0573964702 100644 --- a/src/libstd/alloc.rs +++ b/src/libstd/alloc.rs @@ -142,6 +142,7 @@ pub use alloc_crate::alloc::*; #[derive(Debug, Copy, Clone)] pub struct System; +// The Alloc impl just forwards to the GlobalAlloc impl, which is in `std::sys::*::alloc`. #[unstable(feature = "allocator_api", issue = "32838")] unsafe impl Alloc for System { #[inline] @@ -226,6 +227,10 @@ pub fn rust_oom(layout: Layout) -> ! { #[unstable(feature = "alloc_internals", issue = "0")] pub mod __default_lib_allocator { use super::{System, Layout, GlobalAlloc}; + // These magic symbol names are used as a fallback for implementing the + // `__rust_alloc` etc symbols (see `src/liballoc/alloc.rs) when there is + // no `#[global_allocator]` attribute. + // for symbol names src/librustc/middle/allocator.rs // for signatures src/librustc_allocator/lib.rs From 3c88cfef67905939da71eb44575b18fd1b406e16 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 12 Nov 2018 09:11:29 +0100 Subject: [PATCH 35/41] remove unused import --- src/librustc_mir/interpret/machine.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/librustc_mir/interpret/machine.rs b/src/librustc_mir/interpret/machine.rs index 4f677b086d42..1efd7ca7f897 100644 --- a/src/librustc_mir/interpret/machine.rs +++ b/src/librustc_mir/interpret/machine.rs @@ -17,7 +17,7 @@ use std::hash::Hash; use rustc::hir::{self, def_id::DefId}; use rustc::mir; -use rustc::ty::{self, layout::{Size, TyLayout}, query::TyCtxtAt}; +use rustc::ty::{self, layout::TyLayout, query::TyCtxtAt}; use super::{ Allocation, AllocId, EvalResult, Scalar, AllocationExtra, From 4d2934e803d1c948c5e4681a84f33b91c0a0fc64 Mon Sep 17 00:00:00 2001 From: Stjepan Glavina Date: Mon, 12 Nov 2018 17:19:55 +0100 Subject: [PATCH 36/41] Add forget_unsized only --- src/libcore/mem.rs | 122 ++++++--------------------------------------- 1 file changed, 15 insertions(+), 107 deletions(-) diff --git a/src/libcore/mem.rs b/src/libcore/mem.rs index cff605489ed3..f612f89e0826 100644 --- a/src/libcore/mem.rs +++ b/src/libcore/mem.rs @@ -139,126 +139,34 @@ pub use intrinsics::transmute; /// [ub]: ../../reference/behavior-considered-undefined.html #[inline] #[stable(feature = "rust1", since = "1.0.0")] -#[cfg(not(stage0))] -pub fn forget(t: T) { - unsafe { intrinsics::forget(t) } +pub fn forget(t: T) { + ManuallyDrop::new(t); } /// Takes ownership and "forgets" about the value **without running its destructor**. /// -/// Any resources the value manages, such as heap memory or a file handle, will linger -/// forever in an unreachable state. However, it does not guarantee that pointers -/// to this memory will remain valid. -/// -/// * If you want to leak memory, see [`Box::leak`][leak]. -/// * If you want to obtain a raw pointer to the memory, see [`Box::into_raw`][into_raw]. -/// * If you want to dispose of a value properly, running its destructor, see -/// [`mem::drop`][drop]. -/// -/// # Safety -/// -/// `forget` is not marked as `unsafe`, because Rust's safety guarantees -/// do not include a guarantee that destructors will always run. For example, -/// a program can create a reference cycle using [`Rc`][rc], or call -/// [`process::exit`][exit] to exit without running destructors. Thus, allowing -/// `mem::forget` from safe code does not fundamentally change Rust's safety -/// guarantees. -/// -/// That said, leaking resources such as memory or I/O objects is usually undesirable, -/// so `forget` is only recommended for specialized use cases like those shown below. -/// -/// Because forgetting a value is allowed, any `unsafe` code you write must -/// allow for this possibility. You cannot return a value and expect that the -/// caller will necessarily run the value's destructor. +/// This function works exactly the same as [`forget`], except it also accepts unsized values. It +/// will never be stabilized and is only available because we haven't decided to relax the bounds +/// on [`forget`] just yet. /// -/// [rc]: ../../std/rc/struct.Rc.html -/// [exit]: ../../std/process/fn.exit.html +/// [`forget`]: fn.forget.html /// /// # Examples /// -/// Leak an I/O object, never closing the file: -/// -/// ```no_run -/// use std::mem; -/// use std::fs::File; -/// -/// let file = File::open("foo.txt").unwrap(); -/// mem::forget(file); -/// ``` -/// -/// The practical use cases for `forget` are rather specialized and mainly come -/// up in unsafe or FFI code. -/// -/// ## Use case 1 -/// -/// You have created an uninitialized value using [`mem::uninitialized`][uninit]. -/// You must either initialize or `forget` it on every computation path before -/// Rust drops it automatically, like at the end of a scope or after a panic. -/// Running the destructor on an uninitialized value would be [undefined behavior][ub]. -/// -/// ``` -/// use std::mem; -/// use std::ptr; -/// -/// # let some_condition = false; -/// unsafe { -/// let mut uninit_vec: Vec = mem::uninitialized(); -/// -/// if some_condition { -/// // Initialize the variable. -/// ptr::write(&mut uninit_vec, Vec::new()); -/// } else { -/// // Forget the uninitialized value so its destructor doesn't run. -/// mem::forget(uninit_vec); -/// } -/// } /// ``` +/// #![feature(forget_unsized)] /// -/// ## Use case 2 -/// -/// You have duplicated the bytes making up a value, without doing a proper -/// [`Clone`][clone]. You need the value's destructor to run only once, -/// because a double `free` is undefined behavior. -/// -/// An example is a possible implementation of [`mem::swap`][swap]: -/// -/// ``` /// use std::mem; -/// use std::ptr; -/// -/// # #[allow(dead_code)] -/// fn swap(x: &mut T, y: &mut T) { -/// unsafe { -/// // Give ourselves some scratch space to work with -/// let mut t: T = mem::uninitialized(); /// -/// // Perform the swap, `&mut` pointers never alias -/// ptr::copy_nonoverlapping(&*x, &mut t, 1); -/// ptr::copy_nonoverlapping(&*y, x, 1); -/// ptr::copy_nonoverlapping(&t, y, 1); -/// -/// // y and t now point to the same thing, but we need to completely -/// // forget `t` because we do not want to run the destructor for `T` -/// // on its value, which is still owned somewhere outside this function. -/// mem::forget(t); -/// } -/// } +/// let f: Box = Box::new(|| ()); +/// let f = *f; +/// mem::forget_unsized(f); /// ``` -/// -/// [drop]: fn.drop.html -/// [uninit]: fn.uninitialized.html -/// [clone]: ../clone/trait.Clone.html -/// [swap]: fn.swap.html -/// [FFI]: ../../book/first-edition/ffi.html -/// [box]: ../../std/boxed/struct.Box.html -/// [leak]: ../../std/boxed/struct.Box.html#method.leak -/// [into_raw]: ../../std/boxed/struct.Box.html#method.into_raw -/// [ub]: ../../reference/behavior-considered-undefined.html #[inline] -#[cfg(stage0)] -#[stable(feature = "rust1", since = "1.0.0")] -pub fn forget(t: T) { - ManuallyDrop::new(t); +#[cfg(not(stage0))] +#[unstable(feature = "forget_unsized", issue = "0")] +pub fn forget_unsized(t: T) { + unsafe { intrinsics::forget(t) } } /// Returns the size of a type in bytes. @@ -881,7 +789,7 @@ pub fn replace(dest: &mut T, mut src: T) -> T { /// [`Copy`]: ../../std/marker/trait.Copy.html #[inline] #[stable(feature = "rust1", since = "1.0.0")] -pub fn drop(_x: T) { } +pub fn drop(_x: T) { } /// Interprets `src` as having type `&U`, and then reads `src` without moving /// the contained value. From 56d3a824e46ce9976a017ef41c318a66444da99c Mon Sep 17 00:00:00 2001 From: Stjepan Glavina Date: Mon, 12 Nov 2018 18:36:49 +0100 Subject: [PATCH 37/41] Update docs --- src/libcore/mem.rs | 19 +++---------------- 1 file changed, 3 insertions(+), 16 deletions(-) diff --git a/src/libcore/mem.rs b/src/libcore/mem.rs index f612f89e0826..7fe195d63be7 100644 --- a/src/libcore/mem.rs +++ b/src/libcore/mem.rs @@ -143,25 +143,12 @@ pub fn forget(t: T) { ManuallyDrop::new(t); } -/// Takes ownership and "forgets" about the value **without running its destructor**. +/// Like [`forget`], but also accepts unsized values. /// -/// This function works exactly the same as [`forget`], except it also accepts unsized values. It -/// will never be stabilized and is only available because we haven't decided to relax the bounds -/// on [`forget`] just yet. +/// This function is just a shim intended to be removed when the `unsized_locals` feature gets +/// stabilized. /// /// [`forget`]: fn.forget.html -/// -/// # Examples -/// -/// ``` -/// #![feature(forget_unsized)] -/// -/// use std::mem; -/// -/// let f: Box = Box::new(|| ()); -/// let f = *f; -/// mem::forget_unsized(f); -/// ``` #[inline] #[cfg(not(stage0))] #[unstable(feature = "forget_unsized", issue = "0")] From ab8a947fa0e8f8397ad9c831741e6429fbed2c0b Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Fri, 9 Nov 2018 09:57:02 +1100 Subject: [PATCH 38/41] Move `static_assert!` into librustc_data_structures. This means it can be used by more crates. --- src/librustc/macros.rs | 10 ---------- src/librustc_data_structures/lib.rs | 1 + src/librustc_data_structures/macros.rs | 21 +++++++++++++++++++++ 3 files changed, 22 insertions(+), 10 deletions(-) create mode 100644 src/librustc_data_structures/macros.rs diff --git a/src/librustc/macros.rs b/src/librustc/macros.rs index f21f949c9f5c..781a0fa3f663 100644 --- a/src/librustc/macros.rs +++ b/src/librustc/macros.rs @@ -62,16 +62,6 @@ macro_rules! span_bug { }) } -#[macro_export] -macro_rules! static_assert { - ($name:ident: $test:expr) => { - // Use the bool to access an array such that if the bool is false, the access - // is out-of-bounds. - #[allow(dead_code)] - static $name: () = [()][!$test as usize]; - } -} - #[macro_export] macro_rules! __impl_stable_hash_field { ($field:ident, $ctx:expr, $hasher:expr) => ($field.hash_stable($ctx, $hasher)); diff --git a/src/librustc_data_structures/lib.rs b/src/librustc_data_structures/lib.rs index 07e5548216f3..135abebdacb7 100644 --- a/src/librustc_data_structures/lib.rs +++ b/src/librustc_data_structures/lib.rs @@ -57,6 +57,7 @@ extern crate rustc_cratesio_shim; pub use rustc_serialize::hex::ToHex; +pub mod macros; pub mod svh; pub mod base_n; pub mod bit_set; diff --git a/src/librustc_data_structures/macros.rs b/src/librustc_data_structures/macros.rs new file mode 100644 index 000000000000..3cc91b0e93f0 --- /dev/null +++ b/src/librustc_data_structures/macros.rs @@ -0,0 +1,21 @@ +// Copyright 2018 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. + +/// A simple static assertion macro. The first argument should be a unique +/// ALL_CAPS identifier that describes the condition. +#[macro_export] +macro_rules! static_assert { + ($name:ident: $test:expr) => { + // Use the bool to access an array such that if the bool is false, the access + // is out-of-bounds. + #[allow(dead_code)] + static $name: () = [()][!$test as usize]; + } +} From 49f482f5372c247dc50c1a2159a1ba5ee3cf5f15 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Fri, 9 Nov 2018 10:19:51 +1100 Subject: [PATCH 39/41] Move a `static_assert!` to a better spot. And make it x86_64-only so it can use `==` instead of `<=`. --- src/librustc/mir/mod.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/librustc/mir/mod.rs b/src/librustc/mir/mod.rs index 8a32e8f46c29..46b61d8ffe64 100644 --- a/src/librustc/mir/mod.rs +++ b/src/librustc/mir/mod.rs @@ -1719,14 +1719,14 @@ pub struct Statement<'tcx> { pub kind: StatementKind<'tcx>, } +// `Statement` is used a lot. Make sure it doesn't unintentionally get bigger. +#[cfg(target_arch = "x86_64")] +static_assert!(MEM_SIZE_OF_STATEMENT: mem::size_of::>() == 56); + impl<'tcx> Statement<'tcx> { /// Changes a statement to a nop. This is both faster than deleting instructions and avoids /// invalidating statement indices in `Location`s. pub fn make_nop(&mut self) { - // `Statement` contributes significantly to peak memory usage. Make - // sure it doesn't get bigger. - static_assert!(STATEMENT_IS_AT_MOST_56_BYTES: mem::size_of::>() <= 56); - self.kind = StatementKind::Nop } From fb3dd9f64ee9b34d6d0e25363ceda3a6ba9dcec3 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Fri, 9 Nov 2018 10:10:46 +1100 Subject: [PATCH 40/41] Add a static assertion about the size of `ast::Expr`. --- src/libsyntax/ast.rs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index 2f17bc0548ca..fa6fe3478338 100644 --- a/src/libsyntax/ast.rs +++ b/src/libsyntax/ast.rs @@ -20,6 +20,7 @@ use print::pprust; use ptr::P; use rustc_data_structures::indexed_vec; use rustc_data_structures::indexed_vec::Idx; +use rustc_data_structures::static_assert; use rustc_target::spec::abi::Abi; use source_map::{dummy_spanned, respan, Spanned}; use symbol::{keywords, Symbol}; @@ -924,6 +925,10 @@ pub struct Expr { pub attrs: ThinVec, } +// `Expr` is used a lot. Make sure it doesn't unintentionally get bigger. +#[cfg(target_arch = "x86_64")] +static_assert!(MEM_SIZE_OF_EXPR: std::mem::size_of::() == 88); + impl Expr { /// Whether this expression would be valid somewhere that expects a value, for example, an `if` /// condition. From e01e0b0d8a35baacc09b9c37258106f995fe5382 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Tue, 13 Nov 2018 06:34:11 +1100 Subject: [PATCH 41/41] Move two `static_assert!`s to better spots. And make them x86_64-only so they can use `==` instead of `<=`. --- src/librustc/ty/context.rs | 6 ------ src/librustc/ty/mod.rs | 4 ++++ src/librustc/ty/sty.rs | 4 ++++ 3 files changed, 8 insertions(+), 6 deletions(-) diff --git a/src/librustc/ty/context.rs b/src/librustc/ty/context.rs index 82095a2f5b01..f78fad9f7aa9 100644 --- a/src/librustc/ty/context.rs +++ b/src/librustc/ty/context.rs @@ -823,12 +823,6 @@ impl<'a, 'gcx> HashStable> for TypeckTables<'gcx> { impl<'tcx> CommonTypes<'tcx> { fn new(interners: &CtxtInterners<'tcx>) -> CommonTypes<'tcx> { - // Ensure our type representation does not grow - #[cfg(target_pointer_width = "64")] - static_assert!(ASSERT_TY_KIND: ::std::mem::size_of::>() <= 24); - #[cfg(target_pointer_width = "64")] - static_assert!(ASSERT_TYS: ::std::mem::size_of::>() <= 32); - let mk = |sty| CtxtInterners::intern_ty(interners, interners, sty); let mk_region = |r| { if let Some(r) = interners.region.borrow().get(&r) { diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index ef9b3e3efab2..325034261351 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -514,6 +514,10 @@ pub struct TyS<'tcx> { outer_exclusive_binder: ty::DebruijnIndex, } +// `TyS` is used a lot. Make sure it doesn't unintentionally get bigger. +#[cfg(target_arch = "x86_64")] +static_assert!(MEM_SIZE_OF_TY_S: ::std::mem::size_of::>() == 32); + impl<'tcx> Ord for TyS<'tcx> { fn cmp(&self, other: &TyS<'tcx>) -> Ordering { self.sty.cmp(&other.sty) diff --git a/src/librustc/ty/sty.rs b/src/librustc/ty/sty.rs index a4130bf15cb8..bd3a34cae90f 100644 --- a/src/librustc/ty/sty.rs +++ b/src/librustc/ty/sty.rs @@ -211,6 +211,10 @@ pub enum TyKind<'tcx> { Error, } +// `TyKind` is used a lot. Make sure it doesn't unintentionally get bigger. +#[cfg(target_arch = "x86_64")] +static_assert!(MEM_SIZE_OF_TY_KIND: ::std::mem::size_of::>() == 24); + /// A closure can be modeled as a struct that looks like: /// /// struct Closure<'l0...'li, T0...Tj, CK, CS, U0...Uk> {