Auto merge of #55171 - kennytm:rollup, r=kennytm

Rollup of 18 pull requests

Successful merges:

 - #54646 (improve documentation on std:🧵:sleep)
 - #54933 (Cleanup the rest of codegen_llvm)
 - #54964 (Run both lldb and gdb tests)
 - #55016 (Deduplicate some code and compile-time values around vtables)
 - #55031 (Improve verify_llvm_ir config option)
 - #55050 (doc std::fmt: the Python inspiration is already mentioned in precedin…)
 - #55077 (rustdoc: Use dyn keyword when rendering dynamic traits)
 - #55080 (Detect if access to localStorage is forbidden by the user's browser)
 - #55090 (regression test for move out of borrow via pattern)
 - #55102 (resolve: Do not skip extern prelude during speculative resolution)
 - #55104 (Add test for #34229)
 - #55111 ([Rustc Book] Explain --cfg's arguments)
 - #55122 (Cleanup mir/borrowck)
 - #55127 (Remove HybridBitSet::dummy)
 - #55128 (Fix LLVMRustInlineAsmVerify return type mismatch)
 - #55142 (miri: layout should not affect CTFE checks (outside of validation))
 - #55151 (Cleanup nll)
 - #55161 ([librustdoc] Disable spellcheck for search field)
This commit is contained in:
bors 2018-10-18 07:02:11 +00:00
commit af204b1f3e
58 changed files with 745 additions and 552 deletions

View File

@ -287,10 +287,6 @@ fn main() {
cmd.arg("--cfg").arg("parallel_queries");
}
if env::var_os("RUSTC_VERIFY_LLVM_IR").is_some() {
cmd.arg("-Z").arg("verify-llvm-ir");
}
if env::var_os("RUSTC_DENY_WARNINGS").is_some() && env::var_os("RUSTC_EXTERNAL_TOOL").is_none()
{
cmd.arg("-Dwarnings");

View File

@ -1000,10 +1000,6 @@ impl<'a> Builder<'a> {
cargo.env("RUSTC_BACKTRACE_ON_ICE", "1");
}
if self.config.rust_verify_llvm_ir {
cargo.env("RUSTC_VERIFY_LLVM_IR", "1");
}
cargo.env("RUSTC_VERBOSE", self.verbosity.to_string());
// in std, we want to avoid denying warnings for stage 0 as that makes cfg's painful.

View File

@ -569,6 +569,9 @@ pub fn rustc_cargo_env(builder: &Builder, cargo: &mut Command) {
if builder.config.rustc_parallel_queries {
cargo.env("RUSTC_PARALLEL_QUERIES", "1");
}
if builder.config.rust_verify_llvm_ir {
cargo.env("RUSTC_VERIFY_LLVM_IR", "1");
}
}
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]

View File

