Auto merge of #55803 - Mark-Simulacrum:rollup, r=Mark-Simulacrum

Rollup of 17 pull requests

Successful merges:

 - #55576 (Clarify error message for -C opt-level)
 - #55633 (Support memcpy/memmove with differing src/dst alignment)
 - #55638 (Fix ICE in msg_span_from_free_region on ReEmpty)
 - #55659 (rustc: Delete grouping logic from the musl target)
 - #55719 (Sidestep link error from rustfix'ed code by using a *defined* static.)
 - #55736 (Elide anon lifetimes in conflicting impl note)
 - #55739 (Consume optimization fuel from the MIR inliner)
 - #55742 (Avoid panic when matching function call)
 - #55753 (borrow_set: remove a helper function and a clone it uses)
 - #55755 (Improve creation of 3 IndexVecs)
 - #55758 ([regression - rust2018]: unused_mut lint false positives on nightly)
 - #55760 (Remove intermediate font specs)
 - #55761 (mir: remove a hacky recursive helper function)
 - #55774 (wasm32-unknown-emscripten expects the rust_eh_personality symbol)
 - #55777 (Use `Lit` rather than `P<Lit>` in `ast::ExprKind`.)
 - #55783 (Deprecate mpsc channel selection)
 - #55788 (rustc: Request ansi colors if stderr isn't a tty)

Failed merges:

r? @ghost
This commit is contained in:
bors 2018-11-09 06:56:25 +00:00
commit 36a50c29f6
47 changed files with 403 additions and 172 deletions

View File

@ -97,7 +97,10 @@ pub unsafe extern fn __rust_start_panic(_payload: usize) -> u32 {
pub mod personalities {
#[no_mangle]
#[cfg(not(any(
target_arch = "wasm32",
all(
target_arch = "wasm32",
not(target_os = "emscripten"),
),
all(
target_os = "windows",
target_env = "gnu",

View File

@ -3705,7 +3705,7 @@ impl<'a> LoweringContext<'a> {
let ohs = P(self.lower_expr(ohs));
hir::ExprKind::Unary(op, ohs)
}
ExprKind::Lit(ref l) => hir::ExprKind::Lit(P((**l).clone())),
ExprKind::Lit(ref l) => hir::ExprKind::Lit(P((*l).clone())),
ExprKind::Cast(ref expr, ref ty) => {
let expr = P(self.lower_expr(expr));
hir::ExprKind::Cast(expr, self.lower_ty(ty, ImplTraitContext::disallowed()))

View File

@ -178,6 +178,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
self.msg_span_from_early_bound_and_free_regions(region)
}
ty::ReStatic => ("the static lifetime".to_owned(), None),
ty::ReEmpty => ("an empty lifetime".to_owned(), None),
_ => bug!("{:?}", region),
}
}

View File

@ -304,6 +304,20 @@ impl<'tcx> Mir<'tcx> {
})
}
/// Returns an iterator over all user-declared mutable locals.
#[inline]
pub fn mut_vars_iter<'a>(&'a self) -> impl Iterator<Item = Local> + 'a {
(self.arg_count + 1..self.local_decls.len()).filter_map(move |index| {
let local = Local::new(index);
let decl = &self.local_decls[local];
if decl.is_user_variable.is_some() && decl.mutability == Mutability::Mut {
Some(local)
} else {
None
}
})
}
/// Returns an iterator over all user-declared mutable arguments and locals.
#[inline]
pub fn mut_vars_and_args_iter<'a>(&'a self) -> impl Iterator<Item = Local> + 'a {

View File

@ -2082,7 +2082,7 @@ pub fn build_session_options_and_crate_config(
error_format,
&format!(
"optimization level needs to be \
between 0-3 (instead was `{}`)",
between 0-3, s or z (instead was `{}`)",
arg
),
);

View File

