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:
commit
af204b1f3e
@ -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");
|
||||
|
@ -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.
|
||||
|
@ -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)]
|
||||
|
@ -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 {
|
||||
|
@ -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
|
||||
|
@ -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.
|
||||
|
@ -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
|
||||
//!
|
||||
|
@ -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");
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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,
|
||||
|
@ -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))
|
||||
|
@ -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()
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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.
|
||||
|
@ -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,
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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 })
|
||||
};
|
||||
|
@ -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;
|
||||
|
@ -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()),
|
||||
|
@ -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());
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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)
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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"),
|
||||
}
|
||||
|
@ -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,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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 {
|
||||
|
@ -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));
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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),
|
||||
|
@ -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()
|
||||
};
|
||||
|
@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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)
|
||||
|
@ -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(),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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 } => {
|
||||
|
@ -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)
|
||||
}
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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)
|
||||
|
@ -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\">\
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
///
|
||||
|
@ -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
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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)) {}
|
||||
|
@ -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() { }
|
@ -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`.
|
1
src/test/ui/impl-trait/auxiliary/extra-item.rs
Normal file
1
src/test/ui/impl-trait/auxiliary/extra-item.rs
Normal file
@ -0,0 +1 @@
|
||||
pub trait MyTrait {}
|
10
src/test/ui/impl-trait/extra-item.rs
Normal file
10
src/test/ui/impl-trait/extra-item.rs
Normal 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() {}
|
9
src/test/ui/impl-trait/extra-item.stderr
Normal file
9
src/test/ui/impl-trait/extra-item.stderr
Normal 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`.
|
4
src/test/ui/issues/issue-34229.rs
Normal file
4
src/test/ui/issues/issue-34229.rs
Normal file
@ -0,0 +1,4 @@
|
||||
#[derive(PartialEq)] struct Comparable;
|
||||
#[derive(PartialEq, PartialOrd)] struct Nope(Comparable);
|
||||
|
||||
fn main() {}
|
12
src/test/ui/issues/issue-34229.stderr
Normal file
12
src/test/ui/issues/issue-34229.stderr
Normal 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`.
|
@ -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",
|
||||
|
@ -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
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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 || {
|
||||
|
@ -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
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user