mirror of
https://github.com/rust-lang/rust.git
synced 2024-12-01 11:13:43 +00:00
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:
commit
36a50c29f6
@ -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",
|
||||
|
@ -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()))
|
||||
|
@ -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),
|
||||
}
|
||||
}
|
||||
|
@ -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 {
|
||||
|
@ -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
|
||||
),
|
||||
);
|
||||
|
@ -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('>');
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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(
|
||||
|
@ -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 {
|
||||
|
@ -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);
|
||||
|
@ -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(
|
||||
|
@ -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,
|
||||
|
@ -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)
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
|
@ -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, ®ion, 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(
|
||||
|
@ -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];
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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,
|
||||
|
@ -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>)
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
@ -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() {
|
||||
|
@ -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;
|
||||
|
@ -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),+
|
||||
|
@ -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
|
||||
//
|
||||
|
@ -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;
|
||||
|
@ -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>),
|
||||
|
@ -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(),
|
||||
})
|
||||
|
@ -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,
|
||||
|
@ -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(),
|
||||
});
|
||||
|
@ -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());
|
||||
|
||||
|
@ -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,
|
||||
|
@ -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.
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -16,6 +16,7 @@
|
||||
// expose is still present.
|
||||
|
||||
#![feature(mpsc_select)]
|
||||
#![allow(deprecated)]
|
||||
|
||||
use std::sync::mpsc::{channel, Sender, Receiver};
|
||||
use std::thread;
|
||||
|
@ -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
|
||||
|
@ -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
25
src/test/ui/extern/extern-const.fixed
vendored
Normal 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;
|
||||
}
|
||||
}
|
24
src/test/ui/extern/extern-const.rs
vendored
24
src/test/ui/extern/extern-const.rs
vendored
@ -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;
|
||||
}
|
||||
}
|
||||
|
2
src/test/ui/extern/extern-const.stderr
vendored
2
src/test/ui/extern/extern-const.stderr
vendored
@ -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
|
||||
|
22
src/test/ui/impl-trait/issue-55608-captures-empty-region.rs
Normal file
22
src/test/ui/impl-trait/issue-55608-captures-empty-region.rs
Normal 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(); }
|
@ -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`.
|
12
src/test/ui/match/match-fn-call.rs
Normal file
12
src/test/ui/match/match-fn-call.rs
Normal 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
|
||||
_ => (),
|
||||
}
|
||||
}
|
15
src/test/ui/match/match-fn-call.stderr
Normal file
15
src/test/ui/match/match-fn-call.stderr
Normal 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`.
|
26
src/test/ui/nll/issue-55344.rs
Normal file
26
src/test/ui/nll/issue-55344.rs
Normal 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() {}
|
Loading…
Reference in New Issue
Block a user