@ -396,7 +396,10 @@ fn to_pretty_impl_header(tcx: TyCtxt<'_, '_, '_>, impl_def_id: DefId) -> Option<
if !substs.is_noop() {
types_without_default_bounds.extend(substs.types());
w.push('<');
w.push_str(&substs.iter().map(|k| k.to_string()).collect::<Vec<_>>().join(", "));
w.push_str(&substs.iter()
.map(|k| k.to_string())
.filter(|k| &k[..] != "'_")
.collect::<Vec<_>>().join(", "));
w.push('>');
}

View File

@ -450,8 +450,7 @@ impl<'sess> OnDiskCache<'sess> {
.map(|&(cnum, ..)| cnum)
.max()
.unwrap_or(0) + 1;
let mut map = IndexVec::new();
map.resize(map_size as usize, None);
let mut map = IndexVec::from_elem_n(None, map_size as usize);
for &(prev_cnum, ref crate_name, crate_disambiguator) in prev_cnums {
let key = (crate_name.clone(), crate_disambiguator);

View File

@ -225,9 +225,10 @@ impl ArgTypeExt<'ll, 'tcx> for ArgType<'tcx, Ty<'tcx>> {
// ...and then memcpy it to the intended destination.
base::call_memcpy(bx,
bx.pointercast(dst.llval, Type::i8p(cx)),
self.layout.align,
bx.pointercast(llscratch, Type::i8p(cx)),
scratch_align,
C_usize(cx, self.layout.size.bytes()),
self.layout.align.min(scratch_align),
MemFlags::empty());
bx.lifetime_end(llscratch, scratch_size);

View File

@ -53,7 +53,7 @@ use mir::place::PlaceRef;
use attributes;
use builder::{Builder, MemFlags};
use callee;
use common::{C_bool, C_bytes_in_context, C_i32, C_usize};
use common::{C_bool, C_bytes_in_context, C_usize};
use rustc_mir::monomorphize::item::DefPathBasedNames;
use common::{C_struct_in_context, C_array, val_ty};
use consts;
@ -77,7 +77,6 @@ use rustc_data_structures::sync::Lrc;
use std::any::Any;
use std::cmp;
use std::ffi::CString;
use std::i32;
use std::ops::{Deref, DerefMut};
use std::sync::mpsc;
use std::time::{Instant, Duration};
@ -319,8 +318,8 @@ pub fn coerce_unsized_into(
}
if src_f.layout.ty == dst_f.layout.ty {
memcpy_ty(bx, dst_f.llval, src_f.llval, src_f.layout,
src_f.align.min(dst_f.align), MemFlags::empty());
memcpy_ty(bx, dst_f.llval, dst_f.align, src_f.llval, src_f.align,
src_f.layout, MemFlags::empty());
} else {
coerce_unsized_into(bx, src_f, dst_f);
}
@ -420,36 +419,34 @@ pub fn to_immediate_scalar(
pub fn call_memcpy(
bx: &Builder<'_, 'll, '_>,
dst: &'ll Value,
dst_align: Align,
src: &'ll Value,
src_align: Align,
n_bytes: &'ll Value,
align: Align,
flags: MemFlags,
) {
if flags.contains(MemFlags::NONTEMPORAL) {
// HACK(nox): This is inefficient but there is no nontemporal memcpy.
let val = bx.load(src, align);
let val = bx.load(src, src_align);
let ptr = bx.pointercast(dst, val_ty(val).ptr_to());
bx.store_with_flags(val, ptr, align, flags);
bx.store_with_flags(val, ptr, dst_align, flags);
return;
}
let cx = bx.cx;
let ptr_width = &cx.sess().target.target.target_pointer_width;
let key = format!("llvm.memcpy.p0i8.p0i8.i{}", ptr_width);
let memcpy = cx.get_intrinsic(&key);
let src_ptr = bx.pointercast(src, Type::i8p(cx));
let dst_ptr = bx.pointercast(dst, Type::i8p(cx));
let size = bx.intcast(n_bytes, cx.isize_ty, false);
let align = C_i32(cx, align.abi() as i32);
let volatile = C_bool(cx, flags.contains(MemFlags::VOLATILE));
bx.call(memcpy, &[dst_ptr, src_ptr, size, align, volatile], None);
let volatile = flags.contains(MemFlags::VOLATILE);
bx.memcpy(dst_ptr, dst_align.abi(), src_ptr, src_align.abi(), size, volatile);
}
pub fn memcpy_ty(
bx: &Builder<'_, 'll, 'tcx>,
dst: &'ll Value,
dst_align: Align,
src: &'ll Value,
src_align: Align,
layout: TyLayout<'tcx>,
align: Align,
flags: MemFlags,
) {
let size = layout.size.bytes();
@ -457,7 +454,7 @@ pub fn memcpy_ty(
return;
}
call_memcpy(bx, dst, src, C_usize(bx.cx, size), align, flags);
call_memcpy(bx, dst, dst_align, src, src_align, C_usize(bx.cx, size), flags);
}
pub fn call_memset(

View File

@ -781,6 +781,24 @@ impl Builder<'a, 'll, 'tcx> {
}
}
pub fn memcpy(&self, dst: &'ll Value, dst_align: u64,
src: &'ll Value, src_align: u64,
size: &'ll Value, is_volatile: bool) -> &'ll Value {
unsafe {
llvm::LLVMRustBuildMemCpy(self.llbuilder, dst, dst_align as c_uint,
src, src_align as c_uint, size, is_volatile)
}
}
pub fn memmove(&self, dst: &'ll Value, dst_align: u64,
src: &'ll Value, src_align: u64,
size: &'ll Value, is_volatile: bool) -> &'ll Value {
unsafe {
llvm::LLVMRustBuildMemMove(self.llbuilder, dst, dst_align as c_uint,
src, src_align as c_uint, size, is_volatile)
}
}
pub fn minnum(&self, lhs: &'ll Value, rhs: &'ll Value) -> &'ll Value {
self.count_insn("minnum");
unsafe {

View File

@ -530,12 +530,6 @@ fn declare_intrinsic(cx: &CodegenCx<'ll, '_>, key: &str) -> Option<&'ll Value> {
let t_v4f64 = Type::vector(t_f64, 4);
let t_v8f64 = Type::vector(t_f64, 8);
ifn!("llvm.memcpy.p0i8.p0i8.i16", fn(i8p, i8p, t_i16, t_i32, i1) -> void);
ifn!("llvm.memcpy.p0i8.p0i8.i32", fn(i8p, i8p, t_i32, t_i32, i1) -> void);
ifn!("llvm.memcpy.p0i8.p0i8.i64", fn(i8p, i8p, t_i64, t_i32, i1) -> void);
ifn!("llvm.memmove.p0i8.p0i8.i16", fn(i8p, i8p, t_i16, t_i32, i1) -> void);
ifn!("llvm.memmove.p0i8.p0i8.i32", fn(i8p, i8p, t_i32, t_i32, i1) -> void);
ifn!("llvm.memmove.p0i8.p0i8.i64", fn(i8p, i8p, t_i64, t_i32, i1) -> void);
ifn!("llvm.memset.p0i8.i16", fn(i8p, t_i8, t_i16, t_i32, i1) -> void);
ifn!("llvm.memset.p0i8.i32", fn(i8p, t_i8, t_i32, t_i32, i1) -> void);
ifn!("llvm.memset.p0i8.i64", fn(i8p, t_i8, t_i64, t_i32, i1) -> void);

View File

@ -23,7 +23,7 @@ use glue;
use type_::Type;
use type_of::LayoutLlvmExt;
use rustc::ty::{self, Ty};
use rustc::ty::layout::{HasDataLayout, LayoutOf};
use rustc::ty::layout::LayoutOf;
use rustc::hir;
use syntax::ast;
use syntax::symbol::Symbol;
@ -690,28 +690,14 @@ fn copy_intrinsic(
let cx = bx.cx;
let (size, align) = cx.size_and_align_of(ty);
let size = C_usize(cx, size.bytes());
let align = C_i32(cx, align.abi() as i32);
let operation = if allow_overlap {
"memmove"
} else {
"memcpy"
};
let name = format!("llvm.{}.p0i8.p0i8.i{}", operation,
cx.data_layout().pointer_size.bits());
let align = align.abi();
let dst_ptr = bx.pointercast(dst, Type::i8p(cx));
let src_ptr = bx.pointercast(src, Type::i8p(cx));
let llfn = cx.get_intrinsic(&name);
bx.call(llfn,
&[dst_ptr,
src_ptr,
bx.mul(size, count),
align,
C_bool(cx, volatile)],
None)
if allow_overlap {
bx.memmove(dst_ptr, align, src_ptr, align, bx.mul(size, count), volatile)
} else {
bx.memcpy(dst_ptr, align, src_ptr, align, bx.mul(size, count), volatile)
}
}
fn memset_intrinsic(

View File

@ -998,6 +998,22 @@ extern "C" {
Bundle: Option<&OperandBundleDef<'a>>,
Name: *const c_char)
-> &'a Value;
pub fn LLVMRustBuildMemCpy(B: &Builder<'a>,
Dst: &'a Value,
DstAlign: c_uint,
Src: &'a Value,
SrcAlign: c_uint,
Size: &'a Value,
IsVolatile: bool)
-> &'a Value;
pub fn LLVMRustBuildMemMove(B: &Builder<'a>,
Dst: &'a Value,
DstAlign: c_uint,
Src: &'a Value,
SrcAlign: c_uint,
Size: &'a Value,
IsVolatile: bool)
-> &'a Value;
pub fn LLVMBuildSelect(B: &Builder<'a>,
If: &'a Value,
Then: &'a Value,

View File

@ -784,7 +784,8 @@ impl FunctionCx<'a, 'll, 'tcx> {
// have scary latent bugs around.
let scratch = PlaceRef::alloca(bx, arg.layout, "arg");
base::memcpy_ty(bx, scratch.llval, llval, op.layout, align, MemFlags::empty());
base::memcpy_ty(bx, scratch.llval, scratch.align, llval, align,
op.layout, MemFlags::empty());
(scratch.llval, scratch.align, true)
} else {
(llval, align, true)

View File

@ -282,8 +282,8 @@ impl OperandValue<'ll> {
}
match self {
OperandValue::Ref(r, None, source_align) => {
base::memcpy_ty(bx, dest.llval, r, dest.layout,
source_align.min(dest.align), flags)
base::memcpy_ty(bx, dest.llval, dest.align, r, source_align,
dest.layout, flags)
}
OperandValue::Ref(_, Some(_), _) => {
bug!("cannot directly store unsized values");
@ -324,7 +324,7 @@ impl OperandValue<'ll> {
// Allocate an appropriate region on the stack, and copy the value into it
let (llsize, _) = glue::size_and_align_of_dst(&bx, unsized_ty, Some(llextra));
let lldst = bx.array_alloca(Type::i8(bx.cx), llsize, "unsized_tmp", max_align);
base::call_memcpy(&bx, lldst, llptr, llsize, min_align, flags);
base::call_memcpy(&bx, lldst, max_align, llptr, min_align, llsize, flags);
// Store the allocated region and the extra to the indirect place.
let indirect_operand = OperandValue::Pair(lldst, llextra);

View File

@ -108,7 +108,13 @@ pub enum ColorConfig {
impl ColorConfig {
fn to_color_choice(&self) -> ColorChoice {
match *self {
ColorConfig::Always => ColorChoice::Always,
ColorConfig::Always => {
if atty::is(atty::Stream::Stderr) {
ColorChoice::Always
} else {
ColorChoice::AlwaysAnsi
}
}
ColorConfig::Never => ColorChoice::Never,
ColorConfig::Auto if atty::is(atty::Stream::Stderr) => {
ColorChoice::Auto

View File

@ -21,7 +21,6 @@ use rustc::util::nodemap::{FxHashMap, FxHashSet};
use rustc_data_structures::indexed_vec::IndexVec;
use rustc_data_structures::bit_set::BitSet;
use std::fmt;
use std::hash::Hash;
use std::ops::Index;
crate struct BorrowSet<'tcx> {
@ -233,21 +232,13 @@ impl<'a, 'gcx, 'tcx> Visitor<'tcx> for GatherBorrows<'a, 'gcx, 'tcx> {
self.insert_as_pending_if_two_phase(location, &assigned_place, region, kind, idx);
insert(&mut self.region_map, &region, idx);
self.region_map.entry(region).or_default().insert(idx);
if let Some(local) = borrowed_place.root_local() {
insert(&mut self.local_map, &local, idx);
self.local_map.entry(local).or_default().insert(idx);
}
}
return self.super_assign(block, assigned_place, rvalue, location);
fn insert<'a, K, V>(map: &'a mut FxHashMap<K, FxHashSet<V>>, k: &K, v: V)
where
K: Clone + Eq + Hash,
V: Eq + Hash,
{
map.entry(k.clone()).or_default().insert(v);
}
self.super_assign(block, assigned_place, rvalue, location)
}
fn visit_place(

View File

@ -281,23 +281,21 @@ fn do_mir_borrowck<'a, 'gcx, 'tcx>(
// Note that this set is expected to be small - only upvars from closures
// would have a chance of erroneously adding non-user-defined mutable vars
// to the set.
let temporary_used_locals: FxHashSet<Local> = mbcx
.used_mut
.iter()
let temporary_used_locals: FxHashSet<Local> = mbcx.used_mut.iter()
.filter(|&local| mbcx.mir.local_decls[*local].is_user_variable.is_none())
.cloned()
.collect();
mbcx.gather_used_muts(temporary_used_locals);
// For the remaining unused locals that are marked as mutable, we avoid linting any that
// were never initialized. These locals may have been removed as unreachable code; or will be
// linted as unused variables.
let unused_mut_locals = mbcx.mir.mut_vars_iter()
.filter(|local| !mbcx.used_mut.contains(local))
.collect();
mbcx.gather_used_muts(temporary_used_locals, unused_mut_locals);
debug!("mbcx.used_mut: {:?}", mbcx.used_mut);
let used_mut = mbcx.used_mut;
for local in mbcx
.mir
.mut_vars_and_args_iter()
.filter(|local| !used_mut.contains(local))
{
for local in mbcx.mir.mut_vars_and_args_iter().filter(|local| !used_mut.contains(local)) {
if let ClearCrossCrate::Set(ref vsi) = mbcx.mir.source_scope_local_data {
let local_decl = &mbcx.mir.local_decls[local];

View File

@ -9,43 +9,113 @@
// except according to those terms.
use rustc::mir::visit::{PlaceContext, Visitor};
use rustc::mir::{Local, Location, Place};
use rustc::mir::{BasicBlock, Local, Location, Place, Statement, StatementKind, TerminatorKind};
use rustc_data_structures::fx::FxHashSet;
use borrow_check::MirBorrowckCtxt;
impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
/// Walks the MIR looking for assignments to a set of locals, as part of the unused mutable
/// local variables lint, to update the context's `used_mut` in a single walk.
crate fn gather_used_muts(&mut self, locals: FxHashSet<Local>) {
let mut visitor = GatherUsedMutsVisitor {
needles: locals,
mbcx: self,
};
visitor.visit_mir(visitor.mbcx.mir);
/// Walks the MIR adding to the set of `used_mut` locals that will be ignored for the purposes
/// of the `unused_mut` lint.
///
/// `temporary_used_locals` should contain locals that were found to be temporary, mutable and
/// used from borrow checking. This function looks for assignments into these locals from
/// user-declared locals and adds those user-defined locals to the `used_mut` set. This can
/// occur due to a rare case involving upvars in closures.
///
/// `never_initialized_mut_locals` should contain the set of user-declared mutable locals
/// (not arguments) that have not already been marked as being used.
/// This function then looks for assignments from statements or the terminator into the locals
/// from this set and removes them from the set. This leaves only those locals that have not
/// been assigned to - this set is used as a proxy for locals that were not initialized due to
/// unreachable code. These locals are then considered "used" to silence the lint for them.
/// See #55344 for context.
crate fn gather_used_muts(
&mut self,
temporary_used_locals: FxHashSet<Local>,
mut never_initialized_mut_locals: FxHashSet<Local>,
) {
{
let mut visitor = GatherUsedMutsVisitor {
temporary_used_locals,
never_initialized_mut_locals: &mut never_initialized_mut_locals,
mbcx: self,
};
visitor.visit_mir(visitor.mbcx.mir);
}
// Take the union of the existed `used_mut` set with those variables we've found were
// never initialized.
debug!("gather_used_muts: never_initialized_mut_locals={:?}", never_initialized_mut_locals);
self.used_mut = self.used_mut.union(&never_initialized_mut_locals).cloned().collect();
}
}
/// MIR visitor gathering the assignments to a set of locals, in a single walk.
/// 'visit = the duration of the MIR walk
/// MIR visitor for collecting used mutable variables.
/// The 'visit lifetime represents the duration of the MIR walk.
struct GatherUsedMutsVisitor<'visit, 'cx: 'visit, 'gcx: 'tcx, 'tcx: 'cx> {
needles: FxHashSet<Local>,
temporary_used_locals: FxHashSet<Local>,
never_initialized_mut_locals: &'visit mut FxHashSet<Local>,
mbcx: &'visit mut MirBorrowckCtxt<'cx, 'gcx, 'tcx>,
}
impl<'visit, 'cx, 'gcx, 'tcx> Visitor<'tcx> for GatherUsedMutsVisitor<'visit, 'cx, 'gcx, 'tcx> {
fn visit_terminator_kind(
&mut self,
_block: BasicBlock,
kind: &TerminatorKind<'tcx>,
_location: Location,
) {
debug!("visit_terminator_kind: kind={:?}", kind);
match &kind {
TerminatorKind::Call { destination: Some((into, _)), .. } => {
if let Some(local) = into.base_local() {
debug!(
"visit_terminator_kind: kind={:?} local={:?} \
never_initialized_mut_locals={:?}",
kind, local, self.never_initialized_mut_locals
);
let _ = self.never_initialized_mut_locals.remove(&local);
}
},
_ => {},
}
}
fn visit_statement(
&mut self,
_block: BasicBlock,
statement: &Statement<'tcx>,
_location: Location,
) {
match &statement.kind {
StatementKind::Assign(into, _) => {
// Remove any locals that we found were initialized from the
// `never_initialized_mut_locals` set. At the end, the only remaining locals will
// be those that were never initialized - we will consider those as being used as
// they will either have been removed by unreachable code optimizations; or linted
// as unused variables.
if let Some(local) = into.base_local() {
debug!(
"visit_statement: statement={:?} local={:?} \
never_initialized_mut_locals={:?}",
statement, local, self.never_initialized_mut_locals
);
let _ = self.never_initialized_mut_locals.remove(&local);
}
},
_ => {},
}
}
fn visit_local(
&mut self,
local: &Local,
place_context: PlaceContext<'tcx>,
location: Location,
) {
if !self.needles.contains(local) {
return;
}
if place_context.is_place_assignment() {
if place_context.is_place_assignment() && self.temporary_used_locals.contains(local) {
// Propagate the Local assigned at this Location as a used mutable local variable
for moi in &self.mbcx.move_data.loc_map[location] {
let mpi = &self.mbcx.move_data.moves[*moi].path;

View File

@ -196,7 +196,7 @@ fn build_drop_shim<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
let source_info = SourceInfo { span, scope: OUTERMOST_SOURCE_SCOPE };
let return_block = BasicBlock::new(1);
let mut blocks = IndexVec::new();
let mut blocks = IndexVec::with_capacity(2);
let block = |blocks: &mut IndexVec<_, _>, kind| {
blocks.push(BasicBlockData {
statements: vec![],
@ -768,7 +768,8 @@ fn build_call_shim<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
}));
}
let mut blocks = IndexVec::new();
let n_blocks = if let Adjustment::RefMut = rcvr_adjustment { 5 } else { 2 };
let mut blocks = IndexVec::with_capacity(n_blocks);
let block = |blocks: &mut IndexVec<_, _>, statements, kind, is_cleanup| {
blocks.push(BasicBlockData {
statements,

View File

@ -137,7 +137,7 @@ impl<'a, 'tcx> Inliner<'a, 'tcx> {
let callee_mir = match self.tcx.try_optimized_mir(callsite.location.span,
callsite.callee) {
Ok(callee_mir) if self.should_inline(callsite, callee_mir) => {
Ok(callee_mir) if self.consider_optimizing(callsite, callee_mir) => {
self.tcx.subst_and_normalize_erasing_regions(
&callsite.substs,
param_env,
@ -198,6 +198,18 @@ impl<'a, 'tcx> Inliner<'a, 'tcx> {
}
}
fn consider_optimizing(&self,
callsite: CallSite<'tcx>,
callee_mir: &Mir<'tcx>)
-> bool
{
debug!("consider_optimizing({:?})", callsite);
self.should_inline(callsite, callee_mir)
&& self.tcx.consider_optimizing(|| format!("Inline {:?} into {:?}",
callee_mir.span,
callsite))
}
fn should_inline(&self,
callsite: CallSite<'tcx>,
callee_mir: &Mir<'tcx>)

View File

@ -310,16 +310,11 @@ impl<'a, 'tcx> Promoter<'a, 'tcx> {
match statement.kind {
StatementKind::Assign(_, box Rvalue::Ref(_, _, ref mut place)) => {
// Find the underlying local for this (necessarily interior) borrow.
// HACK(eddyb) using a recursive function because of mutable borrows.
fn interior_base<'a, 'tcx>(place: &'a mut Place<'tcx>)
-> &'a mut Place<'tcx> {
if let Place::Projection(ref mut proj) = *place {
assert_ne!(proj.elem, ProjectionElem::Deref);
return interior_base(&mut proj.base);
}
place
}
let place = interior_base(place);
let mut place = place;
while let Place::Projection(ref mut proj) = *place {
assert_ne!(proj.elem, ProjectionElem::Deref);
place = &mut proj.base;
};
let ty = place.ty(local_decls, self.tcx).to_ty(self.tcx);
let span = statement.source_info.span;

View File

@ -24,31 +24,6 @@ pub fn opts() -> TargetOptions {
// argument is *not* necessary for normal builds, but it can't hurt!
base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap().push("-Wl,--eh-frame-hdr".to_string());
// There's a whole bunch of circular dependencies when dealing with MUSL
// unfortunately. To put this in perspective libc is statically linked to
// liblibc and libunwind is statically linked to libstd:
//
// * libcore depends on `fmod` which is in libc (transitively in liblibc).
// liblibc, however, depends on libcore.
// * compiler-rt has personality symbols that depend on libunwind, but
// libunwind is in libstd which depends on compiler-rt.
//
// Recall that linkers discard libraries and object files as much as
// possible, and with all the static linking and archives flying around with
// MUSL the linker is super aggressively stripping out objects. For example
// the first case has fmod stripped from liblibc (it's in its own object
// file) so it's not there when libcore needs it. In the second example all
// the unused symbols from libunwind are stripped (each is in its own object
// file in libstd) before we end up linking compiler-rt which depends on
// those symbols.
//
// To deal with these circular dependencies we just force the compiler to
// link everything as a group, not stripping anything out until everything
// is processed. The linker will still perform a pass to strip out object
// files but it won't do so until all objects/archives have been processed.
base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap().push("-Wl,-(".to_string());
base.post_link_args.insert(LinkerFlavor::Gcc, vec!["-Wl,-)".to_string()]);
// When generating a statically linked executable there's generally some
// small setup needed which is listed in these files. These are provided by
// a musl toolchain and are linked by default by the `musl-gcc` script. Note

View File

@ -814,11 +814,6 @@ https://doc.rust-lang.org/reference/types.html#trait-objects");
report_unexpected_def(def);
return self.tcx.types.err;
}
// Replace constructor type with constructed type for tuple struct patterns.
let pat_ty = pat_ty.fn_sig(tcx).output();
let pat_ty = pat_ty.no_bound_vars().expect("expected fn type");
self.demand_eqtype(pat.span, expected, pat_ty);
let variant = match def {
Def::Err => {
@ -836,6 +831,13 @@ https://doc.rust-lang.org/reference/types.html#trait-objects");
}
_ => bug!("unexpected pattern definition: {:?}", def)
};
// Replace constructor type with constructed type for tuple struct patterns.
let pat_ty = pat_ty.fn_sig(tcx).output();
let pat_ty = pat_ty.no_bound_vars().expect("expected fn type");
self.demand_eqtype(pat.span, expected, pat_ty);
// Type check subpatterns.
if subpats.len() == variant.fields.len() ||
subpats.len() < variant.fields.len() && ddpos.is_some() {

View File

@ -70,7 +70,7 @@
/* General structure and fonts */
body {
font: 16px/1.4 "Source Serif Pro", Georgia, Times, "Times New Roman", serif;
font: 16px/1.4 "Source Serif Pro", serif;
margin: 0;
position: relative;
padding: 10px 15px 20px 15px;
@ -114,7 +114,7 @@ h3.impl, h3.method, h3.type {
h1, h2, h3, h4,
.sidebar, a.source, .search-input, .content table :not(code)>a,
.collapse-toggle, div.item-list .out-of-band {
font-family: "Fira Sans", "Helvetica Neue", Helvetica, Arial, sans-serif;
font-family: "Fira Sans", sans-serif;
}
ol, ul {
@ -133,7 +133,7 @@ summary {
}
code, pre {
font-family: "Source Code Pro", Menlo, Monaco, Consolas, "DejaVu Sans Mono", Inconsolata, monospace;
font-family: "Source Code Pro", monospace;
white-space: pre-wrap;
}
.docblock code, .docblock-short code {
@ -415,7 +415,7 @@ h4 > code, h3 > code, .invisible > code {
}
#main > .since {
top: inherit;
font-family: "Fira Sans", "Helvetica Neue", Helvetica, Arial, sans-serif;
font-family: "Fira Sans", sans-serif;
}
.content table:not(.table-display) {
@ -1338,7 +1338,7 @@ h3.important {
kbd {
display: inline-block;
padding: 3px 5px;
font: 15px "SFMono-Regular", Consolas, "Liberation Mono", Menlo, Courier, monospace;
font: 15px monospace;
line-height: 10px;
vertical-align: middle;
border: solid 1px;

View File

@ -399,6 +399,8 @@ macro_rules! await {
/// For more information about select, see the `std::sync::mpsc::Select` structure.
#[macro_export]
#[unstable(feature = "mpsc_select", issue = "27800")]
#[rustc_deprecated(since = "1.32.0",
reason = "channel selection will be removed in a future release")]
macro_rules! select {
(
$($name:pat = $rx:ident.$meth:ident() => $code:expr),+

View File

@ -124,6 +124,7 @@
//! ```
#![stable(feature = "rust1", since = "1.0.0")]
#![allow(deprecated)] // for mpsc_select
// A description of how Rust's channel implementation works
//

View File

@ -51,11 +51,10 @@
#![unstable(feature = "mpsc_select",
reason = "This implementation, while likely sufficient, is unsafe and \
likely to be error prone. At some point in the future this \
module will likely be replaced, and it is currently \
unknown how much API breakage that will cause. The ability \
to select over a number of channels will remain forever, \
but no guarantees beyond this are being made",
module will be removed.",
issue = "27800")]
#![rustc_deprecated(since = "1.32.0",
reason = "channel selection will be removed in a future release")]
use fmt;

View File

@ -1086,7 +1086,7 @@ pub enum ExprKind {
/// A unary operation (For example: `!x`, `*x`)
Unary(UnOp, P<Expr>),
/// A literal (For example: `1`, `"foo"`)
Lit(P<Lit>),
Lit(Lit),
/// A cast (`foo as f64`)
Cast(P<Expr>, P<Ty>),
Type(P<Expr>, P<Ty>),

View File

@ -491,7 +491,7 @@ impl DummyResult {
pub fn raw_expr(sp: Span) -> P<ast::Expr> {
P(ast::Expr {
id: ast::DUMMY_NODE_ID,
node: ast::ExprKind::Lit(P(source_map::respan(sp, ast::LitKind::Bool(false)))),
node: ast::ExprKind::Lit(source_map::respan(sp, ast::LitKind::Bool(false))),
span: sp,
attrs: ThinVec::new(),
})

View File

@ -695,7 +695,7 @@ impl<'a> AstBuilder for ExtCtxt<'a> {
}
fn expr_lit(&self, sp: Span, lit: ast::LitKind) -> P<ast::Expr> {
self.expr(sp, ast::ExprKind::Lit(P(respan(sp, lit))))
self.expr(sp, ast::ExprKind::Lit(respan(sp, lit)))
}
fn expr_usize(&self, span: Span, i: usize) -> P<ast::Expr> {
self.expr_lit(span, ast::LitKind::Int(i as u128,

View File

@ -274,7 +274,7 @@ pub mod rt {
// FIXME: This is wrong
P(ast::Expr {
id: ast::DUMMY_NODE_ID,
node: ast::ExprKind::Lit(P(self.clone())),
node: ast::ExprKind::Lit(self.clone()),
span: DUMMY_SP,
attrs: ThinVec::new(),
}).to_tokens(cx)
@ -305,7 +305,7 @@ pub mod rt {
let lit = ast::LitKind::Int(val as u128, ast::LitIntType::Signed($tag));
let lit = P(ast::Expr {
id: ast::DUMMY_NODE_ID,
node: ast::ExprKind::Lit(P(dummy_spanned(lit))),
node: ast::ExprKind::Lit(dummy_spanned(lit)),
span: DUMMY_SP,
attrs: ThinVec::new(),
});

View File

@ -1989,7 +1989,7 @@ impl<'a> Parser<'a> {
let minus_lo = self.span;
let minus_present = self.eat(&token::BinOp(token::Minus));
let lo = self.span;
let literal = P(self.parse_lit()?);
let literal = self.parse_lit()?;
let hi = self.prev_span;
let expr = self.mk_expr(lo.to(hi), ExprKind::Lit(literal), ThinVec::new());

View File

@ -1237,6 +1237,40 @@ extern "C" LLVMValueRef LLVMRustBuildCall(LLVMBuilderRef B, LLVMValueRef Fn,
unwrap(Fn), makeArrayRef(unwrap(Args), NumArgs), Bundles, Name));
}
extern "C" LLVMValueRef LLVMRustBuildMemCpy(LLVMBuilderRef B,
LLVMValueRef Dst, unsigned DstAlign,
LLVMValueRef Src, unsigned SrcAlign,
LLVMValueRef Size, bool IsVolatile) {
#if LLVM_VERSION_GE(7, 0)
return wrap(unwrap(B)->CreateMemCpy(
unwrap(Dst), DstAlign,
unwrap(Src), SrcAlign,
unwrap(Size), IsVolatile));
#else
unsigned Align = std::min(DstAlign, SrcAlign);
return wrap(unwrap(B)->CreateMemCpy(
unwrap(Dst), unwrap(Src),
unwrap(Size), Align, IsVolatile));
#endif
}
extern "C" LLVMValueRef LLVMRustBuildMemMove(LLVMBuilderRef B,
LLVMValueRef Dst, unsigned DstAlign,
LLVMValueRef Src, unsigned SrcAlign,
LLVMValueRef Size, bool IsVolatile) {
#if LLVM_VERSION_GE(7, 0)
return wrap(unwrap(B)->CreateMemMove(
unwrap(Dst), DstAlign,
unwrap(Src), SrcAlign,
unwrap(Size), IsVolatile));
#else
unsigned Align = std::min(DstAlign, SrcAlign);
return wrap(unwrap(B)->CreateMemMove(
unwrap(Dst), unwrap(Src),
unwrap(Size), Align, IsVolatile));
#endif
}
extern "C" LLVMValueRef
LLVMRustBuildInvoke(LLVMBuilderRef B, LLVMValueRef Fn, LLVMValueRef *Args,
unsigned NumArgs, LLVMBasicBlockRef Then,

View File

@ -65,7 +65,7 @@ pub struct BigPacked2 {
pub fn call_pkd1(f: fn() -> Array) -> BigPacked1 {
// CHECK: [[ALLOCA:%[_a-z0-9]+]] = alloca %Array
// CHECK: call void %{{.*}}(%Array* noalias nocapture sret dereferenceable(32) [[ALLOCA]])
// CHECK: call void @llvm.memcpy.{{.*}}(i8* align 1 %{{.*}}, i8* align 1 %{{.*}}, i{{[0-9]+}} 32, i1 false)
// CHECK: call void @llvm.memcpy.{{.*}}(i8* align 1 %{{.*}}, i8* align 4 %{{.*}}, i{{[0-9]+}} 32, i1 false)
// check that calls whose destination is a field of a packed struct
// go through an alloca rather than calling the function with an
// unaligned destination.
@ -77,7 +77,7 @@ pub fn call_pkd1(f: fn() -> Array) -> BigPacked1 {
pub fn call_pkd2(f: fn() -> Array) -> BigPacked2 {
// CHECK: [[ALLOCA:%[_a-z0-9]+]] = alloca %Array
// CHECK: call void %{{.*}}(%Array* noalias nocapture sret dereferenceable(32) [[ALLOCA]])
// CHECK: call void @llvm.memcpy.{{.*}}(i8* align 2 %{{.*}}, i8* align 2 %{{.*}}, i{{[0-9]+}} 32, i1 false)
// CHECK: call void @llvm.memcpy.{{.*}}(i8* align 2 %{{.*}}, i8* align 4 %{{.*}}, i{{[0-9]+}} 32, i1 false)
// check that calls whose destination is a field of a packed struct
// go through an alloca rather than calling the function with an
// unaligned destination.

View File

@ -31,7 +31,7 @@ pub fn small_array_alignment(x: &mut [i8; 4], y: [i8; 4]) {
// CHECK: store i32 %0, i32* [[TMP]]
// CHECK: [[Y8:%[0-9]+]] = bitcast [4 x i8]* %y to i8*
// CHECK: [[TMP8:%[0-9]+]] = bitcast i32* [[TMP]] to i8*
// CHECK: call void @llvm.memcpy.{{.*}}(i8* align 1 [[Y8]], i8* align 1 [[TMP8]], i{{[0-9]+}} 4, i1 false)
// CHECK: call void @llvm.memcpy.{{.*}}(i8* align 1 [[Y8]], i8* align 4 [[TMP8]], i{{[0-9]+}} 4, i1 false)
*x = y;
}
@ -45,6 +45,6 @@ pub fn small_struct_alignment(x: &mut Bytes, y: Bytes) {
// CHECK: store i32 %0, i32* [[TMP]]
// CHECK: [[Y8:%[0-9]+]] = bitcast %Bytes* %y to i8*
// CHECK: [[TMP8:%[0-9]+]] = bitcast i32* [[TMP]] to i8*
// CHECK: call void @llvm.memcpy.{{.*}}(i8* align 1 [[Y8]], i8* align 1 [[TMP8]], i{{[0-9]+}} 4, i1 false)
// CHECK: call void @llvm.memcpy.{{.*}}(i8* align 1 [[Y8]], i8* align 4 [[TMP8]], i{{[0-9]+}} 4, i1 false)
*x = y;
}

View File

@ -16,6 +16,7 @@
// expose is still present.
#![feature(mpsc_select)]
#![allow(deprecated)]
use std::sync::mpsc::{channel, Sender, Receiver};
use std::thread;

View File

@ -14,7 +14,7 @@ LL | impl Copy for &'static NotSync {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: conflicting implementation in crate `core`:
- impl<'_, T> std::marker::Copy for &T
- impl<T> std::marker::Copy for &T
where T: ?Sized;
error[E0119]: conflicting implementations of trait `std::marker::Copy` for type `&[NotSync]`:
@ -24,7 +24,7 @@ LL | impl Copy for &'static [NotSync] {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: conflicting implementation in crate `core`:
- impl<'_, T> std::marker::Copy for &T
- impl<T> std::marker::Copy for &T
where T: ?Sized;
error[E0206]: the trait `Copy` may not be implemented for this type

View File

@ -5,7 +5,7 @@ LL | impl<Foo> Deref for Foo { } //~ ERROR must be used
| ^^^^^^^^^^^^^^^^^^^^^^^
|
= note: conflicting implementation in crate `core`:
- impl<'_, T> std::ops::Deref for &T
- impl<T> std::ops::Deref for &T
where T: ?Sized;
error[E0210]: type parameter `Foo` must be used as the type parameter for some local type (e.g. `MyStruct<Foo>`)

25
src/test/ui/extern/extern-const.fixed vendored Normal file
View File

@ -0,0 +1,25 @@
// Check extern items cannot be const + `rustfix` suggests using
// extern static.
//
// #54388: an unused reference to an undefined static may or may not
// compile. To sidestep this by using one that *is* defined.
// run-rustfix
// ignore-wasm32 no external library to link to.
// compile-flags: -g -Z continue-parse-after-error
#![feature(libc)]
extern crate libc;
#[link(name = "rust_test_helpers", kind = "static")]
extern "C" {
static rust_dbg_static_mut: libc::c_int; //~ ERROR extern items cannot be `const`
}
fn main() {
// We suggest turning the (illegal) extern `const` into an extern `static`,
// but this also requires `unsafe` (a deny-by-default lint at comment time,
// future error; Issue #36247)
unsafe {
let _x = rust_dbg_static_mut;
}
}

View File

@ -1,18 +1,18 @@
// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
// Check extern items cannot be const + `rustfix` suggests using
// extern static.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
// #54388: an unused reference to an undefined static may or may not
// compile. To sidestep this by using one that *is* defined.
// FIXME(#54388): re-enable rustfix later, when this test has consistent output across targets
// compile-flags: -Z continue-parse-after-error
// run-rustfix
// ignore-wasm32 no external library to link to.
// compile-flags: -g -Z continue-parse-after-error
#![feature(libc)]
extern crate libc;
#[link(name = "rust_test_helpers", kind = "static")]
extern "C" {
const C: u8; //~ ERROR extern items cannot be `const`
const rust_dbg_static_mut: libc::c_int; //~ ERROR extern items cannot be `const`
}
fn main() {
@ -20,6 +20,6 @@ fn main() {
// but this also requires `unsafe` (a deny-by-default lint at comment time,
// future error; Issue #36247)
unsafe {
let _x = C;
let _x = rust_dbg_static_mut;
}
}

View File

@ -1,7 +1,7 @@
error: extern items cannot be `const`
--> $DIR/extern-const.rs:15:5
|
LL | const C: u8; //~ ERROR extern items cannot be `const`
LL | const rust_dbg_static_mut: libc::c_int; //~ ERROR extern items cannot be `const`
| ^^^^^ help: try using a static value: `static`
error: aborting due to previous error

View File

@ -0,0 +1,22 @@
// This used to ICE because it creates an `impl Trait` that captures a
// hidden empty region.
#![feature(conservative_impl_trait)]
fn server() -> impl FilterBase2 { //~ ERROR [E0700]
segment2(|| { loop { } }).map2(|| "")
}
trait FilterBase2 {
fn map2<F>(self, _fn: F) -> Map2<F> where Self: Sized { loop { } }
}
struct Map2<F> { _func: F }
impl<F> FilterBase2 for Map2<F> { }
fn segment2<F>(_fn: F) -> Map2<F> where F: Fn() -> Result<(), ()> {
loop { }
}
fn main() { server(); }

View File

@ -0,0 +1,11 @@
error[E0700]: hidden type for `impl Trait` captures lifetime that does not appear in bounds
--> $DIR/issue-55608-captures-empty-region.rs:6:16
|
LL | fn server() -> impl FilterBase2 { //~ ERROR [E0700]
| ^^^^^^^^^^^^^^^^
|
= note: hidden type `Map2<[closure@$DIR/issue-55608-captures-empty-region.rs:7:36: 7:41]>` captures an empty lifetime
error: aborting due to previous error
For more information about this error, try `rustc --explain E0700`.

View File

@ -0,0 +1,12 @@
use std::path::Path;
fn main() {
let path = Path::new("foo");
match path {
Path::new("foo") => println!("foo"),
//~^ ERROR expected tuple struct/variant
Path::new("bar") => println!("bar"),
//~^ ERROR expected tuple struct/variant
_ => (),
}
}

View File

@ -0,0 +1,15 @@
error[E0164]: expected tuple struct/variant, found method `<Path>::new`
--> $DIR/match-fn-call.rs:6:9
|
LL | Path::new("foo") => println!("foo"),
| ^^^^^^^^^^^^^^^^ not a tuple variant or struct
error[E0164]: expected tuple struct/variant, found method `<Path>::new`
--> $DIR/match-fn-call.rs:8:9
|
LL | Path::new("bar") => println!("bar"),
| ^^^^^^^^^^^^^^^^ not a tuple variant or struct
error: aborting due to 2 previous errors
For more information about this error, try `rustc --explain E0164`.

View File

@ -0,0 +1,26 @@
// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
// compile-pass
#![feature(nll)]
#![allow(unreachable_code)]
#![deny(unused_mut)]
pub fn foo() {
return;
let mut v = 0;
assert_eq!(v, 0);
v = 1;
assert_eq!(v, 1);
}
fn main() {}