From 934e4d3b29637261620ddbb57e10627eb98e5eca Mon Sep 17 00:00:00 2001 From: yui-knk Date: Thu, 29 Nov 2018 08:54:35 +0900 Subject: [PATCH 01/32] Remove not used mod `mir_stats` mod has not been used since c1ff10464dc6b685f871d2365e3d8a39de324ba9. --- src/librustc_passes/lib.rs | 1 - src/librustc_passes/mir_stats.rs | 256 ------------------------------- 2 files changed, 257 deletions(-) delete mode 100644 src/librustc_passes/mir_stats.rs diff --git a/src/librustc_passes/lib.rs b/src/librustc_passes/lib.rs index 42ead92783d7a..a5d2edbc5d439 100644 --- a/src/librustc_passes/lib.rs +++ b/src/librustc_passes/lib.rs @@ -41,7 +41,6 @@ pub mod ast_validation; pub mod rvalue_promotion; pub mod hir_stats; pub mod loops; -mod mir_stats; __build_diagnostic_array! { librustc_passes, DIAGNOSTICS } diff --git a/src/librustc_passes/mir_stats.rs b/src/librustc_passes/mir_stats.rs deleted file mode 100644 index fb37f03a1cc41..0000000000000 --- a/src/librustc_passes/mir_stats.rs +++ /dev/null @@ -1,256 +0,0 @@ -// Copyright 2016 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -// The visitors in this module collect sizes and counts of the most important -// pieces of MIR. The resulting numbers are good approximations but not -// completely accurate (some things might be counted twice, others missed). - -use rustc::mir::{AggregateKind, AssertMessage, BasicBlock, BasicBlockData}; -use rustc::mir::{Constant, Location, Local, LocalDecl}; -use rustc::mir::{Place, PlaceElem, PlaceProjection}; -use rustc::mir::{Mir, Operand, ProjectionElem}; -use rustc::mir::{Rvalue, SourceInfo, Statement, StatementKind}; -use rustc::mir::{Terminator, TerminatorKind, SourceScope, SourceScopeData}; -use rustc::mir::interpret::EvalErrorKind; -use rustc::mir::visit as mir_visit; -use rustc::ty::{self, ClosureSubsts, TyCtxt}; -use rustc::util::nodemap::{FxHashMap}; - -struct NodeData { - count: usize, - size: usize, -} - -struct StatCollector<'a, 'tcx: 'a> { - _tcx: TyCtxt<'a, 'tcx, 'tcx>, - data: FxHashMap<&'static str, NodeData>, -} - -impl<'a, 'tcx> StatCollector<'a, 'tcx> { - - fn record_with_size(&mut self, label: &'static str, node_size: usize) { - let entry = self.data.entry(label).or_insert(NodeData { - count: 0, - size: 0, - }); - - entry.count += 1; - entry.size = node_size; - } - - fn record(&mut self, label: &'static str, node: &T) { - self.record_with_size(label, ::std::mem::size_of_val(node)); - } -} - -impl<'a, 'tcx> mir_visit::Visitor<'tcx> for StatCollector<'a, 'tcx> { - fn visit_mir(&mut self, mir: &Mir<'tcx>) { - self.record("Mir", mir); - - // since the `super_mir` method does not traverse the MIR of - // promoted rvalues, (but we still want to gather statistics - // on the structures represented there) we manually traverse - // the promoted rvalues here. - for promoted_mir in &mir.promoted { - self.visit_mir(promoted_mir); - } - - self.super_mir(mir); - } - - fn visit_basic_block_data(&mut self, block: BasicBlock, data: &BasicBlockData<'tcx>) { - self.record("BasicBlockData", data); - self.super_basic_block_data(block, data); - } - - fn visit_source_scope_data(&mut self, scope_data: &SourceScopeData) { - self.record("SourceScopeData", scope_data); - self.super_source_scope_data(scope_data); - } - - fn visit_statement(&mut self, - block: BasicBlock, - statement: &Statement<'tcx>, - location: Location) { - self.record("Statement", statement); - self.record(match statement.kind { - StatementKind::Assign(..) => "StatementKind::Assign", - StatementKind::FakeRead(..) => "StatementKind::FakeRead", - StatementKind::Retag { .. } => "StatementKind::Retag", - StatementKind::EscapeToRaw { .. } => "StatementKind::EscapeToRaw", - StatementKind::SetDiscriminant { .. } => "StatementKind::SetDiscriminant", - StatementKind::StorageLive(..) => "StatementKind::StorageLive", - StatementKind::StorageDead(..) => "StatementKind::StorageDead", - StatementKind::InlineAsm { .. } => "StatementKind::InlineAsm", - StatementKind::AscribeUserType(..) => "StatementKind::AscribeUserType", - StatementKind::Nop => "StatementKind::Nop", - }, &statement.kind); - self.super_statement(block, statement, location); - } - - fn visit_terminator(&mut self, - block: BasicBlock, - terminator: &Terminator<'tcx>, - location: Location) { - self.record("Terminator", terminator); - self.super_terminator(block, terminator, location); - } - - fn visit_terminator_kind(&mut self, - block: BasicBlock, - kind: &TerminatorKind<'tcx>, - location: Location) { - self.record("TerminatorKind", kind); - self.record(match *kind { - TerminatorKind::Goto { .. } => "TerminatorKind::Goto", - TerminatorKind::SwitchInt { .. } => "TerminatorKind::SwitchInt", - TerminatorKind::Resume => "TerminatorKind::Resume", - TerminatorKind::Abort => "TerminatorKind::Abort", - TerminatorKind::Return => "TerminatorKind::Return", - TerminatorKind::Unreachable => "TerminatorKind::Unreachable", - TerminatorKind::Drop { .. } => "TerminatorKind::Drop", - TerminatorKind::DropAndReplace { .. } => "TerminatorKind::DropAndReplace", - TerminatorKind::Call { .. } => "TerminatorKind::Call", - TerminatorKind::Assert { .. } => "TerminatorKind::Assert", - TerminatorKind::GeneratorDrop => "TerminatorKind::GeneratorDrop", - TerminatorKind::Yield { .. } => "TerminatorKind::Yield", - TerminatorKind::FalseEdges { .. } => "TerminatorKind::FalseEdges", - TerminatorKind::FalseUnwind { .. } => "TerminatorKind::FalseUnwind", - }, kind); - self.super_terminator_kind(block, kind, location); - } - - fn visit_assert_message(&mut self, msg: &AssertMessage<'tcx>, location: Location) { - self.record("AssertMessage", msg); - self.record(match *msg { - EvalErrorKind::BoundsCheck { .. } => "AssertMessage::BoundsCheck", - EvalErrorKind::Overflow(..) => "AssertMessage::Overflow", - EvalErrorKind::OverflowNeg => "AssertMessage::OverflowNeg", - EvalErrorKind::DivisionByZero => "AssertMessage::DivisionByZero", - EvalErrorKind::RemainderByZero => "AssertMessage::RemainderByZero", - EvalErrorKind::GeneratorResumedAfterReturn => { - "AssertMessage::GeneratorResumedAfterReturn" - } - EvalErrorKind::GeneratorResumedAfterPanic => { - "AssertMessage::GeneratorResumedAfterPanic" - } - _ => bug!(), - }, msg); - self.super_assert_message(msg, location); - } - - fn visit_rvalue(&mut self, rvalue: &Rvalue<'tcx>, location: Location) { - self.record("Rvalue", rvalue); - let rvalue_kind = match *rvalue { - Rvalue::Use(..) => "Rvalue::Use", - Rvalue::Repeat(..) => "Rvalue::Repeat", - Rvalue::Ref(..) => "Rvalue::Ref", - Rvalue::Len(..) => "Rvalue::Len", - Rvalue::Cast(..) => "Rvalue::Cast", - Rvalue::BinaryOp(..) => "Rvalue::BinaryOp", - Rvalue::CheckedBinaryOp(..) => "Rvalue::CheckedBinaryOp", - Rvalue::UnaryOp(..) => "Rvalue::UnaryOp", - Rvalue::Discriminant(..) => "Rvalue::Discriminant", - Rvalue::NullaryOp(..) => "Rvalue::NullaryOp", - Rvalue::Aggregate(ref kind, ref _operands) => { - // AggregateKind is not distinguished by visit API, so - // record it. (`super_rvalue` handles `_operands`.) - self.record(match **kind { - AggregateKind::Array(_) => "AggregateKind::Array", - AggregateKind::Tuple => "AggregateKind::Tuple", - AggregateKind::Adt(..) => "AggregateKind::Adt", - AggregateKind::Closure(..) => "AggregateKind::Closure", - AggregateKind::Generator(..) => "AggregateKind::Generator", - }, kind); - - "Rvalue::Aggregate" - } - }; - self.record(rvalue_kind, rvalue); - self.super_rvalue(rvalue, location); - } - - fn visit_operand(&mut self, operand: &Operand<'tcx>, location: Location) { - self.record("Operand", operand); - self.record(match *operand { - Operand::Copy(..) => "Operand::Copy", - Operand::Move(..) => "Operand::Move", - Operand::Constant(..) => "Operand::Constant", - }, operand); - self.super_operand(operand, location); - } - - fn visit_place(&mut self, - place: &Place<'tcx>, - context: mir_visit::PlaceContext<'tcx>, - location: Location) { - self.record("Place", place); - self.record(match *place { - Place::Local(..) => "Place::Local", - Place::Static(..) => "Place::Static", - Place::Promoted(..) => "Place::Promoted", - Place::Projection(..) => "Place::Projection", - }, place); - self.super_place(place, context, location); - } - - fn visit_projection(&mut self, - place: &PlaceProjection<'tcx>, - context: mir_visit::PlaceContext<'tcx>, - location: Location) { - self.record("PlaceProjection", place); - self.super_projection(place, context, location); - } - - fn visit_projection_elem(&mut self, - place: &PlaceElem<'tcx>, - location: Location) { - self.record("PlaceElem", place); - self.record(match *place { - ProjectionElem::Deref => "PlaceElem::Deref", - ProjectionElem::Subslice { .. } => "PlaceElem::Subslice", - ProjectionElem::Field(..) => "PlaceElem::Field", - ProjectionElem::Index(..) => "PlaceElem::Index", - ProjectionElem::ConstantIndex { .. } => "PlaceElem::ConstantIndex", - ProjectionElem::Downcast(..) => "PlaceElem::Downcast", - }, place); - self.super_projection_elem(place, location); - } - - fn visit_constant(&mut self, constant: &Constant<'tcx>, location: Location) { - self.record("Constant", constant); - self.super_constant(constant, location); - } - - fn visit_source_info(&mut self, source_info: &SourceInfo) { - self.record("SourceInfo", source_info); - self.super_source_info(source_info); - } - - fn visit_closure_substs(&mut self, substs: &ClosureSubsts<'tcx>, _: Location) { - self.record("ClosureSubsts", substs); - self.super_closure_substs(substs); - } - - fn visit_const(&mut self, constant: &&'tcx ty::Const<'tcx>, _: Location) { - self.record("Const", constant); - self.super_const(constant); - } - - fn visit_local_decl(&mut self, local: Local, local_decl: &LocalDecl<'tcx>) { - self.record("LocalDecl", local_decl); - self.super_local_decl(local, local_decl); - } - - fn visit_source_scope(&mut self, scope: &SourceScope) { - self.record("VisiblityScope", scope); - self.super_source_scope(scope); - } -} From eaeebb55e1962aa12f70165d8bd09c2eb823dfca Mon Sep 17 00:00:00 2001 From: John Ginger Date: Sun, 2 Dec 2018 15:40:24 +0000 Subject: [PATCH 02/32] Clearer error message for dead assign --- src/librustc/middle/liveness.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/librustc/middle/liveness.rs b/src/librustc/middle/liveness.rs index 54a0192d2e8a5..92c4077946feb 100644 --- a/src/librustc/middle/liveness.rs +++ b/src/librustc/middle/liveness.rs @@ -1658,10 +1658,10 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> { if let Some(name) = self.should_warn(var) { if is_argument { self.ir.tcx.lint_hir(lint::builtin::UNUSED_ASSIGNMENTS, hir_id, sp, - &format!("value passed to `{}` is never read", name)); + &format!("value passed to `{}` is never read (maybe it is overwritten before being read)", name)); } else { self.ir.tcx.lint_hir(lint::builtin::UNUSED_ASSIGNMENTS, hir_id, sp, - &format!("value assigned to `{}` is never read", name)); + &format!("value assigned to `{}` is never read (maybe it is overwritten before being read)", name)); } } } From 54026c14cf94230531c24bb52e84f549b3e3dea9 Mon Sep 17 00:00:00 2001 From: John Ginger Date: Sun, 2 Dec 2018 16:35:51 +0000 Subject: [PATCH 03/32] Fix line length --- src/librustc/middle/liveness.rs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/librustc/middle/liveness.rs b/src/librustc/middle/liveness.rs index 92c4077946feb..b154077adb75f 100644 --- a/src/librustc/middle/liveness.rs +++ b/src/librustc/middle/liveness.rs @@ -1658,10 +1658,12 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> { if let Some(name) = self.should_warn(var) { if is_argument { self.ir.tcx.lint_hir(lint::builtin::UNUSED_ASSIGNMENTS, hir_id, sp, - &format!("value passed to `{}` is never read (maybe it is overwritten before being read)", name)); + &format!("value passed to `{}` is never read + (maybe it is overwritten before being read)", name)); } else { self.ir.tcx.lint_hir(lint::builtin::UNUSED_ASSIGNMENTS, hir_id, sp, - &format!("value assigned to `{}` is never read (maybe it is overwritten before being read)", name)); + &format!("value assigned to `{}` is never read + (maybe it is overwritten before being read)", name)); } } } From 4cf5702d527aabc225cb77683e28c8d8600a7e1b Mon Sep 17 00:00:00 2001 From: John Ginger Date: Mon, 3 Dec 2018 10:28:19 +0000 Subject: [PATCH 04/32] Fix stderr files --- src/test/ui/liveness/liveness-dead.stderr | 4 ++++ src/test/ui/liveness/liveness-unused.stderr | 2 ++ 2 files changed, 6 insertions(+) diff --git a/src/test/ui/liveness/liveness-dead.stderr b/src/test/ui/liveness/liveness-dead.stderr index 6709fee0abb72..4237995c3f1bf 100644 --- a/src/test/ui/liveness/liveness-dead.stderr +++ b/src/test/ui/liveness/liveness-dead.stderr @@ -1,4 +1,5 @@ error: value assigned to `x` is never read + (maybe it is overwritten before being read) --> $DIR/liveness-dead.rs:19:13 | LL | let mut x: isize = 3; //~ ERROR: value assigned to `x` is never read @@ -11,18 +12,21 @@ LL | #![deny(unused_assignments)] | ^^^^^^^^^^^^^^^^^^ error: value assigned to `x` is never read + (maybe it is overwritten before being read) --> $DIR/liveness-dead.rs:27:5 | LL | x = 4; //~ ERROR: value assigned to `x` is never read | ^ error: value passed to `x` is never read + (maybe it is overwritten before being read) --> $DIR/liveness-dead.rs:30:11 | LL | fn f4(mut x: i32) { //~ ERROR: value passed to `x` is never read | ^ error: value assigned to `x` is never read + (maybe it is overwritten before being read) --> $DIR/liveness-dead.rs:37:5 | LL | x = 4; //~ ERROR: value assigned to `x` is never read diff --git a/src/test/ui/liveness/liveness-unused.stderr b/src/test/ui/liveness/liveness-unused.stderr index 2846f242fbe4c..b9f4ad7b95a67 100644 --- a/src/test/ui/liveness/liveness-unused.stderr +++ b/src/test/ui/liveness/liveness-unused.stderr @@ -50,6 +50,7 @@ LL | let mut x = 3; = note: consider using `_x` instead error: value assigned to `x` is never read + (maybe it is overwritten before being read) --> $DIR/liveness-unused.rs:42:5 | LL | x += 4; @@ -102,6 +103,7 @@ LL | let x; = note: consider using `_x` instead error: value assigned to `x` is never read + (maybe it is overwritten before being read) --> $DIR/liveness-unused.rs:126:9 | LL | x = 0; //~ ERROR value assigned to `x` is never read From 70536d4b4c8287925ccc4a8255f3d42c70aed6e3 Mon Sep 17 00:00:00 2001 From: John Ginger Date: Mon, 3 Dec 2018 22:53:03 +0000 Subject: [PATCH 05/32] Fix stderr file (unused variable) --- .../ui/lint/issue-47390-unused-variable-in-struct-pattern.stderr | 1 + 1 file changed, 1 insertion(+) diff --git a/src/test/ui/lint/issue-47390-unused-variable-in-struct-pattern.stderr b/src/test/ui/lint/issue-47390-unused-variable-in-struct-pattern.stderr index a8b0e3e4250ea..aea46e4e96cb5 100644 --- a/src/test/ui/lint/issue-47390-unused-variable-in-struct-pattern.stderr +++ b/src/test/ui/lint/issue-47390-unused-variable-in-struct-pattern.stderr @@ -44,6 +44,7 @@ LL | mut hours_are_suns, = note: consider using `_hours_are_suns` instead warning: value assigned to `hours_are_suns` is never read + (maybe it is overwritten before being read) --> $DIR/issue-47390-unused-variable-in-struct-pattern.rs:50:9 | LL | hours_are_suns = false; From c0e3f4b8bbf10cc308823c98913b942b75c6a543 Mon Sep 17 00:00:00 2001 From: John Ginger Date: Fri, 7 Dec 2018 14:15:36 +0000 Subject: [PATCH 06/32] Change to give a help message --- src/librustc/middle/liveness.rs | 14 ++++++++------ ...-47390-unused-variable-in-struct-pattern.stderr | 2 +- src/test/ui/liveness/liveness-dead.stderr | 11 +++++++---- src/test/ui/liveness/liveness-unused.stderr | 5 +++-- 4 files changed, 19 insertions(+), 13 deletions(-) diff --git a/src/librustc/middle/liveness.rs b/src/librustc/middle/liveness.rs index b154077adb75f..2136cd27e4306 100644 --- a/src/librustc/middle/liveness.rs +++ b/src/librustc/middle/liveness.rs @@ -1657,13 +1657,15 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> { fn report_dead_assign(&self, hir_id: HirId, sp: Span, var: Variable, is_argument: bool) { if let Some(name) = self.should_warn(var) { if is_argument { - self.ir.tcx.lint_hir(lint::builtin::UNUSED_ASSIGNMENTS, hir_id, sp, - &format!("value passed to `{}` is never read - (maybe it is overwritten before being read)", name)); + self.ir.tcx.struct_span_lint_hir(lint::builtin::UNUSED_ASSIGNMENTS, hir_id, sp, + &format!("value passed to `{}` is never read", name)) + .help("maybe it is overwritten before being read?") + .emit(); } else { - self.ir.tcx.lint_hir(lint::builtin::UNUSED_ASSIGNMENTS, hir_id, sp, - &format!("value assigned to `{}` is never read - (maybe it is overwritten before being read)", name)); + self.ir.tcx.struct_span_lint_hir(lint::builtin::UNUSED_ASSIGNMENTS, hir_id, sp, + &format!("value assigned to `{}` is never read", name)) + .help("maybe it is overwritten before being read?") + .emit(); } } } diff --git a/src/test/ui/lint/issue-47390-unused-variable-in-struct-pattern.stderr b/src/test/ui/lint/issue-47390-unused-variable-in-struct-pattern.stderr index aea46e4e96cb5..6b9e1dc70573e 100644 --- a/src/test/ui/lint/issue-47390-unused-variable-in-struct-pattern.stderr +++ b/src/test/ui/lint/issue-47390-unused-variable-in-struct-pattern.stderr @@ -44,7 +44,6 @@ LL | mut hours_are_suns, = note: consider using `_hours_are_suns` instead warning: value assigned to `hours_are_suns` is never read - (maybe it is overwritten before being read) --> $DIR/issue-47390-unused-variable-in-struct-pattern.rs:50:9 | LL | hours_are_suns = false; @@ -56,6 +55,7 @@ note: lint level defined here LL | #![warn(unused)] // UI tests pass `-A unused` (#43896) | ^^^^^^ = note: #[warn(unused_assignments)] implied by #[warn(unused)] + = help: maybe it is overwritten before being read? warning: unused variable: `fire` --> $DIR/issue-47390-unused-variable-in-struct-pattern.rs:54:32 diff --git a/src/test/ui/liveness/liveness-dead.stderr b/src/test/ui/liveness/liveness-dead.stderr index 4237995c3f1bf..6e43cccdccff2 100644 --- a/src/test/ui/liveness/liveness-dead.stderr +++ b/src/test/ui/liveness/liveness-dead.stderr @@ -1,5 +1,4 @@ error: value assigned to `x` is never read - (maybe it is overwritten before being read) --> $DIR/liveness-dead.rs:19:13 | LL | let mut x: isize = 3; //~ ERROR: value assigned to `x` is never read @@ -10,27 +9,31 @@ note: lint level defined here | LL | #![deny(unused_assignments)] | ^^^^^^^^^^^^^^^^^^ + = help: maybe it is overwritten before being read? error: value assigned to `x` is never read - (maybe it is overwritten before being read) --> $DIR/liveness-dead.rs:27:5 | LL | x = 4; //~ ERROR: value assigned to `x` is never read | ^ + | + = help: maybe it is overwritten before being read? error: value passed to `x` is never read - (maybe it is overwritten before being read) --> $DIR/liveness-dead.rs:30:11 | LL | fn f4(mut x: i32) { //~ ERROR: value passed to `x` is never read | ^ + | + = help: maybe it is overwritten before being read? error: value assigned to `x` is never read - (maybe it is overwritten before being read) --> $DIR/liveness-dead.rs:37:5 | LL | x = 4; //~ ERROR: value assigned to `x` is never read | ^ + | + = help: maybe it is overwritten before being read? error: aborting due to 4 previous errors diff --git a/src/test/ui/liveness/liveness-unused.stderr b/src/test/ui/liveness/liveness-unused.stderr index b9f4ad7b95a67..35ccc79a19ac0 100644 --- a/src/test/ui/liveness/liveness-unused.stderr +++ b/src/test/ui/liveness/liveness-unused.stderr @@ -50,7 +50,6 @@ LL | let mut x = 3; = note: consider using `_x` instead error: value assigned to `x` is never read - (maybe it is overwritten before being read) --> $DIR/liveness-unused.rs:42:5 | LL | x += 4; @@ -61,6 +60,7 @@ note: lint level defined here | LL | #![deny(unused_assignments)] | ^^^^^^^^^^^^^^^^^^ + = help: maybe it is overwritten before being read? error: variable `z` is assigned to, but never used --> $DIR/liveness-unused.rs:47:13 @@ -103,11 +103,12 @@ LL | let x; = note: consider using `_x` instead error: value assigned to `x` is never read - (maybe it is overwritten before being read) --> $DIR/liveness-unused.rs:126:9 | LL | x = 0; //~ ERROR value assigned to `x` is never read | ^ + | + = help: maybe it is overwritten before being read? error: aborting due to 13 previous errors From 67e7181199d506f26633e4a06073b7a17ad34045 Mon Sep 17 00:00:00 2001 From: myfreeweb Date: Sun, 9 Dec 2018 01:37:57 +0300 Subject: [PATCH 07/32] Add FreeBSD unsigned char platforms to std::os::raw Reference: https://www.freebsd.org/cgi/man.cgi?query=arch&apropos=0&sektion=7 --- src/libstd/os/raw/mod.rs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/libstd/os/raw/mod.rs b/src/libstd/os/raw/mod.rs index 95faf3a5dd63d..05f30f2881a00 100644 --- a/src/libstd/os/raw/mod.rs +++ b/src/libstd/os/raw/mod.rs @@ -27,6 +27,10 @@ all(target_os = "android", any(target_arch = "aarch64", target_arch = "arm")), all(target_os = "l4re", target_arch = "x86_64"), + all(target_os = "freebsd", any(target_arch = "aarch64", + target_arch = "arm", + target_arch = "powerpc", + target_arch = "powerpc64")), all(target_os = "netbsd", any(target_arch = "aarch64", target_arch = "arm", target_arch = "powerpc")), @@ -42,6 +46,10 @@ all(target_os = "android", any(target_arch = "aarch64", target_arch = "arm")), all(target_os = "l4re", target_arch = "x86_64"), + all(target_os = "freebsd", any(target_arch = "aarch64", + target_arch = "arm", + target_arch = "powerpc", + target_arch = "powerpc64")), all(target_os = "netbsd", any(target_arch = "aarch64", target_arch = "arm", target_arch = "powerpc")), From 0e70c269feece979427bcc8795afc43efc1e47c1 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 7 Dec 2018 16:52:10 +0100 Subject: [PATCH 08/32] fix BTree creating shared references that are not entirely in-bounds --- src/liballoc/collections/btree/node.rs | 115 ++++++++++++++++++------- 1 file changed, 86 insertions(+), 29 deletions(-) diff --git a/src/liballoc/collections/btree/node.rs b/src/liballoc/collections/btree/node.rs index 215689dfc48c9..13cbcee2f8e08 100644 --- a/src/liballoc/collections/btree/node.rs +++ b/src/liballoc/collections/btree/node.rs @@ -58,9 +58,34 @@ pub const CAPACITY: usize = 2 * B - 1; /// these should always be put behind pointers, and specifically behind `BoxedNode` in the owned /// case. /// -/// We put the metadata first so that its position is the same for every `K` and `V`, in order -/// to statically allocate a single dummy node to avoid allocations. This struct is `repr(C)` to -/// prevent them from being reordered. +/// We have a separate type for the header and rely on it matching the prefix of `LeafNode`, in +/// order to statically allocate a single dummy node to avoid allocations. This struct is +/// `repr(C)` to prevent them from being reordered. `LeafNode` does not just contain a +/// `NodeHeader` because we do not want unnecessary padding between `len` and the keys. +/// Crucially, `NodeHeader` can be safely transmuted to different K and V. (This is exploited +/// by `as_header`.) +/// See `into_key_slice` for an explanation of K2. K2 cannot be safely transmuted around +/// because the size of `NodeHeader` depends on its alignment! +#[repr(C)] +struct NodeHeader { + /// We use `*const` as opposed to `*mut` so as to be covariant in `K` and `V`. + /// This either points to an actual node or is null. + parent: *const InternalNode, + + /// This node's index into the parent node's `edges` array. + /// `*node.parent.edges[node.parent_idx]` should be the same thing as `node`. + /// This is only guaranteed to be initialized when `parent` is non-null. + parent_idx: MaybeUninit, + + /// The number of keys and values this node stores. + /// + /// This next to `parent_idx` to encourage the compiler to join `len` and + /// `parent_idx` into the same 32-bit word, reducing space overhead. + len: u16, + + /// See `into_key_slice`. + keys_start: [K2; 0], +} #[repr(C)] struct LeafNode { /// We use `*const` as opposed to `*mut` so as to be covariant in `K` and `V`. @@ -98,24 +123,25 @@ impl LeafNode { len: 0 } } +} +impl NodeHeader { fn is_shared_root(&self) -> bool { ptr::eq(self, &EMPTY_ROOT_NODE as *const _ as *const _) } } // We need to implement Sync here in order to make a static instance. -unsafe impl Sync for LeafNode<(), ()> {} +unsafe impl Sync for NodeHeader<(), ()> {} // An empty node used as a placeholder for the root node, to avoid allocations. -// We use () in order to save space, since no operation on an empty tree will +// We use just a header in order to save space, since no operation on an empty tree will // ever take a pointer past the first key. -static EMPTY_ROOT_NODE: LeafNode<(), ()> = LeafNode { +static EMPTY_ROOT_NODE: NodeHeader<(), ()> = NodeHeader { parent: ptr::null(), parent_idx: MaybeUninit::uninitialized(), len: 0, - keys: MaybeUninit::uninitialized(), - vals: MaybeUninit::uninitialized(), + keys_start: [], }; /// The underlying representation of internal nodes. As with `LeafNode`s, these should be hidden @@ -306,6 +332,11 @@ impl Root { /// `Leaf`, the `NodeRef` points to a leaf node, when this is `Internal` the /// `NodeRef` points to an internal node, and when this is `LeafOrInternal` the /// `NodeRef` could be pointing to either type of node. +/// Note that in case of a leaf node, this might still be the shared root! Only turn +/// this into a `LeafNode` reference if you know it is not a root! Shared references +/// must be dereferencable *for the entire size of their pointee*, so `&InternalNode` +/// pointing to the shared root is UB. +/// Turning this into a `NodeHeader` is always safe. pub struct NodeRef { height: usize, node: NonNull>, @@ -352,7 +383,7 @@ impl NodeRef { /// Finds the length of the node. This is the number of keys or values. In an /// internal node, the number of edges is `len() + 1`. pub fn len(&self) -> usize { - self.as_leaf().len as usize + self.as_header().len as usize } /// Returns the height of this node in the whole tree. Zero height denotes the @@ -382,14 +413,19 @@ impl NodeRef { } } - fn as_leaf(&self) -> &LeafNode { + /// Assert that this is indeed a proper leaf node, and not the shared root. + unsafe fn as_leaf(&self) -> &LeafNode { + self.node.as_ref() + } + + fn as_header(&self) -> &NodeHeader { unsafe { - self.node.as_ref() + &*(self.node.as_ptr() as *const NodeHeader) } } pub fn is_shared_root(&self) -> bool { - self.as_leaf().is_shared_root() + self.as_header().is_shared_root() } pub fn keys(&self) -> &[K] { @@ -418,7 +454,7 @@ impl NodeRef { >, Self > { - let parent_as_leaf = self.as_leaf().parent as *const LeafNode; + let parent_as_leaf = self.as_header().parent as *const LeafNode; if let Some(non_zero) = NonNull::new(parent_as_leaf as *mut _) { Ok(Handle { node: NodeRef { @@ -427,7 +463,7 @@ impl NodeRef { root: self.root, _marker: PhantomData }, - idx: unsafe { usize::from(*self.as_leaf().parent_idx.get_ref()) }, + idx: unsafe { usize::from(*self.as_header().parent_idx.get_ref()) }, _marker: PhantomData }) } else { @@ -535,9 +571,8 @@ impl<'a, K, V, Type> NodeRef, K, V, Type> { } fn as_leaf_mut(&mut self) -> &mut LeafNode { - unsafe { - self.node.as_mut() - } + // We are mutable, so we cannot be the root, so this is okay. + unsafe { self.node.as_mut() } } fn keys_mut(&mut self) -> &mut [K] { @@ -551,28 +586,50 @@ impl<'a, K, V, Type> NodeRef, K, V, Type> { impl<'a, K: 'a, V: 'a, Type> NodeRef, K, V, Type> { fn into_key_slice(self) -> &'a [K] { - // When taking a pointer to the keys, if our key has a stricter - // alignment requirement than the shared root does, then the pointer - // would be out of bounds, which LLVM assumes will not happen. If the - // alignment is more strict, we need to make an empty slice that doesn't - // use an out of bounds pointer. + // We have to be careful here because we might be pointing to the shared root. + // In that case, we must not create an `&LeafNode`. We could just return + // an empty slice whenever the lenght is 0 (this includes the shared root), + // but we want to avoid that run-time check. + // Instead, we create a slice pointing into the node whenever possible. + // We can sometimes do this even for the shared root, as the slice will be + // empty. We cannot *always* do this because if the type is too highly + // aligned, the offset of `keys` in a "full node" might be outside the bounds + // of the header! So we do an alignment check first, that will be + // evaluated at compile-time, and only do any run-time check in the rare case + // that the alignment is very big. if mem::align_of::() > mem::align_of::>() && self.is_shared_root() { &[] } else { - // Here either it's not the root, or the alignment is less strict, - // in which case the keys pointer will point "one-past-the-end" of - // the node, which is allowed by LLVM. + // Thanks to the alignment check above, we know that `keys` will be + // in-bounds of some allocation even if this is the shared root! + // (We might be one-past-the-end, but that is allowed by LLVM.) + // Getting the pointer is tricky though. `NodeHeader` does not have a `keys` + // field because we want its size to not depend on the alignment of `K` + // (needed becuase `as_header` should be safe). We cannot call `as_leaf` + // because we might be the shared root. + // For this reason, `NodeHeader` has this `K2` parameter (that's usually `()` + // and hence just adds a size-0-align-1 field, not affecting layout). + // We know that we can transmute `NodeHeader` to `NodeHeader` + // because we did the alignment check above, and hence `NodeHeader` + // is not bigger than `NodeHeader`! Then we can use `NodeHeader` + // to compute the pointer where the keys start. + // This entire hack will become unnecessary once + // lands, then we can just take a raw + // pointer to the `keys` field of `*const InternalNode`. + + // This is a non-debug-assert because it can be completely compile-time evaluated. + assert!(mem::size_of::>() == mem::size_of::>()); + let header = self.as_header() as *const _ as *const NodeHeader; + let keys = unsafe { &(*header).keys_start as *const _ as *const K }; unsafe { - slice::from_raw_parts( - self.as_leaf().keys.as_ptr() as *const K, - self.len() - ) + slice::from_raw_parts(keys, self.len()) } } } fn into_val_slice(self) -> &'a [V] { debug_assert!(!self.is_shared_root()); + // We cannot be the root, so `as_leaf` is okay unsafe { slice::from_raw_parts( self.as_leaf().vals.as_ptr() as *const V, From 4558340ecc64c2702ad89b8175e07ac1c71e273b Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 8 Dec 2018 23:38:12 +0100 Subject: [PATCH 09/32] avoid as_leaf_mut asserting exclusive access --- src/liballoc/collections/btree/node.rs | 63 ++++++++++++++------------ 1 file changed, 33 insertions(+), 30 deletions(-) diff --git a/src/liballoc/collections/btree/node.rs b/src/liballoc/collections/btree/node.rs index 13cbcee2f8e08..a9f6cdbb51ff1 100644 --- a/src/liballoc/collections/btree/node.rs +++ b/src/liballoc/collections/btree/node.rs @@ -307,7 +307,7 @@ impl Root { .node) }; self.height -= 1; - self.as_mut().as_leaf_mut().parent = ptr::null(); + unsafe { (*self.as_mut().as_leaf_mut()).parent = ptr::null(); } unsafe { Global.dealloc(NonNull::from(top).cast(), Layout::new::>()); @@ -570,9 +570,10 @@ impl<'a, K, V, Type> NodeRef, K, V, Type> { } } - fn as_leaf_mut(&mut self) -> &mut LeafNode { - // We are mutable, so we cannot be the root, so this is okay. - unsafe { self.node.as_mut() } + /// Returns a raw ptr to avoid asserting exclusive access to the entire node. + fn as_leaf_mut(&mut self) -> *mut LeafNode { + // We are mutable, so we cannot be the root, so accessing this as a leaf is okay. + self.node.as_ptr() } fn keys_mut(&mut self) -> &mut [K] { @@ -659,7 +660,7 @@ impl<'a, K: 'a, V: 'a, Type> NodeRef, K, V, Type> { } else { unsafe { slice::from_raw_parts_mut( - self.as_leaf_mut().keys.as_mut_ptr() as *mut K, + (*self.as_leaf_mut()).keys.as_mut_ptr() as *mut K, self.len() ) } @@ -670,7 +671,7 @@ impl<'a, K: 'a, V: 'a, Type> NodeRef, K, V, Type> { debug_assert!(!self.is_shared_root()); unsafe { slice::from_raw_parts_mut( - self.as_leaf_mut().vals.as_mut_ptr() as *mut V, + (*self.as_leaf_mut()).vals.as_mut_ptr() as *mut V, self.len() ) } @@ -694,9 +695,9 @@ impl<'a, K, V> NodeRef, K, V, marker::Leaf> { unsafe { ptr::write(self.keys_mut().get_unchecked_mut(idx), key); ptr::write(self.vals_mut().get_unchecked_mut(idx), val); - } - self.as_leaf_mut().len += 1; + (*self.as_leaf_mut()).len += 1; + } } /// Adds a key/value pair to the beginning of the node. @@ -708,9 +709,9 @@ impl<'a, K, V> NodeRef, K, V, marker::Leaf> { unsafe { slice_insert(self.keys_mut(), 0, key); slice_insert(self.vals_mut(), 0, val); - } - self.as_leaf_mut().len += 1; + (*self.as_leaf_mut()).len += 1; + } } } @@ -729,7 +730,7 @@ impl<'a, K, V> NodeRef, K, V, marker::Internal> { ptr::write(self.vals_mut().get_unchecked_mut(idx), val); ptr::write(self.as_internal_mut().edges.get_unchecked_mut(idx + 1), edge.node); - self.as_leaf_mut().len += 1; + (*self.as_leaf_mut()).len += 1; Handle::new_edge(self.reborrow_mut(), idx + 1).correct_parent_link(); } @@ -765,7 +766,7 @@ impl<'a, K, V> NodeRef, K, V, marker::Internal> { edge.node ); - self.as_leaf_mut().len += 1; + (*self.as_leaf_mut()).len += 1; self.correct_all_childrens_parent_links(); } @@ -789,12 +790,12 @@ impl<'a, K, V> NodeRef, K, V, marker::LeafOrInternal> { ForceResult::Internal(internal) => { let edge = ptr::read(internal.as_internal().edges.get_unchecked(idx + 1)); let mut new_root = Root { node: edge, height: internal.height - 1 }; - new_root.as_mut().as_leaf_mut().parent = ptr::null(); + (*new_root.as_mut().as_leaf_mut()).parent = ptr::null(); Some(new_root) } }; - self.as_leaf_mut().len -= 1; + (*self.as_leaf_mut()).len -= 1; (key, val, edge) } } @@ -822,7 +823,7 @@ impl<'a, K, V> NodeRef, K, V, marker::LeafOrInternal> { ); let mut new_root = Root { node: edge, height: internal.height - 1 }; - new_root.as_mut().as_leaf_mut().parent = ptr::null(); + (*new_root.as_mut().as_leaf_mut()).parent = ptr::null(); for i in 0..old_len { Handle::new_edge(internal.reborrow_mut(), i).correct_parent_link(); @@ -832,7 +833,7 @@ impl<'a, K, V> NodeRef, K, V, marker::LeafOrInternal> { } }; - self.as_leaf_mut().len -= 1; + (*self.as_leaf_mut()).len -= 1; (key, val, edge) } @@ -1023,7 +1024,7 @@ impl<'a, K, V> Handle, K, V, marker::Leaf>, marker::Edge slice_insert(self.node.keys_mut(), self.idx, key); slice_insert(self.node.vals_mut(), self.idx, val); - self.node.as_leaf_mut().len += 1; + (*self.node.as_leaf_mut()).len += 1; self.node.vals_mut().get_unchecked_mut(self.idx) } @@ -1066,8 +1067,10 @@ impl<'a, K, V> Handle, K, V, marker::Internal>, marker:: let idx = self.idx as u16; let ptr = self.node.as_internal_mut() as *mut _; let mut child = self.descend(); - child.as_leaf_mut().parent = ptr; - child.as_leaf_mut().parent_idx.set(idx); + unsafe { + (*child.as_leaf_mut()).parent = ptr; + (*child.as_leaf_mut()).parent_idx.set(idx); + } } /// Unsafely asserts to the compiler some static information about whether the underlying @@ -1215,7 +1218,7 @@ impl<'a, K, V> Handle, K, V, marker::Leaf>, marker::KV> new_len ); - self.node.as_leaf_mut().len = self.idx as u16; + (*self.node.as_leaf_mut()).len = self.idx as u16; new_node.len = new_len as u16; ( @@ -1237,7 +1240,7 @@ impl<'a, K, V> Handle, K, V, marker::Leaf>, marker::KV> unsafe { let k = slice_remove(self.node.keys_mut(), self.idx); let v = slice_remove(self.node.vals_mut(), self.idx); - self.node.as_leaf_mut().len -= 1; + (*self.node.as_leaf_mut()).len -= 1; (self.left_edge(), k, v) } } @@ -1278,7 +1281,7 @@ impl<'a, K, V> Handle, K, V, marker::Internal>, marker:: new_len + 1 ); - self.node.as_leaf_mut().len = self.idx as u16; + (*self.node.as_leaf_mut()).len = self.idx as u16; new_node.data.len = new_len as u16; let mut new_root = Root { @@ -1352,9 +1355,9 @@ impl<'a, K, V> Handle, K, V, marker::Internal>, marker:: for i in self.idx+1..self.node.len() { Handle::new_edge(self.node.reborrow_mut(), i).correct_parent_link(); } - self.node.as_leaf_mut().len -= 1; + (*self.node.as_leaf_mut()).len -= 1; - left_node.as_leaf_mut().len += right_len as u16 + 1; + (*left_node.as_leaf_mut()).len += right_len as u16 + 1; if self.node.height > 1 { ptr::copy_nonoverlapping( @@ -1464,8 +1467,8 @@ impl<'a, K, V> Handle, K, V, marker::Internal>, marker:: move_kv(left_kv, new_left_len, parent_kv, 0, 1); } - left_node.reborrow_mut().as_leaf_mut().len -= count as u16; - right_node.reborrow_mut().as_leaf_mut().len += count as u16; + (*left_node.reborrow_mut().as_leaf_mut()).len -= count as u16; + (*right_node.reborrow_mut().as_leaf_mut()).len += count as u16; match (left_node.force(), right_node.force()) { (ForceResult::Internal(left), ForceResult::Internal(mut right)) => { @@ -1525,8 +1528,8 @@ impl<'a, K, V> Handle, K, V, marker::Internal>, marker:: new_right_len); } - left_node.reborrow_mut().as_leaf_mut().len += count as u16; - right_node.reborrow_mut().as_leaf_mut().len -= count as u16; + (*left_node.reborrow_mut().as_leaf_mut()).len += count as u16; + (*right_node.reborrow_mut().as_leaf_mut()).len -= count as u16; match (left_node.force(), right_node.force()) { (ForceResult::Internal(left), ForceResult::Internal(mut right)) => { @@ -1617,8 +1620,8 @@ impl<'a, K, V> Handle, K, V, marker::LeafOrInternal>, ma move_kv(left_kv, left_new_len, right_kv, 0, right_new_len); - left_node.reborrow_mut().as_leaf_mut().len = left_new_len as u16; - right_node.reborrow_mut().as_leaf_mut().len = right_new_len as u16; + (*left_node.reborrow_mut().as_leaf_mut()).len = left_new_len as u16; + (*right_node.reborrow_mut().as_leaf_mut()).len = right_new_len as u16; match (left_node.force(), right_node.force()) { (ForceResult::Internal(left), ForceResult::Internal(right)) => { From 562f33b1a57acb4ccbc741fb32687aedfc4a8398 Mon Sep 17 00:00:00 2001 From: Chris Couzens Date: Mon, 10 Dec 2018 12:43:15 +0000 Subject: [PATCH 10/32] Document time of back operations of a Linked List Popping and pushing from the end of a linked list is constant time. This documentation is already there for popping and pushing from the front. @bors: r+ 38fe8d2 rollup --- src/liballoc/collections/linked_list.rs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/liballoc/collections/linked_list.rs b/src/liballoc/collections/linked_list.rs index 2ef84dbade0fb..ba46fafaf169f 100644 --- a/src/liballoc/collections/linked_list.rs +++ b/src/liballoc/collections/linked_list.rs @@ -627,7 +627,9 @@ impl LinkedList { self.pop_front_node().map(Node::into_element) } - /// Appends an element to the back of a list + /// Appends an element to the back of a list. + /// + /// This operation should compute in O(1) time. /// /// # Examples /// @@ -647,6 +649,8 @@ impl LinkedList { /// Removes the last element from a list and returns it, or `None` if /// it is empty. /// + /// This operation should compute in O(1) time. + /// /// # Examples /// /// ``` From d9c64e50a07dec062c273f4ec4c8f5985af13273 Mon Sep 17 00:00:00 2001 From: Alexis Beingessner Date: Tue, 11 Dec 2018 08:55:15 +0100 Subject: [PATCH 11/32] Typo Co-Authored-By: RalfJung --- src/liballoc/collections/btree/node.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/liballoc/collections/btree/node.rs b/src/liballoc/collections/btree/node.rs index a9f6cdbb51ff1..a2d2d3c74be9d 100644 --- a/src/liballoc/collections/btree/node.rs +++ b/src/liballoc/collections/btree/node.rs @@ -589,7 +589,7 @@ impl<'a, K: 'a, V: 'a, Type> NodeRef, K, V, Type> { fn into_key_slice(self) -> &'a [K] { // We have to be careful here because we might be pointing to the shared root. // In that case, we must not create an `&LeafNode`. We could just return - // an empty slice whenever the lenght is 0 (this includes the shared root), + // an empty slice whenever the length is 0 (this includes the shared root), // but we want to avoid that run-time check. // Instead, we create a slice pointing into the node whenever possible. // We can sometimes do this even for the shared root, as the slice will be From 8d0b64f16d4a477dcc194917b4c9e3d4c9459743 Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Tue, 11 Dec 2018 09:07:03 +0100 Subject: [PATCH 12/32] Make `const unsafe fn` bodies `unsafe` --- src/libcore/num/mod.rs | 2 +- src/libcore/ptr.rs | 2 +- src/librustc_mir/build/mod.rs | 7 -- src/librustc_mir/transform/check_unsafety.rs | 29 ++----- .../min_const_fn/min_const_fn_unsafe.rs | 4 +- .../min_const_fn/min_const_fn_unsafe.stderr | 24 +----- .../min_const_fn_unsafe_feature_gate.rs | 15 ++-- .../min_const_fn_unsafe_feature_gate.stderr | 81 ++++--------------- 8 files changed, 33 insertions(+), 131 deletions(-) diff --git a/src/libcore/num/mod.rs b/src/libcore/num/mod.rs index 13b422162f3d6..01f3919199c3b 100644 --- a/src/libcore/num/mod.rs +++ b/src/libcore/num/mod.rs @@ -70,7 +70,7 @@ assert_eq!(size_of::>(), size_of::<", st #[stable(feature = "nonzero", since = "1.28.0")] #[inline] pub const unsafe fn new_unchecked(n: $Int) -> Self { - $Ty(unsafe { NonZero(n) }) + $Ty(NonZero(n)) } /// Create a non-zero if the given value is not zero. diff --git a/src/libcore/ptr.rs b/src/libcore/ptr.rs index b11ae30327226..dce5ec113f799 100644 --- a/src/libcore/ptr.rs +++ b/src/libcore/ptr.rs @@ -2928,7 +2928,7 @@ impl NonNull { #[stable(feature = "nonnull", since = "1.25.0")] #[inline] pub const unsafe fn new_unchecked(ptr: *mut T) -> Self { - NonNull { pointer: unsafe { NonZero(ptr as _) } } + NonNull { pointer: NonZero(ptr as _) } } /// Creates a new `NonNull` if `ptr` is non-null. diff --git a/src/librustc_mir/build/mod.rs b/src/librustc_mir/build/mod.rs index b0601b3bbefb1..06ba4f6df665e 100644 --- a/src/librustc_mir/build/mod.rs +++ b/src/librustc_mir/build/mod.rs @@ -111,13 +111,6 @@ pub fn mir_build<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> Mir<'t let safety = match fn_sig.unsafety { hir::Unsafety::Normal => Safety::Safe, - hir::Unsafety::Unsafe if tcx.is_min_const_fn(fn_def_id) => { - // As specified in #55607, a `const unsafe fn` differs - // from an `unsafe fn` in that its body is still considered - // safe code by default. - assert!(implicit_argument.is_none()); - Safety::Safe - }, hir::Unsafety::Unsafe => Safety::FnUnsafe, }; diff --git a/src/librustc_mir/transform/check_unsafety.rs b/src/librustc_mir/transform/check_unsafety.rs index 6af29b74c1c4f..3607869384077 100644 --- a/src/librustc_mir/transform/check_unsafety.rs +++ b/src/librustc_mir/transform/check_unsafety.rs @@ -311,13 +311,9 @@ impl<'a, 'tcx> UnsafetyChecker<'a, 'tcx> { violations: &[UnsafetyViolation], unsafe_blocks: &[(ast::NodeId, bool)]) { let safety = self.source_scope_local_data[self.source_info.scope].safety; - let within_unsafe = match (safety, self.min_const_fn) { - // Erring on the safe side, pun intended - (Safety::BuiltinUnsafe, true) | - // mir building encodes const fn bodies as safe, even for `const unsafe fn` - (Safety::FnUnsafe, true) => bug!("const unsafe fn body treated as inherently unsafe"), + let within_unsafe = match safety { // `unsafe` blocks are required in safe code - (Safety::Safe, _) => { + Safety::Safe => { for violation in violations { let mut violation = violation.clone(); match violation.kind { @@ -342,9 +338,9 @@ impl<'a, 'tcx> UnsafetyChecker<'a, 'tcx> { } false } - // regular `unsafe` function bodies allow unsafe without additional unsafe blocks - (Safety::BuiltinUnsafe, false) | (Safety::FnUnsafe, false) => true, - (Safety::ExplicitUnsafe(node_id), _) => { + // `unsafe` function bodies allow unsafe without additional unsafe blocks + Safety::BuiltinUnsafe | Safety::FnUnsafe => true, + Safety::ExplicitUnsafe(node_id) => { // mark unsafe block as used if there are any unsafe operations inside if !violations.is_empty() { self.used_unsafe.insert(node_id); @@ -616,21 +612,6 @@ pub fn check_unsafety<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) { } in violations.iter() { // Report an error. match kind { - UnsafetyViolationKind::General if tcx.is_min_const_fn(def_id) => { - let mut err = tcx.sess.struct_span_err( - source_info.span, - &format!("{} is unsafe and unsafe operations \ - are not allowed in const fn", description)); - err.span_label(source_info.span, &description.as_str()[..]) - .note(&details.as_str()[..]); - if tcx.fn_sig(def_id).unsafety() == hir::Unsafety::Unsafe { - err.note( - "unsafe action within a `const unsafe fn` still require an `unsafe` \ - block in contrast to regular `unsafe fn`." - ); - } - err.emit(); - } UnsafetyViolationKind::GeneralAndConstFn | UnsafetyViolationKind::General => { struct_span_err!( diff --git a/src/test/ui/consts/min_const_fn/min_const_fn_unsafe.rs b/src/test/ui/consts/min_const_fn/min_const_fn_unsafe.rs index f11b43dcd865c..92e99c6228a9b 100644 --- a/src/test/ui/consts/min_const_fn/min_const_fn_unsafe.rs +++ b/src/test/ui/consts/min_const_fn/min_const_fn_unsafe.rs @@ -28,13 +28,13 @@ const fn call_unsafe_generic_cell_const_fn() -> *const Vec> unsafe { ret_null_mut_ptr_no_unsafe::>>() } //~^ ERROR calls to `const unsafe fn` in const fns } -const unsafe fn deref_forbidden(x: *mut usize) -> usize { *x } //~ ERROR not allowed in const fn +const unsafe fn deref_forbidden(x: *mut usize) -> usize { *x } //~^ dereferencing raw pointers in constant functions fn main() {} const unsafe fn no_union() { union Foo { x: (), y: () } - Foo { x: () }.y //~ ERROR not allowed in const fn + Foo { x: () }.y //~^ unions in const fn } diff --git a/src/test/ui/consts/min_const_fn/min_const_fn_unsafe.stderr b/src/test/ui/consts/min_const_fn/min_const_fn_unsafe.stderr index 922a7883b9f2d..fafc89d149368 100644 --- a/src/test/ui/consts/min_const_fn/min_const_fn_unsafe.stderr +++ b/src/test/ui/consts/min_const_fn/min_const_fn_unsafe.stderr @@ -1,7 +1,7 @@ error[E0658]: dereferencing raw pointers in constant functions is unstable (see issue #51911) --> $DIR/min_const_fn_unsafe.rs:31:59 | -LL | const unsafe fn deref_forbidden(x: *mut usize) -> usize { *x } //~ ERROR not allowed in const fn +LL | const unsafe fn deref_forbidden(x: *mut usize) -> usize { *x } | ^^ | = help: add #![feature(const_raw_ptr_deref)] to the crate attributes to enable @@ -9,7 +9,7 @@ LL | const unsafe fn deref_forbidden(x: *mut usize) -> usize { *x } //~ ERROR no error[E0658]: unions in const fn are unstable (see issue #51909) --> $DIR/min_const_fn_unsafe.rs:38:5 | -LL | Foo { x: () }.y //~ ERROR not allowed in const fn +LL | Foo { x: () }.y | ^^^^^^^^^^^^^^^ | = help: add #![feature(const_fn_union)] to the crate attributes to enable @@ -38,24 +38,6 @@ LL | unsafe { ret_null_mut_ptr_no_unsafe::>>() } | = help: add #![feature(min_const_unsafe_fn)] to the crate attributes to enable -error: dereference of raw pointer is unsafe and unsafe operations are not allowed in const fn - --> $DIR/min_const_fn_unsafe.rs:31:59 - | -LL | const unsafe fn deref_forbidden(x: *mut usize) -> usize { *x } //~ ERROR not allowed in const fn - | ^^ dereference of raw pointer - | - = note: raw pointers may be NULL, dangling or unaligned; they can violate aliasing rules and cause data races: all of these are undefined behavior - = note: unsafe action within a `const unsafe fn` still require an `unsafe` block in contrast to regular `unsafe fn`. - -error: access to union field is unsafe and unsafe operations are not allowed in const fn - --> $DIR/min_const_fn_unsafe.rs:38:5 - | -LL | Foo { x: () }.y //~ ERROR not allowed in const fn - | ^^^^^^^^^^^^^^^ access to union field - | - = note: the field may not be properly initialized: using uninitialized data will cause undefined behavior - = note: unsafe action within a `const unsafe fn` still require an `unsafe` block in contrast to regular `unsafe fn`. - -error: aborting due to 7 previous errors +error: aborting due to 5 previous errors For more information about this error, try `rustc --explain E0658`. diff --git a/src/test/ui/consts/min_const_fn/min_const_fn_unsafe_feature_gate.rs b/src/test/ui/consts/min_const_fn/min_const_fn_unsafe_feature_gate.rs index 8a6884bc6b93c..67a4820612642 100644 --- a/src/test/ui/consts/min_const_fn/min_const_fn_unsafe_feature_gate.rs +++ b/src/test/ui/consts/min_const_fn/min_const_fn_unsafe_feature_gate.rs @@ -34,29 +34,28 @@ const unsafe fn foo9_3() -> *const String { const unsafe fn foo10_3() -> *const Vec> { unsafe { foo6::>>() } } -// not ok const unsafe fn foo8_2() -> i32 { - foo4() //~ ERROR not allowed in const fn + foo4() } const unsafe fn foo9_2() -> *const String { - foo5::() //~ ERROR not allowed in const fn + foo5::() } const unsafe fn foo10_2() -> *const Vec> { - foo6::>>() //~ ERROR not allowed in const fn + foo6::>>() } -const unsafe fn foo30_3(x: *mut usize) -> usize { *x } //~ ERROR not allowed in const fn +const unsafe fn foo30_3(x: *mut usize) -> usize { *x } //~^ dereferencing raw pointers in constant functions -const unsafe fn foo30_4(x: *mut usize) -> &'static usize { &*x } //~ ERROR not allowed in const fn +const unsafe fn foo30_4(x: *mut usize) -> &'static usize { &*x } //~^ dereferencing raw pointers in constant functions -const fn foo30_5(x: *mut usize) -> &'static usize { unsafe { &*x } } //~ ERROR not allowed +const fn foo30_5(x: *mut usize) -> &'static usize { unsafe { &*x } } //~ is unsafe //~^ dereferencing raw pointers in constant functions fn main() {} const unsafe fn no_union() { union Foo { x: (), y: () } - Foo { x: () }.y //~ ERROR not allowed in const fn + Foo { x: () }.y //~^ unions in const fn } diff --git a/src/test/ui/consts/min_const_fn/min_const_fn_unsafe_feature_gate.stderr b/src/test/ui/consts/min_const_fn/min_const_fn_unsafe_feature_gate.stderr index 20c75afbe638b..63bf9a53e509c 100644 --- a/src/test/ui/consts/min_const_fn/min_const_fn_unsafe_feature_gate.stderr +++ b/src/test/ui/consts/min_const_fn/min_const_fn_unsafe_feature_gate.stderr @@ -1,97 +1,44 @@ error[E0658]: dereferencing raw pointers in constant functions is unstable (see issue #51911) - --> $DIR/min_const_fn_unsafe_feature_gate.rs:47:51 + --> $DIR/min_const_fn_unsafe_feature_gate.rs:46:51 | -LL | const unsafe fn foo30_3(x: *mut usize) -> usize { *x } //~ ERROR not allowed in const fn +LL | const unsafe fn foo30_3(x: *mut usize) -> usize { *x } | ^^ | = help: add #![feature(const_raw_ptr_deref)] to the crate attributes to enable error[E0658]: dereferencing raw pointers in constant functions is unstable (see issue #51911) - --> $DIR/min_const_fn_unsafe_feature_gate.rs:50:60 + --> $DIR/min_const_fn_unsafe_feature_gate.rs:49:60 | -LL | const unsafe fn foo30_4(x: *mut usize) -> &'static usize { &*x } //~ ERROR not allowed in const fn +LL | const unsafe fn foo30_4(x: *mut usize) -> &'static usize { &*x } | ^^^ | = help: add #![feature(const_raw_ptr_deref)] to the crate attributes to enable error[E0658]: dereferencing raw pointers in constant functions is unstable (see issue #51911) - --> $DIR/min_const_fn_unsafe_feature_gate.rs:53:62 + --> $DIR/min_const_fn_unsafe_feature_gate.rs:52:62 | -LL | const fn foo30_5(x: *mut usize) -> &'static usize { unsafe { &*x } } //~ ERROR not allowed +LL | const fn foo30_5(x: *mut usize) -> &'static usize { unsafe { &*x } } //~ is unsafe | ^^^ | = help: add #![feature(const_raw_ptr_deref)] to the crate attributes to enable error[E0658]: unions in const fn are unstable (see issue #51909) - --> $DIR/min_const_fn_unsafe_feature_gate.rs:60:5 + --> $DIR/min_const_fn_unsafe_feature_gate.rs:59:5 | -LL | Foo { x: () }.y //~ ERROR not allowed in const fn +LL | Foo { x: () }.y | ^^^^^^^^^^^^^^^ | = help: add #![feature(const_fn_union)] to the crate attributes to enable -error: call to unsafe function is unsafe and unsafe operations are not allowed in const fn - --> $DIR/min_const_fn_unsafe_feature_gate.rs:39:5 +error[E0133]: dereference of raw pointer is unsafe and requires unsafe function or block + --> $DIR/min_const_fn_unsafe_feature_gate.rs:52:62 | -LL | foo4() //~ ERROR not allowed in const fn - | ^^^^^^ call to unsafe function - | - = note: consult the function's documentation for information on how to avoid undefined behavior - = note: unsafe action within a `const unsafe fn` still require an `unsafe` block in contrast to regular `unsafe fn`. - -error: call to unsafe function is unsafe and unsafe operations are not allowed in const fn - --> $DIR/min_const_fn_unsafe_feature_gate.rs:42:5 - | -LL | foo5::() //~ ERROR not allowed in const fn - | ^^^^^^^^^^^^^^^^ call to unsafe function - | - = note: consult the function's documentation for information on how to avoid undefined behavior - = note: unsafe action within a `const unsafe fn` still require an `unsafe` block in contrast to regular `unsafe fn`. - -error: call to unsafe function is unsafe and unsafe operations are not allowed in const fn - --> $DIR/min_const_fn_unsafe_feature_gate.rs:45:5 - | -LL | foo6::>>() //~ ERROR not allowed in const fn - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ call to unsafe function - | - = note: consult the function's documentation for information on how to avoid undefined behavior - = note: unsafe action within a `const unsafe fn` still require an `unsafe` block in contrast to regular `unsafe fn`. - -error: dereference of raw pointer is unsafe and unsafe operations are not allowed in const fn - --> $DIR/min_const_fn_unsafe_feature_gate.rs:47:51 - | -LL | const unsafe fn foo30_3(x: *mut usize) -> usize { *x } //~ ERROR not allowed in const fn - | ^^ dereference of raw pointer - | - = note: raw pointers may be NULL, dangling or unaligned; they can violate aliasing rules and cause data races: all of these are undefined behavior - = note: unsafe action within a `const unsafe fn` still require an `unsafe` block in contrast to regular `unsafe fn`. - -error: dereference of raw pointer is unsafe and unsafe operations are not allowed in const fn - --> $DIR/min_const_fn_unsafe_feature_gate.rs:50:60 - | -LL | const unsafe fn foo30_4(x: *mut usize) -> &'static usize { &*x } //~ ERROR not allowed in const fn - | ^^^ dereference of raw pointer - | - = note: raw pointers may be NULL, dangling or unaligned; they can violate aliasing rules and cause data races: all of these are undefined behavior - = note: unsafe action within a `const unsafe fn` still require an `unsafe` block in contrast to regular `unsafe fn`. - -error: dereference of raw pointer is unsafe and unsafe operations are not allowed in const fn - --> $DIR/min_const_fn_unsafe_feature_gate.rs:53:62 - | -LL | const fn foo30_5(x: *mut usize) -> &'static usize { unsafe { &*x } } //~ ERROR not allowed +LL | const fn foo30_5(x: *mut usize) -> &'static usize { unsafe { &*x } } //~ is unsafe | ^^^ dereference of raw pointer | = note: raw pointers may be NULL, dangling or unaligned; they can violate aliasing rules and cause data races: all of these are undefined behavior -error: access to union field is unsafe and unsafe operations are not allowed in const fn - --> $DIR/min_const_fn_unsafe_feature_gate.rs:60:5 - | -LL | Foo { x: () }.y //~ ERROR not allowed in const fn - | ^^^^^^^^^^^^^^^ access to union field - | - = note: the field may not be properly initialized: using uninitialized data will cause undefined behavior - = note: unsafe action within a `const unsafe fn` still require an `unsafe` block in contrast to regular `unsafe fn`. - -error: aborting due to 11 previous errors +error: aborting due to 5 previous errors -For more information about this error, try `rustc --explain E0658`. +Some errors occurred: E0133, E0658. +For more information about an error, try `rustc --explain E0133`. From 94c1c7328ad04318375d404c6c9adb94b769b18a Mon Sep 17 00:00:00 2001 From: Son Date: Wed, 12 Dec 2018 09:41:12 +1100 Subject: [PATCH 13/32] Documentation for impl From for AtomicBool and other Atomic types --- src/libcore/sync/atomic.rs | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/src/libcore/sync/atomic.rs b/src/libcore/sync/atomic.rs index 617e067e0787e..b818e739ba841 100644 --- a/src/libcore/sync/atomic.rs +++ b/src/libcore/sync/atomic.rs @@ -1066,6 +1066,15 @@ impl AtomicPtr { #[cfg(target_has_atomic = "8")] #[stable(feature = "atomic_bool_from", since = "1.24.0")] impl From for AtomicBool { + /// Converts a `bool` into an `AtomicBool`. + /// + /// # Examples + /// + /// ``` + /// use std::sync::atomic::AtomicBool; + /// let atomic_bool = AtomicBool::from(true); + /// assert_eq!(format!("{:?}", atomic_bool), "true") + /// ``` #[inline] fn from(b: bool) -> Self { Self::new(b) } } @@ -1119,8 +1128,12 @@ macro_rules! atomic_int { #[$stable_from] impl From<$int_type> for $atomic_type { - #[inline] - fn from(v: $int_type) -> Self { Self::new(v) } + doc_comment! { + concat!( +"Converts an `", stringify!($int_type), "` into an `", stringify!($atomic_type), "`."), + #[inline] + fn from(v: $int_type) -> Self { Self::new(v) } + } } #[$stable_debug] From 76cb35ee8938c4815b8c77bcd97c68af0c67c5a5 Mon Sep 17 00:00:00 2001 From: ljedrz Date: Wed, 12 Dec 2018 14:24:05 +0100 Subject: [PATCH 14/32] infer: remove Box from a returned Iterator --- .../infer/canonical/query_response.rs | 51 +++++++++---------- 1 file changed, 25 insertions(+), 26 deletions(-) diff --git a/src/librustc/infer/canonical/query_response.rs b/src/librustc/infer/canonical/query_response.rs index 8d2b1d74c554b..43bc9d88895d7 100644 --- a/src/librustc/infer/canonical/query_response.rs +++ b/src/librustc/infer/canonical/query_response.rs @@ -36,6 +36,7 @@ use traits::{Obligation, ObligationCause, PredicateObligation}; use ty::fold::TypeFoldable; use ty::subst::{Kind, UnpackedKind}; use ty::{self, BoundVar, Lift, Ty, TyCtxt}; +use util::captures::Captures; impl<'cx, 'gcx, 'tcx> InferCtxtBuilder<'cx, 'gcx, 'tcx> { /// The "main method" for a canonicalized trait query. Given the @@ -527,32 +528,30 @@ impl<'cx, 'gcx, 'tcx> InferCtxt<'cx, 'gcx, 'tcx> { param_env: ty::ParamEnv<'tcx>, unsubstituted_region_constraints: &'a [QueryRegionConstraint<'tcx>], result_subst: &'a CanonicalVarValues<'tcx>, - ) -> impl Iterator> + 'a { - Box::new( - unsubstituted_region_constraints - .iter() - .map(move |constraint| { - let constraint = substitute_value(self.tcx, result_subst, constraint); - let &ty::OutlivesPredicate(k1, r2) = constraint.skip_binder(); // restored below - - Obligation::new( - cause.clone(), - param_env, - match k1.unpack() { - UnpackedKind::Lifetime(r1) => ty::Predicate::RegionOutlives( - ty::Binder::bind( - ty::OutlivesPredicate(r1, r2) - ) - ), - UnpackedKind::Type(t1) => ty::Predicate::TypeOutlives( - ty::Binder::bind( - ty::OutlivesPredicate(t1, r2) - ) - ), - } - ) - }) - ) as Box> + ) -> impl Iterator> + 'a + Captures<'gcx> { + unsubstituted_region_constraints + .iter() + .map(move |constraint| { + let constraint = substitute_value(self.tcx, result_subst, constraint); + let &ty::OutlivesPredicate(k1, r2) = constraint.skip_binder(); // restored below + + Obligation::new( + cause.clone(), + param_env, + match k1.unpack() { + UnpackedKind::Lifetime(r1) => ty::Predicate::RegionOutlives( + ty::Binder::bind( + ty::OutlivesPredicate(r1, r2) + ) + ), + UnpackedKind::Type(t1) => ty::Predicate::TypeOutlives( + ty::Binder::bind( + ty::OutlivesPredicate(t1, r2) + ) + ), + } + ) + }) } /// Given two sets of values for the same set of canonical variables, unify them. From c7f1b977ed807d987da0350133b1443fd2caa21f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Wed, 12 Dec 2018 16:54:27 -0800 Subject: [PATCH 15/32] Suggest using `.display()` when trying to print a `Path` --- src/libcore/fmt/mod.rs | 9 +++++++-- src/test/ui/suggestions/path-display.rs | 7 +++++++ src/test/ui/suggestions/path-display.stderr | 14 ++++++++++++++ 3 files changed, 28 insertions(+), 2 deletions(-) create mode 100644 src/test/ui/suggestions/path-display.rs create mode 100644 src/test/ui/suggestions/path-display.stderr diff --git a/src/libcore/fmt/mod.rs b/src/libcore/fmt/mod.rs index 0c5256b981e5c..de93651569891 100644 --- a/src/libcore/fmt/mod.rs +++ b/src/libcore/fmt/mod.rs @@ -609,10 +609,15 @@ pub trait Debug { /// println!("The origin is: {}", origin); /// ``` #[rustc_on_unimplemented( + on( + _Self="std::path::Path", + label="`{Self}` cannot be formatted with the default formatter, call `.display()` on it", + note="you need to call `.display()` or `.to_string_lossy()` for safely printing paths as \ + they may contain non-Unicode data" + ), message="`{Self}` doesn't implement `{Display}`", label="`{Self}` cannot be formatted with the default formatter", - note="in format strings you may be able to use `{{:?}}` \ - (or {{:#?}} for pretty-print) instead", + note="in format strings you may be able to use `{{:?}}` (or {{:#?}} for pretty-print) instead", )] #[doc(alias = "{}")] #[stable(feature = "rust1", since = "1.0.0")] diff --git a/src/test/ui/suggestions/path-display.rs b/src/test/ui/suggestions/path-display.rs new file mode 100644 index 0000000000000..62fc9e79f7aa2 --- /dev/null +++ b/src/test/ui/suggestions/path-display.rs @@ -0,0 +1,7 @@ +use std::path::Path; + +fn main() { + let path = Path::new("/tmp/foo/bar.txt"); + println!("{}", path); + //~^ ERROR E0277 +} diff --git a/src/test/ui/suggestions/path-display.stderr b/src/test/ui/suggestions/path-display.stderr new file mode 100644 index 0000000000000..b0493a559f92e --- /dev/null +++ b/src/test/ui/suggestions/path-display.stderr @@ -0,0 +1,14 @@ +error[E0277]: `std::path::Path` doesn't implement `std::fmt::Display` + --> $DIR/path-display.rs:5:20 + | +LL | println!("{}", path); + | ^^^^ `std::path::Path` cannot be formatted with the default formatter, call `.display()` on it + | + = help: the trait `std::fmt::Display` is not implemented for `std::path::Path` + = note: you need to call `.display()` or `.to_string_lossy()` for safely printing paths as they may contain non-Unicode data + = note: required because of the requirements on the impl of `std::fmt::Display` for `&std::path::Path` + = note: required by `std::fmt::Display::fmt` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0277`. From 1d8a3a03b91fea0fdc2f236a7f864bb0c365cdb8 Mon Sep 17 00:00:00 2001 From: Nikita Popov Date: Thu, 13 Dec 2018 16:36:07 +0100 Subject: [PATCH 16/32] Update LLVM submodule --- src/llvm | 2 +- src/rustllvm/llvm-rebuild-trigger | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/llvm b/src/llvm index a784eca10d2c1..95185c8c801c7 160000 --- a/src/llvm +++ b/src/llvm @@ -1 +1 @@ -Subproject commit a784eca10d2c1f09e65d67e16eca266485e1eac3 +Subproject commit 95185c8c801c765ac1072392d081d265af9fb310 diff --git a/src/rustllvm/llvm-rebuild-trigger b/src/rustllvm/llvm-rebuild-trigger index 9cf17c45e87a2..a268838de4515 100644 --- a/src/rustllvm/llvm-rebuild-trigger +++ b/src/rustllvm/llvm-rebuild-trigger @@ -1,4 +1,4 @@ # If this file is modified, then llvm will be (optionally) cleaned and then rebuilt. # The actual contents of this file do not matter, but to trigger a change on the # build bots then the contents should be changed so git updates the mtime. -2018-11-28 +2018-12-13 From 33a34b06ac8828ffddc91b822fdec9f862658600 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Thu, 13 Dec 2018 09:55:16 -0800 Subject: [PATCH 17/32] Wording changes --- src/libcore/fmt/mod.rs | 6 +++--- src/test/ui/suggestions/path-display.stderr | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/libcore/fmt/mod.rs b/src/libcore/fmt/mod.rs index de93651569891..8e0caa5ae330d 100644 --- a/src/libcore/fmt/mod.rs +++ b/src/libcore/fmt/mod.rs @@ -611,9 +611,9 @@ pub trait Debug { #[rustc_on_unimplemented( on( _Self="std::path::Path", - label="`{Self}` cannot be formatted with the default formatter, call `.display()` on it", - note="you need to call `.display()` or `.to_string_lossy()` for safely printing paths as \ - they may contain non-Unicode data" + label="`{Self}` cannot be formatted with the default formatter; call `.display()` on it", + note="call `.display()` or `.to_string_lossy()` to safely print paths, \ + as they may contain non-Unicode data" ), message="`{Self}` doesn't implement `{Display}`", label="`{Self}` cannot be formatted with the default formatter", diff --git a/src/test/ui/suggestions/path-display.stderr b/src/test/ui/suggestions/path-display.stderr index b0493a559f92e..39d236af4f3ae 100644 --- a/src/test/ui/suggestions/path-display.stderr +++ b/src/test/ui/suggestions/path-display.stderr @@ -2,10 +2,10 @@ error[E0277]: `std::path::Path` doesn't implement `std::fmt::Display` --> $DIR/path-display.rs:5:20 | LL | println!("{}", path); - | ^^^^ `std::path::Path` cannot be formatted with the default formatter, call `.display()` on it + | ^^^^ `std::path::Path` cannot be formatted with the default formatter; call `.display()` on it | = help: the trait `std::fmt::Display` is not implemented for `std::path::Path` - = note: you need to call `.display()` or `.to_string_lossy()` for safely printing paths as they may contain non-Unicode data + = note: call `.display()` or `.to_string_lossy()` to safely print paths, as they may contain non-Unicode data = note: required because of the requirements on the impl of `std::fmt::Display` for `&std::path::Path` = note: required by `std::fmt::Display::fmt` From 22de23e303c0b07e3cb4e23fe2abf5ff2c186a3a Mon Sep 17 00:00:00 2001 From: QuietMisdreavus Date: Thu, 13 Dec 2018 14:31:17 -0600 Subject: [PATCH 18/32] add `crates` to the final doctest --- src/librustdoc/test.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/librustdoc/test.rs b/src/librustdoc/test.rs index be9327ced26e9..ff6f5263fc3c2 100644 --- a/src/librustdoc/test.rs +++ b/src/librustdoc/test.rs @@ -395,6 +395,7 @@ pub fn make_test(s: &str, // Now push any outer attributes from the example, assuming they // are intended to be crate attributes. prog.push_str(&crate_attrs); + prog.push_str(&crates); // Uses libsyntax to parse the doctest and find if there's a main fn and the extern // crate already is included. @@ -488,6 +489,8 @@ pub fn make_test(s: &str, prog.push_str("\n}"); } + debug!("final doctest:\n{}", prog); + (prog, line_offset) } From cdd537339eb9fe009f75f285a99aa8257775e656 Mon Sep 17 00:00:00 2001 From: Matthew Jasper Date: Thu, 13 Dec 2018 20:53:07 +0000 Subject: [PATCH 19/32] Make determining the discriminant a normal Shallow read Enum layout optimizations mean that the discriminant of an enum may not be stored in a tag disjoint from the rest of the fields of the enum. Stop borrow checking as though they are. --- src/librustc_mir/borrow_check/mod.rs | 9 +++-- .../borrow_check/nll/invalidation.rs | 8 ++--- .../borrow_check/places_conflict.rs | 13 +++----- .../borrowck-anon-fields-variant.nll.stderr | 33 +++++++++++++++++-- src/test/ui/nll/match-on-borrowed.rs | 8 ++--- src/test/ui/nll/match-on-borrowed.stderr | 26 ++++++++++++++- 6 files changed, 73 insertions(+), 24 deletions(-) diff --git a/src/librustc_mir/borrow_check/mod.rs b/src/librustc_mir/borrow_check/mod.rs index e3029c6a19d49..5eca62938f7a8 100644 --- a/src/librustc_mir/borrow_check/mod.rs +++ b/src/librustc_mir/borrow_check/mod.rs @@ -545,7 +545,7 @@ impl<'cx, 'gcx, 'tcx> DataflowResultsConsumer<'cx, 'tcx> for MirBorrowckCtxt<'cx self.mutate_place( ContextKind::SetDiscrim.new(location), (place, span), - Shallow(Some(ArtificialField::Discriminant)), + Shallow(None), JustWrite, flow_state, ); @@ -782,7 +782,6 @@ use self::AccessDepth::{Deep, Shallow}; #[derive(Copy, Clone, PartialEq, Eq, Debug)] enum ArtificialField { - Discriminant, ArrayLength, ShallowBorrow, } @@ -1191,14 +1190,14 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { Rvalue::Len(ref place) | Rvalue::Discriminant(ref place) => { let af = match *rvalue { - Rvalue::Len(..) => ArtificialField::ArrayLength, - Rvalue::Discriminant(..) => ArtificialField::Discriminant, + Rvalue::Len(..) => Some(ArtificialField::ArrayLength), + Rvalue::Discriminant(..) => None, _ => unreachable!(), }; self.access_place( context, (place, span), - (Shallow(Some(af)), Read(ReadKind::Copy)), + (Shallow(af), Read(ReadKind::Copy)), LocalMutationIsAllowed::No, flow_state, ); diff --git a/src/librustc_mir/borrow_check/nll/invalidation.rs b/src/librustc_mir/borrow_check/nll/invalidation.rs index 8af23a8813a9e..07bda8af62618 100644 --- a/src/librustc_mir/borrow_check/nll/invalidation.rs +++ b/src/librustc_mir/borrow_check/nll/invalidation.rs @@ -99,7 +99,7 @@ impl<'cx, 'tcx, 'gcx> Visitor<'tcx> for InvalidationGenerator<'cx, 'tcx, 'gcx> { self.mutate_place( ContextKind::SetDiscrim.new(location), place, - Shallow(Some(ArtificialField::Discriminant)), + Shallow(None), JustWrite, ); } @@ -360,14 +360,14 @@ impl<'cg, 'cx, 'tcx, 'gcx> InvalidationGenerator<'cx, 'tcx, 'gcx> { Rvalue::Len(ref place) | Rvalue::Discriminant(ref place) => { let af = match *rvalue { - Rvalue::Len(..) => ArtificialField::ArrayLength, - Rvalue::Discriminant(..) => ArtificialField::Discriminant, + Rvalue::Len(..) => Some(ArtificialField::ArrayLength), + Rvalue::Discriminant(..) => None, _ => unreachable!(), }; self.access_place( context, place, - (Shallow(Some(af)), Read(ReadKind::Copy)), + (Shallow(af), Read(ReadKind::Copy)), LocalMutationIsAllowed::No, ); } diff --git a/src/librustc_mir/borrow_check/places_conflict.rs b/src/librustc_mir/borrow_check/places_conflict.rs index eeac915cff37e..e24586cca0929 100644 --- a/src/librustc_mir/borrow_check/places_conflict.rs +++ b/src/librustc_mir/borrow_check/places_conflict.rs @@ -165,15 +165,12 @@ fn place_components_conflict<'gcx, 'tcx>( let base_ty = base.ty(mir, tcx).to_ty(tcx); match (elem, &base_ty.sty, access) { - (_, _, Shallow(Some(ArtificialField::Discriminant))) - | (_, _, Shallow(Some(ArtificialField::ArrayLength))) + (_, _, Shallow(Some(ArtificialField::ArrayLength))) | (_, _, Shallow(Some(ArtificialField::ShallowBorrow))) => { - // The discriminant and array length are like - // additional fields on the type; they do not - // overlap any existing data there. Furthermore, - // they cannot actually be a prefix of any - // borrowed place (at least in MIR as it is - // currently.) + // The array length is like additional fields on the + // type; it does not overlap any existing data there. + // Furthermore, if cannot actually be a prefix of any + // borrowed place (at least in MIR as it is currently.) // // e.g., a (mutable) borrow of `a[5]` while we read the // array length of `a`. diff --git a/src/test/ui/borrowck/borrowck-anon-fields-variant.nll.stderr b/src/test/ui/borrowck/borrowck-anon-fields-variant.nll.stderr index 17722bf226d82..6f72de0edee32 100644 --- a/src/test/ui/borrowck/borrowck-anon-fields-variant.nll.stderr +++ b/src/test/ui/borrowck/borrowck-anon-fields-variant.nll.stderr @@ -1,3 +1,31 @@ +warning[E0503]: cannot use `y` because it was mutably borrowed + --> $DIR/borrowck-anon-fields-variant.rs:27:7 + | +LL | Foo::Y(ref mut a, _) => a, + | --------- borrow of `y.0` occurs here +... +LL | Foo::Y(_, ref mut b) => b, + | ^^^^^^^^^^^^^^^^^^^^ use of borrowed `y.0` +... +LL | *a += 1; + | ------- borrow later used here + | + = warning: This error has been downgraded to a warning for backwards compatibility with previous releases. + It represents potential unsoundness in your code. + This warning will become a hard error in the future. + +error[E0503]: cannot use `y` because it was mutably borrowed + --> $DIR/borrowck-anon-fields-variant.rs:44:7 + | +LL | Foo::Y(ref mut a, _) => a, + | --------- borrow of `y.0` occurs here +... +LL | Foo::Y(ref mut b, _) => b, //~ ERROR cannot borrow + | ^^^^^^^^^^^^^^^^^^^^ use of borrowed `y.0` +... +LL | *a += 1; + | ------- borrow later used here + error[E0499]: cannot borrow `y.0` as mutable more than once at a time --> $DIR/borrowck-anon-fields-variant.rs:44:14 | @@ -10,6 +38,7 @@ LL | Foo::Y(ref mut b, _) => b, //~ ERROR cannot borrow LL | *a += 1; | ------- first borrow later used here -error: aborting due to previous error +error: aborting due to 2 previous errors -For more information about this error, try `rustc --explain E0499`. +Some errors occurred: E0499, E0503. +For more information about an error, try `rustc --explain E0499`. diff --git a/src/test/ui/nll/match-on-borrowed.rs b/src/test/ui/nll/match-on-borrowed.rs index 6a8ce03e8fd25..edce2b185df34 100644 --- a/src/test/ui/nll/match-on-borrowed.rs +++ b/src/test/ui/nll/match-on-borrowed.rs @@ -46,9 +46,9 @@ fn enum_example(mut e: E) { E::V(ref mut x, _) => x, E::W => panic!(), }; - match e { // OK, no access of borrowed data + match e { // Don't know that E uses a tag for its discriminant _ if false => (), - E::V(_, r) => (), + E::V(_, r) => (), //~ ERROR E::W => (), } x; @@ -59,9 +59,9 @@ fn indirect_enum_example(mut f: &mut E) { E::V(ref mut x, _) => x, E::W => panic!(), }; - match f { // OK, no access of borrowed data + match f { // Don't know that E uses a tag for its discriminant _ if false => (), - E::V(_, r) => (), + E::V(_, r) => (), //~ ERROR E::W => (), } x; diff --git a/src/test/ui/nll/match-on-borrowed.stderr b/src/test/ui/nll/match-on-borrowed.stderr index cdff29d44b85b..2d34dd7805dbf 100644 --- a/src/test/ui/nll/match-on-borrowed.stderr +++ b/src/test/ui/nll/match-on-borrowed.stderr @@ -1,3 +1,27 @@ +error[E0503]: cannot use `e` because it was mutably borrowed + --> $DIR/match-on-borrowed.rs:51:9 + | +LL | E::V(ref mut x, _) => x, + | --------- borrow of `e.0` occurs here +... +LL | E::V(_, r) => (), //~ ERROR + | ^^^^^^^^^^ use of borrowed `e.0` +... +LL | x; + | - borrow later used here + +error[E0503]: cannot use `*f` because it was mutably borrowed + --> $DIR/match-on-borrowed.rs:64:9 + | +LL | E::V(ref mut x, _) => x, + | --------- borrow of `f.0` occurs here +... +LL | E::V(_, r) => (), //~ ERROR + | ^^^^^^^^^^ use of borrowed `f.0` +... +LL | x; + | - borrow later used here + error[E0503]: cannot use `t` because it was mutably borrowed --> $DIR/match-on-borrowed.rs:82:9 | @@ -16,7 +40,7 @@ error[E0381]: use of possibly uninitialized variable: `n` LL | match n {} //~ ERROR | ^ use of possibly uninitialized `n` -error: aborting due to 2 previous errors +error: aborting due to 4 previous errors Some errors occurred: E0381, E0503. For more information about an error, try `rustc --explain E0381`. From ea3078d2e035667186d8ffff72522a97059d0b9d Mon Sep 17 00:00:00 2001 From: QuietMisdreavus Date: Thu, 13 Dec 2018 14:31:42 -0600 Subject: [PATCH 20/32] include comments in doctest partition logic --- src/librustdoc/test.rs | 71 ++++++++++++++++++++++++++++++++---------- 1 file changed, 55 insertions(+), 16 deletions(-) diff --git a/src/librustdoc/test.rs b/src/librustdoc/test.rs index ff6f5263fc3c2..396aa1400e35f 100644 --- a/src/librustdoc/test.rs +++ b/src/librustdoc/test.rs @@ -496,32 +496,71 @@ pub fn make_test(s: &str, // FIXME(aburka): use a real parser to deal with multiline attributes fn partition_source(s: &str) -> (String, String, String) { - let mut after_header = false; + #[derive(Copy, Clone, PartialEq)] + enum PartitionState { + Attrs, + Crates, + Other, + } + let mut state = PartitionState::Attrs; let mut before = String::new(); let mut crates = String::new(); let mut after = String::new(); for line in s.lines() { let trimline = line.trim(); - let header = trimline.chars().all(|c| c.is_whitespace()) || - trimline.starts_with("#![") || - trimline.starts_with("#[macro_use] extern crate") || - trimline.starts_with("extern crate"); - if !header || after_header { - after_header = true; - after.push_str(line); - after.push_str("\n"); - } else { - if trimline.starts_with("#[macro_use] extern crate") - || trimline.starts_with("extern crate") { + + // FIXME(misdreavus): if a doc comment is placed on an extern crate statement, it will be + // shunted into "everything else" + match state { + PartitionState::Attrs => { + state = if trimline.starts_with("#![") || + trimline.chars().all(|c| c.is_whitespace()) || + (trimline.starts_with("//") && !trimline.starts_with("///")) + { + PartitionState::Attrs + } else if trimline.starts_with("extern crate") || + trimline.starts_with("#[macro_use] extern crate") + { + PartitionState::Crates + } else { + PartitionState::Other + }; + } + PartitionState::Crates => { + state = if trimline.starts_with("extern crate") || + trimline.starts_with("#[macro_use] extern crate") || + trimline.chars().all(|c| c.is_whitespace()) || + (trimline.starts_with("//") && !trimline.starts_with("///")) + { + PartitionState::Crates + } else { + PartitionState::Other + }; + } + PartitionState::Other => {} + } + + match state { + PartitionState::Attrs => { + before.push_str(line); + before.push_str("\n"); + } + PartitionState::Crates => { crates.push_str(line); crates.push_str("\n"); } - before.push_str(line); - before.push_str("\n"); + PartitionState::Other => { + after.push_str(line); + after.push_str("\n"); + } } } + debug!("before:\n{}", before); + debug!("crates:\n{}", crates); + debug!("after:\n{}", after); + (before, after, crates) } @@ -1038,8 +1077,8 @@ fn main() { assert_eq!(2+2, 4);"; let expected = "#![allow(unused)] -fn main() { //Ceci n'est pas une `fn main` +fn main() { assert_eq!(2+2, 4); }".to_string(); let output = make_test(input, None, false, &opts); @@ -1086,8 +1125,8 @@ assert_eq!(2+2, 4);"; let expected = "#![allow(unused)] -fn main() { // fn main +fn main() { assert_eq!(2+2, 4); }".to_string(); From 8faaef66c921c7c65fa73727ae5bd5d4e4fe7a76 Mon Sep 17 00:00:00 2001 From: QuietMisdreavus Date: Thu, 13 Dec 2018 15:23:36 -0600 Subject: [PATCH 21/32] add test for parsing comments in doctest headers --- src/test/rustdoc/comment-in-doctest.rs | 30 ++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) create mode 100644 src/test/rustdoc/comment-in-doctest.rs diff --git a/src/test/rustdoc/comment-in-doctest.rs b/src/test/rustdoc/comment-in-doctest.rs new file mode 100644 index 0000000000000..3468bb7bda473 --- /dev/null +++ b/src/test/rustdoc/comment-in-doctest.rs @@ -0,0 +1,30 @@ +// 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. + +// compile-flags:--test + +// comments, both doc comments and regular ones, used to trick rustdoc's doctest parser into +// thinking that everything after it was part of the regular program. combined with the libsyntax +// parser loop failing to detect the manual main function, it would wrap everything in `fn main`, +// which would cause the doctest to fail as the "extern crate" declaration was no longer valid. +// oddly enough, it would pass in 2018 if a crate was in the extern prelude. see +// https://github.com/rust-lang/rust/issues/56727 + +//! ``` +//! // crate: proc-macro-test +//! //! this is a test +//! +//! // used to pull in proc-macro specific items +//! extern crate proc_macro; +//! +//! use proc_macro::TokenStream; +//! +//! # fn main() {} +//! ``` From ceee7f34f5cfae23f8b9f43314cf81cf26150b4f Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Thu, 13 Dec 2018 12:50:42 -0800 Subject: [PATCH 22/32] rustc: Add an unstable `simd_select_bitmask` intrinsic This is going to be required for binding a number of AVX-512 intrinsics in the `stdsimd` repository, and this intrinsic is the same as `simd_select` except that it takes a bitmask as the first argument instead of a SIMD vector. This bitmask is then transmuted into a `` argument, depending on how many bits it is. cc rust-lang-nursery/stdsimd#310 --- src/librustc_codegen_llvm/intrinsic.rs | 3 ++- .../simd-intrinsic-generic-select.rs | 6 ++++++ .../simd-intrinsic-generic-select.stderr | 20 +++++++++++++++---- 3 files changed, 24 insertions(+), 5 deletions(-) diff --git a/src/librustc_codegen_llvm/intrinsic.rs b/src/librustc_codegen_llvm/intrinsic.rs index 8b26ada157606..e229f8d95cd5b 100644 --- a/src/librustc_codegen_llvm/intrinsic.rs +++ b/src/librustc_codegen_llvm/intrinsic.rs @@ -1192,7 +1192,7 @@ fn generic_simd_intrinsic( return Ok(bx.select(m_i1s, args[1].immediate(), args[2].immediate())); } - // every intrinsic takes a SIMD vector as its first argument + // every intrinsic below takes a SIMD vector as its first argument require_simd!(arg_tys[0], "input"); let in_ty = arg_tys[0]; let in_elem = arg_tys[0].simd_type(tcx); @@ -1296,6 +1296,7 @@ fn generic_simd_intrinsic( if name == "simd_select" { let m_elem_ty = in_elem; let m_len = in_len; + require_simd!(arg_tys[1], "argument"); let v_len = arg_tys[1].simd_size(tcx); require!(m_len == v_len, "mismatched lengths: mask length `{}` != other vector length `{}`", diff --git a/src/test/ui/simd-intrinsic/simd-intrinsic-generic-select.rs b/src/test/ui/simd-intrinsic/simd-intrinsic-generic-select.rs index 2a2d35e7bd922..31ec8a7dc1c83 100644 --- a/src/test/ui/simd-intrinsic/simd-intrinsic-generic-select.rs +++ b/src/test/ui/simd-intrinsic/simd-intrinsic-generic-select.rs @@ -54,8 +54,14 @@ fn main() { simd_select(z, z, z); //~^ ERROR mask element type is `f32`, expected `i_` + simd_select(m4, 0u32, 1u32); + //~^ ERROR found non-SIMD `u32` + simd_select_bitmask(0u8, x, x); //~^ ERROR mask length `8` != other vector length `4` + // + simd_select_bitmask(0u8, 1u32, 2u32); + //~^ ERROR found non-SIMD `u32` simd_select_bitmask(0.0f32, x, x); //~^ ERROR `f32` is not an integral type diff --git a/src/test/ui/simd-intrinsic/simd-intrinsic-generic-select.stderr b/src/test/ui/simd-intrinsic/simd-intrinsic-generic-select.stderr index 584f3d539213b..05317da2475f1 100644 --- a/src/test/ui/simd-intrinsic/simd-intrinsic-generic-select.stderr +++ b/src/test/ui/simd-intrinsic/simd-intrinsic-generic-select.stderr @@ -16,24 +16,36 @@ error[E0511]: invalid monomorphization of `simd_select` intrinsic: mask element LL | simd_select(z, z, z); | ^^^^^^^^^^^^^^^^^^^^ -error[E0511]: invalid monomorphization of `simd_select_bitmask` intrinsic: mismatched lengths: mask length `8` != other vector length `4` +error[E0511]: invalid monomorphization of `simd_select` intrinsic: expected SIMD argument type, found non-SIMD `u32` --> $DIR/simd-intrinsic-generic-select.rs:57:9 | +LL | simd_select(m4, 0u32, 1u32); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0511]: invalid monomorphization of `simd_select_bitmask` intrinsic: mismatched lengths: mask length `8` != other vector length `4` + --> $DIR/simd-intrinsic-generic-select.rs:60:9 + | LL | simd_select_bitmask(0u8, x, x); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +error[E0511]: invalid monomorphization of `simd_select_bitmask` intrinsic: expected SIMD argument type, found non-SIMD `u32` + --> $DIR/simd-intrinsic-generic-select.rs:63:9 + | +LL | simd_select_bitmask(0u8, 1u32, 2u32); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + error[E0511]: invalid monomorphization of `simd_select_bitmask` intrinsic: `f32` is not an integral type - --> $DIR/simd-intrinsic-generic-select.rs:60:9 + --> $DIR/simd-intrinsic-generic-select.rs:66:9 | LL | simd_select_bitmask(0.0f32, x, x); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0511]: invalid monomorphization of `simd_select_bitmask` intrinsic: `&str` is not an integral type - --> $DIR/simd-intrinsic-generic-select.rs:63:9 + --> $DIR/simd-intrinsic-generic-select.rs:69:9 | LL | simd_select_bitmask("x", x, x); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: aborting due to 6 previous errors +error: aborting due to 8 previous errors For more information about this error, try `rustc --explain E0511`. From fbb56bcf44d28e65a9495decf091b6d0386e540c Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Fri, 14 Dec 2018 11:40:27 -0800 Subject: [PATCH 23/32] rustc: Add the `cmpxchg16b` target feature on x86/x86_64 This appears to be called `cx16` in LLVM and a few other locations, but the Intel Intrinsic Guide doesn't have a name for this and the CPU manual from Intel only mentions `cmpxchg16b`, so that's the name chosen here. --- src/librustc_codegen_llvm/llvm_util.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/librustc_codegen_llvm/llvm_util.rs b/src/librustc_codegen_llvm/llvm_util.rs index 12109ae1662ff..82b1d7e8b40e4 100644 --- a/src/librustc_codegen_llvm/llvm_util.rs +++ b/src/librustc_codegen_llvm/llvm_util.rs @@ -140,6 +140,7 @@ const X86_WHITELIST: &[(&str, Option<&str>)] = &[ ("avx512vpopcntdq", Some("avx512_target_feature")), ("bmi1", None), ("bmi2", None), + ("cmpxchg16b", Some("cmpxchg16b_target_feature")), ("fma", None), ("fxsr", None), ("lzcnt", None), @@ -212,6 +213,7 @@ pub fn to_llvm_feature<'a>(sess: &Session, s: &'a str) -> &'a str { ("x86", "pclmulqdq") => "pclmul", ("x86", "rdrand") => "rdrnd", ("x86", "bmi1") => "bmi", + ("x86", "cmpxchg16b") => "cx16", ("aarch64", "fp") => "fp-armv8", ("aarch64", "fp16") => "fullfp16", (_, s) => s, From fcc8bb41e969c99689cf5ffb48d1cd11c759a498 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Fri, 14 Dec 2018 14:37:51 -0800 Subject: [PATCH 24/32] std: Use `rustc_demangle` from crates.io No more need to duplicate the demangling routine between crates.io and the standard library, we can use the exact same one! --- Cargo.lock | 21 ++- src/libstd/Cargo.toml | 1 + src/libstd/lib.rs | 1 + src/libstd/sys_common/backtrace.rs | 239 ++--------------------------- src/tools/tidy/src/deps.rs | 1 + 5 files changed, 27 insertions(+), 236 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index d22a91073394a..472470de1de7e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -87,7 +87,7 @@ dependencies = [ "backtrace-sys 0.1.24 (registry+https://github.com/rust-lang/crates.io-index)", "cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.45 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc-demangle 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc-demangle 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1813,7 +1813,7 @@ name = "rand_chacha" version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "rand_core 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_core 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1835,7 +1835,7 @@ name = "rand_hc" version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "rand_core 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_core 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1860,7 +1860,7 @@ name = "rand_xorshift" version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "rand_core 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_core 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -2195,8 +2195,12 @@ dependencies = [ [[package]] name = "rustc-demangle" -version = "0.1.9" +version = "0.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "compiler_builtins 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc-std-workspace-core 1.0.0", +] [[package]] name = "rustc-hash" @@ -2315,7 +2319,7 @@ dependencies = [ "cc 1.0.25 (registry+https://github.com/rust-lang/crates.io-index)", "memmap 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", "num_cpus 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc-demangle 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc-demangle 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", "rustc_llvm 0.0.0", ] @@ -2331,7 +2335,7 @@ dependencies = [ "memmap 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", "num_cpus 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)", "rustc 0.0.0", - "rustc-demangle 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc-demangle 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", "rustc_allocator 0.0.0", "rustc_apfloat 0.0.0", "rustc_codegen_utils 0.0.0", @@ -2892,6 +2896,7 @@ dependencies = [ "panic_unwind 0.0.0", "profiler_builtins 0.0.0", "rand 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc-demangle 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", "rustc_asan 0.0.0", "rustc_lsan 0.0.0", "rustc_msan 0.0.0", @@ -3578,7 +3583,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum rustc-ap-serialize 306.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5b2c0e8161e956647592a737074736e6ce05ea36b70c770ea8cca3eb9cb33737" "checksum rustc-ap-syntax 306.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1adc189e5e4500a4167b9afa04e67067f40d0039e0e05870c977bebb561f065a" "checksum rustc-ap-syntax_pos 306.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "4d42c430dbb0be4377bfe6aa5099074c63ac8796b24098562c2e2154aecc5652" -"checksum rustc-demangle 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "bcfe5b13211b4d78e5c2cadfebd7769197d95c639c35a50057eb4c05de811395" +"checksum rustc-demangle 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "82ae957aa1b3055d8e086486723c0ccd3d7b8fa190ae8fa2e35543b6171c810e" "checksum rustc-hash 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7540fc8b0c49f096ee9c961cda096467dce8084bec6bdca2fc83895fd9b28cb8" "checksum rustc-rayon 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "8c6d5a683c6ba4ed37959097e88d71c9e8e26659a3cb5be8b389078e7ad45306" "checksum rustc-rayon-core 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "40f06724db71e18d68b3b946fdf890ca8c921d9edccc1404fdfdb537b0d12649" diff --git a/src/libstd/Cargo.toml b/src/libstd/Cargo.toml index 41e778b6a4c72..9cee00b9c76d0 100644 --- a/src/libstd/Cargo.toml +++ b/src/libstd/Cargo.toml @@ -21,6 +21,7 @@ libc = { version = "0.2.44", default-features = false, features = ['rustc-dep-of compiler_builtins = { version = "0.1.1" } profiler_builtins = { path = "../libprofiler_builtins", optional = true } unwind = { path = "../libunwind" } +rustc-demangle = { version = "0.1.10", features = ['rustc-dep-of-std'] } [dev-dependencies] rand = "0.6.1" diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs index 0febbe5694bc4..ead38f2112687 100644 --- a/src/libstd/lib.rs +++ b/src/libstd/lib.rs @@ -339,6 +339,7 @@ pub use core::{unreachable, unimplemented, write, writeln, try}; extern crate alloc as alloc_crate; #[doc(masked)] extern crate libc; +extern crate rustc_demangle; // We always need an unwinder currently for backtraces #[doc(masked)] diff --git a/src/libstd/sys_common/backtrace.rs b/src/libstd/sys_common/backtrace.rs index 77371782977b1..e44113f76f40e 100644 --- a/src/libstd/sys_common/backtrace.rs +++ b/src/libstd/sys_common/backtrace.rs @@ -14,11 +14,12 @@ use env; use io::prelude::*; use io; +use path::{self, Path}; +use ptr; +use rustc_demangle::demangle; use str; use sync::atomic::{self, Ordering}; -use path::{self, Path}; use sys::mutex::Mutex; -use ptr; pub use sys::backtrace::{ unwind_backtrace, @@ -191,7 +192,14 @@ fn output(w: &mut dyn Write, idx: usize, frame: Frame, PrintFormat::Short => write!(w, " {:2}: ", idx)?, } match s { - Some(string) => demangle(w, string, format)?, + Some(string) => { + let symbol = demangle(string); + match format { + PrintFormat::Full => write!(w, "{}", symbol)?, + // strip the trailing hash if short mode + PrintFormat::Short => write!(w, "{:#}", symbol)?, + } + } None => w.write_all(b"")?, } w.write_all(b"\n") @@ -235,228 +243,3 @@ fn output_fileline(w: &mut dyn Write, w.write_all(b"\n") } - -// All rust symbols are in theory lists of "::"-separated identifiers. Some -// assemblers, however, can't handle these characters in symbol names. To get -// around this, we use C++-style mangling. The mangling method is: -// -// 1. Prefix the symbol with "_ZN" -// 2. For each element of the path, emit the length plus the element -// 3. End the path with "E" -// -// For example, "_ZN4testE" => "test" and "_ZN3foo3barE" => "foo::bar". -// -// We're the ones printing our backtraces, so we can't rely on anything else to -// demangle our symbols. It's *much* nicer to look at demangled symbols, so -// this function is implemented to give us nice pretty output. -// -// Note that this demangler isn't quite as fancy as it could be. We have lots -// of other information in our symbols like hashes, version, type information, -// etc. Additionally, this doesn't handle glue symbols at all. -pub fn demangle(writer: &mut dyn Write, mut s: &str, format: PrintFormat) -> io::Result<()> { - // During ThinLTO LLVM may import and rename internal symbols, so strip out - // those endings first as they're one of the last manglings applied to - // symbol names. - let llvm = ".llvm."; - if let Some(i) = s.find(llvm) { - let candidate = &s[i + llvm.len()..]; - let all_hex = candidate.chars().all(|c| { - match c { - 'A' ..= 'F' | '0' ..= '9' => true, - _ => false, - } - }); - - if all_hex { - s = &s[..i]; - } - } - - // Validate the symbol. If it doesn't look like anything we're - // expecting, we just print it literally. Note that we must handle non-rust - // symbols because we could have any function in the backtrace. - let mut valid = true; - let mut inner = s; - if s.len() > 4 && s.starts_with("_ZN") && s.ends_with("E") { - inner = &s[3 .. s.len() - 1]; - // On Windows, dbghelp strips leading underscores, so we accept "ZN...E" form too. - } else if s.len() > 3 && s.starts_with("ZN") && s.ends_with("E") { - inner = &s[2 .. s.len() - 1]; - } else { - valid = false; - } - - if valid { - let mut chars = inner.chars(); - while valid { - let mut i = 0; - for c in chars.by_ref() { - if c.is_numeric() { - i = i * 10 + c as usize - '0' as usize; - } else { - break - } - } - if i == 0 { - valid = chars.next().is_none(); - break - } else if chars.by_ref().take(i - 1).count() != i - 1 { - valid = false; - } - } - } - - // Alright, let's do this. - if !valid { - writer.write_all(s.as_bytes())?; - } else { - // remove the `::hfc2edb670e5eda97` part at the end of the symbol. - if format == PrintFormat::Short { - // The symbol in still mangled. - let mut split = inner.rsplitn(2, "17h"); - match (split.next(), split.next()) { - (Some(addr), rest) => { - if addr.len() == 16 && - addr.chars().all(|c| c.is_digit(16)) - { - inner = rest.unwrap_or(""); - } - } - _ => (), - } - } - - let mut first = true; - while !inner.is_empty() { - if !first { - writer.write_all(b"::")?; - } else { - first = false; - } - let mut rest = inner; - while rest.chars().next().unwrap().is_numeric() { - rest = &rest[1..]; - } - let i: usize = inner[.. (inner.len() - rest.len())].parse().unwrap(); - inner = &rest[i..]; - rest = &rest[..i]; - if rest.starts_with("_$") { - rest = &rest[1..]; - } - while !rest.is_empty() { - if rest.starts_with(".") { - if let Some('.') = rest[1..].chars().next() { - writer.write_all(b"::")?; - rest = &rest[2..]; - } else { - writer.write_all(b".")?; - rest = &rest[1..]; - } - } else if rest.starts_with("$") { - macro_rules! demangle { - ($($pat:expr => $demangled:expr),*) => ({ - $(if rest.starts_with($pat) { - writer.write_all($demangled)?; - rest = &rest[$pat.len()..]; - } else)* - { - writer.write_all(rest.as_bytes())?; - break; - } - - }) - } - - // see src/librustc/back/link.rs for these mappings - demangle! ( - "$SP$" => b"@", - "$BP$" => b"*", - "$RF$" => b"&", - "$LT$" => b"<", - "$GT$" => b">", - "$LP$" => b"(", - "$RP$" => b")", - "$C$" => b",", - - // in theory we can demangle any Unicode code point, but - // for simplicity we just catch the common ones. - "$u7e$" => b"~", - "$u20$" => b" ", - "$u27$" => b"'", - "$u5b$" => b"[", - "$u5d$" => b"]", - "$u7b$" => b"{", - "$u7d$" => b"}", - "$u3b$" => b";", - "$u2b$" => b"+", - "$u22$" => b"\"" - ) - } else { - let idx = match rest.char_indices().find(|&(_, c)| c == '$' || c == '.') { - None => rest.len(), - Some((i, _)) => i, - }; - writer.write_all(rest[..idx].as_bytes())?; - rest = &rest[idx..]; - } - } - } - } - - Ok(()) -} - -#[cfg(test)] -mod tests { - use sys_common; - macro_rules! t { ($a:expr, $b:expr) => ({ - let mut m = Vec::new(); - sys_common::backtrace::demangle(&mut m, - $a, - super::PrintFormat::Full).unwrap(); - assert_eq!(String::from_utf8(m).unwrap(), $b); - }) } - - #[test] - fn demangle() { - t!("test", "test"); - t!("_ZN4testE", "test"); - t!("_ZN4test", "_ZN4test"); - t!("_ZN4test1a2bcE", "test::a::bc"); - } - - #[test] - fn demangle_dollars() { - t!("_ZN4$RP$E", ")"); - t!("_ZN8$RF$testE", "&test"); - t!("_ZN8$BP$test4foobE", "*test::foob"); - t!("_ZN9$u20$test4foobE", " test::foob"); - t!("_ZN35Bar$LT$$u5b$u32$u3b$$u20$4$u5d$$GT$E", "Bar<[u32; 4]>"); - } - - #[test] - fn demangle_many_dollars() { - t!("_ZN13test$u20$test4foobE", "test test::foob"); - t!("_ZN12test$BP$test4foobE", "test*test::foob"); - } - - #[test] - fn demangle_windows() { - t!("ZN4testE", "test"); - t!("ZN13test$u20$test4foobE", "test test::foob"); - t!("ZN12test$RF$test4foobE", "test&test::foob"); - } - - #[test] - fn demangle_elements_beginning_with_underscore() { - t!("_ZN13_$LT$test$GT$E", ""); - t!("_ZN28_$u7b$$u7b$closure$u7d$$u7d$E", "{{closure}}"); - t!("_ZN15__STATIC_FMTSTRE", "__STATIC_FMTSTR"); - } - - #[test] - fn demangle_trait_impls() { - t!("_ZN71_$LT$Test$u20$$u2b$$u20$$u27$static$u20$as$u20$foo..Bar$LT$Test$GT$$GT$3barE", - ">::bar"); - } -} diff --git a/src/tools/tidy/src/deps.rs b/src/tools/tidy/src/deps.rs index 2b5cff6e07b2a..d1e4387166ca6 100644 --- a/src/tools/tidy/src/deps.rs +++ b/src/tools/tidy/src/deps.rs @@ -79,6 +79,7 @@ const WHITELIST: &[Crate] = &[ Crate("chalk-macros"), Crate("cloudabi"), Crate("cmake"), + Crate("compiler_builtins"), Crate("crc"), Crate("crc32fast"), Crate("crossbeam-deque"), From 122684d3934a2a51b53a65c281cfad0c7663dda1 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Sat, 15 Dec 2018 12:42:10 +0100 Subject: [PATCH 25/32] Improve CSS rule --- src/librustdoc/html/static/rustdoc.css | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/librustdoc/html/static/rustdoc.css b/src/librustdoc/html/static/rustdoc.css index d1336b1e8eb0b..01d2cbec19221 100644 --- a/src/librustdoc/html/static/rustdoc.css +++ b/src/librustdoc/html/static/rustdoc.css @@ -305,7 +305,7 @@ nav.sub { overflow-x: auto; } -body:not(.source) .example-wrap > pre { +.rustdoc:not(.source) .example-wrap > pre { margin: 0; } From c0ed771382cafb03232a9b8e7e1c5ef83a98a836 Mon Sep 17 00:00:00 2001 From: Nikita Popov Date: Sat, 15 Dec 2018 17:26:18 +0100 Subject: [PATCH 26/32] Remove u8 cttz hack This issue has since been fixed in LLVM: https://github.com/llvm-mirror/llvm/commit/1886c8e29a9992d73c5e6ba0d52eb98ee036ab5d Furthermore this doesn't actually work, because the "8" literal does not match the $BITS provided from the macro invocation, so effectively this code was not being used anyway... --- src/libcore/num/mod.rs | 15 +-------------- 1 file changed, 1 insertion(+), 14 deletions(-) diff --git a/src/libcore/num/mod.rs b/src/libcore/num/mod.rs index 4acf3a15ebf0d..38a20bf9388bb 100644 --- a/src/libcore/num/mod.rs +++ b/src/libcore/num/mod.rs @@ -2150,19 +2150,6 @@ impl isize { "[0x12, 0x34, 0x56, 0x78, 0x90, 0x12, 0x34, 0x56]" } } -// Emits the correct `cttz` call, depending on the size of the type. -macro_rules! uint_cttz_call { - // As of LLVM 3.6 the codegen for the zero-safe cttz8 intrinsic - // emits two conditional moves on x86_64. By promoting the value to - // u16 and setting bit 8, we get better code without any conditional - // operations. - // FIXME: There's a LLVM patch (http://reviews.llvm.org/D9284) - // pending, remove this workaround once LLVM generates better code - // for cttz8. - ($value:expr, 8) => { intrinsics::cttz($value as u16 | 0x100) }; - ($value:expr, $_BITS:expr) => { intrinsics::cttz($value) } -} - // `Int` + `UnsignedInt` implemented for unsigned integers macro_rules! uint_impl { ($SelfT:ty, $ActualT:ty, $BITS:expr, $MaxV:expr, $Feature:expr, $EndFeature:expr, @@ -2306,7 +2293,7 @@ assert_eq!(n.trailing_zeros(), 3);", $EndFeature, " #[rustc_const_unstable(feature = "const_int_ops")] #[inline] pub const fn trailing_zeros(self) -> u32 { - unsafe { uint_cttz_call!(self, $BITS) as u32 } + unsafe { intrinsics::cttz(self) as u32 } } } From 967b1fc3b723117d57ff27417d811747b1bf1242 Mon Sep 17 00:00:00 2001 From: Tobias Bucher Date: Sat, 15 Dec 2018 18:41:21 +0100 Subject: [PATCH 27/32] Fix a small mistake regarding NaNs in a deprecation message `max` on floats returns the other argument if one of them is NaN, which would be `0.0` in this case. This is unlike the C functions `fdim` and `fdimf` which return NaN if either of their arguments is NaN. https://doc.rust-lang.org/1.31.0/std/primitive.f32.html#method.max https://en.cppreference.com/w/c/numeric/math/fdim --- src/libstd/f32.rs | 3 ++- src/libstd/f64.rs | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/libstd/f32.rs b/src/libstd/f32.rs index 7d17aaf2f261b..d0dd4d4adcb98 100644 --- a/src/libstd/f32.rs +++ b/src/libstd/f32.rs @@ -550,7 +550,8 @@ impl f32 { #[inline] #[rustc_deprecated(since = "1.10.0", reason = "you probably meant `(self - other).abs()`: \ - this operation is `(self - other).max(0.0)` (also \ + this operation is `(self - other).max(0.0)` \ + except that `abs_sub` also propagates NaNs (also \ known as `fdimf` in C). If you truly need the positive \ difference, consider using that expression or the C function \ `fdimf`, depending on how you wish to handle NaN (please consider \ diff --git a/src/libstd/f64.rs b/src/libstd/f64.rs index c800763167fcb..9e627ec204291 100644 --- a/src/libstd/f64.rs +++ b/src/libstd/f64.rs @@ -491,7 +491,8 @@ impl f64 { #[inline] #[rustc_deprecated(since = "1.10.0", reason = "you probably meant `(self - other).abs()`: \ - this operation is `(self - other).max(0.0)` (also \ + this operation is `(self - other).max(0.0)` \ + except that `abs_sub` also propagates NaNs (also \ known as `fdim` in C). If you truly need the positive \ difference, consider using that expression or the C function \ `fdim`, depending on how you wish to handle NaN (please consider \ From f61686ae705a8d149a922b52cb09a9298d7b7cad Mon Sep 17 00:00:00 2001 From: Tobias Bucher Date: Sat, 15 Dec 2018 18:51:08 +0100 Subject: [PATCH 28/32] Fix doc of `std::fs::canonicalize` Point out that the final component of the path name might be a filename (and not a directory name). Previously, the doc said that all components of the path must be directory names, when it actually only ment all but the final one. Fixes #54056. --- src/libstd/fs.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libstd/fs.rs b/src/libstd/fs.rs index edcfdd9e53483..35ae4939249ea 100644 --- a/src/libstd/fs.rs +++ b/src/libstd/fs.rs @@ -1729,7 +1729,7 @@ pub fn read_link>(path: P) -> io::Result { /// limited to just these cases: /// /// * `path` does not exist. -/// * A component in path is not a directory. +/// * A non-final component in path is not a directory. /// /// # Examples /// From 3199bef05596afce72813658eaed9f839184cffa Mon Sep 17 00:00:00 2001 From: Alexander Regueiro Date: Tue, 11 Dec 2018 00:05:35 +0000 Subject: [PATCH 29/32] Fixed issue #56199. --- src/librustc/ty/mod.rs | 84 +++++++++++++++++---------- src/librustc_typeck/check/callee.rs | 2 +- src/librustc_typeck/check/mod.rs | 67 ++++++++++++++------- src/test/ui/issues/issue-56199.rs | 23 ++++++++ src/test/ui/issues/issue-56199.stderr | 30 ++++++++++ 5 files changed, 151 insertions(+), 55 deletions(-) create mode 100644 src/test/ui/issues/issue-56199.rs create mode 100644 src/test/ui/issues/issue-56199.stderr diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index a1fc949137dde..dbefa396cdaf3 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -1754,17 +1754,19 @@ bitflags! { pub struct AdtFlags: u32 { const NO_ADT_FLAGS = 0; const IS_ENUM = 1 << 0; - const IS_PHANTOM_DATA = 1 << 1; - const IS_FUNDAMENTAL = 1 << 2; - const IS_UNION = 1 << 3; - const IS_BOX = 1 << 4; + const IS_UNION = 1 << 1; + const IS_STRUCT = 1 << 2; + const IS_TUPLE_STRUCT = 1 << 3; + const IS_PHANTOM_DATA = 1 << 4; + const IS_FUNDAMENTAL = 1 << 5; + const IS_BOX = 1 << 6; /// Indicates whether the type is an `Arc`. - const IS_ARC = 1 << 5; + const IS_ARC = 1 << 7; /// Indicates whether the type is an `Rc`. - const IS_RC = 1 << 6; + const IS_RC = 1 << 8; /// Indicates whether the variant list of this ADT is `#[non_exhaustive]`. /// (i.e., this flag is never set unless this ADT is an enum). - const IS_VARIANT_LIST_NON_EXHAUSTIVE = 1 << 7; + const IS_VARIANT_LIST_NON_EXHAUSTIVE = 1 << 9; } } @@ -2079,31 +2081,43 @@ impl<'a, 'gcx, 'tcx> AdtDef { repr: ReprOptions) -> Self { debug!("AdtDef::new({:?}, {:?}, {:?}, {:?})", did, kind, variants, repr); let mut flags = AdtFlags::NO_ADT_FLAGS; + + if kind == AdtKind::Enum && tcx.has_attr(did, "non_exhaustive") { + debug!("found non-exhaustive variant list for {:?}", did); + flags = flags | AdtFlags::IS_VARIANT_LIST_NON_EXHAUSTIVE; + } + flags |= match kind { + AdtKind::Enum => AdtFlags::IS_ENUM, + AdtKind::Union => AdtFlags::IS_UNION, + AdtKind::Struct => AdtFlags::IS_STRUCT, + }; + + if let AdtKind::Struct = kind { + let variant_def = &variants[VariantIdx::new(0)]; + let def_key = tcx.def_key(variant_def.did); + match def_key.disambiguated_data.data { + DefPathData::StructCtor => flags |= AdtFlags::IS_TUPLE_STRUCT, + _ => (), + } + } + let attrs = tcx.get_attrs(did); if attr::contains_name(&attrs, "fundamental") { - flags = flags | AdtFlags::IS_FUNDAMENTAL; + flags |= AdtFlags::IS_FUNDAMENTAL; } if Some(did) == tcx.lang_items().phantom_data() { - flags = flags | AdtFlags::IS_PHANTOM_DATA; + flags |= AdtFlags::IS_PHANTOM_DATA; } if Some(did) == tcx.lang_items().owned_box() { - flags = flags | AdtFlags::IS_BOX; + flags |= AdtFlags::IS_BOX; } if Some(did) == tcx.lang_items().arc() { - flags = flags | AdtFlags::IS_ARC; + flags |= AdtFlags::IS_ARC; } if Some(did) == tcx.lang_items().rc() { - flags = flags | AdtFlags::IS_RC; - } - if kind == AdtKind::Enum && tcx.has_attr(did, "non_exhaustive") { - debug!("found non-exhaustive variant list for {:?}", did); - flags = flags | AdtFlags::IS_VARIANT_LIST_NON_EXHAUSTIVE; - } - match kind { - AdtKind::Enum => flags = flags | AdtFlags::IS_ENUM, - AdtKind::Union => flags = flags | AdtFlags::IS_UNION, - AdtKind::Struct => {} + flags |= AdtFlags::IS_RC; } + AdtDef { did, variants, @@ -2114,25 +2128,31 @@ impl<'a, 'gcx, 'tcx> AdtDef { #[inline] pub fn is_struct(&self) -> bool { - !self.is_union() && !self.is_enum() + self.flags.contains(AdtFlags::IS_STRUCT) + } + + /// If this function returns `true`, it implies that `is_struct` must return `true`. + #[inline] + pub fn is_tuple_struct(&self) -> bool { + self.flags.contains(AdtFlags::IS_TUPLE_STRUCT) } #[inline] pub fn is_union(&self) -> bool { - self.flags.intersects(AdtFlags::IS_UNION) + self.flags.contains(AdtFlags::IS_UNION) } #[inline] pub fn is_enum(&self) -> bool { - self.flags.intersects(AdtFlags::IS_ENUM) + self.flags.contains(AdtFlags::IS_ENUM) } #[inline] pub fn is_variant_list_non_exhaustive(&self) -> bool { - self.flags.intersects(AdtFlags::IS_VARIANT_LIST_NON_EXHAUSTIVE) + self.flags.contains(AdtFlags::IS_VARIANT_LIST_NON_EXHAUSTIVE) } - /// Returns the kind of the ADT - Struct or Enum. + /// Returns the kind of the ADT. #[inline] pub fn adt_kind(&self) -> AdtKind { if self.is_enum() { @@ -2161,33 +2181,33 @@ impl<'a, 'gcx, 'tcx> AdtDef { } } - /// Returns whether this type is #[fundamental] for the purposes + /// Returns whether this type is `#[fundamental]` for the purposes /// of coherence checking. #[inline] pub fn is_fundamental(&self) -> bool { - self.flags.intersects(AdtFlags::IS_FUNDAMENTAL) + self.flags.contains(AdtFlags::IS_FUNDAMENTAL) } /// Returns `true` if this is PhantomData. #[inline] pub fn is_phantom_data(&self) -> bool { - self.flags.intersects(AdtFlags::IS_PHANTOM_DATA) + self.flags.contains(AdtFlags::IS_PHANTOM_DATA) } /// Returns `true` if this is `Arc`. pub fn is_arc(&self) -> bool { - self.flags.intersects(AdtFlags::IS_ARC) + self.flags.contains(AdtFlags::IS_ARC) } /// Returns `true` if this is `Rc`. pub fn is_rc(&self) -> bool { - self.flags.intersects(AdtFlags::IS_RC) + self.flags.contains(AdtFlags::IS_RC) } /// Returns `true` if this is Box. #[inline] pub fn is_box(&self) -> bool { - self.flags.intersects(AdtFlags::IS_BOX) + self.flags.contains(AdtFlags::IS_BOX) } /// Returns whether this type has a destructor. diff --git a/src/librustc_typeck/check/callee.rs b/src/librustc_typeck/check/callee.rs index e4ce04916ce64..75ae868883484 100644 --- a/src/librustc_typeck/check/callee.rs +++ b/src/librustc_typeck/check/callee.rs @@ -280,7 +280,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { Def::Local(id) | Def::Upvar(id, ..) => { Some(self.tcx.hir().span(id)) } - _ => self.tcx.hir().span_if_local(def.def_id()) + _ => def.opt_def_id().and_then(|did| self.tcx.hir().span_if_local(did)), }; if let Some(span) = def_span { let label = match (unit_variant, inner_callee_path) { diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 8901f4b6b291b..d558558c764a7 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -95,7 +95,7 @@ mod op; use astconv::AstConv; use errors::{Applicability, DiagnosticBuilder, DiagnosticId}; -use rustc::hir::{self, GenericArg, Node, ItemKind, PatKind}; +use rustc::hir::{self, GenericArg, ItemKind, Node, PatKind}; use rustc::hir::def::Def; use rustc::hir::def_id::{CrateNum, DefId, LOCAL_CRATE}; use rustc::hir::intravisit::{self, Visitor, NestedVisitorMap}; @@ -113,7 +113,8 @@ use rustc::mir::interpret::{ConstValue, GlobalId}; use rustc::ty::subst::{CanonicalUserSubsts, UnpackedKind, Subst, Substs, UserSelfTy, UserSubsts}; use rustc::traits::{self, ObligationCause, ObligationCauseCode, TraitEngine}; -use rustc::ty::{self, Ty, TyCtxt, GenericParamDefKind, Visibility, ToPredicate, RegionKind}; +use rustc::ty::{self, AdtKind, Ty, TyCtxt, GenericParamDefKind, Visibility, ToPredicate, + RegionKind}; use rustc::ty::adjustment::{Adjust, Adjustment, AllowTwoPhase, AutoBorrow, AutoBorrowMutability}; use rustc::ty::fold::TypeFoldable; use rustc::ty::query::Providers; @@ -3217,8 +3218,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { return_expr_ty); } - // A generic function for checking the then and else in an if - // or if-else. + // A generic function for checking the 'then' and 'else' clauses in an 'if' + // or 'if-else' expression. fn check_then_else(&self, cond_expr: &'gcx hir::Expr, then_expr: &'gcx hir::Expr, @@ -3544,7 +3545,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // We don't look at stability attributes on // struct-like enums (yet...), but it's definitely not // a bug to have constructed one. - if adt_kind != ty::AdtKind::Enum { + if adt_kind != AdtKind::Enum { tcx.check_stability(v_field.did, Some(expr_id), field.span); } @@ -5156,26 +5157,48 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { }).unwrap_or(false); let mut new_def = def; - let (def_id, ty) = if let Def::SelfCtor(impl_def_id) = def { - let ty = self.impl_self_ty(span, impl_def_id).ty; - - match ty.ty_adt_def() { - Some(adt_def) if adt_def.is_struct() => { - let variant = adt_def.non_enum_variant(); - new_def = Def::StructCtor(variant.did, variant.ctor_kind); - (variant.did, self.tcx.type_of(variant.did)) - } - _ => { - (impl_def_id, self.tcx.types.err) + let (def_id, ty) = match def { + Def::SelfCtor(impl_def_id) => { + let ty = self.impl_self_ty(span, impl_def_id).ty; + let adt_def = ty.ty_adt_def(); + + match adt_def { + Some(adt_def) if adt_def.is_tuple_struct() => { + let variant = adt_def.non_enum_variant(); + new_def = Def::StructCtor(variant.did, variant.ctor_kind); + (variant.did, self.tcx.type_of(variant.did)) + } + _ => { + let mut err = self.tcx.sess.struct_span_err(span, + "the `Self` constructor can only be used with tuple or unit structs"); + if let Some(adt_def) = adt_def { + match adt_def.adt_kind() { + AdtKind::Enum => { + err.note("did you mean to use one of the enum's variants?"); + }, + AdtKind::Union => {}, + AdtKind::Struct => { + err.span_label( + span, + format!("did you mean `Self {{ /* fields */ }}`?"), + ); + } + } + } + err.emit(); + + (impl_def_id, self.tcx.types.err) + } } } - } else { - let def_id = def.def_id(); + _ => { + let def_id = def.def_id(); - // The things we are substituting into the type should not contain - // escaping late-bound regions, and nor should the base type scheme. - let ty = self.tcx.type_of(def_id); - (def_id, ty) + // The things we are substituting into the type should not contain + // escaping late-bound regions, and nor should the base type scheme. + let ty = self.tcx.type_of(def_id); + (def_id, ty) + } }; let substs = AstConv::create_substs_for_generic_args( diff --git a/src/test/ui/issues/issue-56199.rs b/src/test/ui/issues/issue-56199.rs new file mode 100644 index 0000000000000..bbd51823cf1af --- /dev/null +++ b/src/test/ui/issues/issue-56199.rs @@ -0,0 +1,23 @@ + +enum Foo {} +struct Bar {} + +impl Foo { + fn foo() { + let _ = Self; + //~^ ERROR the `Self` constructor can only be used with tuple structs + let _ = Self(); + //~^ ERROR the `Self` constructor can only be used with tuple structs + } +} + +impl Bar { + fn bar() { + let _ = Self; + //~^ ERROR the `Self` constructor can only be used with tuple structs + let _ = Self(); + //~^ ERROR the `Self` constructor can only be used with tuple structs + } +} + +fn main() {} diff --git a/src/test/ui/issues/issue-56199.stderr b/src/test/ui/issues/issue-56199.stderr new file mode 100644 index 0000000000000..feb88e926b2d8 --- /dev/null +++ b/src/test/ui/issues/issue-56199.stderr @@ -0,0 +1,30 @@ +error: the `Self` constructor can only be used with tuple structs + --> $DIR/issue-56199.rs:7:17 + | +LL | let _ = Self; + | ^^^^ + | + = note: did you mean to use one of the enum's variants? + +error: the `Self` constructor can only be used with tuple structs + --> $DIR/issue-56199.rs:9:17 + | +LL | let _ = Self(); + | ^^^^ + | + = note: did you mean to use one of the enum's variants? + +error: the `Self` constructor can only be used with tuple structs + --> $DIR/issue-56199.rs:16:17 + | +LL | let _ = Self; + | ^^^^ did you mean `Self { /* fields */ }`? + +error: the `Self` constructor can only be used with tuple structs + --> $DIR/issue-56199.rs:18:17 + | +LL | let _ = Self(); + | ^^^^ did you mean `Self { /* fields */ }`? + +error: aborting due to 4 previous errors + From 5656c96c71442b2dfc5aa01519dfe2027c6051b0 Mon Sep 17 00:00:00 2001 From: Alexander Regueiro Date: Sat, 15 Dec 2018 04:33:54 +0000 Subject: [PATCH 30/32] Added test for issue #56835. --- src/test/ui/issues/issue-56835.rs | 10 ++++++++++ src/test/ui/issues/issue-56835.stderr | 15 +++++++++++++++ 2 files changed, 25 insertions(+) create mode 100644 src/test/ui/issues/issue-56835.rs create mode 100644 src/test/ui/issues/issue-56835.stderr diff --git a/src/test/ui/issues/issue-56835.rs b/src/test/ui/issues/issue-56835.rs new file mode 100644 index 0000000000000..0b3a665ccf9fd --- /dev/null +++ b/src/test/ui/issues/issue-56835.rs @@ -0,0 +1,10 @@ + +pub struct Foo {} + +impl Foo { + fn bar(Self(foo): Self) {} + //~^ ERROR the `Self` constructor can only be used with tuple structs + //~^^ ERROR expected tuple struct/variant, found self constructor `Self` [E0164] +} + +fn main() {} diff --git a/src/test/ui/issues/issue-56835.stderr b/src/test/ui/issues/issue-56835.stderr new file mode 100644 index 0000000000000..32bbc49ffd991 --- /dev/null +++ b/src/test/ui/issues/issue-56835.stderr @@ -0,0 +1,15 @@ +error: the `Self` constructor can only be used with tuple structs + --> $DIR/issue-56835.rs:5:12 + | +LL | fn bar(Self(foo): Self) {} + | ^^^^^^^^^ did you mean `Self { /* fields */ }`? + +error[E0164]: expected tuple struct/variant, found self constructor `Self` + --> $DIR/issue-56835.rs:5:12 + | +LL | fn bar(Self(foo): Self) {} + | ^^^^^^^^^ not a tuple variant or struct + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0164`. From 616885ec2c529bc795995108ac5c87d1c532b17f Mon Sep 17 00:00:00 2001 From: Alexander Regueiro Date: Thu, 13 Dec 2018 15:35:45 +0000 Subject: [PATCH 31/32] Fixed minor issues raised in review. --- src/librustc/ty/mod.rs | 16 ++++++++-------- src/librustc_typeck/check/mod.rs | 6 +++--- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index dbefa396cdaf3..429b7f03af8e4 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -1756,7 +1756,7 @@ bitflags! { const IS_ENUM = 1 << 0; const IS_UNION = 1 << 1; const IS_STRUCT = 1 << 2; - const IS_TUPLE_STRUCT = 1 << 3; + const HAS_CTOR = 1 << 3; const IS_PHANTOM_DATA = 1 << 4; const IS_FUNDAMENTAL = 1 << 5; const IS_BOX = 1 << 6; @@ -2096,7 +2096,7 @@ impl<'a, 'gcx, 'tcx> AdtDef { let variant_def = &variants[VariantIdx::new(0)]; let def_key = tcx.def_key(variant_def.did); match def_key.disambiguated_data.data { - DefPathData::StructCtor => flags |= AdtFlags::IS_TUPLE_STRUCT, + DefPathData::StructCtor => flags |= AdtFlags::HAS_CTOR, _ => (), } } @@ -2131,12 +2131,6 @@ impl<'a, 'gcx, 'tcx> AdtDef { self.flags.contains(AdtFlags::IS_STRUCT) } - /// If this function returns `true`, it implies that `is_struct` must return `true`. - #[inline] - pub fn is_tuple_struct(&self) -> bool { - self.flags.contains(AdtFlags::IS_TUPLE_STRUCT) - } - #[inline] pub fn is_union(&self) -> bool { self.flags.contains(AdtFlags::IS_UNION) @@ -2181,6 +2175,12 @@ impl<'a, 'gcx, 'tcx> AdtDef { } } + /// If this function returns `true`, it implies that `is_struct` must return `true`. + #[inline] + pub fn has_ctor(&self) -> bool { + self.flags.contains(AdtFlags::HAS_CTOR) + } + /// Returns whether this type is `#[fundamental]` for the purposes /// of coherence checking. #[inline] diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index d558558c764a7..957c8d9f19f0e 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -5163,7 +5163,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { let adt_def = ty.ty_adt_def(); match adt_def { - Some(adt_def) if adt_def.is_tuple_struct() => { + Some(adt_def) if adt_def.has_ctor() => { let variant = adt_def.non_enum_variant(); new_def = Def::StructCtor(variant.did, variant.ctor_kind); (variant.did, self.tcx.type_of(variant.did)) @@ -5176,8 +5176,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { AdtKind::Enum => { err.note("did you mean to use one of the enum's variants?"); }, - AdtKind::Union => {}, - AdtKind::Struct => { + AdtKind::Struct | + AdtKind::Union => { err.span_label( span, format!("did you mean `Self {{ /* fields */ }}`?"), From 0211856c0e381c658b2decca0f31e4c9579d8e0d Mon Sep 17 00:00:00 2001 From: Alexander Regueiro Date: Sat, 15 Dec 2018 17:31:46 +0000 Subject: [PATCH 32/32] Corrected expected test err messages. --- src/test/ui/issues/issue-56199.rs | 8 ++++---- src/test/ui/issues/issue-56199.stderr | 8 ++++---- src/test/ui/issues/issue-56835.rs | 2 +- src/test/ui/issues/issue-56835.stderr | 2 +- 4 files changed, 10 insertions(+), 10 deletions(-) diff --git a/src/test/ui/issues/issue-56199.rs b/src/test/ui/issues/issue-56199.rs index bbd51823cf1af..83d4e31b5d126 100644 --- a/src/test/ui/issues/issue-56199.rs +++ b/src/test/ui/issues/issue-56199.rs @@ -5,18 +5,18 @@ struct Bar {} impl Foo { fn foo() { let _ = Self; - //~^ ERROR the `Self` constructor can only be used with tuple structs + //~^ ERROR the `Self` constructor can only be used with tuple or unit structs let _ = Self(); - //~^ ERROR the `Self` constructor can only be used with tuple structs + //~^ ERROR the `Self` constructor can only be used with tuple or unit structs } } impl Bar { fn bar() { let _ = Self; - //~^ ERROR the `Self` constructor can only be used with tuple structs + //~^ ERROR the `Self` constructor can only be used with tuple or unit structs let _ = Self(); - //~^ ERROR the `Self` constructor can only be used with tuple structs + //~^ ERROR the `Self` constructor can only be used with tuple or unit structs } } diff --git a/src/test/ui/issues/issue-56199.stderr b/src/test/ui/issues/issue-56199.stderr index feb88e926b2d8..6e3c7fd17b437 100644 --- a/src/test/ui/issues/issue-56199.stderr +++ b/src/test/ui/issues/issue-56199.stderr @@ -1,4 +1,4 @@ -error: the `Self` constructor can only be used with tuple structs +error: the `Self` constructor can only be used with tuple or unit structs --> $DIR/issue-56199.rs:7:17 | LL | let _ = Self; @@ -6,7 +6,7 @@ LL | let _ = Self; | = note: did you mean to use one of the enum's variants? -error: the `Self` constructor can only be used with tuple structs +error: the `Self` constructor can only be used with tuple or unit structs --> $DIR/issue-56199.rs:9:17 | LL | let _ = Self(); @@ -14,13 +14,13 @@ LL | let _ = Self(); | = note: did you mean to use one of the enum's variants? -error: the `Self` constructor can only be used with tuple structs +error: the `Self` constructor can only be used with tuple or unit structs --> $DIR/issue-56199.rs:16:17 | LL | let _ = Self; | ^^^^ did you mean `Self { /* fields */ }`? -error: the `Self` constructor can only be used with tuple structs +error: the `Self` constructor can only be used with tuple or unit structs --> $DIR/issue-56199.rs:18:17 | LL | let _ = Self(); diff --git a/src/test/ui/issues/issue-56835.rs b/src/test/ui/issues/issue-56835.rs index 0b3a665ccf9fd..c16550e370179 100644 --- a/src/test/ui/issues/issue-56835.rs +++ b/src/test/ui/issues/issue-56835.rs @@ -3,7 +3,7 @@ pub struct Foo {} impl Foo { fn bar(Self(foo): Self) {} - //~^ ERROR the `Self` constructor can only be used with tuple structs + //~^ ERROR the `Self` constructor can only be used with tuple or unit structs //~^^ ERROR expected tuple struct/variant, found self constructor `Self` [E0164] } diff --git a/src/test/ui/issues/issue-56835.stderr b/src/test/ui/issues/issue-56835.stderr index 32bbc49ffd991..b7c3b142ec452 100644 --- a/src/test/ui/issues/issue-56835.stderr +++ b/src/test/ui/issues/issue-56835.stderr @@ -1,4 +1,4 @@ -error: the `Self` constructor can only be used with tuple structs +error: the `Self` constructor can only be used with tuple or unit structs --> $DIR/issue-56835.rs:5:12 | LL | fn bar(Self(foo): Self) {}