@ -812,8 +812,7 @@ default_test!(Incremental {
default_test!(Debuginfo {
path: "src/test/debuginfo",
// What this runs varies depending on the native platform being apple
mode: "debuginfo-XXX",
mode: "debuginfo",
suite: "debuginfo"
});
@ -950,18 +949,11 @@ impl Step for Compiletest {
return;
}
if mode == "debuginfo-XXX" {
return if builder.config.build.contains("apple") {
builder.ensure(Compiletest {
mode: "debuginfo-lldb",
..self
});
} else {
builder.ensure(Compiletest {
mode: "debuginfo-gdb",
..self
});
};
if mode == "debuginfo" {
return builder.ensure(Compiletest {
mode: "debuginfo-both",
..self
});
}
builder.ensure(dist::DebuggerScripts {

View File

@ -61,6 +61,7 @@ if [ "$DEPLOY$DEPLOY_ALT" != "" ]; then
RUST_CONFIGURE_ARGS="$RUST_CONFIGURE_ARGS --disable-llvm-assertions"
elif [ "$DEPLOY_ALT" != "" ]; then
RUST_CONFIGURE_ARGS="$RUST_CONFIGURE_ARGS --enable-llvm-assertions"
RUST_CONFIGURE_ARGS="$RUST_CONFIGURE_ARGS --set rust.verify-llvm-ir"
fi
else
# We almost always want debug assertions enabled, but sometimes this takes too
@ -74,6 +75,8 @@ else
if [ "$NO_LLVM_ASSERTIONS" = "" ]; then
RUST_CONFIGURE_ARGS="$RUST_CONFIGURE_ARGS --enable-llvm-assertions"
fi
RUST_CONFIGURE_ARGS="$RUST_CONFIGURE_ARGS --set rust.verify-llvm-ir"
fi
if [ "$RUST_RELEASE_CHANNEL" = "nightly" ] || [ "$DIST_REQUIRE_ALL_TOOLS" = "" ]; then

View File

@ -10,6 +10,11 @@ This flag will print out help information for `rustc`.
This flag can turn on or off various `#[cfg]` settings.
The value can either be a single identifier or two identifiers separated by `=`.
For examples, `--cfg 'verbose'` or `--cfg 'feature="serde"'`. These correspond
to `#[cfg(verbose)]` and `#[cfg(feature = "serde")]` respectively.
## `-L`: add a directory to the library search path
When looking for external crates, a directory passed to this flag will be searched.

View File

@ -335,8 +335,7 @@
//!
//! Each argument being formatted can be transformed by a number of formatting
//! parameters (corresponding to `format_spec` in the syntax above). These
//! parameters affect the string representation of what's being formatted. This
//! syntax draws heavily from Python's, so it may seem a bit familiar.
//! parameters affect the string representation of what's being formatted.
//!
//! ## Fill/Alignment
//!

View File

@ -8,8 +8,15 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use std::env;
fn main() {
println!("cargo:rerun-if-changed=build.rs");
println!("cargo:rerun-if-env-changed=CFG_LIBDIR_RELATIVE");
println!("cargo:rerun-if-env-changed=CFG_COMPILER_HOST_TRIPLE");
println!("cargo:rerun-if-env-changed=RUSTC_VERIFY_LLVM_IR");
if env::var_os("RUSTC_VERIFY_LLVM_IR").is_some() {
println!("cargo:rustc-cfg=always_verify_llvm_ir");
}
}

View File

@ -525,6 +525,7 @@ impl Session {
}
pub fn verify_llvm_ir(&self) -> bool {
self.opts.debugging_opts.verify_llvm_ir
|| cfg!(always_verify_llvm_ir)
}
pub fn borrowck_stats(&self) -> bool {
self.opts.debugging_opts.borrowck_stats

View File

@ -369,16 +369,16 @@ define_queries! { <'tcx>
-> Lrc<specialization_graph::Graph>,
[] fn is_object_safe: ObjectSafety(DefId) -> bool,
// Get the ParameterEnvironment for a given item; this environment
// will be in "user-facing" mode, meaning that it is suitabe for
// type-checking etc, and it does not normalize specializable
// associated types. This is almost always what you want,
// unless you are doing MIR optimizations, in which case you
// might want to use `reveal_all()` method to change modes.
/// Get the ParameterEnvironment for a given item; this environment
/// will be in "user-facing" mode, meaning that it is suitabe for
/// type-checking etc, and it does not normalize specializable
/// associated types. This is almost always what you want,
/// unless you are doing MIR optimizations, in which case you
/// might want to use `reveal_all()` method to change modes.
[] fn param_env: ParamEnv(DefId) -> ty::ParamEnv<'tcx>,
// Trait selection queries. These are best used by invoking `ty.moves_by_default()`,
// `ty.is_copy()`, etc, since that will prune the environment where possible.
/// Trait selection queries. These are best used by invoking `ty.moves_by_default()`,
/// `ty.is_copy()`, etc, since that will prune the environment where possible.
[] fn is_copy_raw: is_copy_dep_node(ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> bool,
[] fn is_sized_raw: is_sized_dep_node(ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> bool,
[] fn is_freeze_raw: is_freeze_dep_node(ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> bool,

View File

@ -756,7 +756,7 @@ impl Builder<'a, 'll, 'tcx> {
// Ask LLVM to verify that the constraints are well-formed.
let constraints_ok = llvm::LLVMRustInlineAsmVerify(fty, cons);
debug!("Constraint verification result: {:?}", constraints_ok);
if constraints_ok == llvm::True {
if constraints_ok {
let v = llvm::LLVMRustInlineAsm(
fty, asm, cons, volatile, alignstack, dia);
Some(self.call(v, inputs, None))

View File

@ -37,7 +37,7 @@ pub struct MirDebugScope<'ll> {
impl MirDebugScope<'ll> {
pub fn is_valid(&self) -> bool {
!self.scope_metadata.is_none()
self.scope_metadata.is_some()
}
}

View File

@ -163,10 +163,10 @@ impl TypeMap<'ll, 'tcx> {
fn get_unique_type_id_of_type<'a>(&mut self, cx: &CodegenCx<'a, 'tcx>,
type_: Ty<'tcx>) -> UniqueTypeId {
// Let's see if we already have something in the cache
match self.type_to_unique_id.get(&type_).cloned() {
Some(unique_type_id) => return unique_type_id,
None => { /* generate one */}
};
if let Some(unique_type_id) = self.type_to_unique_id.get(&type_).cloned() {
return unique_type_id;
}
// if not, generate one
// The hasher we are using to generate the UniqueTypeId. We want
// something that provides more than the 64 bits of the DefaultHasher.
@ -286,11 +286,11 @@ impl RecursiveTypeDescription<'ll, 'tcx> {
// unique id can be found in the type map
macro_rules! return_if_metadata_created_in_meantime {
($cx: expr, $unique_type_id: expr) => (
match debug_context($cx).type_map
.borrow()
.find_metadata_for_unique_id($unique_type_id) {
Some(metadata) => return MetadataCreationResult::new(metadata, true),
None => { /* proceed normally */ }
if let Some(metadata) = debug_context($cx).type_map
.borrow()
.find_metadata_for_unique_id($unique_type_id)
{
return MetadataCreationResult::new(metadata, true);
}
)
}
@ -352,7 +352,7 @@ fn vec_slice_metadata(
let member_descriptions = vec![
MemberDescription {
name: "data_ptr".to_string(),
name: "data_ptr".to_owned(),
type_metadata: data_ptr_metadata,
offset: Size::ZERO,
size: pointer_size,
@ -360,7 +360,7 @@ fn vec_slice_metadata(
flags: DIFlags::FlagZero,
},
MemberDescription {
name: "length".to_string(),
name: "length".to_owned(),
type_metadata: type_metadata(cx, cx.tcx.types.usize, span),
offset: pointer_size,
size: usize_size,
@ -458,7 +458,7 @@ fn trait_pointer_metadata(
let vtable_field = layout.field(cx, 1);
let member_descriptions = vec![
MemberDescription {
name: "pointer".to_string(),
name: "pointer".to_owned(),
type_metadata: type_metadata(cx,
cx.tcx.mk_mut_ptr(cx.tcx.types.u8),
syntax_pos::DUMMY_SP),
@ -468,7 +468,7 @@ fn trait_pointer_metadata(
flags: DIFlags::FlagArtificial,
},
MemberDescription {
name: "vtable".to_string(),
name: "vtable".to_owned(),
type_metadata: type_metadata(cx, vtable_field.ty, syntax_pos::DUMMY_SP),
offset: layout.fields.offset(1),
size: vtable_field.size,
@ -543,12 +543,12 @@ pub fn type_metadata(
_ => {
let pointee_metadata = type_metadata(cx, ty, usage_site_span);
match debug_context(cx).type_map
.borrow()
.find_metadata_for_unique_id(unique_type_id) {
Some(metadata) => return Err(metadata),
None => { /* proceed normally */ }
};
if let Some(metadata) = debug_context(cx).type_map
.borrow()
.find_metadata_for_unique_id(unique_type_id)
{
return Err(metadata);
}
Ok(MetadataCreationResult::new(pointer_type_metadata(cx, t, pointee_metadata),
false))
@ -577,12 +577,12 @@ pub fn type_metadata(
}
ty::Dynamic(..) => {
MetadataCreationResult::new(
trait_pointer_metadata(cx, t, None, unique_type_id),
false)
trait_pointer_metadata(cx, t, None, unique_type_id),
false)
}
ty::Foreign(..) => {
MetadataCreationResult::new(
foreign_type_metadata(cx, t, unique_type_id),
foreign_type_metadata(cx, t, unique_type_id),
false)
}
ty::RawPtr(ty::TypeAndMut{ty, ..}) |
@ -603,12 +603,12 @@ pub fn type_metadata(
unique_type_id,
t.fn_sig(cx.tcx),
usage_site_span).metadata;
match debug_context(cx).type_map
.borrow()
.find_metadata_for_unique_id(unique_type_id) {
Some(metadata) => return metadata,
None => { /* proceed normally */ }
};
if let Some(metadata) = debug_context(cx).type_map
.borrow()
.find_metadata_for_unique_id(unique_type_id)
{
return metadata;
}
// This is actually a function pointer, so wrap it in pointer DI
MetadataCreationResult::new(pointer_type_metadata(cx, t, fn_metadata), false)
@ -641,16 +641,16 @@ pub fn type_metadata(
}
AdtKind::Union => {
prepare_union_metadata(cx,
t,
unique_type_id,
usage_site_span).finalize(cx)
t,
unique_type_id,
usage_site_span).finalize(cx)
}
AdtKind::Enum => {
prepare_enum_metadata(cx,
t,
def.did,
unique_type_id,
usage_site_span).finalize(cx)
t,
def.did,
unique_type_id,
usage_site_span).finalize(cx)
}
},
ty::Tuple(ref elements) => {
@ -938,7 +938,7 @@ enum MemberDescriptionFactory<'ll, 'tcx> {
impl MemberDescriptionFactory<'ll, 'tcx> {
fn create_member_descriptions(&self, cx: &CodegenCx<'ll, 'tcx>)
-> Vec<MemberDescription<'ll>> {
-> Vec<MemberDescription<'ll>> {
match *self {
StructMDF(ref this) => {
this.create_member_descriptions(cx)
@ -972,7 +972,7 @@ struct StructMemberDescriptionFactory<'tcx> {
impl<'tcx> StructMemberDescriptionFactory<'tcx> {
fn create_member_descriptions(&self, cx: &CodegenCx<'ll, 'tcx>)
-> Vec<MemberDescription<'ll>> {
-> Vec<MemberDescription<'ll>> {
let layout = cx.layout_of(self.ty);
self.variant.fields.iter().enumerate().map(|(i, f)| {
let name = if self.variant.ctor_kind == CtorKind::Fn {
@ -1042,7 +1042,7 @@ struct TupleMemberDescriptionFactory<'tcx> {
impl<'tcx> TupleMemberDescriptionFactory<'tcx> {
fn create_member_descriptions(&self, cx: &CodegenCx<'ll, 'tcx>)
-> Vec<MemberDescription<'ll>> {
-> Vec<MemberDescription<'ll>> {
let layout = cx.layout_of(self.ty);
self.component_types.iter().enumerate().map(|(i, &component_type)| {
let (size, align) = cx.size_and_align_of(component_type);
@ -1096,7 +1096,7 @@ struct UnionMemberDescriptionFactory<'tcx> {
impl<'tcx> UnionMemberDescriptionFactory<'tcx> {
fn create_member_descriptions(&self, cx: &CodegenCx<'ll, 'tcx>)
-> Vec<MemberDescription<'ll>> {
-> Vec<MemberDescription<'ll>> {
self.variant.fields.iter().enumerate().map(|(i, f)| {
let field = self.layout.field(cx, i);
let (size, align) = field.size_and_align();
@ -1165,7 +1165,7 @@ struct EnumMemberDescriptionFactory<'ll, 'tcx> {
impl EnumMemberDescriptionFactory<'ll, 'tcx> {
fn create_member_descriptions(&self, cx: &CodegenCx<'ll, 'tcx>)
-> Vec<MemberDescription<'ll>> {
-> Vec<MemberDescription<'ll>> {
let adt = &self.enum_type.ty_adt_def().unwrap();
match self.layout.variants {
layout::Variants::Single { .. } if adt.variants.is_empty() => vec![],
@ -1357,7 +1357,7 @@ fn describe_enum_variant(
// We have the layout of an enum variant, we need the layout of the outer enum
let enum_layout = cx.layout_of(layout.ty);
(Some(enum_layout.fields.offset(0)),
Some(("RUST$ENUM$DISR".to_string(), enum_layout.field(cx, 0).ty)))
Some(("RUST$ENUM$DISR".to_owned(), enum_layout.field(cx, 0).ty)))
}
_ => (None, None),
};
@ -1471,9 +1471,8 @@ fn prepare_enum_metadata(
}
};
match (&layout.abi, discriminant_type_metadata) {
(&layout::Abi::Scalar(_), Some(discr)) => return FinalMetadata(discr),
_ => {}
if let (&layout::Abi::Scalar(_), Some(discr)) = (&layout.abi, discriminant_type_metadata) {
return FinalMetadata(discr);
}
let (enum_type_size, enum_type_align) = layout.size_and_align();
@ -1546,7 +1545,7 @@ fn composite_type_metadata(
composite_type_metadata,
member_descriptions);
return composite_type_metadata;
composite_type_metadata
}
fn set_members_of_composite_type(cx: &CodegenCx<'ll, '_>,
@ -1634,7 +1633,7 @@ fn create_struct_stub(
unique_type_id.as_ptr())
};
return metadata_stub;
metadata_stub
}
fn create_union_stub(
@ -1670,7 +1669,7 @@ fn create_union_stub(
unique_type_id.as_ptr())
};
return metadata_stub;
metadata_stub
}
/// Creates debug information for the given global variable.

View File

@ -271,16 +271,14 @@ pub fn create_function_debug_context(
let mut flags = DIFlags::FlagPrototyped;
let local_id = cx.tcx.hir.as_local_node_id(def_id);
match *cx.sess().entry_fn.borrow() {
Some((id, _, _)) => {
if local_id == Some(id) {
flags = flags | DIFlags::FlagMainSubprogram;
}
if let Some((id, _, _)) = *cx.sess().entry_fn.borrow() {
if local_id == Some(id) {
flags |= DIFlags::FlagMainSubprogram;
}
None => {}
};
}
if cx.layout_of(sig.output()).abi.is_uninhabited() {
flags = flags | DIFlags::FlagNoReturn;
flags |= DIFlags::FlagNoReturn;
}
let fn_metadata = unsafe {
@ -371,7 +369,7 @@ pub fn create_function_debug_context(
}
}
return create_DIArray(DIB(cx), &signature[..]);
create_DIArray(DIB(cx), &signature[..])
}
fn get_template_parameters(
@ -428,7 +426,7 @@ pub fn create_function_debug_context(
vec![]
};
return create_DIArray(DIB(cx), &template_params[..]);
create_DIArray(DIB(cx), &template_params[..])
}
fn get_parameter_names(cx: &CodegenCx,

View File

@ -56,11 +56,8 @@ pub fn set_source_location(
/// switches source location emitting on and must therefore be called before the
/// first real statement/expression of the function is codegened.
pub fn start_emitting_source_locations(dbg_context: &FunctionDebugContext<'ll>) {
match *dbg_context {
FunctionDebugContext::RegularContext(ref data) => {
data.source_locations_enabled.set(true)
},
_ => { /* safe to ignore */ }
if let FunctionDebugContext::RegularContext(ref data) = *dbg_context {
data.source_locations_enabled.set(true);
}
}

View File

@ -177,7 +177,7 @@ pub fn push_debuginfo_type_name<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>,
ty::GeneratorWitness(..) |
ty::Param(_) => {
bug!("debuginfo: Trying to create type name for \
unexpected type: {:?}", t);
unexpected type: {:?}", t);
}
}

View File

@ -40,7 +40,7 @@ impl ArchiveRO {
return unsafe {
let s = path2cstr(dst);
let ar = super::LLVMRustOpenArchive(s.as_ptr()).ok_or_else(|| {
super::last_error().unwrap_or("failed to open archive".to_string())
super::last_error().unwrap_or("failed to open archive".to_owned())
})?;
Ok(ArchiveRO { raw: ar })
};

View File

@ -1212,8 +1212,8 @@ extern "C" {
Dialect: AsmDialect)
-> &Value;
pub fn LLVMRustInlineAsmVerify(Ty: &Type,
Constraints: *const c_char)
-> Bool;
Constraints: *const c_char)
-> bool;
pub fn LLVMRustDebugMetadataVersion() -> u32;
pub fn LLVMRustVersionMajor() -> u32;

View File

@ -94,6 +94,10 @@ pub fn get_vtable(
});
let (size, align) = cx.size_and_align_of(ty);
// /////////////////////////////////////////////////////////////////////////////////////////////
// If you touch this code, be sure to also make the corresponding changes to
// `get_vtable` in rust_mir/interpret/traits.rs
// /////////////////////////////////////////////////////////////////////////////////////////////
let components: Vec<_> = [
callee::get_fn(cx, monomorphize::resolve_drop_in_place(cx.tcx, ty)),
C_usize(cx, size.bytes()),

View File

@ -125,10 +125,10 @@ impl FunctionCx<'a, 'll, 'tcx> {
this.unreachable_block()
};
let invokeret = bx.invoke(fn_ptr,
&llargs,
ret_bx,
llblock(this, cleanup),
cleanup_bundle);
&llargs,
ret_bx,
llblock(this, cleanup),
cleanup_bundle);
fn_ty.apply_attrs_callsite(&bx, invokeret);
if let Some((ret_dest, target)) = destination {
@ -213,7 +213,8 @@ impl FunctionCx<'a, 'll, 'tcx> {
} else {
let (otherwise, targets) = targets.split_last().unwrap();
let switch = bx.switch(discr.immediate(),
llblock(self, *otherwise), values.len());
llblock(self, *otherwise),
values.len());
let switch_llty = bx.cx.layout_of(switch_ty).immediate_llvm_type(bx.cx);
for (&value, target) in values.iter().zip(targets) {
let llval = C_uint_big(switch_llty, value);
@ -387,8 +388,8 @@ impl FunctionCx<'a, 'll, 'tcx> {
let msg_str = Symbol::intern(str).as_str();
let msg_str = C_str_slice(bx.cx, msg_str);
let msg_file_line_col = C_struct(bx.cx,
&[msg_str, filename, line, col],
false);
&[msg_str, filename, line, col],
false);
let msg_file_line_col = consts::addr_of(bx.cx,
msg_file_line_col,
align,
@ -509,8 +510,8 @@ impl FunctionCx<'a, 'll, 'tcx> {
let msg_str = Symbol::intern(&str).as_str();
let msg_str = C_str_slice(bx.cx, msg_str);
let msg_file_line_col = C_struct(bx.cx,
&[msg_str, filename, line, col],
false);
&[msg_str, filename, line, col],
false);
let msg_file_line_col = consts::addr_of(bx.cx,
msg_file_line_col,
align,
@ -619,7 +620,7 @@ impl FunctionCx<'a, 'll, 'tcx> {
let callee_ty = instance.as_ref().unwrap().ty(bx.cx.tcx);
codegen_intrinsic_call(&bx, callee_ty, &fn_ty, &args, dest,
terminator.source_info.span);
terminator.source_info.span);
if let ReturnDest::IndirectOperand(dst, _) = ret_dest {
self.store_return(&bx, ret_dest, &fn_ty.ret, dst.llval);
@ -756,7 +757,7 @@ impl FunctionCx<'a, 'll, 'tcx> {
// Have to load the argument, maybe while casting it.
if let PassMode::Cast(ty) = arg.mode {
llval = bx.load(bx.pointercast(llval, ty.llvm_type(bx.cx).ptr_to()),
align.min(arg.layout.align));
align.min(arg.layout.align));
} else {
// We can't use `PlaceRef::load` here because the argument
// may have a type we don't treat as immediate, but the ABI
@ -778,10 +779,10 @@ impl FunctionCx<'a, 'll, 'tcx> {
}
fn codegen_arguments_untupled(&mut self,
bx: &Builder<'a, 'll, 'tcx>,
operand: &mir::Operand<'tcx>,
llargs: &mut Vec<&'ll Value>,
args: &[ArgType<'tcx, Ty<'tcx>>]) {
bx: &Builder<'a, 'll, 'tcx>,
operand: &mir::Operand<'tcx>,
llargs: &mut Vec<&'ll Value>,
args: &[ArgType<'tcx, Ty<'tcx>>]) {
let tuple = self.codegen_operand(bx, operand);
// Handle both by-ref and immediate tuples.
@ -933,8 +934,8 @@ impl FunctionCx<'a, 'll, 'tcx> {
}
fn codegen_transmute(&mut self, bx: &Builder<'a, 'll, 'tcx>,
src: &mir::Operand<'tcx>,
dst: &mir::Place<'tcx>) {
src: &mir::Operand<'tcx>,
dst: &mir::Place<'tcx>) {
if let mir::Place::Local(index) = *dst {
match self.locals[index] {
LocalRef::Place(place) => self.codegen_transmute_into(bx, src, place),
@ -961,8 +962,8 @@ impl FunctionCx<'a, 'll, 'tcx> {
}
fn codegen_transmute_into(&mut self, bx: &Builder<'a, 'll, 'tcx>,
src: &mir::Operand<'tcx>,
dst: PlaceRef<'ll, 'tcx>) {
src: &mir::Operand<'tcx>,
dst: PlaceRef<'ll, 'tcx>) {
let src = self.codegen_operand(bx, src);
let llty = src.layout.llvm_type(bx.cx);
let cast_ptr = bx.pointercast(dst.llval, llty.ptr_to());

View File

@ -162,16 +162,16 @@ impl FunctionCx<'a, 'll, 'tcx> {
// corresponding to span's containing source scope. If so, we need to create a DIScope
// "extension" into that file.
fn scope_metadata_for_loc(&self, scope_id: mir::SourceScope, pos: BytePos)
-> Option<&'ll DIScope> {
-> Option<&'ll DIScope> {
let scope_metadata = self.scopes[scope_id].scope_metadata;
if pos < self.scopes[scope_id].file_start_pos ||
pos >= self.scopes[scope_id].file_end_pos {
let cm = self.cx.sess().source_map();
let defining_crate = self.debug_context.get_ref(DUMMY_SP).defining_crate;
Some(debuginfo::extend_scope_to_file(self.cx,
scope_metadata.unwrap(),
&cm.lookup_char_pos(pos).file,
defining_crate))
scope_metadata.unwrap(),
&cm.lookup_char_pos(pos).file,
defining_crate))
} else {
scope_metadata
}

View File

@ -423,15 +423,6 @@ pub enum HybridBitSet<T: Idx> {
}
impl<T: Idx> HybridBitSet<T> {
// FIXME: This function is used in conjunction with `mem::replace()` in
// several pieces of awful code below. I can't work out how else to appease
// the borrow checker.
fn dummy() -> Self {
// The cheapest HybridBitSet to construct, which is only used to get
// around the borrow checker.
HybridBitSet::Sparse(SparseBitSet::new_empty(0))
}
pub fn new_empty(domain_size: usize) -> Self {
HybridBitSet::Sparse(SparseBitSet::new_empty(domain_size))
}
@ -487,20 +478,14 @@ impl<T: Idx> HybridBitSet<T> {
// that doesn't matter because `elem` is already present.
false
}
HybridBitSet::Sparse(_) => {
HybridBitSet::Sparse(sparse) => {
// The set is sparse and full. Convert to a dense set.
match mem::replace(self, HybridBitSet::dummy()) {
HybridBitSet::Sparse(sparse) => {
let mut dense = sparse.to_dense();
let changed = dense.insert(elem);
assert!(changed);
*self = HybridBitSet::Dense(dense);
changed
}
_ => unreachable!()
}
let mut dense = sparse.to_dense();
let changed = dense.insert(elem);
assert!(changed);
*self = HybridBitSet::Dense(dense);
changed
}
HybridBitSet::Dense(dense) => dense.insert(elem),
}
}
@ -525,33 +510,26 @@ impl<T: Idx> HybridBitSet<T> {
pub fn union(&mut self, other: &HybridBitSet<T>) -> bool {
match self {
HybridBitSet::Sparse(_) => {
HybridBitSet::Sparse(self_sparse) => {
match other {
HybridBitSet::Sparse(other_sparse) => {
// Both sets are sparse. Add the elements in
// `other_sparse` to `self_hybrid` one at a time. This
// may or may not cause `self_hybrid` to be densified.
// `other_sparse` to `self` one at a time. This
// may or may not cause `self` to be densified.
assert_eq!(self.domain_size(), other.domain_size());
let mut self_hybrid = mem::replace(self, HybridBitSet::dummy());
let mut changed = false;
for elem in other_sparse.iter() {
changed |= self_hybrid.insert(*elem);
changed |= self.insert(*elem);
}
*self = self_hybrid;
changed
}
HybridBitSet::Dense(other_dense) => {
// `self` is sparse and `other` is dense. Densify
// `self` and then do the bitwise union.
match mem::replace(self, HybridBitSet::dummy()) {
HybridBitSet::Sparse(self_sparse) => {
let mut new_dense = self_sparse.to_dense();
let changed = new_dense.union(other_dense);
*self = HybridBitSet::Dense(new_dense);
changed
}
_ => unreachable!()
}
let mut new_dense = self_sparse.to_dense();
let changed = new_dense.union(other_dense);
*self = HybridBitSet::Dense(new_dense);
changed
}
}
}

View File

@ -92,12 +92,12 @@ impl<'tcx> fmt::Display for BorrowData<'tcx> {
mir::BorrowKind::Mut { .. } => "mut ",
};
let region = self.region.to_string();
let region = if region.len() > 0 {
format!("{} ", region)
let separator = if !region.is_empty() {
" "
} else {
region
""
};
write!(w, "&{}{}{:?}", region, kind, self.borrowed_place)
write!(w, "&{}{}{}{:?}", region, separator, kind, self.borrowed_place)
}
}
@ -244,7 +244,7 @@ impl<'a, 'gcx, 'tcx> Visitor<'tcx> for GatherBorrows<'a, 'gcx, 'tcx> {
K: Clone + Eq + Hash,
V: Eq + Hash,
{
map.entry(k.clone()).or_insert(FxHashSet()).insert(v);
map.entry(k.clone()).or_default().insert(v);
}
}
@ -261,57 +261,53 @@ impl<'a, 'gcx, 'tcx> Visitor<'tcx> for GatherBorrows<'a, 'gcx, 'tcx> {
// ... check whether we (earlier) saw a 2-phase borrow like
//
// TMP = &mut place
match self.pending_activations.get(temp) {
Some(&borrow_index) => {
let borrow_data = &mut self.idx_vec[borrow_index];
if let Some(&borrow_index) = self.pending_activations.get(temp) {
let borrow_data = &mut self.idx_vec[borrow_index];
// Watch out: the use of TMP in the borrow itself
// doesn't count as an activation. =)
if borrow_data.reserve_location == location && context == PlaceContext::Store {
return;
}
if let TwoPhaseActivation::ActivatedAt(other_location) =
borrow_data.activation_location {
span_bug!(
self.mir.source_info(location).span,
"found two uses for 2-phase borrow temporary {:?}: \
{:?} and {:?}",
temp,
location,
other_location,
);
}
// Otherwise, this is the unique later use
// that we expect.
borrow_data.activation_location = match context {
// The use of TMP in a shared borrow does not
// count as an actual activation.
PlaceContext::Borrow { kind: mir::BorrowKind::Shared, .. }
| PlaceContext::Borrow { kind: mir::BorrowKind::Shallow, .. } => {
TwoPhaseActivation::NotActivated
}
_ => {
// Double check: This borrow is indeed a two-phase borrow (that is,
// we are 'transitioning' from `NotActivated` to `ActivatedAt`) and
// we've not found any other activations (checked above).
assert_eq!(
borrow_data.activation_location,
TwoPhaseActivation::NotActivated,
"never found an activation for this borrow!",
);
self.activation_map
.entry(location)
.or_default()
.push(borrow_index);
TwoPhaseActivation::ActivatedAt(location)
}
};
// Watch out: the use of TMP in the borrow itself
// doesn't count as an activation. =)
if borrow_data.reserve_location == location && context == PlaceContext::Store {
return;
}
None => {}
if let TwoPhaseActivation::ActivatedAt(other_location) =
borrow_data.activation_location {
span_bug!(
self.mir.source_info(location).span,
"found two uses for 2-phase borrow temporary {:?}: \
{:?} and {:?}",
temp,
location,
other_location,
);
}
// Otherwise, this is the unique later use
// that we expect.
borrow_data.activation_location = match context {
// The use of TMP in a shared borrow does not
// count as an actual activation.
PlaceContext::Borrow { kind: mir::BorrowKind::Shared, .. }
| PlaceContext::Borrow { kind: mir::BorrowKind::Shallow, .. } => {
TwoPhaseActivation::NotActivated
}
_ => {
// Double check: This borrow is indeed a two-phase borrow (that is,
// we are 'transitioning' from `NotActivated` to `ActivatedAt`) and
// we've not found any other activations (checked above).
assert_eq!(
borrow_data.activation_location,
TwoPhaseActivation::NotActivated,
"never found an activation for this borrow!",
);
self.activation_map
.entry(location)
.or_default()
.push(borrow_index);
TwoPhaseActivation::ActivatedAt(location)
}
};
}
}
}

View File

@ -77,9 +77,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
if move_out_indices.is_empty() {
let root_place = self.prefixes(&used_place, PrefixSet::All).last().unwrap();
if self.uninitialized_error_reported
.contains(&root_place.clone())
{
if self.uninitialized_error_reported.contains(root_place) {
debug!(
"report_use_of_moved_or_uninitialized place: error about {:?} suppressed",
root_place
@ -188,11 +186,8 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
let tables = self.infcx.tcx.typeck_tables_of(id);
let node_id = self.infcx.tcx.hir.as_local_node_id(id).unwrap();
let hir_id = self.infcx.tcx.hir.node_to_hir_id(node_id);
if tables.closure_kind_origins().get(hir_id).is_some() {
false
} else {
true
}
tables.closure_kind_origins().get(hir_id).is_none()
}
_ => true,
};
@ -582,7 +577,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
fn report_local_value_does_not_live_long_enough(
&mut self,
context: Context,
name: &String,
name: &str,
scope_tree: &Lrc<ScopeTree>,
borrow: &BorrowData<'tcx>,
drop_span: Span,
@ -1195,10 +1190,8 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
Place::Static(ref static_) => self.describe_field_from_ty(&static_.ty, field),
Place::Projection(ref proj) => match proj.elem {
ProjectionElem::Deref => self.describe_field(&proj.base, field),
ProjectionElem::Downcast(def, variant_index) => format!(
"{}",
def.variants[variant_index].fields[field.index()].ident
),
ProjectionElem::Downcast(def, variant_index) =>
def.variants[variant_index].fields[field.index()].ident.to_string(),
ProjectionElem::Field(_, field_type) => {
self.describe_field_from_ty(&field_type, field)
}
@ -1366,191 +1359,184 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
"annotate_argument_and_return_for_borrow: location={:?}",
location
);
match &self.mir[location.block]
.statements
.get(location.statement_index)
if let Some(&Statement { kind: StatementKind::Assign(ref reservation, _), ..})
= &self.mir[location.block].statements.get(location.statement_index)
{
Some(&Statement {
kind: StatementKind::Assign(ref reservation, _),
..
}) => {
debug!(
"annotate_argument_and_return_for_borrow: reservation={:?}",
reservation
);
// Check that the initial assignment of the reserve location is into a temporary.
let mut target = *match reservation {
Place::Local(local) if self.mir.local_kind(*local) == LocalKind::Temp => local,
_ => return None,
};
// Next, look through the rest of the block, checking if we are assigning the
// `target` (that is, the place that contains our borrow) to anything.
let mut annotated_closure = None;
for stmt in &self.mir[location.block].statements[location.statement_index + 1..] {
debug!(
"annotate_argument_and_return_for_borrow: reservation={:?}",
reservation
"annotate_argument_and_return_for_borrow: target={:?} stmt={:?}",
target, stmt
);
// Check that the initial assignment of the reserve location is into a temporary.
let mut target = *match reservation {
Place::Local(local) if self.mir.local_kind(*local) == LocalKind::Temp => local,
_ => return None,
};
// Next, look through the rest of the block, checking if we are assigning the
// `target` (that is, the place that contains our borrow) to anything.
let mut annotated_closure = None;
for stmt in &self.mir[location.block].statements[location.statement_index + 1..] {
if let StatementKind::Assign(Place::Local(assigned_to), box rvalue) = &stmt.kind
{
debug!(
"annotate_argument_and_return_for_borrow: target={:?} stmt={:?}",
target, stmt
"annotate_argument_and_return_for_borrow: assigned_to={:?} \
rvalue={:?}",
assigned_to, rvalue
);
if let StatementKind::Assign(Place::Local(assigned_to), box rvalue) = &stmt.kind
// Check if our `target` was captured by a closure.
if let Rvalue::Aggregate(
box AggregateKind::Closure(def_id, substs),
operands,
) = rvalue
{
debug!(
"annotate_argument_and_return_for_borrow: assigned_to={:?} \
rvalue={:?}",
assigned_to, rvalue
);
// Check if our `target` was captured by a closure.
if let Rvalue::Aggregate(
box AggregateKind::Closure(def_id, substs),
operands,
) = rvalue
{
for operand in operands {
let assigned_from = match operand {
Operand::Copy(assigned_from) | Operand::Move(assigned_from) => {
assigned_from
}
_ => continue,
};
debug!(
"annotate_argument_and_return_for_borrow: assigned_from={:?}",
assigned_from
);
// Find the local from the operand.
let assigned_from_local = match assigned_from.local() {
Some(local) => local,
None => continue,
};
if assigned_from_local != target {
continue;
}
// If a closure captured our `target` and then assigned
// into a place then we should annotate the closure in
// case it ends up being assigned into the return place.
annotated_closure = self.annotate_fn_sig(
*def_id,
self.infcx.closure_sig(*def_id, *substs),
);
debug!(
"annotate_argument_and_return_for_borrow: \
annotated_closure={:?} assigned_from_local={:?} \
assigned_to={:?}",
annotated_closure, assigned_from_local, assigned_to
);
if *assigned_to == mir::RETURN_PLACE {
// If it was assigned directly into the return place, then
// return now.
return annotated_closure;
} else {
// Otherwise, update the target.
target = *assigned_to;
}
}
// If none of our closure's operands matched, then skip to the next
// statement.
continue;
}
// Otherwise, look at other types of assignment.
let assigned_from = match rvalue {
Rvalue::Ref(_, _, assigned_from) => assigned_from,
Rvalue::Use(operand) => match operand {
for operand in operands {
let assigned_from = match operand {
Operand::Copy(assigned_from) | Operand::Move(assigned_from) => {
assigned_from
}
_ => continue,
},
_ => continue,
};
debug!(
"annotate_argument_and_return_for_borrow: \
assigned_from={:?}",
assigned_from,
);
};
debug!(
"annotate_argument_and_return_for_borrow: assigned_from={:?}",
assigned_from
);
// Find the local from the rvalue.
let assigned_from_local = match assigned_from.local() {
Some(local) => local,
None => continue,
};
debug!(
"annotate_argument_and_return_for_borrow: \
assigned_from_local={:?}",
assigned_from_local,
);
// Find the local from the operand.
let assigned_from_local = match assigned_from.local() {
Some(local) => local,
None => continue,
};
// Check if our local matches the target - if so, we've assigned our
// borrow to a new place.
if assigned_from_local != target {
continue;
if assigned_from_local != target {
continue;
}
// If a closure captured our `target` and then assigned
// into a place then we should annotate the closure in
// case it ends up being assigned into the return place.
annotated_closure = self.annotate_fn_sig(
*def_id,
self.infcx.closure_sig(*def_id, *substs),
);
debug!(
"annotate_argument_and_return_for_borrow: \
annotated_closure={:?} assigned_from_local={:?} \
assigned_to={:?}",
annotated_closure, assigned_from_local, assigned_to
);
if *assigned_to == mir::RETURN_PLACE {
// If it was assigned directly into the return place, then
// return now.
return annotated_closure;
} else {
// Otherwise, update the target.
target = *assigned_to;
}
}
// If we assigned our `target` into a new place, then we should
// check if it was the return place.
debug!(
"annotate_argument_and_return_for_borrow: \
assigned_from_local={:?} assigned_to={:?}",
assigned_from_local, assigned_to
);
if *assigned_to == mir::RETURN_PLACE {
// If it was then return the annotated closure if there was one,
// else, annotate this function.
return annotated_closure.or_else(fallback);
}
// If we didn't assign into the return place, then we just update
// the target.
target = *assigned_to;
// If none of our closure's operands matched, then skip to the next
// statement.
continue;
}
}
// Check the terminator if we didn't find anything in the statements.
let terminator = &self.mir[location.block].terminator();
debug!(
"annotate_argument_and_return_for_borrow: target={:?} terminator={:?}",
target, terminator
);
if let TerminatorKind::Call {
destination: Some((Place::Local(assigned_to), _)),
args,
..
} = &terminator.kind
{
debug!(
"annotate_argument_and_return_for_borrow: assigned_to={:?} args={:?}",
assigned_to, args
);
for operand in args {
let assigned_from = match operand {
// Otherwise, look at other types of assignment.
let assigned_from = match rvalue {
Rvalue::Ref(_, _, assigned_from) => assigned_from,
Rvalue::Use(operand) => match operand {
Operand::Copy(assigned_from) | Operand::Move(assigned_from) => {
assigned_from
}
_ => continue,
};
},
_ => continue,
};
debug!(
"annotate_argument_and_return_for_borrow: \
assigned_from={:?}",
assigned_from,
);
// Find the local from the rvalue.
let assigned_from_local = match assigned_from.local() {
Some(local) => local,
None => continue,
};
debug!(
"annotate_argument_and_return_for_borrow: \
assigned_from_local={:?}",
assigned_from_local,
);
// Check if our local matches the target - if so, we've assigned our
// borrow to a new place.
if assigned_from_local != target {
continue;
}
// If we assigned our `target` into a new place, then we should
// check if it was the return place.
debug!(
"annotate_argument_and_return_for_borrow: \
assigned_from_local={:?} assigned_to={:?}",
assigned_from_local, assigned_to
);
if *assigned_to == mir::RETURN_PLACE {
// If it was then return the annotated closure if there was one,
// else, annotate this function.
return annotated_closure.or_else(fallback);
}
// If we didn't assign into the return place, then we just update
// the target.
target = *assigned_to;
}
}
// Check the terminator if we didn't find anything in the statements.
let terminator = &self.mir[location.block].terminator();
debug!(
"annotate_argument_and_return_for_borrow: target={:?} terminator={:?}",
target, terminator
);
if let TerminatorKind::Call {
destination: Some((Place::Local(assigned_to), _)),
args,
..
} = &terminator.kind
{
debug!(
"annotate_argument_and_return_for_borrow: assigned_to={:?} args={:?}",
assigned_to, args
);
for operand in args {
let assigned_from = match operand {
Operand::Copy(assigned_from) | Operand::Move(assigned_from) => {
assigned_from
}
_ => continue,
};
debug!(
"annotate_argument_and_return_for_borrow: assigned_from={:?}",
assigned_from,
);
if let Some(assigned_from_local) = assigned_from.local() {
debug!(
"annotate_argument_and_return_for_borrow: assigned_from={:?}",
assigned_from,
"annotate_argument_and_return_for_borrow: assigned_from_local={:?}",
assigned_from_local,
);
if let Some(assigned_from_local) = assigned_from.local() {
debug!(
"annotate_argument_and_return_for_borrow: assigned_from_local={:?}",
assigned_from_local,
);
if *assigned_to == mir::RETURN_PLACE && assigned_from_local == target {
return annotated_closure.or_else(fallback);
}
if *assigned_to == mir::RETURN_PLACE && assigned_from_local == target {
return annotated_closure.or_else(fallback);
}
}
}
}
_ => {}
}
// If we haven't found an assignment into the return place, then we need not add
@ -1605,13 +1591,12 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
// Need to use the `rustc::ty` types to compare against the
// `return_region`. Then use the `rustc::hir` type to get only
// the lifetime span.
match &fn_decl.inputs[index].node {
hir::TyKind::Rptr(lifetime, _) => {
// With access to the lifetime, we can get
// the span of it.
arguments.push((*argument, lifetime.span));
}
_ => bug!("ty type is a ref but hir type is not"),
if let hir::TyKind::Rptr(lifetime, _) = &fn_decl.inputs[index].node {
// With access to the lifetime, we can get
// the span of it.
arguments.push((*argument, lifetime.span));
} else {
bug!("ty type is a ref but hir type is not");
}
}
}
@ -1794,8 +1779,8 @@ impl<'tcx> AnnotatedBorrowFnSignature<'tcx> {
ty::RegionKind::RePlaceholder(ty::Placeholder { name: br, .. }),
_,
_,
) => with_highlight_region_for_bound_region(*br, counter, || format!("{}", ty)),
_ => format!("{}", ty),
) => with_highlight_region_for_bound_region(*br, counter, || ty.to_string()),
_ => ty.to_string(),
}
}
@ -1806,9 +1791,9 @@ impl<'tcx> AnnotatedBorrowFnSignature<'tcx> {
ty::TyKind::Ref(region, _, _) => match region {
ty::RegionKind::ReLateBound(_, br)
| ty::RegionKind::RePlaceholder(ty::Placeholder { name: br, .. }) => {
with_highlight_region_for_bound_region(*br, counter, || format!("{}", region))
with_highlight_region_for_bound_region(*br, counter, || region.to_string())
}
_ => format!("{}", region),
_ => region.to_string(),
},
_ => bug!("ty for annotation of borrow region is not a reference"),
}

View File

@ -284,7 +284,7 @@ fn do_mir_borrowck<'a, 'gcx, 'tcx>(
let temporary_used_locals: FxHashSet<Local> = mbcx
.used_mut
.iter()
.filter(|&local| !mbcx.mir.local_decls[*local].is_user_variable.is_some())
.filter(|&local| mbcx.mir.local_decls[*local].is_user_variable.is_none())
.cloned()
.collect();
mbcx.gather_used_muts(temporary_used_locals);
@ -342,7 +342,7 @@ fn do_mir_borrowck<'a, 'gcx, 'tcx>(
diag.buffer(&mut mbcx.errors_buffer);
}
if mbcx.errors_buffer.len() > 0 {
if !mbcx.errors_buffer.is_empty() {
mbcx.errors_buffer.sort_by_key(|diag| diag.span.primary_span());
if tcx.migrate_borrowck() {
@ -1009,13 +1009,12 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
return Control::Continue;
}
error_reported = true;
match kind {
ReadKind::Copy => {
error_reported = true;
this.report_use_while_mutably_borrowed(context, place_span, borrow)
}
ReadKind::Borrow(bk) => {
error_reported = true;
this.report_conflicting_borrow(context, place_span, bk, &borrow)
}
}
@ -1045,13 +1044,12 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
Read(..) | Write(..) => {}
}
error_reported = true;
match kind {
WriteKind::MutableBorrow(bk) => {
error_reported = true;
this.report_conflicting_borrow(context, place_span, bk, &borrow)
}
WriteKind::StorageDeadOrDrop => {
error_reported = true;
this.report_borrowed_value_does_not_live_long_enough(
context,
borrow,
@ -1059,11 +1057,9 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
Some(kind))
}
WriteKind::Mutate => {
error_reported = true;
this.report_illegal_mutation_of_borrowed(context, place_span, borrow)
}
WriteKind::Move => {
error_reported = true;
this.report_move_out_while_borrowed(context, place_span, &borrow)
}
}
@ -1593,7 +1589,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
Place::Local(_) => panic!("should have move path for every Local"),
Place::Projection(_) => panic!("PrefixSet::All meant don't stop for Projection"),
Place::Promoted(_) |
Place::Static(_) => return Err(NoMovePathFound::ReachedStatic),
Place::Static(_) => Err(NoMovePathFound::ReachedStatic),
}
}
@ -1885,7 +1881,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
}
// at this point, we have set up the error reporting state.
if previously_initialized {
return if previously_initialized {
self.report_mutability_error(
place,
span,
@ -1893,10 +1889,10 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
error_access,
location,
);
return true;
true
} else {
return false;
}
false
};
}
fn is_local_ever_initialized(&self,
@ -1911,7 +1907,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
return Some(index);
}
}
return None;
None
}
/// Adds the place into the used mutable variables set
@ -2171,7 +2167,7 @@ impl ContextKind {
fn new(self, loc: Location) -> Context {
Context {
kind: self,
loc: loc,
loc,
}
}
}

View File

@ -331,7 +331,7 @@ impl<'a, 'gcx, 'tcx> MirBorrowckCtxt<'a, 'gcx, 'tcx> {
_ => {
let source = self.borrowed_content_source(place);
self.infcx.tcx.cannot_move_out_of(
span, &format!("{}", source), origin
span, &source.to_string(), origin
)
},
}
@ -469,9 +469,9 @@ impl<'a, 'gcx, 'tcx> MirBorrowckCtxt<'a, 'gcx, 'tcx> {
let binding_span = bind_to.source_info.span;
if j == 0 {
err.span_label(binding_span, format!("data moved here"));
err.span_label(binding_span, "data moved here");
} else {
err.span_label(binding_span, format!("...and here"));
err.span_label(binding_span, "...and here");
}
if binds_to.len() == 1 {

View File

@ -408,7 +408,6 @@ impl<'a, 'gcx, 'tcx> MirBorrowckCtxt<'a, 'gcx, 'tcx> {
.map(|replacement| (pattern_span, replacement))
}
//
ClearCrossCrate::Set(mir::BindingForm::RefForGuard) => unreachable!(),
ClearCrossCrate::Clear => bug!("saw cleared local state"),
@ -505,7 +504,7 @@ impl<'a, 'gcx, 'tcx> MirBorrowckCtxt<'a, 'gcx, 'tcx> {
);
let extra = if found {
String::from("")
String::new()
} else {
format!(", but it is not implemented for `{}`",
substs.type_at(0))
@ -573,7 +572,7 @@ fn suggest_ampmut<'cx, 'gcx, 'tcx>(
opt_ty_info: Option<Span>,
) -> (Span, String) {
let locations = mir.find_assignments(local);
if locations.len() > 0 {
if !locations.is_empty() {
let assignment_rhs_span = mir.source_info(locations[0]).span;
if let Ok(src) = tcx.sess.source_map().span_to_snippet(assignment_rhs_span) {
if let (true, Some(ws_pos)) = (
@ -584,7 +583,7 @@ fn suggest_ampmut<'cx, 'gcx, 'tcx>(
let ty = &src[ws_pos..];
return (assignment_rhs_span, format!("&{} mut {}", lt_name, ty));
} else if src.starts_with('&') {
let borrowed_expr = src[1..].to_string();
let borrowed_expr = &src[1..];
return (assignment_rhs_span, format!("&mut {}", borrowed_expr));
}
}

View File

@ -141,6 +141,7 @@ impl<'cg, 'cx, 'gcx, 'tcx> Visitor<'tcx> for ConstraintGeneration<'cg, 'cx, 'gcx
if let Some(all_facts) = self.all_facts {
if let Place::Local(temp) = place {
if let Some(borrow_indices) = self.borrow_set.local_map.get(temp) {
all_facts.killed.reserve(borrow_indices.len());
for &borrow_index in borrow_indices {
let location_index = self.location_table.mid_index(location);
all_facts.killed.push((borrow_index, location_index));
@ -164,7 +165,9 @@ impl<'cg, 'cx, 'gcx, 'tcx> Visitor<'tcx> for ConstraintGeneration<'cg, 'cx, 'gcx
self.location_table.mid_index(location),
));
for successor_block in terminator.successors() {
let successor_blocks = terminator.successors();
all_facts.cfg_edge.reserve(successor_blocks.size_hint().0);
for successor_block in successor_blocks {
all_facts.cfg_edge.push((
self.location_table.mid_index(location),
self.location_table

View File

@ -87,9 +87,9 @@ impl<'tcx> BorrowExplanation<'tcx> {
// Otherwise, just report the whole type (and use
// the intentionally fuzzy phrase "destructor")
ty::Closure(..) =>
("destructor", format!("closure")),
("destructor", "closure".to_owned()),
ty::Generator(..) =>
("destructor", format!("generator")),
("destructor", "generator".to_owned()),
_ => ("destructor", format!("type `{}`", local_decl.ty)),
};
@ -279,9 +279,8 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
pending_locations.push(target.start_location());
},
TerminatorKind::SwitchInt { ref targets, .. } => {
for target in targets {
pending_locations.push(target.start_location());
}
pending_locations.extend(
targets.into_iter().map(|target| target.start_location()));
},
TerminatorKind::Drop { target, unwind, .. } |
TerminatorKind::DropAndReplace { target, unwind, .. } |
@ -303,9 +302,8 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
},
TerminatorKind::FalseEdges { real_target, ref imaginary_targets, .. } => {
pending_locations.push(real_target.start_location());
for target in imaginary_targets {
pending_locations.push(target.start_location());
}
pending_locations.extend(
imaginary_targets.into_iter().map(|target| target.start_location()));
},
_ => {},
}
@ -441,17 +439,17 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
Operand::Move(Place::Local(from)) if *from == target => {
debug!("was_captured_by_trait_object: ty={:?}", ty);
// Check the type for a trait object.
match ty.sty {
return match ty.sty {
// `&dyn Trait`
ty::TyKind::Ref(_, ty, _) if ty.is_trait() => return true,
ty::TyKind::Ref(_, ty, _) if ty.is_trait() => true,
// `Box<dyn Trait>`
_ if ty.is_box() && ty.boxed_ty().is_trait() =>
return true,
true,
// `dyn Trait`
_ if ty.is_trait() => return true,
_ if ty.is_trait() => true,
// Anything else.
_ => return false,
}
_ => false,
};
},
_ => return false,
},
@ -466,32 +464,29 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
let terminator = block.terminator();
debug!("was_captured_by_trait_object: terminator={:?}", terminator);
match &terminator.kind {
TerminatorKind::Call {
destination: Some((Place::Local(dest), block)),
args,
..
} => {
debug!(
"was_captured_by_trait_object: target={:?} dest={:?} args={:?}",
target, dest, args
);
// Check if one of the arguments to this function is the target place.
let found_target = args.iter().any(|arg| {
if let Operand::Move(Place::Local(potential)) = arg {
*potential == target
} else {
false
}
});
// If it is, follow this to the next block and update the target.
if found_target {
target = *dest;
queue.push(block.start_location());
if let TerminatorKind::Call {
destination: Some((Place::Local(dest), block)),
args,
..
} = &terminator.kind {
debug!(
"was_captured_by_trait_object: target={:?} dest={:?} args={:?}",
target, dest, args
);
// Check if one of the arguments to this function is the target place.
let found_target = args.iter().any(|arg| {
if let Operand::Move(Place::Local(potential)) = arg {
*potential == target
} else {
false
}
},
_ => {},
});
// If it is, follow this to the next block and update the target.
if found_target {
target = *dest;
queue.push(block.start_location());
}
}
}

View File

@ -35,7 +35,7 @@ pub(super) fn generate_invalidates<'cx, 'gcx, 'tcx>(
mir: &Mir<'tcx>,
borrow_set: &BorrowSet<'tcx>,
) {
if !all_facts.is_some() {
if all_facts.is_none() {
// Nothing to do if we don't have any facts
return;
}

View File

@ -36,12 +36,12 @@ impl<'tcx> RegionInferenceContext<'tcx> {
let outlived_by = self.universal_region_relations.regions_outlived_by(region);
writeln!(
out,
"| {r:rw$} | {c:cw$} | {ob}",
r = format!("{:?}", region),
"| {r:rw$?} | {c:cw$?} | {ob:?}",
r = region,
rw = REGION_WIDTH,
c = format!("{:?}", classification),
c = classification,
cw = 8, // "External" at most
ob = format!("{:?}", outlived_by)
ob = outlived_by
)?;
}
}
@ -51,8 +51,8 @@ impl<'tcx> RegionInferenceContext<'tcx> {
for region in self.regions() {
writeln!(
out,
"| {r:rw$} | {ui:4?} | {v}",
r = format!("{:?}", region),
"| {r:rw$?} | {ui:4?} | {v}",
r = region,
rw = REGION_WIDTH,
ui = self.region_universe(region),
v = self.region_value_str(region),

View File

@ -550,7 +550,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
let span = infcx.tcx.def_span(*did);
if let Ok(snippet) = infcx.tcx.sess.source_map().span_to_snippet(span) {
let suggestable_fr_name = if fr_name.was_named() {
format!("{}", fr_name)
fr_name.to_string()
} else {
"'_".to_string()
};

View File

@ -462,9 +462,8 @@ impl<'tcx> RegionInferenceContext<'tcx> {
argument_hir_ty: &hir::Ty,
counter: &mut usize,
) -> Option<RegionName> {
let search_stack: &mut Vec<(Ty<'tcx>, &hir::Ty)> = &mut Vec::new();
search_stack.push((argument_ty, argument_hir_ty));
let search_stack: &mut Vec<(Ty<'tcx>, &hir::Ty)> =
&mut vec![(argument_ty, argument_hir_ty)];
while let Some((ty, hir_ty)) = search_stack.pop() {
match (&ty.sty, &hir_ty.node) {
@ -567,10 +566,10 @@ impl<'tcx> RegionInferenceContext<'tcx> {
| hir::LifetimeName::Underscore => {
let region_name = self.synthesize_region_name(counter);
let ampersand_span = lifetime.span;
return Some(RegionName {
Some(RegionName {
name: region_name,
source: RegionNameSource::MatchedAdtAndSegment(ampersand_span),
});
})
}
hir::LifetimeName::Implicit => {
@ -585,7 +584,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
// T>`. We don't consider this a match; instead we let
// the "fully elaborated" type fallback above handle
// it.
return None;
None
}
}
}

View File

@ -327,12 +327,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M>
}
(_, &ty::Dynamic(ref data, _)) => {
// Initial cast from sized to dyn trait
let trait_ref = data.principal().with_self_ty(
*self.tcx,
src_pointee_ty,
);
let trait_ref = self.tcx.erase_regions(&trait_ref);
let vtable = self.get_vtable(src_pointee_ty, trait_ref)?;
let vtable = self.get_vtable(src_pointee_ty, data.principal())?;
let ptr = self.read_value(src)?.to_scalar_ptr()?;
let val = Value::new_dyn_trait(ptr, vtable);
self.write_value(val, dest)

View File

@ -27,6 +27,7 @@ use rustc::mir::interpret::{
EvalResult, EvalErrorKind,
truncate, sign_extend,
};
use rustc_data_structures::fx::FxHashMap;
use syntax::source_map::{self, Span};
@ -50,6 +51,9 @@ pub struct EvalContext<'a, 'mir, 'tcx: 'a + 'mir, M: Machine<'a, 'mir, 'tcx>> {
/// The virtual call stack.
pub(crate) stack: Vec<Frame<'mir, 'tcx, M::PointerTag>>,
/// A cache for deduplicating vtables
pub(super) vtables: FxHashMap<(Ty<'tcx>, ty::PolyExistentialTraitRef<'tcx>), AllocId>,
}
/// A stack frame.
@ -209,6 +213,7 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tc
param_env,
memory: Memory::new(tcx, memory_data),
stack: Vec::new(),
vtables: FxHashMap::default(),
}
}

View File

@ -688,9 +688,6 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M>
rval: OpTy<'tcx, M::PointerTag>,
) -> EvalResult<'tcx, (u128, usize)> {
trace!("read_discriminant_value {:#?}", rval.layout);
if rval.layout.abi.is_uninhabited() {
return err!(Unreachable);
}
match rval.layout.variants {
layout::Variants::Single { index } => {

View File

@ -24,20 +24,32 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M>
pub fn get_vtable(
&mut self,
ty: Ty<'tcx>,
trait_ref: ty::PolyTraitRef<'tcx>,
poly_trait_ref: ty::PolyExistentialTraitRef<'tcx>,
) -> EvalResult<'tcx, Pointer<M::PointerTag>> {
debug!("get_vtable(trait_ref={:?})", trait_ref);
debug!("get_vtable(trait_ref={:?})", poly_trait_ref);
// FIXME: Cache this!
let (ty, poly_trait_ref) = self.tcx.erase_regions(&(ty, poly_trait_ref));
let layout = self.layout_of(trait_ref.self_ty())?;
if let Some(&vtable) = self.vtables.get(&(ty, poly_trait_ref)) {
return Ok(Pointer::from(vtable).with_default_tag());
}
let trait_ref = poly_trait_ref.with_self_ty(*self.tcx, ty);
let trait_ref = self.tcx.erase_regions(&trait_ref);
let methods = self.tcx.vtable_methods(trait_ref);
let layout = self.layout_of(ty)?;
assert!(!layout.is_unsized(), "can't create a vtable for an unsized type");
let size = layout.size.bytes();
let align = layout.align.abi();
let ptr_size = self.pointer_size();
let ptr_align = self.tcx.data_layout.pointer_align;
let methods = self.tcx.vtable_methods(trait_ref);
// /////////////////////////////////////////////////////////////////////////////////////////
// If you touch this code, be sure to also make the corresponding changes to
// `get_vtable` in rust_codegen_llvm/meth.rs
// /////////////////////////////////////////////////////////////////////////////////////////
let vtable = self.memory.allocate(
ptr_size * (3 + methods.len() as u64),
ptr_align,
@ -64,6 +76,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M>
}
self.memory.mark_immutable(vtable.alloc_id)?;
assert!(self.vtables.insert((ty, poly_trait_ref), vtable.alloc_id).is_none());
Ok(vtable)
}

View File

@ -1980,9 +1980,15 @@ impl<'a, 'crateloader: 'a> Resolver<'a, 'crateloader> {
}
if !module.no_implicit_prelude {
// `record_used` means that we don't try to load crates during speculative resolution
if record_used && ns == TypeNS && self.extern_prelude.contains(&ident.name) {
let crate_id = self.crate_loader.process_path_extern(ident.name, ident.span);
if ns == TypeNS && self.extern_prelude.contains(&ident.name) {
let crate_id = if record_used {
self.crate_loader.process_path_extern(ident.name, ident.span)
} else if let Some(crate_id) =
self.crate_loader.maybe_process_path_extern(ident.name, ident.span) {
crate_id
} else {
return None;
};
let crate_root = self.get_module(DefId { krate: crate_id, index: CRATE_DEF_INDEX });
self.populate_module_if_necessary(&crate_root);

View File

@ -553,6 +553,9 @@ fn fmt_type(t: &clean::Type, f: &mut fmt::Formatter, use_absolute: bool) -> fmt:
f.write_str(name)
}
clean::ResolvedPath{ did, ref typarams, ref path, is_generic } => {
if typarams.is_some() {
f.write_str("dyn ")?;
}
// Paths like T::Output and Self::Output should be rendered with all segments
resolved_path(f, did, path, is_generic, use_absolute)?;
tybounds(f, typarams)

View File

@ -83,6 +83,7 @@ pub fn render<T: fmt::Display, S: fmt::Display>(
<div class=\"search-container\">\
<input class=\"search-input\" name=\"search\" \
autocomplete=\"off\" \
spellcheck=\"false\" \
placeholder=\"Click or press S to search, ? for more options…\" \
type=\"search\">\
<a id=\"settings-menu\" href=\"{root_path}settings.html\">\

View File

@ -26,8 +26,26 @@ function onEach(arr, func) {
return false;
}
function usableLocalStorage() {
// Check if the browser supports localStorage at all:
if (typeof(Storage) === "undefined") {
return false;
}
// Check if we can access it; this access will fail if the browser
// preferences deny access to localStorage, e.g., to prevent storage of
// "cookies" (or cookie-likes, as is the case here).
try {
window.localStorage;
} catch(err) {
// Storage is supported, but browser preferences deny access to it.
return false;
}
return true;
}
function updateLocalStorage(name, value) {
if (typeof(Storage) !== "undefined") {
if (usableLocalStorage()) {
localStorage[name] = value;
} else {
// No Web Storage support so we do nothing
@ -35,7 +53,7 @@ function updateLocalStorage(name, value) {
}
function getCurrentValue(name) {
if (typeof(Storage) !== "undefined" && localStorage[name] !== undefined) {
if (usableLocalStorage() && localStorage[name] !== undefined) {
return localStorage[name];
}
return null;

View File

@ -650,15 +650,17 @@ pub fn panicking() -> bool {
panicking::panicking()
}
/// Puts the current thread to sleep for the specified amount of time.
/// Puts the current thread to sleep for at least the specified amount of time.
///
/// The thread may sleep longer than the duration specified due to scheduling
/// specifics or platform-dependent functionality.
/// specifics or platform-dependent functionality. It will never sleep less.
///
/// # Platform-specific behavior
///
/// On Unix platforms this function will not return early due to a
/// signal being received or a spurious wakeup.
/// On Unix platforms, the underlying syscall may be interrupted by a
/// spurious wakeup or signal handler. To ensure the sleep occurs for at least
/// the specified duration, this function may invoke that system call multiple
/// times.
///
/// # Examples
///
@ -674,17 +676,19 @@ pub fn sleep_ms(ms: u32) {
sleep(Duration::from_millis(ms as u64))
}
/// Puts the current thread to sleep for the specified amount of time.
/// Puts the current thread to sleep for at least the specified amount of time.
///
/// The thread may sleep longer than the duration specified due to scheduling
/// specifics or platform-dependent functionality.
/// specifics or platform-dependent functionality. It will never sleep less.
///
/// # Platform-specific behavior
///
/// On Unix platforms this function will not return early due to a
/// signal being received or a spurious wakeup. Platforms which do not support
/// nanosecond precision for sleeping will have `dur` rounded up to the nearest
/// granularity of time they can sleep for.
/// On Unix platforms, the underlying syscall may be interrupted by a
/// spurious wakeup or signal handler. To ensure the sleep occurs for at least
/// the specified duration, this function may invoke that system call multiple
/// times.
/// Platforms which do not support nanosecond precision for sleeping will
/// have `dur` rounded up to the nearest granularity of time they can sleep for.
///
/// # Examples
///

View File

@ -9,7 +9,7 @@
// except according to those terms.
// min-lldb-version: 310
// ignore-macos FIXME #48807
// ignore-lldb FIXME #48807
// compile-flags:-g -Zdebug-macros

View File

@ -10,7 +10,7 @@
// run-pass
#![allow(unused_variables)]
// compile-flags: --extern LooksLikeExternCrate=/path/to/nowhere
// compile-flags: --extern LooksLikeExternCrate
mod m {
pub struct LooksLikeExternCrate;

View File

@ -52,7 +52,7 @@ pub fn f(_: &(ToString + 'static)) {}
impl Bar {
// @has assoc_consts/struct.Bar.html '//*[@id="associatedconstant.F"]' \
// "const F: fn(_: &(ToString + 'static))"
// "const F: fn(_: &(dyn ToString + 'static))"
pub const F: fn(_: &(ToString + 'static)) = f;
}

View File

@ -15,8 +15,8 @@
extern crate rustdoc_trait_object_impl;
// @has issue_32881/trait.Bar.html
// @has - '//code' "impl<'a> Bar"
// @has - '//code' "impl<'a> Debug for Bar"
// @has - '//code' "impl<'a> dyn Bar"
// @has - '//code' "impl<'a> Debug for dyn Bar"
pub use rustdoc_trait_object_impl::Bar;

View File

@ -11,5 +11,5 @@
#![crate_name = "foo"]
// @has foo/fn.foo.html
// @has - '//*[@class="rust fn"]' "_: &(ToString + 'static)"
// @has - '//*[@class="rust fn"]' "_: &(dyn ToString + 'static)"
pub fn foo(_: &(ToString + 'static)) {}

View File

@ -0,0 +1,22 @@
#![feature(nll)]
#![allow(dead_code)]
#[derive(Debug)]
struct Value;
impl Value {
fn as_array(&self) -> Option<&Vec<Value>> {
None
}
}
fn foo(val: Value) {
let _reviewers_original: Vec<Value> = match val.as_array() {
Some(array) => {
*array
}
None => vec![]
};
}
fn main() { }

View File

@ -0,0 +1,12 @@
error[E0507]: cannot move out of borrowed content
--> $DIR/issue-54597-reject-move-out-of-borrow-via-pat.rs:16:13
|
LL | *array
| ^^^^^^
| |
| cannot move out of borrowed content
| help: consider removing the `*`: `array`
error: aborting due to previous error
For more information about this error, try `rustc --explain E0507`.

View File

@ -0,0 +1 @@
pub trait MyTrait {}

View File

@ -0,0 +1,10 @@
// aux-build:extra-item.rs
// compile-flags:--extern extra_item
struct S;
impl extra_item::MyTrait for S {
fn extra() {} //~ ERROR method `extra` is not a member of trait `extra_item::MyTrait`
}
fn main() {}

View File

@ -0,0 +1,9 @@
error[E0407]: method `extra` is not a member of trait `extra_item::MyTrait`
--> $DIR/extra-item.rs:7:5
|
LL | fn extra() {} //~ ERROR method `extra` is not a member of trait `extra_item::MyTrait`
| ^^^^^^^^^^^^^ not a member of trait `extra_item::MyTrait`
error: aborting due to previous error
For more information about this error, try `rustc --explain E0407`.

View File

@ -0,0 +1,4 @@
#[derive(PartialEq)] struct Comparable;
#[derive(PartialEq, PartialOrd)] struct Nope(Comparable);
fn main() {}

View File

@ -0,0 +1,12 @@
error[E0277]: can't compare `Comparable` with `Comparable`
--> $DIR/issue-34229.rs:2:46
|
LL | #[derive(PartialEq, PartialOrd)] struct Nope(Comparable);
| ^^^^^^^^^^ no implementation for `Comparable < Comparable` and `Comparable > Comparable`
|
= help: the trait `std::cmp::PartialOrd` is not implemented for `Comparable`
= note: required by `std::cmp::PartialOrd::partial_cmp`
error: aborting due to previous error
For more information about this error, try `rustc --explain E0277`.

View File

@ -25,6 +25,7 @@ pub enum Mode {
RunPass,
RunPassValgrind,
Pretty,
DebugInfoBoth,
DebugInfoGdb,
DebugInfoLldb,
Codegen,
@ -60,6 +61,7 @@ impl FromStr for Mode {
"run-pass" => Ok(RunPass),
"run-pass-valgrind" => Ok(RunPassValgrind),
"pretty" => Ok(Pretty),
"debuginfo-both" => Ok(DebugInfoBoth),
"debuginfo-lldb" => Ok(DebugInfoLldb),
"debuginfo-gdb" => Ok(DebugInfoGdb),
"codegen" => Ok(Codegen),
@ -83,6 +85,7 @@ impl fmt::Display for Mode {
RunPass => "run-pass",
RunPassValgrind => "run-pass-valgrind",
Pretty => "pretty",
DebugInfoBoth => "debuginfo-both",
DebugInfoGdb => "debuginfo-gdb",
DebugInfoLldb => "debuginfo-lldb",
Codegen => "codegen",

View File

@ -19,10 +19,62 @@ use util;
use extract_gdb_version;
/// Whether to ignore the test.
#[derive(Clone, Copy, PartialEq, Debug)]
pub enum Ignore {
/// Run it.
Run,
/// Ignore it totally.
Ignore,
/// Ignore only the gdb test, but run the lldb test.
IgnoreGdb,
/// Ignore only the lldb test, but run the gdb test.
IgnoreLldb,
}
impl Ignore {
pub fn can_run_gdb(&self) -> bool {
*self == Ignore::Run || *self == Ignore::IgnoreLldb
}
pub fn can_run_lldb(&self) -> bool {
*self == Ignore::Run || *self == Ignore::IgnoreGdb
}
pub fn no_gdb(&self) -> Ignore {
match *self {
Ignore::Run => Ignore::IgnoreGdb,
Ignore::IgnoreGdb => Ignore::IgnoreGdb,
_ => Ignore::Ignore,
}
}
pub fn no_lldb(&self) -> Ignore {
match *self {
Ignore::Run => Ignore::IgnoreLldb,
Ignore::IgnoreLldb => Ignore::IgnoreLldb,
_ => Ignore::Ignore,
}
}
}
/// The result of parse_cfg_name_directive.
#[derive(Clone, Copy, PartialEq, Debug)]
enum ParsedNameDirective {
/// No match.
NoMatch,
/// Match.
Match,
/// Mode was DebugInfoBoth and this matched gdb.
MatchGdb,
/// Mode was DebugInfoBoth and this matched lldb.
MatchLldb,
}
/// Properties which must be known very early, before actually running
/// the test.
pub struct EarlyProps {
pub ignore: bool,
pub ignore: Ignore,
pub should_fail: bool,
pub aux: Vec<String>,
pub revisions: Vec<String>,
@ -31,20 +83,55 @@ pub struct EarlyProps {
impl EarlyProps {
pub fn from_file(config: &Config, testfile: &Path) -> Self {
let mut props = EarlyProps {
ignore: false,
ignore: Ignore::Run,
should_fail: false,
aux: Vec::new(),
revisions: vec![],
};
if config.mode == common::DebugInfoBoth {
if config.lldb_python_dir.is_none() {
props.ignore = props.ignore.no_lldb();
}
if config.gdb_version.is_none() {
props.ignore = props.ignore.no_gdb();
}
}
iter_header(testfile, None, &mut |ln| {
// we should check if any only-<platform> exists and if it exists
// and does not matches the current platform, skip the test
props.ignore = props.ignore || config.parse_cfg_name_directive(ln, "ignore")
|| (config.has_cfg_prefix(ln, "only")
&& !config.parse_cfg_name_directive(ln, "only"))
|| ignore_gdb(config, ln) || ignore_lldb(config, ln)
|| ignore_llvm(config, ln);
if props.ignore != Ignore::Ignore {
props.ignore = match config.parse_cfg_name_directive(ln, "ignore") {
ParsedNameDirective::Match => Ignore::Ignore,
ParsedNameDirective::NoMatch => props.ignore,
ParsedNameDirective::MatchGdb => props.ignore.no_gdb(),
ParsedNameDirective::MatchLldb => props.ignore.no_lldb(),
};
if config.has_cfg_prefix(ln, "only") {
props.ignore = match config.parse_cfg_name_directive(ln, "only") {
ParsedNameDirective::Match => props.ignore,
ParsedNameDirective::NoMatch => Ignore::Ignore,
ParsedNameDirective::MatchLldb => props.ignore.no_gdb(),
ParsedNameDirective::MatchGdb => props.ignore.no_lldb(),
};
}
if ignore_llvm(config, ln) {
props.ignore = Ignore::Ignore;
}
}
if (config.mode == common::DebugInfoGdb || config.mode == common::DebugInfoBoth) &&
props.ignore.can_run_gdb() && ignore_gdb(config, ln) {
props.ignore = props.ignore.no_gdb();
}
if (config.mode == common::DebugInfoLldb || config.mode == common::DebugInfoBoth) &&
props.ignore.can_run_lldb() && ignore_lldb(config, ln) {
props.ignore = props.ignore.no_lldb();
}
if let Some(s) = config.parse_aux_build(ln) {
props.aux.push(s);
@ -60,10 +147,6 @@ impl EarlyProps {
return props;
fn ignore_gdb(config: &Config, line: &str) -> bool {
if config.mode != common::DebugInfoGdb {
return false;
}
if let Some(actual_version) = config.gdb_version {
if line.starts_with("min-gdb-version") {
let (start_ver, end_ver) = extract_gdb_version_range(line);
@ -120,10 +203,6 @@ impl EarlyProps {
}
fn ignore_lldb(config: &Config, line: &str) -> bool {
if config.mode != common::DebugInfoLldb {
return false;
}
if let Some(ref actual_version) = config.lldb_version {
if line.starts_with("min-lldb-version") {
let min_version = line.trim_right()
@ -604,7 +683,7 @@ impl Config {
}
fn parse_custom_normalization(&self, mut line: &str, prefix: &str) -> Option<(String, String)> {
if self.parse_cfg_name_directive(line, prefix) {
if self.parse_cfg_name_directive(line, prefix) == ParsedNameDirective::Match {
let from = match parse_normalization_string(&mut line) {
Some(s) => s,
None => return None,
@ -620,35 +699,59 @@ impl Config {
}
/// Parses a name-value directive which contains config-specific information, e.g. `ignore-x86`
/// or `normalize-stderr-32bit`. Returns `true` if the line matches it.
fn parse_cfg_name_directive(&self, line: &str, prefix: &str) -> bool {
/// or `normalize-stderr-32bit`.
fn parse_cfg_name_directive(&self, line: &str, prefix: &str) -> ParsedNameDirective {
if line.starts_with(prefix) && line.as_bytes().get(prefix.len()) == Some(&b'-') {
let name = line[prefix.len() + 1..]
.split(&[':', ' '][..])
.next()
.unwrap();
name == "test" ||
if name == "test" ||
util::matches_os(&self.target, name) || // target
name == util::get_arch(&self.target) || // architecture
name == util::get_pointer_width(&self.target) || // pointer width
name == self.stage_id.split('-').next().unwrap() || // stage
Some(name) == util::get_env(&self.target) || // env
match self.mode {
common::DebugInfoGdb => name == "gdb",
common::DebugInfoLldb => name == "lldb",
common::Pretty => name == "pretty",
_ => false,
} ||
(self.target != self.host && name == "cross-compile") ||
match self.compare_mode {
Some(CompareMode::Nll) => name == "compare-mode-nll",
Some(CompareMode::Polonius) => name == "compare-mode-polonius",
None => false,
} ||
(cfg!(debug_assertions) && name == "debug")
(cfg!(debug_assertions) && name == "debug") {
ParsedNameDirective::Match
} else {
match self.mode {
common::DebugInfoBoth => {
if name == "gdb" {
ParsedNameDirective::MatchGdb
} else if name == "lldb" {
ParsedNameDirective::MatchLldb
} else {
ParsedNameDirective::NoMatch
}
},
common::DebugInfoGdb => if name == "gdb" {
ParsedNameDirective::Match
} else {
ParsedNameDirective::NoMatch
},
common::DebugInfoLldb => if name == "lldb" {
ParsedNameDirective::Match
} else {
ParsedNameDirective::NoMatch
},
common::Pretty => if name == "pretty" {
ParsedNameDirective::Match
} else {
ParsedNameDirective::NoMatch
},
_ => ParsedNameDirective::NoMatch,
}
}
} else {
false
ParsedNameDirective::NoMatch
}
}

View File

@ -32,7 +32,7 @@ extern crate rustfix;
use common::CompareMode;
use common::{expected_output_path, output_base_dir, output_relative_path, UI_EXTENSIONS};
use common::{Config, TestPaths};
use common::{DebugInfoGdb, DebugInfoLldb, Mode, Pretty};
use common::{DebugInfoBoth, DebugInfoGdb, DebugInfoLldb, Mode, Pretty};
use filetime::FileTime;
use getopts::Options;
use std::env;
@ -44,7 +44,7 @@ use std::process::Command;
use test::ColorConfig;
use util::logv;
use self::header::EarlyProps;
use self::header::{EarlyProps, Ignore};
pub mod common;
pub mod errors;
@ -425,7 +425,7 @@ pub fn opt_str2(maybestr: Option<String>) -> String {
pub fn run_tests(config: &Config) {
if config.target.contains("android") {
if let DebugInfoGdb = config.mode {
if config.mode == DebugInfoGdb || config.mode == DebugInfoBoth {
println!(
"{} debug-info test uses tcp 5039 port.\
please reserve it",
@ -443,7 +443,9 @@ pub fn run_tests(config: &Config) {
}
match config.mode {
DebugInfoLldb => {
// Note that we don't need to emit the gdb warning when
// DebugInfoBoth, so it is ok to list that here.
DebugInfoBoth | DebugInfoLldb => {
if let Some(lldb_version) = config.lldb_version.as_ref() {
if is_blacklisted_lldb_version(&lldb_version[..]) {
println!(
@ -647,15 +649,18 @@ pub fn make_test(config: &Config, testpaths: &TestPaths) -> Vec<test::TestDescAn
.into_iter()
.map(|revision| {
// Debugging emscripten code doesn't make sense today
let ignore = early_props.ignore
let ignore = early_props.ignore == Ignore::Ignore
|| !up_to_date(
config,
testpaths,
&early_props,
revision.map(|s| s.as_str()),
)
|| (config.mode == DebugInfoGdb || config.mode == DebugInfoLldb)
&& config.target.contains("emscripten");
|| ((config.mode == DebugInfoBoth ||
config.mode == DebugInfoGdb || config.mode == DebugInfoLldb)
&& config.target.contains("emscripten"))
|| (config.mode == DebugInfoGdb && !early_props.ignore.can_run_gdb())
|| (config.mode == DebugInfoLldb && !early_props.ignore.can_run_lldb());
test::TestDescAndFn {
desc: test::TestDesc {
name: make_test_name(config, testpaths, revision),
@ -663,7 +668,7 @@ pub fn make_test(config: &Config, testpaths: &TestPaths) -> Vec<test::TestDescAn
should_panic,
allow_fail: false,
},
testfn: make_test_closure(config, testpaths, revision),
testfn: make_test_closure(config, early_props.ignore, testpaths, revision),
}
})
.collect()
@ -774,10 +779,21 @@ fn make_test_name(
fn make_test_closure(
config: &Config,
ignore: Ignore,
testpaths: &TestPaths,
revision: Option<&String>,
) -> test::TestFn {
let config = config.clone();
let mut config = config.clone();
if config.mode == DebugInfoBoth {
// If both gdb and lldb were ignored, then the test as a whole
// would be ignored.
if !ignore.can_run_gdb() {
config.mode = DebugInfoLldb;
} else if !ignore.can_run_lldb() {
config.mode = DebugInfoGdb;
}
}
let testpaths = testpaths.clone();
let revision = revision.cloned();
test::DynTestFn(Box::new(move || {

View File

@ -11,7 +11,7 @@
use common::CompareMode;
use common::{expected_output_path, UI_EXTENSIONS, UI_FIXED, UI_STDERR, UI_STDOUT};
use common::{output_base_dir, output_base_name, output_testname_unique};
use common::{Codegen, CodegenUnits, DebugInfoGdb, DebugInfoLldb, Rustdoc};
use common::{Codegen, CodegenUnits, DebugInfoBoth, DebugInfoGdb, DebugInfoLldb, Rustdoc};
use common::{CompileFail, ParseFail, Pretty, RunFail, RunPass, RunPassValgrind};
use common::{Config, TestPaths};
use common::{Incremental, MirOpt, RunMake, Ui};
@ -225,19 +225,20 @@ pub fn run(config: Config, testpaths: &TestPaths, revision: Option<&str>) {
pub fn compute_stamp_hash(config: &Config) -> String {
let mut hash = DefaultHasher::new();
config.stage_id.hash(&mut hash);
match config.mode {
DebugInfoGdb => match config.gdb {
if config.mode == DebugInfoGdb || config.mode == DebugInfoBoth {
match config.gdb {
None => env::var_os("PATH").hash(&mut hash),
Some(ref s) if s.is_empty() => env::var_os("PATH").hash(&mut hash),
Some(ref s) => s.hash(&mut hash),
},
DebugInfoLldb => {
env::var_os("PATH").hash(&mut hash);
env::var_os("PYTHONPATH").hash(&mut hash);
},
};
}
if config.mode == DebugInfoLldb || config.mode == DebugInfoBoth {
env::var_os("PATH").hash(&mut hash);
env::var_os("PYTHONPATH").hash(&mut hash);
}
_ => {},
};
format!("{:x}", hash.finish())
}
@ -268,6 +269,10 @@ impl<'test> TestCx<'test> {
RunFail => self.run_rfail_test(),
RunPassValgrind => self.run_valgrind_test(),
Pretty => self.run_pretty_test(),
DebugInfoBoth => {
self.run_debuginfo_gdb_test();
self.run_debuginfo_lldb_test();
},
DebugInfoGdb => self.run_debuginfo_gdb_test(),
DebugInfoLldb => self.run_debuginfo_lldb_test(),
Codegen => self.run_codegen_test(),
@ -640,6 +645,7 @@ impl<'test> TestCx<'test> {
let config = Config {
target_rustcflags: self.cleanup_debug_info_options(&self.config.target_rustcflags),
host_rustcflags: self.cleanup_debug_info_options(&self.config.host_rustcflags),
mode: DebugInfoGdb,
..self.config.clone()
};
@ -910,6 +916,7 @@ impl<'test> TestCx<'test> {
let config = Config {
target_rustcflags: self.cleanup_debug_info_options(&self.config.target_rustcflags),
host_rustcflags: self.cleanup_debug_info_options(&self.config.host_rustcflags),
mode: DebugInfoLldb,
..self.config.clone()
};
@ -1774,7 +1781,7 @@ impl<'test> TestCx<'test> {
rustc.arg(dir_opt);
}
RunFail | RunPassValgrind | Pretty | DebugInfoGdb | DebugInfoLldb
RunFail | RunPassValgrind | Pretty | DebugInfoBoth | DebugInfoGdb | DebugInfoLldb
| Codegen | Rustdoc | RunMake | CodegenUnits => {
// do not use JSON output
}