MACOSX_DEPLOYMENT_TARGET=10.7
NO_LLVM_ASSERTIONS=1
NO_DEBUG_ASSERTIONS=1
+ DIST_REQUIRE_ALL_TOOLS=1
CI_JOB_NAME=dist-i686-apple
os: osx
osx_image: xcode9.3-moar
MACOSX_DEPLOYMENT_TARGET=10.7
NO_LLVM_ASSERTIONS=1
NO_DEBUG_ASSERTIONS=1
+ DIST_REQUIRE_ALL_TOOLS=1
CI_JOB_NAME=dist-x86_64-apple
os: osx
osx_image: xcode9.3-moar
to fix the issue.
* The dark blue **final-comment-period** label marks bugs that are using the
- RFC signoff functionality of [rfcbot][rfcbot] and are currenty in the final
+ RFC signoff functionality of [rfcbot][rfcbot] and are currently in the final
comment period.
* Red, **I**-prefixed labels indicate the **importance** of the issue. The
--enable-full-tools
--enable-profiler
SCRIPT: python x.py dist
+ DIST_REQUIRE_ALL_TOOLS: 1
DEPLOY: 1
CI_JOB_NAME: dist-x86_64-msvc
- RUST_CONFIGURE_ARGS: >
--enable-full-tools
--enable-profiler
SCRIPT: python x.py dist
+ DIST_REQUIRE_ALL_TOOLS: 1
DEPLOY: 1
CI_JOB_NAME: dist-i686-msvc
- MSYS_BITS: 32
MINGW_URL: https://s3-us-west-1.amazonaws.com/rust-lang-ci2/rust-ci-mirror
MINGW_ARCHIVE: i686-6.3.0-release-posix-dwarf-rt_v5-rev2.7z
MINGW_DIR: mingw32
+ DIST_REQUIRE_ALL_TOOLS: 1
DEPLOY: 1
CI_JOB_NAME: dist-i686-mingw
- MSYS_BITS: 64
MINGW_URL: https://s3-us-west-1.amazonaws.com/rust-lang-ci2/rust-ci-mirror
MINGW_ARCHIVE: x86_64-6.3.0-release-posix-seh-rt_v5-rev2.7z
MINGW_DIR: mingw64
+ DIST_REQUIRE_ALL_TOOLS: 1
DEPLOY: 1
CI_JOB_NAME: dist-x86_64-mingw
# as the one built on Windows will contain backslashes in paths causing problems
# on linux
#src-tarball = true
+#
+
+# Whether to allow failures when building tools
+#missing-tools = false
name = "rustc-workspace-hack"
version = "1.0.0"
dependencies = [
+ "rand 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)",
+ "serde_json 1.0.31 (registry+https://github.com/rust-lang/crates.io-index)",
"syn 0.14.9 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)",
]
version = "0.0.0"
dependencies = [
"arena 0.0.0",
+ "bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)",
"rustc 0.0.0",
"rustc_data_structures 0.0.0",
pub test_miri: bool,
pub save_toolstates: Option<PathBuf>,
pub print_step_timings: bool,
+ pub missing_tools: bool,
// Fallback musl-root for all targets
pub musl_root: Option<PathBuf>,
gpg_password_file: Option<String>,
upload_addr: Option<String>,
src_tarball: Option<bool>,
+ missing_tools: Option<bool>,
}
#[derive(Deserialize)]
config.rust_codegen_backends = vec![INTERNER.intern_str("llvm")];
config.rust_codegen_backends_dir = "codegen-backends".to_owned();
config.deny_warnings = true;
+ config.missing_tools = false;
// set by bootstrap.py
config.build = INTERNER.intern_str(&env::var("BUILD").expect("'BUILD' to be set"));
config.dist_gpg_password_file = t.gpg_password_file.clone().map(PathBuf::from);
config.dist_upload_addr = t.upload_addr.clone();
set(&mut config.rust_dist_src, t.src_tarball);
+ set(&mut config.missing_tools, t.missing_tools);
}
// Now that we've reached the end of our configuration, infer the
o("emscripten", None, "compile the emscripten backend as well as LLVM")
o("full-tools", None, "enable all tools")
o("lldb", "rust.lldb", "build lldb")
+o("missing-tools", "dist.missing-tools", "allow failures when building tools")
# Optimization and debugging options. These may be overridden by the release
# channel, etc.
builder.tool_cmd(Tool::RustInstaller)
}
+fn missing_tool(tool_name: &str, skip: bool) {
+ if skip {
+ println!("Unable to build {}, skipping dist", tool_name)
+ } else {
+ panic!("Unable to build {}", tool_name)
+ }
+}
+
#[derive(Debug, PartialOrd, Ord, Copy, Clone, Hash, PartialEq, Eq)]
pub struct Docs {
pub stage: u32,
let rls = builder.ensure(tool::Rls {
compiler: builder.compiler(stage, builder.config.build),
target, extra_features: Vec::new()
- }).or_else(|| { println!("Unable to build RLS, skipping dist"); None })?;
+ }).or_else(|| { missing_tool("RLS", builder.build.config.missing_tools); None })?;
builder.install(&rls, &image.join("bin"), 0o755);
let doc = image.join("share/doc/rls");
let clippy = builder.ensure(tool::Clippy {
compiler: builder.compiler(stage, builder.config.build),
target, extra_features: Vec::new()
- }).or_else(|| { println!("Unable to build clippy, skipping dist"); None })?;
+ }).or_else(|| { missing_tool("clippy", builder.build.config.missing_tools); None })?;
let cargoclippy = builder.ensure(tool::CargoClippy {
compiler: builder.compiler(stage, builder.config.build),
target, extra_features: Vec::new()
- }).or_else(|| { println!("Unable to build cargo clippy, skipping dist"); None })?;
+ }).or_else(|| { missing_tool("cargo clippy", builder.build.config.missing_tools); None })?;
builder.install(&clippy, &image.join("bin"), 0o755);
builder.install(&cargoclippy, &image.join("bin"), 0o755);
let rustfmt = builder.ensure(tool::Rustfmt {
compiler: builder.compiler(stage, builder.config.build),
target, extra_features: Vec::new()
- }).or_else(|| { println!("Unable to build Rustfmt, skipping dist"); None })?;
+ }).or_else(|| { missing_tool("Rustfmt", builder.build.config.missing_tools); None })?;
let cargofmt = builder.ensure(tool::Cargofmt {
compiler: builder.compiler(stage, builder.config.build),
target, extra_features: Vec::new()
- }).or_else(|| { println!("Unable to build Cargofmt, skipping dist"); None })?;
+ }).or_else(|| { missing_tool("Cargofmt", builder.build.config.missing_tools); None })?;
builder.install(&rustfmt, &image.join("bin"), 0o755);
builder.install(&cargofmt, &image.join("bin"), 0o755);
# When we build cargo in this container, we don't want it to use the system
# libcurl, instead it should compile its own.
ENV LIBCURL_NO_PKG_CONFIG 1
+
+ENV DIST_REQUIRE_ALL_TOOLS 1
# When we build cargo in this container, we don't want it to use the system
# libcurl, instead it should compile its own.
ENV LIBCURL_NO_PKG_CONFIG 1
+
+ENV DIST_REQUIRE_ALL_TOOLS 1
fi
fi
+if [ "$RUST_RELEASE_CHANNEL" = "nightly" ] || [ "$DIST_REQUIRE_ALL_TOOLS" = "" ]; then
+ RUST_CONFIGURE_ARGS="$RUST_CONFIGURE_ARGS --enable-missing-tools"
+fi
+
# We've had problems in the past of shell scripts leaking fds into the sccache
# server (#48192) which causes Cargo to erroneously think that a build script
# hasn't finished yet. Try to solve that problem by starting a very long-lived
- `freeze`: `libcore/marker.rs`
- `debug_trait`: `libcore/fmt/mod.rs`
- `non_zero`: `libcore/nonzero.rs`
+ - `arc`: `liballoc/sync.rs`
+ - `rc`: `liballoc/rc.rs`
/// type `T`.
///
/// [get_mut]: #method.get_mut
+#[cfg_attr(all(not(stage0), not(test)), lang = "rc")]
#[stable(feature = "rust1", since = "1.0.0")]
pub struct Rc<T: ?Sized> {
ptr: NonNull<RcBox<T>>,
/// counting in general.
///
/// [rc_examples]: ../../std/rc/index.html#examples
+#[cfg_attr(all(not(stage0), not(test)), lang = "arc")]
#[stable(feature = "rust1", since = "1.0.0")]
pub struct Arc<T: ?Sized> {
ptr: NonNull<ArcInner<T>>,
unsafe {
let mut ptr = self.as_mut_ptr().add(self.len());
let mut local_len = SetLenOnDrop::new(&mut self.len);
- for element in iterator {
+ iterator.for_each(move |element| {
ptr::write(ptr, element);
ptr = ptr.offset(1);
// NB can't overflow since we would have had to alloc the address space
local_len.increment_len(1);
- }
+ });
}
} else {
self.extend_desugared(iterator)
#![feature(powerpc_target_feature)]
#![feature(mips_target_feature)]
#![feature(aarch64_target_feature)]
+#![feature(wasm_target_feature)]
#![feature(const_slice_len)]
#![feature(const_str_as_bytes)]
#![feature(const_str_len)]
/// [alignment]: ./fn.align_of.html
#[inline]
#[stable(feature = "rust1", since = "1.0.0")]
+#[cfg_attr(not(stage0), rustc_promotable)]
pub const fn size_of<T>() -> usize {
intrinsics::size_of::<T>()
}
/// ```
#[inline]
#[stable(feature = "rust1", since = "1.0.0")]
+#[cfg_attr(not(stage0), rustc_promotable)]
pub const fn align_of<T>() -> usize {
intrinsics::min_align_of::<T>()
}
```"),
#[stable(feature = "rust1", since = "1.0.0")]
#[inline]
+ #[cfg_attr(not(stage0), rustc_promotable)]
pub const fn min_value() -> Self {
!0 ^ ((!0 as $UnsignedT) >> 1) as Self
}
```"),
#[stable(feature = "rust1", since = "1.0.0")]
#[inline]
+ #[cfg_attr(not(stage0), rustc_promotable)]
pub const fn max_value() -> Self {
!Self::min_value()
}
/// ```
#[stable(feature = "inclusive_range_methods", since = "1.27.0")]
#[inline]
+ #[cfg_attr(not(stage0), rustc_promotable)]
pub const fn new(start: Idx, end: Idx) -> Self {
Self { start, end, is_empty: None }
}
/// ```
#[inline]
#[stable(feature = "rust1", since = "1.0.0")]
+#[cfg_attr(not(stage0), rustc_promotable)]
pub const fn null<T>() -> *const T { 0 as *const T }
/// Creates a null mutable raw pointer.
/// ```
#[inline]
#[stable(feature = "rust1", since = "1.0.0")]
+#[cfg_attr(not(stage0), rustc_promotable)]
pub const fn null_mut<T>() -> *mut T { 0 as *mut T }
/// Swaps the values at two mutable locations of the same type, without
/// [`Relaxed`]: enum.Ordering.html#variant.Relaxed
#[inline]
#[stable(feature = "rust1", since = "1.0.0")]
+#[cfg_attr(target_arch = "wasm32", allow(unused_variables))]
pub fn fence(order: Ordering) {
+ // On wasm32 it looks like fences aren't implemented in LLVM yet in that
+ // they will cause LLVM to abort. The wasm instruction set doesn't have
+ // fences right now. There's discussion online about the best way for tools
+ // to conventionally implement fences at
+ // https://github.com/WebAssembly/tool-conventions/issues/59. We should
+ // follow that discussion and implement a solution when one comes about!
+ #[cfg(not(target_arch = "wasm32"))]
unsafe {
match order {
Acquire => intrinsics::atomic_fence_acq(),
/// ```
#[stable(feature = "duration", since = "1.3.0")]
#[inline]
+ #[cfg_attr(not(stage0), rustc_promotable)]
pub const fn from_secs(secs: u64) -> Duration {
Duration { secs, nanos: 0 }
}
/// ```
#[stable(feature = "duration", since = "1.3.0")]
#[inline]
+ #[cfg_attr(not(stage0), rustc_promotable)]
pub const fn from_millis(millis: u64) -> Duration {
Duration {
secs: millis / MILLIS_PER_SEC,
/// ```
#[stable(feature = "duration_from_micros", since = "1.27.0")]
#[inline]
+ #[cfg_attr(not(stage0), rustc_promotable)]
pub const fn from_micros(micros: u64) -> Duration {
Duration {
secs: micros / MICROS_PER_SEC,
/// ```
#[stable(feature = "duration_extras", since = "1.27.0")]
#[inline]
+ #[cfg_attr(not(stage0), rustc_promotable)]
pub const fn from_nanos(nanos: u64) -> Duration {
Duration {
secs: nanos / (NANOS_PER_SEC as u64),
self.cur.next();
Some(pos)
} else {
- let pos = pos + padding + 1;
+ let pos = pos + raw + 1;
self.err(format!("expected `{:?}`, found `{:?}`", c, maybe),
format!("expected `{}`", c),
pos,
[] ItemVarianceConstraints(DefId),
[] ItemVariances(DefId),
[] IsConstFn(DefId),
+ [] IsPromotableConstFn(DefId),
[] IsForeignItem(DefId),
[] TypeParamPredicates { item_id: DefId, param_id: DefId },
[] SizedConstraint(DefId),
Tool,
/// Single-segment custom attribute registered by a derive macro (`#[serde(default)]`).
DeriveHelper,
+ /// Single-segment custom attriubte registered by a legacy plugin (`register_attribute`).
+ LegacyPluginHelper,
/// Single-segment custom attribute not registered in any way (`#[my_attr]`).
Custom,
}
NonMacroAttrKind::Builtin => "built-in attribute",
NonMacroAttrKind::Tool => "tool attribute",
NonMacroAttrKind::DeriveHelper => "derive helper attribute",
+ NonMacroAttrKind::LegacyPluginHelper => "legacy plugin helper attribute",
NonMacroAttrKind::Custom => "custom attribute",
}
}
TyKind::Path(ref qpath) => {
visitor.visit_qpath(qpath, typ.hir_id, typ.span);
}
+ TyKind::Def(item_id, ref lifetimes) => {
+ visitor.visit_nested_item(item_id);
+ walk_list!(visitor, visit_generic_arg, lifetimes);
+ }
TyKind::Array(ref ty, ref length) => {
visitor.visit_ty(ty);
visitor.visit_anon_const(length)
lctx.items.insert(exist_ty_id.node_id, exist_ty_item);
// `impl Trait` now just becomes `Foo<'a, 'b, ..>`
- let path = P(hir::Path {
- span: exist_ty_span,
- def: Def::Existential(DefId::local(exist_ty_def_index)),
- segments: hir_vec![hir::PathSegment {
- infer_types: false,
- ident: Ident::new(keywords::Invalid.name(), exist_ty_span),
- args: Some(P(hir::GenericArgs {
- parenthesized: false,
- bindings: HirVec::new(),
- args: lifetimes,
- }))
- }],
- });
- hir::TyKind::Path(hir::QPath::Resolved(None, path))
+ hir::TyKind::Def(hir::ItemId { id: exist_ty_id.node_id }, lifetimes)
})
}
inputs,
output,
variadic: decl.variadic,
- has_implicit_self: decl.inputs.get(0).map_or(false, |arg| match arg.ty.node {
- TyKind::ImplicitSelf => true,
- TyKind::Rptr(_, ref mt) => mt.ty.node.is_implicit_self(),
- _ => false,
- }),
+ implicit_self: decl.inputs.get(0).map_or(
+ hir::ImplicitSelfKind::None,
+ |arg| {
+ let is_mutable_pat = match arg.pat.node {
+ PatKind::Ident(BindingMode::ByValue(mt), _, _) |
+ PatKind::Ident(BindingMode::ByRef(mt), _, _) =>
+ mt == Mutability::Mutable,
+ _ => false,
+ };
+
+ match arg.ty.node {
+ TyKind::ImplicitSelf if is_mutable_pat => hir::ImplicitSelfKind::Mut,
+ TyKind::ImplicitSelf => hir::ImplicitSelfKind::Imm,
+ // Given we are only considering `ImplicitSelf` types, we needn't consider
+ // the case where we have a mutable pattern to a reference as that would
+ // no longer be an `ImplicitSelf`.
+ TyKind::Rptr(_, ref mt) if mt.ty.node.is_implicit_self() &&
+ mt.mutbl == ast::Mutability::Mutable =>
+ hir::ImplicitSelfKind::MutRef,
+ TyKind::Rptr(_, ref mt) if mt.ty.node.is_implicit_self() =>
+ hir::ImplicitSelfKind::ImmRef,
+ _ => hir::ImplicitSelfKind::None,
+ }
+ },
+ ),
})
}
}
}
- /// Lowers `impl Trait` items for a function and appends them to the list
- fn lower_fn_impl_trait_ids(
- &mut self,
- decl: &FnDecl,
- header: &FnHeader,
- ids: &mut SmallVec<[hir::ItemId; 1]>,
- ) {
- if let Some(id) = header.asyncness.opt_return_id() {
- ids.push(hir::ItemId { id });
- }
- let mut visitor = ImplTraitTypeIdVisitor { ids };
- match decl.output {
- FunctionRetTy::Default(_) => {},
- FunctionRetTy::Ty(ref ty) => visitor.visit_ty(ty),
- }
- }
-
fn lower_item_id(&mut self, i: &Item) -> SmallVec<[hir::ItemId; 1]> {
match i.node {
ItemKind::Use(ref use_tree) => {
vec
}
ItemKind::MacroDef(..) => SmallVec::new(),
- ItemKind::Fn(ref decl, ref header, ..) => {
- let mut ids = smallvec![hir::ItemId { id: i.id }];
- self.lower_fn_impl_trait_ids(decl, header, &mut ids);
- ids
- },
- ItemKind::Impl(.., None, _, ref items) => {
- let mut ids = smallvec![hir::ItemId { id: i.id }];
- for item in items {
- if let ImplItemKind::Method(ref sig, _) = item.node {
- self.lower_fn_impl_trait_ids(&sig.decl, &sig.header, &mut ids);
- }
- }
- ids
- },
+ ItemKind::Fn(..) |
+ ItemKind::Impl(.., None, _, _) => smallvec![hir::ItemId { id: i.id }],
ItemKind::Static(ref ty, ..) => {
let mut ids = smallvec![hir::ItemId { id: i.id }];
if self.sess.features_untracked().impl_trait_in_bindings {
ExprKind::Yield(..) => ExprPrecedence::Yield,
}
}
+
+ pub fn is_place_expr(&self) -> bool {
+ match self.node {
+ ExprKind::Path(QPath::Resolved(_, ref path)) => {
+ match path.def {
+ Def::Local(..) | Def::Upvar(..) | Def::Static(..) | Def::Err => true,
+ _ => false,
+ }
+ }
+
+ ExprKind::Type(ref e, _) => {
+ e.is_place_expr()
+ }
+
+ ExprKind::Unary(UnDeref, _) |
+ ExprKind::Field(..) |
+ ExprKind::Index(..) => {
+ true
+ }
+
+ // Partially qualified paths in expressions can only legally
+ // refer to associated items which are always rvalues.
+ ExprKind::Path(QPath::TypeRelative(..)) |
+
+ ExprKind::Call(..) |
+ ExprKind::MethodCall(..) |
+ ExprKind::Struct(..) |
+ ExprKind::Tup(..) |
+ ExprKind::If(..) |
+ ExprKind::Match(..) |
+ ExprKind::Closure(..) |
+ ExprKind::Block(..) |
+ ExprKind::Repeat(..) |
+ ExprKind::Array(..) |
+ ExprKind::Break(..) |
+ ExprKind::Continue(..) |
+ ExprKind::Ret(..) |
+ ExprKind::While(..) |
+ ExprKind::Loop(..) |
+ ExprKind::Assign(..) |
+ ExprKind::InlineAsm(..) |
+ ExprKind::AssignOp(..) |
+ ExprKind::Lit(_) |
+ ExprKind::Unary(..) |
+ ExprKind::Box(..) |
+ ExprKind::AddrOf(..) |
+ ExprKind::Binary(..) |
+ ExprKind::Yield(..) |
+ ExprKind::Cast(..) => {
+ false
+ }
+ }
+ }
}
impl fmt::Debug for Expr {
///
/// Type parameters may be stored in each `PathSegment`.
Path(QPath),
+ /// A type definition itself. This is currently only used for the `existential type`
+ /// item that `impl Trait` in return position desugars to.
+ ///
+ /// The generic arg list are the lifetimes (and in the future possibly parameters) that are
+ /// actually bound on the `impl Trait`.
+ Def(ItemId, HirVec<GenericArg>),
/// A trait object type `Bound1 + Bound2 + Bound3`
/// where `Bound` is a trait or a lifetime.
TraitObject(HirVec<PolyTraitRef>, Lifetime),
pub inputs: HirVec<Ty>,
pub output: FunctionRetTy,
pub variadic: bool,
- /// True if this function has an `self`, `&self` or `&mut self` receiver
- /// (but not a `self: Xxx` one).
- pub has_implicit_self: bool,
+ /// Does the function have an implicit self?
+ pub implicit_self: ImplicitSelfKind,
+}
+
+/// Represents what type of implicit self a function has, if any.
+#[derive(Clone, Copy, RustcEncodable, RustcDecodable, Debug)]
+pub enum ImplicitSelfKind {
+ /// Represents a `fn x(self);`.
+ Imm,
+ /// Represents a `fn x(mut self);`.
+ Mut,
+ /// Represents a `fn x(&self);`.
+ ImmRef,
+ /// Represents a `fn x(&mut self);`.
+ MutRef,
+ /// Represents when a function does not have a self argument or
+ /// when a function has a `self: X` argument.
+ None
+}
+
+impl ImplicitSelfKind {
+ /// Does this represent an implicit self?
+ pub fn has_implicit_self(&self) -> bool {
+ match *self {
+ ImplicitSelfKind::None => false,
+ _ => true,
+ }
+ }
}
/// Is the trait definition an auto trait?
self.print_ty_fn(f.abi, f.unsafety, &f.decl, None, &f.generic_params,
&f.arg_names[..])?;
}
+ hir::TyKind::Def(..) => {},
hir::TyKind::Path(ref qpath) => {
self.print_qpath(qpath, false)?
}
Never,
Tup(ts),
Path(qpath),
+ Def(it, lt),
TraitObject(trait_refs, lifetime),
Typeof(body_id),
Err,
inputs,
output,
variadic,
- has_implicit_self
+ implicit_self
});
impl_stable_hash_for!(enum hir::FunctionRetTy {
Return(t)
});
+impl_stable_hash_for!(enum hir::ImplicitSelfKind {
+ Imm,
+ Mut,
+ ImmRef,
+ MutRef,
+ None
+});
+
impl_stable_hash_for!(struct hir::TraitRef {
// Don't hash the ref_id. It is tracked via the thing it is used to access
ref_id -> _,
Builtin,
Tool,
DeriveHelper,
+ LegacyPluginHelper,
Custom,
});
mir::TerminatorKind::Call { ref func,
ref args,
ref destination,
- cleanup } => {
+ cleanup,
+ from_hir_call, } => {
func.hash_stable(hcx, hasher);
args.hash_stable(hcx, hasher);
destination.hash_stable(hcx, hasher);
cleanup.hash_stable(hcx, hasher);
+ from_hir_call.hash_stable(hcx, hasher);
}
mir::TerminatorKind::Assert { ref cond,
expected,
level,
feature,
rustc_depr,
+ promotable,
const_stability
});
}
ty::ReLateBound(..) |
ty::ReVar(..) |
- ty::ReSkolemized(..) => {
+ ty::RePlaceholder(..) => {
bug!("StableHasher: unexpected region {:?}", *self)
}
}
Tuple(inner_tys) => {
inner_tys.hash_stable(hcx, hasher);
}
- Projection(ref projection_ty) => {
- projection_ty.hash_stable(hcx, hasher);
+ Projection(ref data) | UnnormalizedProjection(ref data) => {
+ data.hash_stable(hcx, hasher);
}
Opaque(def_id, substs) => {
def_id.hash_stable(hcx, hasher);
ty::ReEarlyBound(..)
| ty::ReFree(_)
| ty::ReScope(_)
- | ty::ReSkolemized(..)
+ | ty::RePlaceholder(..)
| ty::ReEmpty
| ty::ReErased => {
if self.canonicalize_region_mode.other_free_regions {
| ty::Never
| ty::Tuple(..)
| ty::Projection(..)
+ | ty::UnnormalizedProjection(..)
| ty::Foreign(..)
| ty::Param(..)
| ty::Opaque(..) => {
return Ok(r);
}
- // Always make a fresh region variable for skolemized regions;
- // the higher-ranked decision procedures rely on this.
- ty::ReSkolemized(..) => { }
+ // Always make a fresh region variable for placeholder
+ // regions; the higher-ranked decision procedures rely on
+ // this.
+ ty::RePlaceholder(..) => { }
// For anything else, we make a region variable, unless we
// are *equating*, in which case it's just wasteful.
ty::ReEmpty => ("the empty lifetime".to_owned(), None),
- // FIXME(#13998) ReSkolemized should probably print like
+ // FIXME(#13998) RePlaceholder should probably print like
// ReFree rather than dumping Debug output on the user.
//
// We shouldn't really be having unification failures with ReVar
// and ReLateBound though.
- ty::ReSkolemized(..) | ty::ReVar(_) | ty::ReLateBound(..) | ty::ReErased => {
+ ty::RePlaceholder(..) | ty::ReVar(_) | ty::ReLateBound(..) | ty::ReErased => {
(format!("lifetime {:?}", region), None)
}
ty::ReFree(_) |
ty::ReScope(_) |
ty::ReVar(_) |
- ty::ReSkolemized(..) |
+ ty::RePlaceholder(..) |
ty::ReEmpty |
ty::ReErased => {
// replace all free regions with 'erased
ty::Never |
ty::Tuple(..) |
ty::Projection(..) |
+ ty::UnnormalizedProjection(..) |
ty::Foreign(..) |
ty::Param(..) |
ty::Closure(..) |
Here is the algorithm we use to perform the subtyping check:
1. Replace all bound regions in the subtype with new variables
-2. Replace all bound regions in the supertype with skolemized
- equivalents. A "skolemized" region is just a new fresh region
+2. Replace all bound regions in the supertype with placeholder
+ equivalents. A "placeholder" region is just a new fresh region
name.
3. Check that the parameter and return types match as normal
-4. Ensure that no skolemized regions 'leak' into region variables
+4. Ensure that no placeholder regions 'leak' into region variables
visible from "the outside"
Let's walk through some examples and see how this algorithm plays out.
Here the upper case `&A` indicates a *region variable*, that is, a
region whose value is being inferred by the system. I also replaced
`&b` with `&x`---I'll use letters late in the alphabet (`x`, `y`, `z`)
-to indicate skolemized region names. We can assume they don't appear
+to indicate placeholder region names. We can assume they don't appear
elsewhere. Note that neither the sub- nor the supertype bind any
region names anymore (as indicated by the absence of `<` and `>`).
must hold: but this does not hold. `self` and `x` are both distinct
free regions. So the subtype check fails.
-#### Checking for skolemization leaks
+#### Checking for placeholder leaks
You may be wondering about that mysterious last step in the algorithm.
So far it has not been relevant. The purpose of that last step is to
fn(&'A T) <: for<'b> fn(&'b T)?
-Here we skolemize the bound region in the supertype to yield:
+Here we replace the bound region in the supertype with a placeholder to yield:
fn(&'A T) <: fn(&'x T)?
is *necessary*, it was key to the first example we walked through.
The difference between this example and the first one is that the variable
-`A` already existed at the point where the skolemization occurred. In
+`A` already existed at the point where the placeholders were added. In
the first example, you had two functions:
for<'a> fn(&'a T) <: for<'b> fn(&'b T)
and hence `&A` and `&x` were created "together". In general, the
-intention of the skolemized names is that they are supposed to be
+intention of the placeholder names is that they are supposed to be
fresh names that could never be equal to anything from the outside.
But when inference comes into play, we might not be respecting this
rule.
So the way we solve this is to add a fourth step that examines the
-constraints that refer to skolemized names. Basically, consider a
+constraints that refer to placeholder names. Basically, consider a
non-directed version of the constraint graph. Let `Tainted(x)` be the
-set of all things reachable from a skolemized variable `x`.
+set of all things reachable from a placeholder variable `x`.
`Tainted(x)` should not contain any regions that existed before the
-step at which the skolemization was performed. So this case here
+step at which the placeholders were created. So this case here
would fail because `&x` was created alone, but is relatable to `&A`.
## Computing the LUB and GLB
InferCtxt,
HigherRankedType,
SubregionOrigin,
- SkolemizationMap};
+ PlaceholderMap};
use super::combine::CombineFields;
use super::region_constraints::{TaintDirections};
return self.infcx.commit_if_ok(|snapshot| {
let span = self.trace.cause.span;
- // First, we instantiate each bound region in the subtype with a fresh
- // region variable.
+ // First, we instantiate each bound region in the supertype with a
+ // fresh placeholder region.
+ let (b_prime, placeholder_map) =
+ self.infcx.replace_late_bound_regions_with_placeholders(b);
+
+ // Next, we instantiate each bound region in the subtype
+ // with a fresh region variable. These region variables --
+ // but no other pre-existing region variables -- can name
+ // the placeholders.
let (a_prime, _) =
self.infcx.replace_late_bound_regions_with_fresh_var(
span,
HigherRankedType,
a);
- // Second, we instantiate each bound region in the supertype with a
- // fresh concrete region.
- let (b_prime, skol_map) =
- self.infcx.skolemize_late_bound_regions(b);
-
debug!("a_prime={:?}", a_prime);
debug!("b_prime={:?}", b_prime);
let result = self.sub(a_is_expected).relate(&a_prime, &b_prime)?;
// Presuming type comparison succeeds, we need to check
- // that the skolemized regions do not "leak".
- self.infcx.leak_check(!a_is_expected, span, &skol_map, snapshot)?;
+ // that the placeholder regions do not "leak".
+ self.infcx.leak_check(!a_is_expected, span, &placeholder_map, snapshot)?;
- // We are finished with the skolemized regions now so pop
+ // We are finished with the placeholder regions now so pop
// them off.
- self.infcx.pop_skolemized(skol_map, snapshot);
+ self.infcx.pop_placeholders(placeholder_map, snapshot);
debug!("higher_ranked_sub: OK result={:?}", result);
// created as part of this type comparison".
return self.infcx.commit_if_ok(|snapshot| {
// First, we instantiate each bound region in the matcher
- // with a skolemized region.
- let ((a_match, a_value), skol_map) =
- self.infcx.skolemize_late_bound_regions(a_pair);
+ // with a placeholder region.
+ let ((a_match, a_value), placeholder_map) =
+ self.infcx.replace_late_bound_regions_with_placeholders(a_pair);
debug!("higher_ranked_match: a_match={:?}", a_match);
- debug!("higher_ranked_match: skol_map={:?}", skol_map);
+ debug!("higher_ranked_match: placeholder_map={:?}", placeholder_map);
// Equate types now that bound regions have been replaced.
self.equate(a_is_expected).relate(&a_match, &b_match)?;
- // Map each skolemized region to a vector of other regions that it
+ // Map each placeholder region to a vector of other regions that it
// must be equated with. (Note that this vector may include other
- // skolemized regions from `skol_map`.)
- let skol_resolution_map: FxHashMap<_, _> =
- skol_map
+ // placeholder regions from `placeholder_map`.)
+ let placeholder_resolution_map: FxHashMap<_, _> =
+ placeholder_map
.iter()
- .map(|(&br, &skol)| {
+ .map(|(&br, &placeholder)| {
let tainted_regions =
self.infcx.tainted_regions(snapshot,
- skol,
+ placeholder,
TaintDirections::incoming()); // [1]
- // [1] this routine executes after the skolemized
+ // [1] this routine executes after the placeholder
// regions have been *equated* with something
// else, so examining the incoming edges ought to
// be enough to collect all constraints
- (skol, (br, tainted_regions))
+ (placeholder, (br, tainted_regions))
})
.collect();
- // For each skolemized region, pick a representative -- which can
+ // For each placeholder region, pick a representative -- which can
// be any region from the sets above, except for other members of
- // `skol_map`. There should always be a representative if things
+ // `placeholder_map`. There should always be a representative if things
// are properly well-formed.
- let skol_representatives: FxHashMap<_, _> =
- skol_resolution_map
+ let placeholder_representatives: FxHashMap<_, _> =
+ placeholder_resolution_map
.iter()
- .map(|(&skol, &(_, ref regions))| {
+ .map(|(&placeholder, &(_, ref regions))| {
let representative =
regions.iter()
- .filter(|&&r| !skol_resolution_map.contains_key(r))
+ .filter(|&&r| !placeholder_resolution_map.contains_key(r))
.cloned()
.next()
.unwrap_or_else(|| {
bug!("no representative region for `{:?}` in `{:?}`",
- skol, regions)
+ placeholder, regions)
});
- (skol, representative)
+ (placeholder, representative)
})
.collect();
- // Equate all the members of each skolemization set with the
+ // Equate all the members of each placeholder set with the
// representative.
- for (skol, &(_br, ref regions)) in &skol_resolution_map {
- let representative = &skol_representatives[skol];
+ for (placeholder, &(_br, ref regions)) in &placeholder_resolution_map {
+ let representative = &placeholder_representatives[placeholder];
debug!("higher_ranked_match: \
- skol={:?} representative={:?} regions={:?}",
- skol, representative, regions);
+ placeholder={:?} representative={:?} regions={:?}",
+ placeholder, representative, regions);
for region in regions.iter()
- .filter(|&r| !skol_resolution_map.contains_key(r))
+ .filter(|&r| !placeholder_resolution_map.contains_key(r))
.filter(|&r| r != representative)
{
let origin = SubregionOrigin::Subtype(self.trace.clone());
}
}
- // Replace the skolemized regions appearing in value with
+ // Replace the placeholder regions appearing in value with
// their representatives
let a_value =
fold_regions_in(
self.tcx(),
&a_value,
- |r, _| skol_representatives.get(&r).cloned().unwrap_or(r));
+ |r, _| placeholder_representatives.get(&r).cloned().unwrap_or(r));
debug!("higher_ranked_match: value={:?}", a_value);
- // We are now done with these skolemized variables.
- self.infcx.pop_skolemized(skol_map, snapshot);
+ // We are now done with these placeholder variables.
+ self.infcx.pop_placeholders(placeholder_map, snapshot);
Ok(HrMatchResult { value: a_value })
});
* started. This is used in the sub/lub/glb computations. The
* idea here is that when we are computing lub/glb of two
* regions, we sometimes create intermediate region variables.
- * Those region variables may touch some of the skolemized or
+ * Those region variables may touch some of the placeholder or
* other "forbidden" regions we created to replace bound
* regions, but they don't really represent an "external"
* constraint.
* we're not careful, it will succeed.
*
* The reason is that when we walk through the subtyping
- * algorithm, we begin by replacing `'a` with a skolemized
+ * algorithm, we begin by replacing `'a` with a placeholder
* variable `'1`. We then have `fn(_#0t) <: fn(&'1 int)`. This
* can be made true by unifying `_#0t` with `&'1 int`. In the
- * process, we create a fresh variable for the skolemized
+ * process, we create a fresh variable for the placeholder
* region, `'$2`, and hence we have that `_#0t == &'$2
* int`. However, because `'$2` was created during the sub
* computation, if we're not careful we will erroneously
region_vars
}
- /// Replace all regions bound by `binder` with skolemized regions and
+ /// Replace all regions bound by `binder` with placeholder regions and
/// return a map indicating which bound-region was replaced with what
- /// skolemized region. This is the first step of checking subtyping
+ /// placeholder region. This is the first step of checking subtyping
/// when higher-ranked things are involved.
///
/// **Important:** you must call this function from within a snapshot.
/// Moreover, before committing the snapshot, you must eventually call
- /// either `plug_leaks` or `pop_skolemized` to remove the skolemized
+ /// either `plug_leaks` or `pop_placeholders` to remove the placeholder
/// regions. If you rollback the snapshot (or are using a probe), then
/// the pop occurs as part of the rollback, so an explicit call is not
/// needed (but is also permitted).
///
- /// For more information about how skolemization for HRTBs works, see
+ /// For more information about how placeholders and HRTBs work, see
/// the [rustc guide].
///
/// [rustc guide]: https://rust-lang-nursery.github.io/rustc-guide/traits/hrtb.html
- pub fn skolemize_late_bound_regions<T>(&self,
- binder: &ty::Binder<T>)
- -> (T, SkolemizationMap<'tcx>)
- where T : TypeFoldable<'tcx>
+ pub fn replace_late_bound_regions_with_placeholders<T>(
+ &self,
+ binder: &ty::Binder<T>,
+ ) -> (T, PlaceholderMap<'tcx>)
+ where
+ T : TypeFoldable<'tcx>,
{
+ let new_universe = self.create_subuniverse();
+
let (result, map) = self.tcx.replace_late_bound_regions(binder, |br| {
- self.universe.set(self.universe().subuniverse());
- self.tcx.mk_region(ty::ReSkolemized(self.universe(), br))
+ self.tcx.mk_region(ty::RePlaceholder(ty::Placeholder {
+ universe: new_universe,
+ name: br,
+ }))
});
- debug!("skolemize_bound_regions(binder={:?}, result={:?}, map={:?})",
+ debug!("replace_late_bound_regions_with_placeholders(binder={:?}, result={:?}, map={:?})",
binder,
result,
map);
}
/// Searches the region constraints created since `snapshot` was started
- /// and checks to determine whether any of the skolemized regions created
- /// in `skol_map` would "escape" -- meaning that they are related to
+ /// and checks to determine whether any of the placeholder regions created
+ /// in `placeholder_map` would "escape" -- meaning that they are related to
/// other regions in some way. If so, the higher-ranked subtyping doesn't
/// hold. See `README.md` for more details.
pub fn leak_check(&self,
overly_polymorphic: bool,
_span: Span,
- skol_map: &SkolemizationMap<'tcx>,
+ placeholder_map: &PlaceholderMap<'tcx>,
snapshot: &CombinedSnapshot<'a, 'tcx>)
-> RelateResult<'tcx, ()>
{
- debug!("leak_check: skol_map={:?}",
- skol_map);
+ debug!("leak_check: placeholder_map={:?}",
+ placeholder_map);
// If the user gave `-Zno-leak-check`, then skip the leak
// check completely. This is wildly unsound and also not
}
let new_vars = self.region_vars_confined_to_snapshot(snapshot);
- for (&skol_br, &skol) in skol_map {
- // The inputs to a skolemized variable can only
+ for (&placeholder_br, &placeholder) in placeholder_map {
+ // The inputs to a placeholder variable can only
// be itself or other new variables.
let incoming_taints = self.tainted_regions(snapshot,
- skol,
+ placeholder,
TaintDirections::both());
for &tainted_region in &incoming_taints {
- // Each skolemized should only be relatable to itself
+ // Each placeholder should only be relatable to itself
// or new variables:
match *tainted_region {
ty::ReVar(vid) => {
}
}
_ => {
- if tainted_region == skol { continue; }
+ if tainted_region == placeholder { continue; }
}
};
debug!("{:?} (which replaced {:?}) is tainted by {:?}",
- skol,
- skol_br,
+ placeholder,
+ placeholder_br,
tainted_region);
return Err(if overly_polymorphic {
debug!("Overly polymorphic!");
- TypeError::RegionsOverlyPolymorphic(skol_br, tainted_region)
+ TypeError::RegionsOverlyPolymorphic(placeholder_br, tainted_region)
} else {
debug!("Not as polymorphic!");
- TypeError::RegionsInsufficientlyPolymorphic(skol_br, tainted_region)
+ TypeError::RegionsInsufficientlyPolymorphic(placeholder_br, tainted_region)
})
}
}
Ok(())
}
- /// This code converts from skolemized regions back to late-bound
+ /// This code converts from placeholder regions back to late-bound
/// regions. It works by replacing each region in the taint set of a
- /// skolemized region with a bound-region. The bound region will be bound
+ /// placeholder region with a bound-region. The bound region will be bound
/// by the outer-most binder in `value`; the caller must ensure that there is
/// such a binder and it is the right place.
///
/// where A : Clone
/// { ... }
///
- /// Here we will have replaced `'a` with a skolemized region
+ /// Here we will have replaced `'a` with a placeholder region
/// `'0`. This means that our substitution will be `{A=>&'0
/// int, R=>&'0 int}`.
///
/// to the depth of the predicate, in this case 1, so that the final
/// predicate is `for<'a> &'a int : Clone`.
pub fn plug_leaks<T>(&self,
- skol_map: SkolemizationMap<'tcx>,
+ placeholder_map: PlaceholderMap<'tcx>,
snapshot: &CombinedSnapshot<'a, 'tcx>,
value: T) -> T
where T : TypeFoldable<'tcx>
{
- debug!("plug_leaks(skol_map={:?}, value={:?})",
- skol_map,
+ debug!("plug_leaks(placeholder_map={:?}, value={:?})",
+ placeholder_map,
value);
- if skol_map.is_empty() {
+ if placeholder_map.is_empty() {
return value;
}
- // Compute a mapping from the "taint set" of each skolemized
+ // Compute a mapping from the "taint set" of each placeholder
// region back to the `ty::BoundRegion` that it originally
// represented. Because `leak_check` passed, we know that
// these taint sets are mutually disjoint.
- let inv_skol_map: FxHashMap<ty::Region<'tcx>, ty::BoundRegion> =
- skol_map
+ let inv_placeholder_map: FxHashMap<ty::Region<'tcx>, ty::BoundRegion> =
+ placeholder_map
.iter()
- .flat_map(|(&skol_br, &skol)| {
- self.tainted_regions(snapshot, skol, TaintDirections::both())
+ .flat_map(|(&placeholder_br, &placeholder)| {
+ self.tainted_regions(snapshot, placeholder, TaintDirections::both())
.into_iter()
- .map(move |tainted_region| (tainted_region, skol_br))
+ .map(move |tainted_region| (tainted_region, placeholder_br))
})
.collect();
- debug!("plug_leaks: inv_skol_map={:?}",
- inv_skol_map);
+ debug!("plug_leaks: inv_placeholder_map={:?}",
+ inv_placeholder_map);
// Remove any instantiated type variables from `value`; those can hide
// references to regions from the `fold_regions` code below.
let value = self.resolve_type_vars_if_possible(&value);
- // Map any skolemization byproducts back to a late-bound
+ // Map any placeholder byproducts back to a late-bound
// region. Put that late-bound region at whatever the outermost
// binder is that we encountered in `value`. The caller is
// responsible for ensuring that (a) `value` contains at least one
// binder and (b) that binder is the one we want to use.
let result = self.tcx.fold_regions(&value, &mut false, |r, current_depth| {
- match inv_skol_map.get(&r) {
+ match inv_placeholder_map.get(&r) {
None => r,
Some(br) => {
// It is the responsibility of the caller to ensure
- // that each skolemized region appears within a
+ // that each placeholder region appears within a
// binder. In practice, this routine is only used by
- // trait checking, and all of the skolemized regions
+ // trait checking, and all of the placeholder regions
// appear inside predicates, which always have
// binders, so this assert is satisfied.
assert!(current_depth > ty::INNERMOST);
- // since leak-check passed, this skolemized region
+ // since leak-check passed, this placeholder region
// should only have incoming edges from variables
// (which ought not to escape the snapshot, but we
// don't check that) or itself
assert!(
match *r {
ty::ReVar(_) => true,
- ty::ReSkolemized(_, ref br1) => br == br1,
+ ty::RePlaceholder(index) => index.name == *br,
_ => false,
},
"leak-check would have us replace {:?} with {:?}",
}
});
- self.pop_skolemized(skol_map, snapshot);
+ self.pop_placeholders(placeholder_map, snapshot);
debug!("plug_leaks: result={:?}", result);
result
}
- /// Pops the skolemized regions found in `skol_map` from the region
- /// inference context. Whenever you create skolemized regions via
- /// `skolemize_late_bound_regions`, they must be popped before you
+ /// Pops the placeholder regions found in `placeholder_map` from the region
+ /// inference context. Whenever you create placeholder regions via
+ /// `replace_late_bound_regions_with_placeholders`, they must be popped before you
/// commit the enclosing snapshot (if you do not commit, e.g. within a
/// probe or as a result of an error, then this is not necessary, as
/// popping happens as part of the rollback).
///
/// Note: popping also occurs implicitly as part of `leak_check`.
- pub fn pop_skolemized(&self,
- skol_map: SkolemizationMap<'tcx>,
- snapshot: &CombinedSnapshot<'a, 'tcx>) {
- debug!("pop_skolemized({:?})", skol_map);
- let skol_regions: FxHashSet<_> = skol_map.values().cloned().collect();
+ pub fn pop_placeholders(
+ &self,
+ placeholder_map: PlaceholderMap<'tcx>,
+ snapshot: &CombinedSnapshot<'a, 'tcx>,
+ ) {
+ debug!("pop_placeholders({:?})", placeholder_map);
+ let placeholder_regions: FxHashSet<_> = placeholder_map.values().cloned().collect();
self.borrow_region_constraints()
- .pop_skolemized(self.universe(), &skol_regions, &snapshot.region_constraints_snapshot);
+ .pop_placeholders(
+ &placeholder_regions,
+ &snapshot.region_constraints_snapshot,
+ );
self.universe.set(snapshot.universe);
- if !skol_map.is_empty() {
- self.projection_cache.borrow_mut().rollback_skolemized(
+ if !placeholder_map.is_empty() {
+ self.projection_cache.borrow_mut().rollback_placeholder(
&snapshot.projection_cache_snapshot);
}
}
use ty::fold::TypeFoldable;
use ty::{self, Ty, TyCtxt};
use ty::{ReEarlyBound, ReEmpty, ReErased, ReFree, ReStatic};
-use ty::{ReLateBound, ReScope, ReSkolemized, ReVar};
+use ty::{ReLateBound, ReScope, RePlaceholder, ReVar};
use ty::{Region, RegionVid};
mod graphviz;
// For these types, we cannot define any additional
// relationship:
- (&ReSkolemized(..), _) | (_, &ReSkolemized(..)) => if a == b {
+ (&RePlaceholder(..), _) | (_, &RePlaceholder(..)) => if a == b {
a
} else {
tcx.types.re_static
universe: Cell<ty::UniverseIndex>,
}
-/// A map returned by `skolemize_late_bound_regions()` indicating the skolemized
-/// region that each late-bound region was replaced with.
-pub type SkolemizationMap<'tcx> = BTreeMap<ty::BoundRegion, ty::Region<'tcx>>;
+/// A map returned by `replace_late_bound_regions_with_placeholders()`
+/// indicating the placeholder region that each late-bound region was
+/// replaced with.
+pub type PlaceholderMap<'tcx> = BTreeMap<ty::BoundRegion, ty::Region<'tcx>>;
/// See `error_reporting` module for more details
#[derive(Clone, Debug)]
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
pub enum NLLRegionVariableOrigin {
- // During NLL region processing, we create variables for free
- // regions that we encounter in the function signature and
- // elsewhere. This origin indices we've got one of those.
+ /// During NLL region processing, we create variables for free
+ /// regions that we encounter in the function signature and
+ /// elsewhere. This origin indices we've got one of those.
FreeRegion,
- BoundRegion(ty::UniverseIndex),
+ /// "Universal" instantiation of a higher-ranked region (e.g.,
+ /// from a `for<'a> T` binder). Meant to represent "any region".
+ Placeholder(ty::Placeholder),
Existential,
}
pub fn is_universal(self) -> bool {
match self {
NLLRegionVariableOrigin::FreeRegion => true,
- NLLRegionVariableOrigin::BoundRegion(..) => true,
+ NLLRegionVariableOrigin::Placeholder(..) => true,
NLLRegionVariableOrigin::Existential => false,
}
}
a,
b,
},
- skol_map,
- ) = self.skolemize_late_bound_regions(predicate);
+ placeholder_map,
+ ) = self.replace_late_bound_regions_with_placeholders(predicate);
let cause_span = cause.span;
let ok = self.at(cause, param_env).sub_exp(a_is_expected, a, b)?;
- self.leak_check(false, cause_span, &skol_map, snapshot)?;
- self.pop_skolemized(skol_map, snapshot);
+ self.leak_check(false, cause_span, &placeholder_map, snapshot)?;
+ self.pop_placeholders(placeholder_map, snapshot);
Ok(ok.unit())
}))
}
predicate: &ty::PolyRegionOutlivesPredicate<'tcx>,
) -> UnitResult<'tcx> {
self.commit_if_ok(|snapshot| {
- let (ty::OutlivesPredicate(r_a, r_b), skol_map) =
- self.skolemize_late_bound_regions(predicate);
+ let (ty::OutlivesPredicate(r_a, r_b), placeholder_map) =
+ self.replace_late_bound_regions_with_placeholders(predicate);
let origin = SubregionOrigin::from_obligation_cause(cause, || {
RelateRegionParamBound(cause.span)
});
self.sub_regions(origin, r_b, r_a); // `b : a` ==> `a <= b`
- self.leak_check(false, cause.span, &skol_map, snapshot)?;
- Ok(self.pop_skolemized(skol_map, snapshot))
+ self.leak_check(false, cause.span, &placeholder_map, snapshot)?;
+ Ok(self.pop_placeholders(placeholder_map, snapshot))
})
}
//! See README.md
-use self::UndoLogEntry::*;
use self::CombineMapType::*;
+use self::UndoLogEntry::*;
-use super::{MiscVariable, RegionVariableOrigin, SubregionOrigin};
use super::unify_key;
+use super::{MiscVariable, RegionVariableOrigin, SubregionOrigin};
-use rustc_data_structures::indexed_vec::IndexVec;
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
+use rustc_data_structures::indexed_vec::IndexVec;
use rustc_data_structures::unify as ut;
-use ty::{self, Ty, TyCtxt};
-use ty::{Region, RegionVid};
use ty::ReStatic;
+use ty::{self, Ty, TyCtxt};
use ty::{BrFresh, ReLateBound, ReVar};
+use ty::{Region, RegionVid};
use std::collections::BTreeMap;
use std::{cmp, fmt, mem, u32};
any_unifications: bool,
}
-/// When working with skolemized regions, we often wish to find all of
-/// the regions that are either reachable from a skolemized region, or
-/// which can reach a skolemized region, or both. We call such regions
-/// *tained* regions. This struct allows you to decide what set of
+/// When working with placeholder regions, we often wish to find all of
+/// the regions that are either reachable from a placeholder region, or
+/// which can reach a placeholder region, or both. We call such regions
+/// *tainted* regions. This struct allows you to decide what set of
/// tainted regions you want.
#[derive(Debug)]
pub struct TaintDirections {
}
}
- pub fn new_region_var(&mut self,
- universe: ty::UniverseIndex,
- origin: RegionVariableOrigin) -> RegionVid {
- let vid = self.var_infos.push(RegionVariableInfo {
- origin,
- universe,
- });
+ pub fn new_region_var(
+ &mut self,
+ universe: ty::UniverseIndex,
+ origin: RegionVariableOrigin,
+ ) -> RegionVid {
+ let vid = self.var_infos.push(RegionVariableInfo { origin, universe });
let u_vid = self.unification_table
.new_key(unify_key::RegionVidKey { min_vid: vid });
}
debug!(
"created new region variable {:?} with origin {:?}",
- vid,
- origin
+ vid, origin
);
return vid;
}
self.var_infos[vid].origin
}
- /// Removes all the edges to/from the skolemized regions that are
+ /// Removes all the edges to/from the placeholder regions that are
/// in `skols`. This is used after a higher-ranked operation
- /// completes to remove all trace of the skolemized regions
+ /// completes to remove all trace of the placeholder regions
/// created in that time.
- pub fn pop_skolemized(
+ pub fn pop_placeholders(
&mut self,
- skolemization_count: ty::UniverseIndex,
- skols: &FxHashSet<ty::Region<'tcx>>,
+ placeholders: &FxHashSet<ty::Region<'tcx>>,
snapshot: &RegionSnapshot,
) {
- debug!("pop_skolemized_regions(skols={:?})", skols);
+ debug!("pop_placeholders(placeholders={:?})", placeholders);
assert!(self.in_snapshot());
assert!(self.undo_log[snapshot.length] == OpenSnapshot);
- assert!(
- skolemization_count.as_usize() >= skols.len(),
- "popping more skolemized variables than actually exist, \
- sc now = {:?}, skols.len = {:?}",
- skolemization_count,
- skols.len()
- );
-
- let last_to_pop = skolemization_count.subuniverse();
- let first_to_pop = ty::UniverseIndex::from(last_to_pop.as_u32() - skols.len() as u32);
-
- debug_assert! {
- skols.iter()
- .all(|&k| match *k {
- ty::ReSkolemized(universe, _) =>
- universe >= first_to_pop &&
- universe < last_to_pop,
- _ =>
- false
- }),
- "invalid skolemization keys or keys out of range ({:?}..{:?}): {:?}",
- first_to_pop,
- last_to_pop,
- skols
- }
let constraints_to_kill: Vec<usize> = self.undo_log
.iter()
.enumerate()
.rev()
- .filter(|&(_, undo_entry)| kill_constraint(skols, undo_entry))
+ .filter(|&(_, undo_entry)| kill_constraint(placeholders, undo_entry))
.map(|(index, _)| index)
.collect();
return;
fn kill_constraint<'tcx>(
- skols: &FxHashSet<ty::Region<'tcx>>,
+ placeholders: &FxHashSet<ty::Region<'tcx>>,
undo_entry: &UndoLogEntry<'tcx>,
) -> bool {
match undo_entry {
&AddConstraint(Constraint::VarSubVar(..)) => false,
- &AddConstraint(Constraint::RegSubVar(a, _)) => skols.contains(&a),
- &AddConstraint(Constraint::VarSubReg(_, b)) => skols.contains(&b),
+ &AddConstraint(Constraint::RegSubVar(a, _)) => placeholders.contains(&a),
+ &AddConstraint(Constraint::VarSubReg(_, b)) => placeholders.contains(&b),
&AddConstraint(Constraint::RegSubReg(a, b)) => {
- skols.contains(&a) || skols.contains(&b)
+ placeholders.contains(&a) || placeholders.contains(&b)
}
&AddGiven(..) => false,
&AddVerify(_) => false,
&AddCombination(_, ref two_regions) => {
- skols.contains(&two_regions.a) || skols.contains(&two_regions.b)
+ placeholders.contains(&two_regions.a) || placeholders.contains(&two_regions.b)
}
&AddVar(..) | &OpenSnapshot | &Purged | &CommitedSnapshot => false,
}
// cannot add constraints once regions are resolved
debug!(
"RegionConstraintCollector: make_subregion({:?}, {:?}) due to {:?}",
- sub,
- sup,
- origin
+ sub, sup, origin
);
match (sub, sup) {
fn universe(&self, region: Region<'tcx>) -> ty::UniverseIndex {
match *region {
- ty::ReScope(..) |
- ty::ReStatic |
- ty::ReEmpty |
- ty::ReErased |
- ty::ReFree(..) |
- ty::ReEarlyBound(..) => ty::UniverseIndex::ROOT,
- ty::ReSkolemized(universe, _) => universe,
- ty::ReClosureBound(vid) |
- ty::ReVar(vid) => self.var_universe(vid),
- ty::ReLateBound(..) =>
- bug!("universe(): encountered bound region {:?}", region),
- ty::ReCanonical(..) =>
- bug!("region_universe(): encountered canonical region {:?}", region),
+ ty::ReScope(..)
+ | ty::ReStatic
+ | ty::ReEmpty
+ | ty::ReErased
+ | ty::ReFree(..)
+ | ty::ReEarlyBound(..) => ty::UniverseIndex::ROOT,
+ ty::RePlaceholder(placeholder) => placeholder.universe,
+ ty::ReClosureBound(vid) | ty::ReVar(vid) => self.var_universe(vid),
+ ty::ReLateBound(..) => bug!("universe(): encountered bound region {:?}", region),
+ ty::ReCanonical(..) => bug!(
+ "region_universe(): encountered canonical region {:?}",
+ region
+ ),
}
}
/// relations are considered. For example, one can say that only
/// "incoming" edges to `r0` are desired, in which case one will
/// get the set of regions `{r|r <= r0}`. This is used when
- /// checking whether skolemized regions are being improperly
+ /// checking whether placeholder regions are being improperly
/// related to other regions.
pub fn tainted(
&self,
) -> FxHashSet<ty::Region<'tcx>> {
debug!(
"tainted(mark={:?}, r0={:?}, directions={:?})",
- mark,
- r0,
- directions
+ mark, r0, directions
);
// `result_set` acts as a worklist: we explore all outgoing
AlignOffsetLangItem, "align_offset", align_offset_fn;
TerminationTraitLangItem, "termination", termination;
+
+ Arc, "arc", arc;
+ Rc, "rc", rc;
}
impl<'a, 'tcx, 'gcx> TyCtxt<'a, 'tcx, 'gcx> {
};
self.with(scope, |_, this| this.visit_ty(&mt.ty));
}
- hir::TyKind::Path(hir::QPath::Resolved(None, ref path)) => {
- if let Def::Existential(exist_ty_did) = path.def {
- let id = self.tcx.hir.as_local_node_id(exist_ty_did).unwrap();
-
- // Resolve the lifetimes in the bounds to the lifetime defs in the generics.
- // `fn foo<'a>() -> impl MyTrait<'a> { ... }` desugars to
- // `abstract type MyAnonTy<'b>: MyTrait<'b>;`
- // ^ ^ this gets resolved in the scope of
- // the exist_ty generics
- let (generics, bounds) = match self.tcx.hir.expect_item(id).node {
- // named existential types don't need these hacks
- hir::ItemKind::Existential(hir::ExistTy{ impl_trait_fn: None, .. }) => {
- intravisit::walk_ty(self, ty);
- return;
- },
- hir::ItemKind::Existential(hir::ExistTy{
- ref generics,
- ref bounds,
- ..
- }) => (
- generics,
- bounds,
- ),
- ref i => bug!("impl Trait pointed to non-existential type?? {:#?}", i),
- };
+ hir::TyKind::Def(item_id, ref lifetimes) => {
+ // Resolve the lifetimes in the bounds to the lifetime defs in the generics.
+ // `fn foo<'a>() -> impl MyTrait<'a> { ... }` desugars to
+ // `abstract type MyAnonTy<'b>: MyTrait<'b>;`
+ // ^ ^ this gets resolved in the scope of
+ // the exist_ty generics
+ let (generics, bounds) = match self.tcx.hir.expect_item(item_id.id).node {
+ // named existential types are reached via TyKind::Path
+ // this arm is for `impl Trait` in the types of statics, constants and locals
+ hir::ItemKind::Existential(hir::ExistTy{ impl_trait_fn: None, .. }) => {
+ intravisit::walk_ty(self, ty);
+ return;
+ },
+ // RPIT (return position impl trait)
+ hir::ItemKind::Existential(hir::ExistTy{
+ ref generics,
+ ref bounds,
+ ..
+ }) => (
+ generics,
+ bounds,
+ ),
+ ref i => bug!("impl Trait pointed to non-existential type?? {:#?}", i),
+ };
+
+ // Resolve the lifetimes that are applied to the existential type.
+ // These are resolved in the current scope.
+ // `fn foo<'a>() -> impl MyTrait<'a> { ... }` desugars to
+ // `fn foo<'a>() -> MyAnonTy<'a> { ... }`
+ // ^ ^this gets resolved in the current scope
+ for lifetime in lifetimes {
+ if let hir::GenericArg::Lifetime(lifetime) = lifetime {
+ self.visit_lifetime(lifetime);
- assert!(exist_ty_did.is_local());
- // Resolve the lifetimes that are applied to the existential type.
- // These are resolved in the current scope.
- // `fn foo<'a>() -> impl MyTrait<'a> { ... }` desugars to
- // `fn foo<'a>() -> MyAnonTy<'a> { ... }`
- // ^ ^this gets resolved in the current scope
- for lifetime in &path.segments[0].args.as_ref().unwrap().args {
- if let hir::GenericArg::Lifetime(lifetime) = lifetime {
- self.visit_lifetime(lifetime);
-
- // Check for predicates like `impl for<'a> Trait<impl OtherTrait<'a>>`
- // and ban them. Type variables instantiated inside binders aren't
- // well-supported at the moment, so this doesn't work.
- // In the future, this should be fixed and this error should be removed.
- let def = self.map.defs.get(&lifetime.id).cloned();
- if let Some(Region::LateBound(_, def_id, _)) = def {
- if let Some(node_id) = self.tcx.hir.as_local_node_id(def_id) {
- // Ensure that the parent of the def is an item, not HRTB
- let parent_id = self.tcx.hir.get_parent_node(node_id);
- let parent_impl_id = hir::ImplItemId { node_id: parent_id };
- let parent_trait_id = hir::TraitItemId { node_id: parent_id };
- let krate = self.tcx.hir.forest.krate();
- if !(krate.items.contains_key(&parent_id)
- || krate.impl_items.contains_key(&parent_impl_id)
- || krate.trait_items.contains_key(&parent_trait_id))
- {
- span_err!(
- self.tcx.sess,
- lifetime.span,
- E0657,
- "`impl Trait` can only capture lifetimes \
- bound at the fn or impl level"
- );
- self.uninsert_lifetime_on_error(lifetime, def.unwrap());
- }
+ // Check for predicates like `impl for<'a> Trait<impl OtherTrait<'a>>`
+ // and ban them. Type variables instantiated inside binders aren't
+ // well-supported at the moment, so this doesn't work.
+ // In the future, this should be fixed and this error should be removed.
+ let def = self.map.defs.get(&lifetime.id).cloned();
+ if let Some(Region::LateBound(_, def_id, _)) = def {
+ if let Some(node_id) = self.tcx.hir.as_local_node_id(def_id) {
+ // Ensure that the parent of the def is an item, not HRTB
+ let parent_id = self.tcx.hir.get_parent_node(node_id);
+ let parent_impl_id = hir::ImplItemId { node_id: parent_id };
+ let parent_trait_id = hir::TraitItemId { node_id: parent_id };
+ let krate = self.tcx.hir.forest.krate();
+ if !(krate.items.contains_key(&parent_id)
+ || krate.impl_items.contains_key(&parent_impl_id)
+ || krate.trait_items.contains_key(&parent_trait_id))
+ {
+ span_err!(
+ self.tcx.sess,
+ lifetime.span,
+ E0657,
+ "`impl Trait` can only capture lifetimes \
+ bound at the fn or impl level"
+ );
+ self.uninsert_lifetime_on_error(lifetime, def.unwrap());
}
}
}
}
+ }
- // We want to start our early-bound indices at the end of the parent scope,
- // not including any parent `impl Trait`s.
- let mut index = self.next_early_index_for_abstract_type();
- debug!("visit_ty: index = {}", index);
+ // We want to start our early-bound indices at the end of the parent scope,
+ // not including any parent `impl Trait`s.
+ let mut index = self.next_early_index_for_abstract_type();
+ debug!("visit_ty: index = {}", index);
- let mut elision = None;
- let mut lifetimes = FxHashMap();
- let mut type_count = 0;
- for param in &generics.params {
- match param.kind {
- GenericParamKind::Lifetime { .. } => {
- let (name, reg) = Region::early(&self.tcx.hir, &mut index, ¶m);
- if let hir::ParamName::Plain(param_name) = name {
- if param_name.name == keywords::UnderscoreLifetime.name() {
- // Pick the elided lifetime "definition" if one exists
- // and use it to make an elision scope.
- elision = Some(reg);
- } else {
- lifetimes.insert(name, reg);
- }
+ let mut elision = None;
+ let mut lifetimes = FxHashMap();
+ let mut type_count = 0;
+ for param in &generics.params {
+ match param.kind {
+ GenericParamKind::Lifetime { .. } => {
+ let (name, reg) = Region::early(&self.tcx.hir, &mut index, ¶m);
+ if let hir::ParamName::Plain(param_name) = name {
+ if param_name.name == keywords::UnderscoreLifetime.name() {
+ // Pick the elided lifetime "definition" if one exists
+ // and use it to make an elision scope.
+ elision = Some(reg);
} else {
lifetimes.insert(name, reg);
}
- }
- GenericParamKind::Type { .. } => {
- type_count += 1;
+ } else {
+ lifetimes.insert(name, reg);
}
}
+ GenericParamKind::Type { .. } => {
+ type_count += 1;
+ }
}
- let next_early_index = index + type_count;
+ }
+ let next_early_index = index + type_count;
- if let Some(elision_region) = elision {
- let scope = Scope::Elision {
- elide: Elide::Exact(elision_region),
- s: self.scope,
- };
- self.with(scope, |_old_scope, this| {
- let scope = Scope::Binder {
- lifetimes,
- next_early_index,
- s: this.scope,
- track_lifetime_uses: true,
- abstract_type_parent: false,
- };
- this.with(scope, |_old_scope, this| {
- this.visit_generics(generics);
- for bound in bounds {
- this.visit_param_bound(bound);
- }
- });
- });
- } else {
+ if let Some(elision_region) = elision {
+ let scope = Scope::Elision {
+ elide: Elide::Exact(elision_region),
+ s: self.scope,
+ };
+ self.with(scope, |_old_scope, this| {
let scope = Scope::Binder {
lifetimes,
next_early_index,
- s: self.scope,
+ s: this.scope,
track_lifetime_uses: true,
abstract_type_parent: false,
};
- self.with(scope, |_old_scope, this| {
+ this.with(scope, |_old_scope, this| {
this.visit_generics(generics);
for bound in bounds {
this.visit_param_bound(bound);
}
});
- }
+ });
} else {
- intravisit::walk_ty(self, ty)
+ let scope = Scope::Binder {
+ lifetimes,
+ next_early_index,
+ s: self.scope,
+ track_lifetime_uses: true,
+ abstract_type_parent: false,
+ };
+ self.with(scope, |_old_scope, this| {
+ this.visit_generics(generics);
+ for bound in bounds {
+ this.visit_param_bound(bound);
+ }
+ });
}
}
_ => intravisit::walk_ty(self, ty),
feature: Symbol::intern("rustc_private"),
rustc_depr: None,
const_stability: None,
+ promotable: false,
});
annotator.parent_stab = Some(stability);
}
pub fn from_uint(i: impl Into<u128>, size: Size) -> Self {
let i = i.into();
debug_assert_eq!(truncate(i, size), i,
- "Unsigned value {} does not fit in {} bits", i, size.bits());
+ "Unsigned value {} does not fit in {} bits", i, size.bits());
Scalar::Bits { bits: i, size: size.bytes() as u8 }
}
// `into` performed sign extension, we have to truncate
let truncated = truncate(i as u128, size);
debug_assert_eq!(sign_extend(truncated, size) as i128, i,
- "Signed value {} does not fit in {} bits", i, size.bits());
+ "Signed value {} does not fit in {} bits", i, size.bits());
Scalar::Bits { bits: truncated, size: size.bytes() as u8 }
}
//!
//! [rustc guide]: https://rust-lang-nursery.github.io/rustc-guide/mir/index.html
-use graphviz::IntoCow;
use hir::def::CtorKind;
use hir::def_id::DefId;
use hir::{self, HirId, InlineAsm};
if idx < stmts.len() {
&stmts[idx].source_info
} else {
- assert!(idx == stmts.len());
+ assert_eq!(idx, stmts.len());
&block.terminator().source_info
}
}
/// Check if `sub` is a sub scope of `sup`
pub fn is_sub_scope(&self, mut sub: SourceScope, sup: SourceScope) -> bool {
- loop {
- if sub == sup {
- return true;
- }
+ while sub != sup {
match self.source_scopes[sub].parent_scope {
None => return false,
Some(p) => sub = p,
}
}
+ true
}
/// Return the return type, it always return first element from `local_decls` array
pub fn allows_two_phase_borrow(&self) -> bool {
match *self {
BorrowKind::Shared | BorrowKind::Shallow | BorrowKind::Unique => false,
- BorrowKind::Mut {
- allow_two_phase_borrow,
- } => allow_two_phase_borrow,
+ BorrowKind::Mut { allow_two_phase_borrow } => allow_two_phase_borrow,
}
}
}
/// This is a binding for a non-`self` binding, or a `self` that has an explicit type.
Var(VarBindingForm<'tcx>),
/// Binding for a `self`/`&self`/`&mut self` binding where the type is implicit.
- ImplicitSelf,
+ ImplicitSelf(ImplicitSelfKind),
/// Reference used in a guard expression to ensure immutability.
RefForGuard,
}
+/// Represents what type of implicit self a function has, if any.
+#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, RustcEncodable, RustcDecodable)]
+pub enum ImplicitSelfKind {
+ /// Represents a `fn x(self);`.
+ Imm,
+ /// Represents a `fn x(mut self);`.
+ Mut,
+ /// Represents a `fn x(&self);`.
+ ImmRef,
+ /// Represents a `fn x(&mut self);`.
+ MutRef,
+ /// Represents when a function does not have a self argument or
+ /// when a function has a `self: X` argument.
+ None
+}
+
CloneTypeFoldableAndLiftImpls! { BindingForm<'tcx>, }
impl_stable_hash_for!(struct self::VarBindingForm<'tcx> {
pat_span
});
+impl_stable_hash_for!(enum self::ImplicitSelfKind {
+ Imm,
+ Mut,
+ ImmRef,
+ MutRef,
+ None
+});
+
mod binding_form_impl {
use ich::StableHashingContext;
use rustc_data_structures::stable_hasher::{HashStable, StableHasher, StableHasherResult};
match self {
Var(binding) => binding.hash_stable(hcx, hasher),
- ImplicitSelf => (),
+ ImplicitSelf(kind) => kind.hash_stable(hcx, hasher),
RefForGuard => (),
}
}
pat_span: _,
}))) => true,
- // FIXME: might be able to thread the distinction between
- // `self`/`mut self`/`&self`/`&mut self` into the
- // `BindingForm::ImplicitSelf` variant, (and then return
- // true here for solely the first case).
+ Some(ClearCrossCrate::Set(BindingForm::ImplicitSelf(ImplicitSelfKind::Imm)))
+ => true,
+
_ => false,
}
}
pat_span: _,
}))) => true,
- Some(ClearCrossCrate::Set(BindingForm::ImplicitSelf)) => true,
+ Some(ClearCrossCrate::Set(BindingForm::ImplicitSelf(_))) => true,
_ => false,
}
destination: Option<(Place<'tcx>, BasicBlock)>,
/// Cleanups to be done if the call unwinds.
cleanup: Option<BasicBlock>,
+ /// Whether this is from a call in HIR, rather than from an overloaded
+ /// operator. True for overloaded function call.
+ from_hir_call: bool,
},
/// Jump to the target if the condition has the expected value,
};
fmt_const_val(&mut s, &c).unwrap();
s.into()
- }).chain(iter::once(String::from("otherwise").into()))
+ }).chain(iter::once("otherwise".into()))
.collect()
}
Call {
destination: Some(_),
cleanup: Some(_),
..
- } => vec!["return".into_cow(), "unwind".into_cow()],
+ } => vec!["return".into(), "unwind".into()],
Call {
destination: Some(_),
cleanup: None,
..
- } => vec!["return".into_cow()],
+ } => vec!["return".into()],
Call {
destination: None,
cleanup: Some(_),
..
- } => vec!["unwind".into_cow()],
+ } => vec!["unwind".into()],
Call {
destination: None,
cleanup: None,
..
} => vec![],
- Yield { drop: Some(_), .. } => vec!["resume".into_cow(), "drop".into_cow()],
- Yield { drop: None, .. } => vec!["resume".into_cow()],
+ Yield { drop: Some(_), .. } => vec!["resume".into(), "drop".into()],
+ Yield { drop: None, .. } => vec!["resume".into()],
DropAndReplace { unwind: None, .. } | Drop { unwind: None, .. } => {
- vec!["return".into_cow()]
+ vec!["return".into()]
}
DropAndReplace {
unwind: Some(_), ..
}
| Drop {
unwind: Some(_), ..
- } => vec!["return".into_cow(), "unwind".into_cow()],
+ } => vec!["return".into(), "unwind".into()],
Assert { cleanup: None, .. } => vec!["".into()],
- Assert { .. } => vec!["success".into_cow(), "unwind".into_cow()],
+ Assert { .. } => vec!["success".into(), "unwind".into()],
FalseEdges {
ref imaginary_targets,
..
ref args,
ref destination,
cleanup,
+ from_hir_call,
} => {
let dest = destination
.as_ref()
args: args.fold_with(folder),
destination: dest,
cleanup,
+ from_hir_call,
}
}
Assert {
String::new()
};
- let crate_disambiguator = format!("{}", tcx.crate_disambiguator(cnum));
+ let crate_disambiguator = tcx.crate_disambiguator(cnum).to_string();
// Using a shortened disambiguator of about 40 bits
format!("{}.{}{}",
tcx.crate_name(cnum),
assert!(index < adt_def.variants.len());
assert_eq!(adt_def, adt_def1);
PlaceTy::Downcast { adt_def,
- substs,
- variant_index: index }
+ substs,
+ variant_index: index }
}
_ => {
bug!("cannot downcast non-ADT type: `{:?}`", self)
}
},
_ => None,
- }\f
+ }
_ => None,
}
}
impl<'tcx> BinOp {
pub fn ty<'a, 'gcx>(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>,
- lhs_ty: Ty<'tcx>,
- rhs_ty: Ty<'tcx>)
- -> Ty<'tcx> {
+ lhs_ty: Ty<'tcx>,
+ rhs_ty: Ty<'tcx>)
+ -> Ty<'tcx> {
// FIXME: handle SIMD correctly
match self {
&BinOp::Add | &BinOp::Sub | &BinOp::Mul | &BinOp::Div | &BinOp::Rem |
TerminatorKind::Call { ref $($mutability)* func,
ref $($mutability)* args,
ref $($mutability)* destination,
- cleanup } => {
+ cleanup,
+ from_hir_call: _, } => {
self.visit_operand(func, source_location);
for arg in args {
self.visit_operand(arg, source_location);
{
debug!("overlap(a_def_id={:?}, b_def_id={:?})", a_def_id, b_def_id);
- // For the purposes of this check, we don't bring any skolemized
+ // For the purposes of this check, we don't bring any placeholder
// types into scope; instead, we replace the generic types with
// fresh type variables, and hence we do our evaluations in an
// empty environment.
ty::Error => true,
+ ty::UnnormalizedProjection(..) |
ty::Closure(..) |
ty::Generator(..) |
ty::GeneratorWitness(..) |
ty::Generator(..) => Some(18),
ty::Foreign(..) => Some(19),
ty::GeneratorWitness(..) => Some(20),
- ty::Infer(..) | ty::Error => None
+ ty::Infer(..) | ty::Error => None,
+ ty::UnnormalizedProjection(..) => bug!("only used with chalk-engine"),
}
}
ty::Predicate::Trait(ref data) => {
let trait_obligation = obligation.with(data.clone());
- if data.is_global() && !data.has_late_bound_regions() {
+ if data.is_global() {
// no type variables present, can use evaluation for better caching.
// FIXME: consider caching errors too.
if self.selcx.infcx().predicate_must_hold(&obligation) {
match binder.no_late_bound_regions() {
// If so, this obligation is an error (for now). Eventually we should be
// able to support additional cases here, like `for<'a> &'a str: 'a`.
+ // NOTE: this is duplicate-implemented between here and fulfillment.
None => {
ProcessResult::Error(CodeSelectionError(Unimplemented))
}
let infcx = selcx.infcx();
infcx.commit_if_ok(|snapshot| {
- let (skol_predicate, skol_map) =
- infcx.skolemize_late_bound_regions(&obligation.predicate);
+ let (placeholder_predicate, placeholder_map) =
+ infcx.replace_late_bound_regions_with_placeholders(&obligation.predicate);
- let skol_obligation = obligation.with(skol_predicate);
+ let skol_obligation = obligation.with(placeholder_predicate);
let r = match project_and_unify_type(selcx, &skol_obligation) {
Ok(result) => {
let span = obligation.cause.span;
- match infcx.leak_check(false, span, &skol_map, snapshot) {
- Ok(()) => Ok(infcx.plug_leaks(skol_map, snapshot, result)),
+ match infcx.leak_check(false, span, &placeholder_map, snapshot) {
+ Ok(()) => Ok(infcx.plug_leaks(placeholder_map, snapshot, result)),
Err(e) => {
debug!("poly_project_and_unify_type: leak check encountered error {:?}", e);
Err(MismatchedProjectionTypes { err: e })
// # Cache
-/// The projection cache. Unlike the standard caches, this can
-/// include infcx-dependent type variables - therefore, we have to roll
-/// the cache back each time we roll a snapshot back, to avoid assumptions
-/// on yet-unresolved inference variables. Types with skolemized regions
-/// also have to be removed when the respective snapshot ends.
+/// The projection cache. Unlike the standard caches, this can include
+/// infcx-dependent type variables - therefore, we have to roll the
+/// cache back each time we roll a snapshot back, to avoid assumptions
+/// on yet-unresolved inference variables. Types with placeholder
+/// regions also have to be removed when the respective snapshot ends.
///
/// Because of that, projection cache entries can be "stranded" and left
/// inaccessible when type variables inside the key are resolved. We make no
self.map.rollback_to(&snapshot.snapshot);
}
- pub fn rollback_skolemized(&mut self, snapshot: &ProjectionCacheSnapshot) {
+ pub fn rollback_placeholder(&mut self, snapshot: &ProjectionCacheSnapshot) {
self.map.partial_rollback(&snapshot.snapshot, &|k| k.ty.has_re_skol());
}
| ty::Opaque(..)
| ty::Infer(_)
| ty::Generator(..) => false,
+
+ ty::UnnormalizedProjection(..) => bug!("only used with chalk-engine"),
}
}
//!
//! [rustc guide]: https://rust-lang-nursery.github.io/rustc-guide/traits/resolution.html#selection
-use self::SelectionCandidate::*;
use self::EvaluationResult::*;
+use self::SelectionCandidate::*;
use super::coherence::{self, Conflict};
-use super::DerivedObligationCause;
-use super::{IntercrateMode, TraitQueryMode};
use super::project;
use super::project::{normalize_with_depth, Normalized, ProjectionCacheKey};
-use super::{PredicateObligation, TraitObligation, ObligationCause};
-use super::{ObligationCauseCode, BuiltinDerivedObligation, ImplDerivedObligation};
-use super::{SelectionError, Unimplemented, OutputTypeParameterMismatch, Overflow};
-use super::{ObjectCastObligation, Obligation};
-use super::TraitNotObjectSafe;
+use super::util;
+use super::DerivedObligationCause;
use super::Selection;
use super::SelectionResult;
-use super::{VtableBuiltin, VtableImpl, VtableParam, VtableClosure, VtableGenerator,
- VtableFnPointer, VtableObject, VtableAutoImpl};
-use super::{VtableImplData, VtableObjectData, VtableBuiltinData, VtableGeneratorData,
- VtableClosureData, VtableAutoImplData, VtableFnPointerData};
-use super::util;
-
-use dep_graph::{DepNodeIndex, DepKind};
+use super::TraitNotObjectSafe;
+use super::{BuiltinDerivedObligation, ImplDerivedObligation, ObligationCauseCode};
+use super::{IntercrateMode, TraitQueryMode};
+use super::{ObjectCastObligation, Obligation};
+use super::{ObligationCause, PredicateObligation, TraitObligation};
+use super::{OutputTypeParameterMismatch, Overflow, SelectionError, Unimplemented};
+use super::{
+ VtableAutoImpl, VtableBuiltin, VtableClosure, VtableFnPointer, VtableGenerator, VtableImpl,
+ VtableObject, VtableParam,
+};
+use super::{
+ VtableAutoImplData, VtableBuiltinData, VtableClosureData, VtableFnPointerData,
+ VtableGeneratorData, VtableImplData, VtableObjectData,
+};
+
+use dep_graph::{DepKind, DepNodeIndex};
use hir::def_id::DefId;
use infer;
use infer::{InferCtxt, InferOk, TypeFreshener};
-use ty::subst::{Subst, Substs};
-use ty::{self, ToPredicate, ToPolyTraitRef, Ty, TyCtxt, TypeFoldable};
+use middle::lang_items;
+use mir::interpret::GlobalId;
use ty::fast_reject;
use ty::relate::TypeRelation;
-use middle::lang_items;
-use mir::interpret::{GlobalId};
+use ty::subst::{Subst, Substs};
+use ty::{self, ToPolyTraitRef, ToPredicate, Ty, TyCtxt, TypeFoldable};
+use hir;
use rustc_data_structures::bit_set::GrowableBitSet;
use rustc_data_structures::sync::Lock;
-use std::iter;
+use rustc_target::spec::abi::Abi;
use std::cmp;
use std::fmt;
+use std::iter;
use std::mem;
use std::rc::Rc;
-use rustc_target::spec::abi::Abi;
-use hir;
use util::nodemap::{FxHashMap, FxHashSet};
-pub struct SelectionContext<'cx, 'gcx: 'cx+'tcx, 'tcx: 'cx> {
+pub struct SelectionContext<'cx, 'gcx: 'cx + 'tcx, 'tcx: 'cx> {
infcx: &'cx InferCtxt<'cx, 'gcx, 'tcx>,
- /// Freshener used specifically for skolemizing entries on the
- /// obligation stack. This ensures that all entries on the stack
- /// at one time will have the same set of skolemized entries,
- /// which is important for checking for trait bounds that
- /// recursively require themselves.
+ /// Freshener used specifically for entries on the obligation
+ /// stack. This ensures that all entries on the stack at one time
+ /// will have the same set of placeholder entries, which is
+ /// important for checking for trait bounds that recursively
+ /// require themselves.
freshener: TypeFreshener<'cx, 'gcx, 'tcx>,
/// If true, indicates that the evaluation should be conservative
impl IntercrateAmbiguityCause {
/// Emits notes when the overlap is caused by complex intercrate ambiguities.
/// See #23980 for details.
- pub fn add_intercrate_ambiguity_hint<'a, 'tcx>(&self,
- err: &mut ::errors::DiagnosticBuilder<'_>) {
+ pub fn add_intercrate_ambiguity_hint<'a, 'tcx>(
+ &self,
+ err: &mut ::errors::DiagnosticBuilder<'_>,
+ ) {
err.note(&self.intercrate_ambiguity_hint());
}
pub fn intercrate_ambiguity_hint(&self) -> String {
match self {
- &IntercrateAmbiguityCause::DownstreamCrate { ref trait_desc, ref self_desc } => {
+ &IntercrateAmbiguityCause::DownstreamCrate {
+ ref trait_desc,
+ ref self_desc,
+ } => {
let self_desc = if let &Some(ref ty) = self_desc {
format!(" for type `{}`", ty)
- } else { String::new() };
- format!("downstream crates may implement trait `{}`{}", trait_desc, self_desc)
+ } else {
+ String::new()
+ };
+ format!(
+ "downstream crates may implement trait `{}`{}",
+ trait_desc, self_desc
+ )
}
- &IntercrateAmbiguityCause::UpstreamCrateUpdate { ref trait_desc, ref self_desc } => {
+ &IntercrateAmbiguityCause::UpstreamCrateUpdate {
+ ref trait_desc,
+ ref self_desc,
+ } => {
let self_desc = if let &Some(ref ty) = self_desc {
format!(" for type `{}`", ty)
- } else { String::new() };
- format!("upstream crates may add new impl of trait `{}`{} \
- in future versions",
- trait_desc, self_desc)
+ } else {
+ String::new()
+ };
+ format!(
+ "upstream crates may add new impl of trait `{}`{} \
+ in future versions",
+ trait_desc, self_desc
+ )
}
}
}
struct TraitObligationStack<'prev, 'tcx: 'prev> {
obligation: &'prev TraitObligation<'tcx>,
- /// Trait ref from `obligation` but skolemized with the
+ /// Trait ref from `obligation` but "freshened" with the
/// selection-context's freshener. Used to check for recursion.
fresh_trait_ref: ty::PolyTraitRef<'tcx>,
#[derive(Clone)]
pub struct SelectionCache<'tcx> {
- hashmap: Lock<FxHashMap<ty::TraitRef<'tcx>,
- WithDepNode<SelectionResult<'tcx, SelectionCandidate<'tcx>>>>>,
+ hashmap: Lock<
+ FxHashMap<ty::TraitRef<'tcx>, WithDepNode<SelectionResult<'tcx, SelectionCandidate<'tcx>>>>,
+ >,
}
/// The selection process begins by considering all impls, where
/// required for associated types to work in default impls, as the bounds
/// are visible both as projection bounds and as where-clauses from the
/// parameter environment.
-#[derive(PartialEq,Eq,Debug,Clone)]
+#[derive(PartialEq, Eq, Debug, Clone)]
enum SelectionCandidate<'tcx> {
/// If has_nested is false, there are no *further* obligations
- BuiltinCandidate { has_nested: bool },
+ BuiltinCandidate {
+ has_nested: bool,
+ },
ParamCandidate(ty::PolyTraitRef<'tcx>),
ImplCandidate(DefId),
AutoImplCandidate(DefId),
type Lifted = SelectionCandidate<'tcx>;
fn lift_to_tcx<'b, 'gcx>(&self, tcx: TyCtxt<'b, 'gcx, 'tcx>) -> Option<Self::Lifted> {
Some(match *self {
- BuiltinCandidate { has_nested } => {
- BuiltinCandidate {
- has_nested,
- }
- }
+ BuiltinCandidate { has_nested } => BuiltinCandidate { has_nested },
ImplCandidate(def_id) => ImplCandidate(def_id),
AutoImplCandidate(def_id) => AutoImplCandidate(def_id),
ProjectionCandidate => ProjectionCandidate,
ambiguous: bool,
}
-#[derive(PartialEq,Eq,Debug,Clone)]
+#[derive(PartialEq, Eq, Debug, Clone)]
struct EvaluatedCandidate<'tcx> {
candidate: SelectionCandidate<'tcx>,
evaluation: EvaluationResult,
/// candidate (a where-clause or user-defined impl).
None,
/// It is unknown whether there is an impl.
- Ambiguous
+ Ambiguous,
}
#[derive(Copy, Clone, Debug, PartialOrd, Ord, PartialEq, Eq)]
impl EvaluationResult {
pub fn may_apply(self) -> bool {
match self {
- EvaluatedToOk |
- EvaluatedToAmbig |
- EvaluatedToUnknown => true,
+ EvaluatedToOk | EvaluatedToAmbig | EvaluatedToUnknown => true,
- EvaluatedToErr |
- EvaluatedToRecur => false
+ EvaluatedToErr | EvaluatedToRecur => false,
}
}
fn is_stack_dependent(self) -> bool {
match self {
- EvaluatedToUnknown |
- EvaluatedToRecur => true,
+ EvaluatedToUnknown | EvaluatedToRecur => true,
- EvaluatedToOk |
- EvaluatedToAmbig |
- EvaluatedToErr => false,
+ EvaluatedToOk | EvaluatedToAmbig | EvaluatedToErr => false,
}
}
}
/// Indicates that trait evaluation caused overflow.
pub struct OverflowError;
-impl_stable_hash_for!(struct OverflowError { });
+impl_stable_hash_for!(struct OverflowError {});
impl<'tcx> From<OverflowError> for SelectionError<'tcx> {
fn from(OverflowError: OverflowError) -> SelectionError<'tcx> {
#[derive(Clone)]
pub struct EvaluationCache<'tcx> {
- hashmap: Lock<FxHashMap<ty::PolyTraitRef<'tcx>, WithDepNode<EvaluationResult>>>
+ hashmap: Lock<FxHashMap<ty::PolyTraitRef<'tcx>, WithDepNode<EvaluationResult>>>,
}
impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
}
}
- pub fn intercrate(infcx: &'cx InferCtxt<'cx, 'gcx, 'tcx>,
- mode: IntercrateMode) -> SelectionContext<'cx, 'gcx, 'tcx> {
+ pub fn intercrate(
+ infcx: &'cx InferCtxt<'cx, 'gcx, 'tcx>,
+ mode: IntercrateMode,
+ ) -> SelectionContext<'cx, 'gcx, 'tcx> {
debug!("intercrate({:?})", mode);
SelectionContext {
infcx,
}
}
- pub fn with_negative(infcx: &'cx InferCtxt<'cx, 'gcx, 'tcx>,
- allow_negative_impls: bool) -> SelectionContext<'cx, 'gcx, 'tcx> {
+ pub fn with_negative(
+ infcx: &'cx InferCtxt<'cx, 'gcx, 'tcx>,
+ allow_negative_impls: bool,
+ ) -> SelectionContext<'cx, 'gcx, 'tcx> {
debug!("with_negative({:?})", allow_negative_impls);
SelectionContext {
infcx,
}
}
- pub fn with_query_mode(infcx: &'cx InferCtxt<'cx, 'gcx, 'tcx>,
- query_mode: TraitQueryMode) -> SelectionContext<'cx, 'gcx, 'tcx> {
+ pub fn with_query_mode(
+ infcx: &'cx InferCtxt<'cx, 'gcx, 'tcx>,
+ query_mode: TraitQueryMode,
+ ) -> SelectionContext<'cx, 'gcx, 'tcx> {
debug!("with_query_mode({:?})", query_mode);
SelectionContext {
infcx,
/// Wraps the inference context's in_snapshot s.t. snapshot handling is only from the selection
/// context's self.
fn in_snapshot<R, F>(&mut self, f: F) -> R
- where F: FnOnce(&mut Self, &infer::CombinedSnapshot<'cx, 'tcx>) -> R
+ where
+ F: FnOnce(&mut Self, &infer::CombinedSnapshot<'cx, 'tcx>) -> R,
{
self.infcx.in_snapshot(|snapshot| f(self, snapshot))
}
/// Wraps a probe s.t. obligations collected during it are ignored and old obligations are
/// retained.
fn probe<R, F>(&mut self, f: F) -> R
- where F: FnOnce(&mut Self, &infer::CombinedSnapshot<'cx, 'tcx>) -> R
+ where
+ F: FnOnce(&mut Self, &infer::CombinedSnapshot<'cx, 'tcx>) -> R,
{
self.infcx.probe(|snapshot| f(self, snapshot))
}
/// Wraps a commit_if_ok s.t. obligations collected during it are not returned in selection if
/// the transaction fails and s.t. old obligations are retained.
- fn commit_if_ok<T, E, F>(&mut self, f: F) -> Result<T, E> where
- F: FnOnce(&mut Self, &infer::CombinedSnapshot<'cx, 'tcx>) -> Result<T, E>
+ fn commit_if_ok<T, E, F>(&mut self, f: F) -> Result<T, E>
+ where
+ F: FnOnce(&mut Self, &infer::CombinedSnapshot<'cx, 'tcx>) -> Result<T, E>,
{
self.infcx.commit_if_ok(|snapshot| f(self, snapshot))
}
-
///////////////////////////////////////////////////////////////////////////
// Selection
//
/// Attempts to satisfy the obligation. If successful, this will affect the surrounding
/// type environment by performing unification.
- pub fn select(&mut self, obligation: &TraitObligation<'tcx>)
- -> SelectionResult<'tcx, Selection<'tcx>> {
+ pub fn select(
+ &mut self,
+ obligation: &TraitObligation<'tcx>,
+ ) -> SelectionResult<'tcx, Selection<'tcx>> {
debug!("select({:?})", obligation);
debug_assert!(!obligation.predicate.has_escaping_regions());
// earlier.
assert!(self.query_mode == TraitQueryMode::Canonical);
return Err(SelectionError::Overflow);
- },
- Err(e) => { return Err(e); },
- Ok(None) => { return Ok(None); },
- Ok(Some(candidate)) => candidate
+ }
+ Err(e) => {
+ return Err(e);
+ }
+ Ok(None) => {
+ return Ok(None);
+ }
+ Ok(Some(candidate)) => candidate,
};
match self.confirm_candidate(obligation, candidate) {
Err(SelectionError::Overflow) => {
assert!(self.query_mode == TraitQueryMode::Canonical);
Err(SelectionError::Overflow)
- },
+ }
Err(e) => Err(e),
- Ok(candidate) => Ok(Some(candidate))
+ Ok(candidate) => Ok(Some(candidate)),
}
}
// we can be sure it does not.
/// Evaluates whether the obligation `obligation` can be satisfied (by any means).
- pub fn predicate_may_hold_fatal(&mut self,
- obligation: &PredicateObligation<'tcx>)
- -> bool
- {
- debug!("predicate_may_hold_fatal({:?})",
- obligation);
+ pub fn predicate_may_hold_fatal(&mut self, obligation: &PredicateObligation<'tcx>) -> bool {
+ debug!("predicate_may_hold_fatal({:?})", obligation);
// This fatal query is a stopgap that should only be used in standard mode,
// where we do not expect overflow to be propagated.
/// Evaluates whether the obligation `obligation` can be satisfied and returns
/// an `EvaluationResult`.
- pub fn evaluate_obligation_recursively(&mut self,
- obligation: &PredicateObligation<'tcx>)
- -> Result<EvaluationResult, OverflowError>
- {
- self.probe(|this, _|
+ pub fn evaluate_obligation_recursively(
+ &mut self,
+ obligation: &PredicateObligation<'tcx>,
+ ) -> Result<EvaluationResult, OverflowError> {
+ self.probe(|this, _| {
this.evaluate_predicate_recursively(TraitObligationStackList::empty(), obligation)
- )
+ })
}
/// Evaluates the predicates in `predicates` recursively. Note that
/// this applies projections in the predicates, and therefore
/// is run within an inference probe.
- fn evaluate_predicates_recursively<'a,'o,I>(&mut self,
- stack: TraitObligationStackList<'o, 'tcx>,
- predicates: I)
- -> Result<EvaluationResult, OverflowError>
- where I : IntoIterator<Item=&'a PredicateObligation<'tcx>>, 'tcx:'a
+ fn evaluate_predicates_recursively<'a, 'o, I>(
+ &mut self,
+ stack: TraitObligationStackList<'o, 'tcx>,
+ predicates: I,
+ ) -> Result<EvaluationResult, OverflowError>
+ where
+ I: IntoIterator<Item = &'a PredicateObligation<'tcx>>,
+ 'tcx: 'a,
{
let mut result = EvaluatedToOk;
for obligation in predicates {
let eval = self.evaluate_predicate_recursively(stack, obligation)?;
- debug!("evaluate_predicate_recursively({:?}) = {:?}",
- obligation, eval);
+ debug!(
+ "evaluate_predicate_recursively({:?}) = {:?}",
+ obligation, eval
+ );
if let EvaluatedToErr = eval {
// fast-path - EvaluatedToErr is the top of the lattice,
// so we don't need to look on the other predicates.
Ok(result)
}
- fn evaluate_predicate_recursively<'o>(&mut self,
- previous_stack: TraitObligationStackList<'o, 'tcx>,
- obligation: &PredicateObligation<'tcx>)
- -> Result<EvaluationResult, OverflowError>
- {
- debug!("evaluate_predicate_recursively({:?})",
- obligation);
+ fn evaluate_predicate_recursively<'o>(
+ &mut self,
+ previous_stack: TraitObligationStackList<'o, 'tcx>,
+ obligation: &PredicateObligation<'tcx>,
+ ) -> Result<EvaluationResult, OverflowError> {
+ debug!("evaluate_predicate_recursively({:?})", obligation);
match obligation.predicate {
ty::Predicate::Trait(ref t) => {
ty::Predicate::Subtype(ref p) => {
// does this code ever run?
- match self.infcx.subtype_predicate(&obligation.cause, obligation.param_env, p) {
+ match self.infcx
+ .subtype_predicate(&obligation.cause, obligation.param_env, p)
+ {
Some(Ok(InferOk { obligations, .. })) => {
self.evaluate_predicates_recursively(previous_stack, &obligations)
- },
+ }
Some(Err(_)) => Ok(EvaluatedToErr),
None => Ok(EvaluatedToAmbig),
}
}
- ty::Predicate::WellFormed(ty) => {
- match ty::wf::obligations(self.infcx,
- obligation.param_env,
- obligation.cause.body_id,
- ty, obligation.cause.span) {
- Some(obligations) =>
- self.evaluate_predicates_recursively(previous_stack, obligations.iter()),
- None =>
- Ok(EvaluatedToAmbig),
+ ty::Predicate::WellFormed(ty) => match ty::wf::obligations(
+ self.infcx,
+ obligation.param_env,
+ obligation.cause.body_id,
+ ty,
+ obligation.cause.span,
+ ) {
+ Some(obligations) => {
+ self.evaluate_predicates_recursively(previous_stack, obligations.iter())
+ }
+ None => Ok(EvaluatedToAmbig),
+ },
+
+ ty::Predicate::TypeOutlives(ref binder) => {
+ assert!(!binder.has_escaping_regions());
+ // Check if the type has higher-ranked regions.
+ if binder.skip_binder().0.has_escaping_regions() {
+ // If so, this obligation is an error (for now). Eventually we should be
+ // able to support additional cases here, like `for<'a> &'a str: 'a`.
+
+ // NOTE: this hack is implemented in both trait fulfillment and
+ // evaluation. If you fix it in one place, make sure you fix it
+ // in the other.
+
+ // We don't want to allow this sort of reasoning in intercrate
+ // mode, for backwards-compatibility reasons.
+ if self.intercrate.is_some() {
+ Ok(EvaluatedToAmbig)
+ } else {
+ Ok(EvaluatedToErr)
+ }
+ } else {
+ // If the type has no late bound regions, then if we assign all
+ // the inference variables in it to be 'static, then the type
+ // will be 'static itself.
+ //
+ // Therefore, `staticize(T): 'a` holds for any `'a`, so this
+ // obligation is fulfilled. Because evaluation works with
+ // staticized types (yes I know this is involved with #21974),
+ // we are 100% OK here.
+ Ok(EvaluatedToOk)
}
}
- ty::Predicate::TypeOutlives(..) | ty::Predicate::RegionOutlives(..) => {
- // we do not consider region relationships when
- // evaluating trait matches
- Ok(EvaluatedToOk)
+ ty::Predicate::RegionOutlives(ref binder) => {
+ let ty::OutlivesPredicate(r_a, r_b) = binder.skip_binder();
+
+ if r_a == r_b {
+ // for<'a> 'a: 'a. OK
+ Ok(EvaluatedToOk)
+ } else if **r_a == ty::ReStatic {
+ // 'static: 'x always holds.
+ //
+ // This special case is handled somewhat inconsistently - if we
+ // have an inference variable that is supposed to be equal to
+ // `'static`, then we don't allow it to be equated to an LBR,
+ // but if we have a literal `'static`, then we *do*.
+ //
+ // This is actually consistent with how our region inference works.
+ //
+ // It would appear that this sort of inconsistency would
+ // cause "instability" problems with evaluation caching. However,
+ // evaluation caching is only for trait predicates, and when
+ // trait predicates create nested obligations, they contain
+ // inference variables for all the regions in the trait - the
+ // only way this codepath can be reached from trait predicate
+ // evaluation is when the user typed an explicit `where 'static: 'a`
+ // lifetime bound (in which case we want to return EvaluatedToOk).
+ //
+ // If we ever want to handle inference variables that might be
+ // equatable with ReStatic, we need to make sure we are not confused by
+ // technically-allowed-by-RFC-447-but-probably-should-not-be
+ // impls such as
+ // ```Rust
+ // impl<'a, 's, T> X<'s> for T where T: Debug + 'a, 'a: 's
+ // ```
+ Ok(EvaluatedToOk)
+ } else if r_a.is_late_bound() || r_b.is_late_bound() {
+ // There is no current way to prove `for<'a> 'a: 'x`
+ // unless `'a = 'x`, because there are no bounds involving
+ // lifetimes.
+
+ // It might be possible to prove `for<'a> 'x: 'a` by forcing `'x`
+ // to be `'static`. However, this is not currently done by type
+ // inference unless `'x` is literally ReStatic. See the comment
+ // above.
+
+ // We don't want to allow this sort of reasoning in intercrate
+ // mode, for backwards-compatibility reasons.
+ if self.intercrate.is_some() {
+ Ok(EvaluatedToAmbig)
+ } else {
+ Ok(EvaluatedToErr)
+ }
+ } else {
+ // Relating 2 inference variable regions. These will
+ // always hold if our query is "staticized".
+ Ok(EvaluatedToOk)
+ }
}
ty::Predicate::ObjectSafe(trait_def_id) => {
let project_obligation = obligation.with(data.clone());
match project::poly_project_and_unify_type(self, &project_obligation) {
Ok(Some(subobligations)) => {
- let result = self.evaluate_predicates_recursively(previous_stack,
- subobligations.iter());
+ let result = self.evaluate_predicates_recursively(
+ previous_stack,
+ subobligations.iter(),
+ );
if let Some(key) =
ProjectionCacheKey::from_poly_projection_predicate(self, data)
{
self.infcx.projection_cache.borrow_mut().complete(key);
}
result
- },
+ }
Ok(None) => Ok(EvaluatedToAmbig),
- Err(_) => Ok(EvaluatedToErr)
+ Err(_) => Ok(EvaluatedToErr),
}
}
} else {
Ok(EvaluatedToErr)
}
- },
- None => Ok(EvaluatedToAmbig)
+ }
+ None => Ok(EvaluatedToAmbig),
}
}
let tcx = self.tcx();
match tcx.lift_to_global(&(obligation.param_env, substs)) {
Some((param_env, substs)) => {
- let instance = ty::Instance::resolve(
- tcx.global_tcx(),
- param_env,
- def_id,
- substs,
- );
+ let instance =
+ ty::Instance::resolve(tcx.global_tcx(), param_env, def_id, substs);
if let Some(instance) = instance {
let cid = GlobalId {
instance,
- promoted: None
+ promoted: None,
};
match self.tcx().const_eval(param_env.and(cid)) {
Ok(_) => Ok(EvaluatedToOk),
- Err(_) => Ok(EvaluatedToErr)
+ Err(_) => Ok(EvaluatedToErr),
}
} else {
Ok(EvaluatedToErr)
}
}
- fn evaluate_trait_predicate_recursively<'o>(&mut self,
- previous_stack: TraitObligationStackList<'o, 'tcx>,
- mut obligation: TraitObligation<'tcx>)
- -> Result<EvaluationResult, OverflowError>
- {
+ fn evaluate_trait_predicate_recursively<'o>(
+ &mut self,
+ previous_stack: TraitObligationStackList<'o, 'tcx>,
+ mut obligation: TraitObligation<'tcx>,
+ ) -> Result<EvaluationResult, OverflowError> {
debug!("evaluate_trait_predicate_recursively({:?})", obligation);
if self.intercrate.is_none() && obligation.is_global()
- && obligation.param_env.caller_bounds.iter().all(|bound| bound.needs_subst()) {
+ && obligation
+ .param_env
+ .caller_bounds
+ .iter()
+ .all(|bound| bound.needs_subst())
+ {
// If a param env has no global bounds, global obligations do not
// depend on its particular value in order to work, so we can clear
// out the param env and get better caching.
- debug!("evaluate_trait_predicate_recursively({:?}) - in global", obligation);
+ debug!(
+ "evaluate_trait_predicate_recursively({:?}) - in global",
+ obligation
+ );
obligation.param_env = obligation.param_env.without_caller_bounds();
}
let stack = self.push_stack(previous_stack, &obligation);
let fresh_trait_ref = stack.fresh_trait_ref;
if let Some(result) = self.check_evaluation_cache(obligation.param_env, fresh_trait_ref) {
- debug!("CACHE HIT: EVAL({:?})={:?}",
- fresh_trait_ref,
- result);
+ debug!("CACHE HIT: EVAL({:?})={:?}", fresh_trait_ref, result);
return Ok(result);
}
let (result, dep_node) = self.in_task(|this| this.evaluate_stack(&stack));
let result = result?;
- debug!("CACHE MISS: EVAL({:?})={:?}",
- fresh_trait_ref,
- result);
+ debug!("CACHE MISS: EVAL({:?})={:?}", fresh_trait_ref, result);
self.insert_evaluation_cache(obligation.param_env, fresh_trait_ref, dep_node, result);
Ok(result)
}
- fn evaluate_stack<'o>(&mut self,
- stack: &TraitObligationStack<'o, 'tcx>)
- -> Result<EvaluationResult, OverflowError>
- {
+ fn evaluate_stack<'o>(
+ &mut self,
+ stack: &TraitObligationStack<'o, 'tcx>,
+ ) -> Result<EvaluationResult, OverflowError> {
// In intercrate mode, whenever any of the types are unbound,
// there can always be an impl. Even if there are no impls in
// this crate, perhaps the type would be unified with
// This suffices to allow chains like `FnMut` implemented in
// terms of `Fn` etc, but we could probably make this more
// precise still.
- let unbound_input_types =
- stack.fresh_trait_ref.skip_binder().input_types().any(|ty| ty.is_fresh());
+ let unbound_input_types = stack
+ .fresh_trait_ref
+ .skip_binder()
+ .input_types()
+ .any(|ty| ty.is_fresh());
// this check was an imperfect workaround for a bug n the old
// intercrate mode, it should be removed when that goes away.
- if unbound_input_types &&
- self.intercrate == Some(IntercrateMode::Issue43355)
- {
- debug!("evaluate_stack({:?}) --> unbound argument, intercrate --> ambiguous",
- stack.fresh_trait_ref);
+ if unbound_input_types && self.intercrate == Some(IntercrateMode::Issue43355) {
+ debug!(
+ "evaluate_stack({:?}) --> unbound argument, intercrate --> ambiguous",
+ stack.fresh_trait_ref
+ );
// Heuristics: show the diagnostics when there are no candidates in crate.
if self.intercrate_ambiguity_causes.is_some() {
debug!("evaluate_stack: intercrate_ambiguity_causes is some");
},
};
debug!("evaluate_stack: pushing cause = {:?}", cause);
- self.intercrate_ambiguity_causes.as_mut().unwrap().push(cause);
+ self.intercrate_ambiguity_causes
+ .as_mut()
+ .unwrap()
+ .push(cause);
}
}
}
return Ok(EvaluatedToAmbig);
}
- if unbound_input_types &&
- stack.iter().skip(1).any(
- |prev| stack.obligation.param_env == prev.obligation.param_env &&
- self.match_fresh_trait_refs(&stack.fresh_trait_ref,
- &prev.fresh_trait_ref))
- {
- debug!("evaluate_stack({:?}) --> unbound argument, recursive --> giving up",
- stack.fresh_trait_ref);
+ if unbound_input_types && stack.iter().skip(1).any(|prev| {
+ stack.obligation.param_env == prev.obligation.param_env
+ && self.match_fresh_trait_refs(&stack.fresh_trait_ref, &prev.fresh_trait_ref)
+ }) {
+ debug!(
+ "evaluate_stack({:?}) --> unbound argument, recursive --> giving up",
+ stack.fresh_trait_ref
+ );
return Ok(EvaluatedToUnknown);
}
// `Send`.
//
// Note that we do this comparison using the `fresh_trait_ref`
- // fields. Because these have all been skolemized using
+ // fields. Because these have all been freshened using
// `self.freshener`, we can be sure that (a) this will not
// affect the inferencer state and (b) that if we see two
- // skolemized types with the same index, they refer to the
- // same unbound type variable.
- if let Some(rec_index) =
- stack.iter()
+ // fresh regions with the same index, they refer to the same
+ // unbound type variable.
+ if let Some(rec_index) = stack.iter()
.skip(1) // skip top-most frame
.position(|prev| stack.obligation.param_env == prev.obligation.param_env &&
stack.fresh_trait_ref == prev.fresh_trait_ref)
{
- debug!("evaluate_stack({:?}) --> recursive",
- stack.fresh_trait_ref);
+ debug!("evaluate_stack({:?}) --> recursive", stack.fresh_trait_ref);
+
let cycle = stack.iter().skip(1).take(rec_index + 1);
let cycle = cycle.map(|stack| ty::Predicate::Trait(stack.obligation.predicate));
if self.coinductive_match(cycle) {
- debug!("evaluate_stack({:?}) --> recursive, coinductive",
- stack.fresh_trait_ref);
+ debug!(
+ "evaluate_stack({:?}) --> recursive, coinductive",
+ stack.fresh_trait_ref
+ );
return Ok(EvaluatedToOk);
} else {
- debug!("evaluate_stack({:?}) --> recursive, inductive",
- stack.fresh_trait_ref);
+ debug!(
+ "evaluate_stack({:?}) --> recursive, inductive",
+ stack.fresh_trait_ref
+ );
return Ok(EvaluatedToRecur);
}
}
Ok(Some(c)) => self.evaluate_candidate(stack, &c),
Ok(None) => Ok(EvaluatedToAmbig),
Err(Overflow) => Err(OverflowError),
- Err(..) => Ok(EvaluatedToErr)
+ Err(..) => Ok(EvaluatedToErr),
}
}
/// - all the predicates at positions `X..` between `X` an the top are
/// also defaulted traits.
pub fn coinductive_match<I>(&mut self, cycle: I) -> bool
- where I: Iterator<Item=ty::Predicate<'tcx>>
+ where
+ I: Iterator<Item = ty::Predicate<'tcx>>,
{
let mut cycle = cycle;
cycle.all(|predicate| self.coinductive_predicate(predicate))
fn coinductive_predicate(&self, predicate: ty::Predicate<'tcx>) -> bool {
let result = match predicate {
- ty::Predicate::Trait(ref data) => {
- self.tcx().trait_is_auto(data.def_id())
- },
- _ => false
+ ty::Predicate::Trait(ref data) => self.tcx().trait_is_auto(data.def_id()),
+ _ => false,
};
debug!("coinductive_predicate({:?}) = {:?}", predicate, result);
result
/// Further evaluate `candidate` to decide whether all type parameters match and whether nested
/// obligations are met. Returns true if `candidate` remains viable after this further
/// scrutiny.
- fn evaluate_candidate<'o>(&mut self,
- stack: &TraitObligationStack<'o, 'tcx>,
- candidate: &SelectionCandidate<'tcx>)
- -> Result<EvaluationResult, OverflowError>
- {
- debug!("evaluate_candidate: depth={} candidate={:?}",
- stack.obligation.recursion_depth, candidate);
+ fn evaluate_candidate<'o>(
+ &mut self,
+ stack: &TraitObligationStack<'o, 'tcx>,
+ candidate: &SelectionCandidate<'tcx>,
+ ) -> Result<EvaluationResult, OverflowError> {
+ debug!(
+ "evaluate_candidate: depth={} candidate={:?}",
+ stack.obligation.recursion_depth, candidate
+ );
let result = self.probe(|this, _| {
let candidate = (*candidate).clone();
match this.confirm_candidate(stack.obligation, candidate) {
- Ok(selection) => {
- this.evaluate_predicates_recursively(
- stack.list(),
- selection.nested_obligations().iter())
- }
- Err(..) => Ok(EvaluatedToErr)
+ Ok(selection) => this.evaluate_predicates_recursively(
+ stack.list(),
+ selection.nested_obligations().iter(),
+ ),
+ Err(..) => Ok(EvaluatedToErr),
}
})?;
- debug!("evaluate_candidate: depth={} result={:?}",
- stack.obligation.recursion_depth, result);
+ debug!(
+ "evaluate_candidate: depth={} result={:?}",
+ stack.obligation.recursion_depth, result
+ );
Ok(result)
}
- fn check_evaluation_cache(&self,
- param_env: ty::ParamEnv<'tcx>,
- trait_ref: ty::PolyTraitRef<'tcx>)
- -> Option<EvaluationResult>
- {
+ fn check_evaluation_cache(
+ &self,
+ param_env: ty::ParamEnv<'tcx>,
+ trait_ref: ty::PolyTraitRef<'tcx>,
+ ) -> Option<EvaluationResult> {
let tcx = self.tcx();
if self.can_use_global_caches(param_env) {
let cache = tcx.evaluation_cache.hashmap.borrow();
return Some(cached.get(tcx));
}
}
- self.infcx.evaluation_cache.hashmap
- .borrow()
- .get(&trait_ref)
- .map(|v| v.get(tcx))
+ self.infcx
+ .evaluation_cache
+ .hashmap
+ .borrow()
+ .get(&trait_ref)
+ .map(|v| v.get(tcx))
}
- fn insert_evaluation_cache(&mut self,
- param_env: ty::ParamEnv<'tcx>,
- trait_ref: ty::PolyTraitRef<'tcx>,
- dep_node: DepNodeIndex,
- result: EvaluationResult)
- {
+ fn insert_evaluation_cache(
+ &mut self,
+ param_env: ty::ParamEnv<'tcx>,
+ trait_ref: ty::PolyTraitRef<'tcx>,
+ dep_node: DepNodeIndex,
+ result: EvaluationResult,
+ ) {
// Avoid caching results that depend on more than just the trait-ref
// - the stack can create recursion.
if result.is_stack_dependent() {
if let Some(trait_ref) = self.tcx().lift_to_global(&trait_ref) {
debug!(
"insert_evaluation_cache(trait_ref={:?}, candidate={:?}) global",
- trait_ref,
- result,
+ trait_ref, result,
);
// This may overwrite the cache with the same value
// FIXME: Due to #50507 this overwrites the different values
// This should be changed to use HashMapExt::insert_same
// when that is fixed
- self.tcx().evaluation_cache
- .hashmap.borrow_mut()
- .insert(trait_ref, WithDepNode::new(dep_node, result));
+ self.tcx()
+ .evaluation_cache
+ .hashmap
+ .borrow_mut()
+ .insert(trait_ref, WithDepNode::new(dep_node, result));
return;
}
}
debug!(
"insert_evaluation_cache(trait_ref={:?}, candidate={:?})",
- trait_ref,
- result,
+ trait_ref, result,
);
- self.infcx.evaluation_cache.hashmap
- .borrow_mut()
- .insert(trait_ref, WithDepNode::new(dep_node, result));
+ self.infcx
+ .evaluation_cache
+ .hashmap
+ .borrow_mut()
+ .insert(trait_ref, WithDepNode::new(dep_node, result));
}
///////////////////////////////////////////////////////////////////////////
// [rustc guide]:
// https://rust-lang-nursery.github.io/rustc-guide/traits/resolution.html#candidate-assembly
- fn candidate_from_obligation<'o>(&mut self,
- stack: &TraitObligationStack<'o, 'tcx>)
- -> SelectionResult<'tcx, SelectionCandidate<'tcx>>
- {
+ fn candidate_from_obligation<'o>(
+ &mut self,
+ stack: &TraitObligationStack<'o, 'tcx>,
+ ) -> SelectionResult<'tcx, SelectionCandidate<'tcx>> {
// Watch out for overflow. This intentionally bypasses (and does
// not update) the cache.
let recursion_limit = *self.infcx.tcx.sess.recursion_limit.get();
match self.query_mode {
TraitQueryMode::Standard => {
self.infcx().report_overflow_error(&stack.obligation, true);
- },
+ }
TraitQueryMode::Canonical => {
return Err(Overflow);
- },
+ }
}
}
- // Check the cache. Note that we skolemize the trait-ref
- // separately rather than using `stack.fresh_trait_ref` -- this
- // is because we want the unbound variables to be replaced
- // with fresh skolemized types starting from index 0.
- let cache_fresh_trait_pred =
- self.infcx.freshen(stack.obligation.predicate.clone());
- debug!("candidate_from_obligation(cache_fresh_trait_pred={:?}, obligation={:?})",
- cache_fresh_trait_pred,
- stack);
+ // Check the cache. Note that we freshen the trait-ref
+ // separately rather than using `stack.fresh_trait_ref` --
+ // this is because we want the unbound variables to be
+ // replaced with fresh types starting from index 0.
+ let cache_fresh_trait_pred = self.infcx.freshen(stack.obligation.predicate.clone());
+ debug!(
+ "candidate_from_obligation(cache_fresh_trait_pred={:?}, obligation={:?})",
+ cache_fresh_trait_pred, stack
+ );
debug_assert!(!stack.obligation.predicate.has_escaping_regions());
- if let Some(c) = self.check_candidate_cache(stack.obligation.param_env,
- &cache_fresh_trait_pred) {
- debug!("CACHE HIT: SELECT({:?})={:?}",
- cache_fresh_trait_pred,
- c);
+ if let Some(c) =
+ self.check_candidate_cache(stack.obligation.param_env, &cache_fresh_trait_pred)
+ {
+ debug!("CACHE HIT: SELECT({:?})={:?}", cache_fresh_trait_pred, c);
return c;
}
// If no match, compute result and insert into cache.
- let (candidate, dep_node) = self.in_task(|this|
- this.candidate_from_obligation_no_cache(stack)
- );
+ let (candidate, dep_node) =
+ self.in_task(|this| this.candidate_from_obligation_no_cache(stack));
- debug!("CACHE MISS: SELECT({:?})={:?}",
- cache_fresh_trait_pred, candidate);
- self.insert_candidate_cache(stack.obligation.param_env,
- cache_fresh_trait_pred,
- dep_node,
- candidate.clone());
+ debug!(
+ "CACHE MISS: SELECT({:?})={:?}",
+ cache_fresh_trait_pred, candidate
+ );
+ self.insert_candidate_cache(
+ stack.obligation.param_env,
+ cache_fresh_trait_pred,
+ dep_node,
+ candidate.clone(),
+ );
candidate
}
fn in_task<OP, R>(&mut self, op: OP) -> (R, DepNodeIndex)
- where OP: FnOnce(&mut Self) -> R
+ where
+ OP: FnOnce(&mut Self) -> R,
{
- let (result, dep_node) = self.tcx().dep_graph.with_anon_task(DepKind::TraitSelect, ||
- op(self)
- );
+ let (result, dep_node) = self.tcx()
+ .dep_graph
+ .with_anon_task(DepKind::TraitSelect, || op(self));
self.tcx().dep_graph.read_index(dep_node);
(result, dep_node)
}
// Treat negative impls as unimplemented
- fn filter_negative_impls(&self, candidate: SelectionCandidate<'tcx>)
- -> SelectionResult<'tcx, SelectionCandidate<'tcx>> {
+ fn filter_negative_impls(
+ &self,
+ candidate: SelectionCandidate<'tcx>,
+ ) -> SelectionResult<'tcx, SelectionCandidate<'tcx>> {
if let ImplCandidate(def_id) = candidate {
- if !self.allow_negative_impls &&
- self.tcx().impl_polarity(def_id) == hir::ImplPolarity::Negative {
- return Err(Unimplemented)
+ if !self.allow_negative_impls
+ && self.tcx().impl_polarity(def_id) == hir::ImplPolarity::Negative
+ {
+ return Err(Unimplemented);
}
}
Ok(Some(candidate))
}
- fn candidate_from_obligation_no_cache<'o>(&mut self,
- stack: &TraitObligationStack<'o, 'tcx>)
- -> SelectionResult<'tcx, SelectionCandidate<'tcx>>
- {
+ fn candidate_from_obligation_no_cache<'o>(
+ &mut self,
+ stack: &TraitObligationStack<'o, 'tcx>,
+ ) -> SelectionResult<'tcx, SelectionCandidate<'tcx>> {
if stack.obligation.predicate.references_error() {
// If we encounter a `Error`, we generally prefer the
// most "optimistic" result in response -- that is, the
if let Ok(candidate_set) = self.assemble_candidates(stack) {
let mut no_candidates_apply = true;
{
- let evaluated_candidates = candidate_set.vec.iter().map(|c|
- self.evaluate_candidate(stack, &c));
+ let evaluated_candidates = candidate_set
+ .vec
+ .iter()
+ .map(|c| self.evaluate_candidate(stack, &c));
for ec in evaluated_candidates {
match ec {
Ok(c) => {
if c.may_apply() {
no_candidates_apply = false;
- break
+ break;
}
- },
- Err(e) => return Err(e.into())
+ }
+ Err(e) => return Err(e.into()),
}
}
}
self_desc,
}
} else {
- IntercrateAmbiguityCause::DownstreamCrate { trait_desc, self_desc }
+ IntercrateAmbiguityCause::DownstreamCrate {
+ trait_desc,
+ self_desc,
+ }
};
debug!("evaluate_stack: pushing cause = {:?}", cause);
- self.intercrate_ambiguity_causes.as_mut().unwrap().push(cause);
+ self.intercrate_ambiguity_causes
+ .as_mut()
+ .unwrap()
+ .push(cause);
}
}
}
let mut candidates = candidate_set.vec;
- debug!("assembled {} candidates for {:?}: {:?}",
- candidates.len(),
- stack,
- candidates);
+ debug!(
+ "assembled {} candidates for {:?}: {:?}",
+ candidates.len(),
+ stack,
+ candidates
+ );
// At this point, we know that each of the entries in the
// candidate set is *individually* applicable. Now we have to
let mut candidates: Vec<EvaluatedCandidate<'_>> =
candidates?.into_iter().filter_map(|c| c).collect();
- debug!("winnowed to {} candidates for {:?}: {:?}",
- candidates.len(),
- stack,
- candidates);
+ debug!(
+ "winnowed to {} candidates for {:?}: {:?}",
+ candidates.len(),
+ stack,
+ candidates
+ );
// If there are STILL multiple candidate, we can further
// reduce the list by dropping duplicates -- including
if candidates.len() > 1 {
let mut i = 0;
while i < candidates.len() {
- let is_dup =
- (0..candidates.len())
- .filter(|&j| i != j)
- .any(|j| self.candidate_should_be_dropped_in_favor_of(&candidates[i],
- &candidates[j]));
+ let is_dup = (0..candidates.len()).filter(|&j| i != j).any(|j| {
+ self.candidate_should_be_dropped_in_favor_of(&candidates[i], &candidates[j])
+ });
if is_dup {
- debug!("Dropping candidate #{}/{}: {:?}",
- i, candidates.len(), candidates[i]);
+ debug!(
+ "Dropping candidate #{}/{}: {:?}",
+ i,
+ candidates.len(),
+ candidates[i]
+ );
candidates.swap_remove(i);
} else {
- debug!("Retaining candidate #{}/{}: {:?}",
- i, candidates.len(), candidates[i]);
+ debug!(
+ "Retaining candidate #{}/{}: {:?}",
+ i,
+ candidates.len(),
+ candidates[i]
+ );
i += 1;
// If there are *STILL* multiple candidates, give up
self.filter_negative_impls(candidates.pop().unwrap().candidate)
}
- fn is_knowable<'o>(&mut self,
- stack: &TraitObligationStack<'o, 'tcx>)
- -> Option<Conflict>
- {
+ fn is_knowable<'o>(&mut self, stack: &TraitObligationStack<'o, 'tcx>) -> Option<Conflict> {
debug!("is_knowable(intercrate={:?})", self.intercrate);
if !self.intercrate.is_some() {
}
let obligation = &stack.obligation;
- let predicate = self.infcx().resolve_type_vars_if_possible(&obligation.predicate);
+ let predicate = self.infcx()
+ .resolve_type_vars_if_possible(&obligation.predicate);
// ok to skip binder because of the nature of the
// trait-ref-is-knowable check, which does not care about
let trait_ref = predicate.skip_binder().trait_ref;
let result = coherence::trait_ref_is_knowable(self.tcx(), trait_ref);
- if let (Some(Conflict::Downstream { used_to_be_broken: true }),
- Some(IntercrateMode::Issue43355)) = (result, self.intercrate) {
+ if let (
+ Some(Conflict::Downstream {
+ used_to_be_broken: true,
+ }),
+ Some(IntercrateMode::Issue43355),
+ ) = (result, self.intercrate)
+ {
debug!("is_knowable: IGNORING conflict to be bug-compatible with #43355");
None
} else {
true
}
- fn check_candidate_cache(&mut self,
- param_env: ty::ParamEnv<'tcx>,
- cache_fresh_trait_pred: &ty::PolyTraitPredicate<'tcx>)
- -> Option<SelectionResult<'tcx, SelectionCandidate<'tcx>>>
- {
+ fn check_candidate_cache(
+ &mut self,
+ param_env: ty::ParamEnv<'tcx>,
+ cache_fresh_trait_pred: &ty::PolyTraitPredicate<'tcx>,
+ ) -> Option<SelectionResult<'tcx, SelectionCandidate<'tcx>>> {
let tcx = self.tcx();
let trait_ref = &cache_fresh_trait_pred.skip_binder().trait_ref;
if self.can_use_global_caches(param_env) {
return Some(cached.get(tcx));
}
}
- self.infcx.selection_cache.hashmap
- .borrow()
- .get(trait_ref)
- .map(|v| v.get(tcx))
+ self.infcx
+ .selection_cache
+ .hashmap
+ .borrow()
+ .get(trait_ref)
+ .map(|v| v.get(tcx))
}
- fn insert_candidate_cache(&mut self,
- param_env: ty::ParamEnv<'tcx>,
- cache_fresh_trait_pred: ty::PolyTraitPredicate<'tcx>,
- dep_node: DepNodeIndex,
- candidate: SelectionResult<'tcx, SelectionCandidate<'tcx>>)
- {
+ fn insert_candidate_cache(
+ &mut self,
+ param_env: ty::ParamEnv<'tcx>,
+ cache_fresh_trait_pred: ty::PolyTraitPredicate<'tcx>,
+ dep_node: DepNodeIndex,
+ candidate: SelectionResult<'tcx, SelectionCandidate<'tcx>>,
+ ) {
let tcx = self.tcx();
let trait_ref = cache_fresh_trait_pred.skip_binder().trait_ref;
if self.can_use_global_caches(param_env) {
if let Some(candidate) = tcx.lift_to_global(&candidate) {
debug!(
"insert_candidate_cache(trait_ref={:?}, candidate={:?}) global",
- trait_ref,
- candidate,
+ trait_ref, candidate,
);
// This may overwrite the cache with the same value
tcx.selection_cache
- .hashmap.borrow_mut()
- .insert(trait_ref, WithDepNode::new(dep_node, candidate));
+ .hashmap
+ .borrow_mut()
+ .insert(trait_ref, WithDepNode::new(dep_node, candidate));
return;
}
}
debug!(
"insert_candidate_cache(trait_ref={:?}, candidate={:?}) local",
- trait_ref,
- candidate,
+ trait_ref, candidate,
);
- self.infcx.selection_cache.hashmap
- .borrow_mut()
- .insert(trait_ref, WithDepNode::new(dep_node, candidate));
+ self.infcx
+ .selection_cache
+ .hashmap
+ .borrow_mut()
+ .insert(trait_ref, WithDepNode::new(dep_node, candidate));
}
- fn assemble_candidates<'o>(&mut self,
- stack: &TraitObligationStack<'o, 'tcx>)
- -> Result<SelectionCandidateSet<'tcx>, SelectionError<'tcx>>
- {
- let obligation = stack.obligation;
+ fn assemble_candidates<'o>(
+ &mut self,
+ stack: &TraitObligationStack<'o, 'tcx>,
+ ) -> Result<SelectionCandidateSet<'tcx>, SelectionError<'tcx>> {
+ let TraitObligationStack { obligation, .. } = *stack;
let ref obligation = Obligation {
param_env: obligation.param_env,
cause: obligation.cause.clone(),
recursion_depth: obligation.recursion_depth,
- predicate: self.infcx().resolve_type_vars_if_possible(&obligation.predicate)
+ predicate: self.infcx()
+ .resolve_type_vars_if_possible(&obligation.predicate),
};
if obligation.predicate.skip_binder().self_ty().is_ty_var() {
// Take the fast path out - this also improves
// performance by preventing assemble_candidates_from_impls from
// matching every impl for this trait.
- return Ok(SelectionCandidateSet { vec: vec![], ambiguous: true });
+ return Ok(SelectionCandidateSet {
+ vec: vec![],
+ ambiguous: true,
+ });
}
let mut candidates = SelectionCandidateSet {
vec: Vec::new(),
- ambiguous: false
+ ambiguous: false,
};
// Other bounds. Consider both in-scope bounds from fn decl
let lang_items = self.tcx().lang_items();
if lang_items.copy_trait() == Some(def_id) {
- debug!("obligation self ty is {:?}",
- obligation.predicate.skip_binder().self_ty());
+ debug!(
+ "obligation self ty is {:?}",
+ obligation.predicate.skip_binder().self_ty()
+ );
// User-defined copy impls are permitted, but only for
// structs and enums.
// Sized is never implementable by end-users, it is
// always automatically computed.
let sized_conditions = self.sized_conditions(obligation);
- self.assemble_builtin_bound_candidates(sized_conditions,
- &mut candidates)?;
+ self.assemble_builtin_bound_candidates(sized_conditions, &mut candidates)?;
} else if lang_items.unsize_trait() == Some(def_id) {
self.assemble_candidates_for_unsizing(obligation, &mut candidates);
} else {
Ok(candidates)
}
- fn assemble_candidates_from_projected_tys(&mut self,
- obligation: &TraitObligation<'tcx>,
- candidates: &mut SelectionCandidateSet<'tcx>)
- {
+ fn assemble_candidates_from_projected_tys(
+ &mut self,
+ obligation: &TraitObligation<'tcx>,
+ candidates: &mut SelectionCandidateSet<'tcx>,
+ ) {
debug!("assemble_candidates_for_projected_tys({:?})", obligation);
- // before we go into the whole skolemization thing, just
+ // before we go into the whole placeholder thing, just
// quickly check if the self-type is a projection at all.
match obligation.predicate.skip_binder().trait_ref.self_ty().sty {
ty::Projection(_) | ty::Opaque(..) => {}
ty::Infer(ty::TyVar(_)) => {
- span_bug!(obligation.cause.span,
- "Self=_ should have been handled by assemble_candidates");
+ span_bug!(
+ obligation.cause.span,
+ "Self=_ should have been handled by assemble_candidates"
+ );
}
- _ => return
+ _ => return,
}
- let result = self.probe(|this, snapshot|
- this.match_projection_obligation_against_definition_bounds(obligation,
- snapshot)
- );
+ let result = self.probe(|this, snapshot| {
+ this.match_projection_obligation_against_definition_bounds(obligation, snapshot)
+ });
if result {
candidates.vec.push(ProjectionCandidate);
fn match_projection_obligation_against_definition_bounds(
&mut self,
obligation: &TraitObligation<'tcx>,
- snapshot: &infer::CombinedSnapshot<'cx, 'tcx>)
- -> bool
- {
- let poly_trait_predicate =
- self.infcx().resolve_type_vars_if_possible(&obligation.predicate);
- let (skol_trait_predicate, skol_map) =
- self.infcx().skolemize_late_bound_regions(&poly_trait_predicate);
- debug!("match_projection_obligation_against_definition_bounds: \
- skol_trait_predicate={:?} skol_map={:?}",
- skol_trait_predicate,
- skol_map);
+ snapshot: &infer::CombinedSnapshot<'cx, 'tcx>,
+ ) -> bool {
+ let poly_trait_predicate = self.infcx()
+ .resolve_type_vars_if_possible(&obligation.predicate);
+ let (skol_trait_predicate, placeholder_map) = self.infcx()
+ .replace_late_bound_regions_with_placeholders(&poly_trait_predicate);
+ debug!(
+ "match_projection_obligation_against_definition_bounds: \
+ skol_trait_predicate={:?} placeholder_map={:?}",
+ skol_trait_predicate, placeholder_map
+ );
let (def_id, substs) = match skol_trait_predicate.trait_ref.self_ty().sty {
- ty::Projection(ref data) =>
- (data.trait_ref(self.tcx()).def_id, data.substs),
+ ty::Projection(ref data) => (data.trait_ref(self.tcx()).def_id, data.substs),
ty::Opaque(def_id, substs) => (def_id, substs),
_ => {
span_bug!(
obligation.cause.span,
"match_projection_obligation_against_definition_bounds() called \
but self-ty is not a projection: {:?}",
- skol_trait_predicate.trait_ref.self_ty());
+ skol_trait_predicate.trait_ref.self_ty()
+ );
}
};
- debug!("match_projection_obligation_against_definition_bounds: \
- def_id={:?}, substs={:?}",
- def_id, substs);
+ debug!(
+ "match_projection_obligation_against_definition_bounds: \
+ def_id={:?}, substs={:?}",
+ def_id, substs
+ );
let predicates_of = self.tcx().predicates_of(def_id);
let bounds = predicates_of.instantiate(self.tcx(), substs);
- debug!("match_projection_obligation_against_definition_bounds: \
- bounds={:?}",
- bounds);
+ debug!(
+ "match_projection_obligation_against_definition_bounds: \
+ bounds={:?}",
+ bounds
+ );
- let matching_bound =
- util::elaborate_predicates(self.tcx(), bounds.predicates)
+ let matching_bound = util::elaborate_predicates(self.tcx(), bounds.predicates)
.filter_to_traits()
- .find(
- |bound| self.probe(
- |this, _| this.match_projection(obligation,
- bound.clone(),
- skol_trait_predicate.trait_ref.clone(),
- &skol_map,
- snapshot)));
-
- debug!("match_projection_obligation_against_definition_bounds: \
- matching_bound={:?}",
- matching_bound);
+ .find(|bound| {
+ self.probe(|this, _| {
+ this.match_projection(
+ obligation,
+ bound.clone(),
+ skol_trait_predicate.trait_ref.clone(),
+ &placeholder_map,
+ snapshot,
+ )
+ })
+ });
+
+ debug!(
+ "match_projection_obligation_against_definition_bounds: \
+ matching_bound={:?}",
+ matching_bound
+ );
match matching_bound {
None => false,
Some(bound) => {
// Repeat the successful match, if any, this time outside of a probe.
- let result = self.match_projection(obligation,
- bound,
- skol_trait_predicate.trait_ref.clone(),
- &skol_map,
- snapshot);
+ let result = self.match_projection(
+ obligation,
+ bound,
+ skol_trait_predicate.trait_ref.clone(),
+ &placeholder_map,
+ snapshot,
+ );
- self.infcx.pop_skolemized(skol_map, snapshot);
+ self.infcx.pop_placeholders(placeholder_map, snapshot);
assert!(result);
true
}
}
- fn match_projection(&mut self,
- obligation: &TraitObligation<'tcx>,
- trait_bound: ty::PolyTraitRef<'tcx>,
- skol_trait_ref: ty::TraitRef<'tcx>,
- skol_map: &infer::SkolemizationMap<'tcx>,
- snapshot: &infer::CombinedSnapshot<'cx, 'tcx>)
- -> bool
- {
+ fn match_projection(
+ &mut self,
+ obligation: &TraitObligation<'tcx>,
+ trait_bound: ty::PolyTraitRef<'tcx>,
+ skol_trait_ref: ty::TraitRef<'tcx>,
+ placeholder_map: &infer::PlaceholderMap<'tcx>,
+ snapshot: &infer::CombinedSnapshot<'cx, 'tcx>,
+ ) -> bool {
debug_assert!(!skol_trait_ref.has_escaping_regions());
- if self.infcx.at(&obligation.cause, obligation.param_env)
- .sup(ty::Binder::dummy(skol_trait_ref), trait_bound).is_err() {
+ if self.infcx
+ .at(&obligation.cause, obligation.param_env)
+ .sup(ty::Binder::dummy(skol_trait_ref), trait_bound)
+ .is_err()
+ {
return false;
}
- self.infcx.leak_check(false, obligation.cause.span, skol_map, snapshot).is_ok()
+ self.infcx
+ .leak_check(false, obligation.cause.span, placeholder_map, snapshot)
+ .is_ok()
}
/// Given an obligation like `<SomeTrait for T>`, search the obligations that the caller
/// supplied to find out whether it is listed among them.
///
/// Never affects inference environment.
- fn assemble_candidates_from_caller_bounds<'o>(&mut self,
- stack: &TraitObligationStack<'o, 'tcx>,
- candidates: &mut SelectionCandidateSet<'tcx>)
- -> Result<(),SelectionError<'tcx>>
- {
- debug!("assemble_candidates_from_caller_bounds({:?})",
- stack.obligation);
+ fn assemble_candidates_from_caller_bounds<'o>(
+ &mut self,
+ stack: &TraitObligationStack<'o, 'tcx>,
+ candidates: &mut SelectionCandidateSet<'tcx>,
+ ) -> Result<(), SelectionError<'tcx>> {
+ debug!(
+ "assemble_candidates_from_caller_bounds({:?})",
+ stack.obligation
+ );
- let all_bounds =
- stack.obligation.param_env.caller_bounds
- .iter()
- .filter_map(|o| o.to_opt_poly_trait_ref());
+ let all_bounds = stack
+ .obligation
+ .param_env
+ .caller_bounds
+ .iter()
+ .filter_map(|o| o.to_opt_poly_trait_ref());
// micro-optimization: filter out predicates relating to different
// traits.
Ok(())
}
- fn evaluate_where_clause<'o>(&mut self,
- stack: &TraitObligationStack<'o, 'tcx>,
- where_clause_trait_ref: ty::PolyTraitRef<'tcx>)
- -> Result<EvaluationResult, OverflowError>
- {
- self.probe(move |this, _|
+ fn evaluate_where_clause<'o>(
+ &mut self,
+ stack: &TraitObligationStack<'o, 'tcx>,
+ where_clause_trait_ref: ty::PolyTraitRef<'tcx>,
+ ) -> Result<EvaluationResult, OverflowError> {
+ self.probe(move |this, _| {
match this.match_where_clause_trait_ref(stack.obligation, where_clause_trait_ref) {
Ok(obligations) => {
this.evaluate_predicates_recursively(stack.list(), obligations.iter())
}
- Err(()) => Ok(EvaluatedToErr)
+ Err(()) => Ok(EvaluatedToErr),
}
- )
+ })
}
- fn assemble_generator_candidates(&mut self,
- obligation: &TraitObligation<'tcx>,
- candidates: &mut SelectionCandidateSet<'tcx>)
- -> Result<(),SelectionError<'tcx>>
- {
+ fn assemble_generator_candidates(
+ &mut self,
+ obligation: &TraitObligation<'tcx>,
+ candidates: &mut SelectionCandidateSet<'tcx>,
+ ) -> Result<(), SelectionError<'tcx>> {
if self.tcx().lang_items().gen_trait() != Some(obligation.predicate.def_id()) {
return Ok(());
}
let self_ty = *obligation.self_ty().skip_binder();
match self_ty.sty {
ty::Generator(..) => {
- debug!("assemble_generator_candidates: self_ty={:?} obligation={:?}",
- self_ty,
- obligation);
+ debug!(
+ "assemble_generator_candidates: self_ty={:?} obligation={:?}",
+ self_ty, obligation
+ );
candidates.vec.push(GeneratorCandidate);
}
/// Note: the type parameters on a closure candidate are modeled as *output* type
/// parameters and hence do not affect whether this trait is a match or not. They will be
/// unified during the confirmation step.
- fn assemble_closure_candidates(&mut self,
- obligation: &TraitObligation<'tcx>,
- candidates: &mut SelectionCandidateSet<'tcx>)
- -> Result<(),SelectionError<'tcx>>
- {
- let kind = match self.tcx().lang_items().fn_trait_kind(obligation.predicate.def_id()) {
+ fn assemble_closure_candidates(
+ &mut self,
+ obligation: &TraitObligation<'tcx>,
+ candidates: &mut SelectionCandidateSet<'tcx>,
+ ) -> Result<(), SelectionError<'tcx>> {
+ let kind = match self.tcx()
+ .lang_items()
+ .fn_trait_kind(obligation.predicate.def_id())
+ {
Some(k) => k,
- None => { return Ok(()); }
+ None => {
+ return Ok(());
+ }
};
// ok to skip binder because the substs on closure types never
// type/region parameters
match obligation.self_ty().skip_binder().sty {
ty::Closure(closure_def_id, closure_substs) => {
- debug!("assemble_unboxed_candidates: kind={:?} obligation={:?}",
- kind, obligation);
+ debug!(
+ "assemble_unboxed_candidates: kind={:?} obligation={:?}",
+ kind, obligation
+ );
match self.infcx.closure_kind(closure_def_id, closure_substs) {
Some(closure_kind) => {
- debug!("assemble_unboxed_candidates: closure_kind = {:?}", closure_kind);
+ debug!(
+ "assemble_unboxed_candidates: closure_kind = {:?}",
+ closure_kind
+ );
if closure_kind.extends(kind) {
candidates.vec.push(ClosureCandidate);
}
}
/// Implement one of the `Fn()` family for a fn pointer.
- fn assemble_fn_pointer_candidates(&mut self,
- obligation: &TraitObligation<'tcx>,
- candidates: &mut SelectionCandidateSet<'tcx>)
- -> Result<(),SelectionError<'tcx>>
- {
+ fn assemble_fn_pointer_candidates(
+ &mut self,
+ obligation: &TraitObligation<'tcx>,
+ candidates: &mut SelectionCandidateSet<'tcx>,
+ ) -> Result<(), SelectionError<'tcx>> {
// We provide impl of all fn traits for fn pointers.
- if self.tcx().lang_items().fn_trait_kind(obligation.predicate.def_id()).is_none() {
+ if self.tcx()
+ .lang_items()
+ .fn_trait_kind(obligation.predicate.def_id())
+ .is_none()
+ {
return Ok(());
}
abi: Abi::Rust,
variadic: false,
..
- } = self_ty.fn_sig(self.tcx()).skip_binder() {
+ } = self_ty.fn_sig(self.tcx()).skip_binder()
+ {
candidates.vec.push(FnPointerCandidate);
}
}
}
/// Search for impls that might apply to `obligation`.
- fn assemble_candidates_from_impls(&mut self,
- obligation: &TraitObligation<'tcx>,
- candidates: &mut SelectionCandidateSet<'tcx>)
- -> Result<(), SelectionError<'tcx>>
- {
- debug!("assemble_candidates_from_impls(obligation={:?})", obligation);
+ fn assemble_candidates_from_impls(
+ &mut self,
+ obligation: &TraitObligation<'tcx>,
+ candidates: &mut SelectionCandidateSet<'tcx>,
+ ) -> Result<(), SelectionError<'tcx>> {
+ debug!(
+ "assemble_candidates_from_impls(obligation={:?})",
+ obligation
+ );
self.tcx().for_each_relevant_impl(
obligation.predicate.def_id(),
obligation.predicate.skip_binder().trait_ref.self_ty(),
|impl_def_id| {
- self.probe(|this, snapshot| /* [1] */
- if let Ok(skol_map) = this.match_impl(impl_def_id, obligation, snapshot) {
+ self.probe(|this, snapshot| {
+ if let Ok(placeholder_map) = this.match_impl(impl_def_id, obligation, snapshot)
+ {
candidates.vec.push(ImplCandidate(impl_def_id));
- // NB: we can safely drop the skol map
- // since we are in a probe [1]
- mem::drop(skol_map);
+ // NB: we can safely drop the placeholder map
+ // since we are in a probe.
+ mem::drop(placeholder_map);
}
- );
- }
+ });
+ },
);
Ok(())
}
- fn assemble_candidates_from_auto_impls(&mut self,
- obligation: &TraitObligation<'tcx>,
- candidates: &mut SelectionCandidateSet<'tcx>)
- -> Result<(), SelectionError<'tcx>>
- {
+ fn assemble_candidates_from_auto_impls(
+ &mut self,
+ obligation: &TraitObligation<'tcx>,
+ candidates: &mut SelectionCandidateSet<'tcx>,
+ ) -> Result<(), SelectionError<'tcx>> {
// OK to skip binder here because the tests we do below do not involve bound regions
let self_ty = *obligation.self_ty().skip_binder();
debug!("assemble_candidates_from_auto_impls(self_ty={:?})", self_ty);
// still be provided by a manual implementation for
// this trait and type.
}
- ty::Param(..) |
- ty::Projection(..) => {
+ ty::Param(..) | ty::Projection(..) => {
// In these cases, we don't know what the actual
// type is. Therefore, we cannot break it down
// into its constituent types. So we don't
// the auto impl might apply, we don't know
candidates.ambiguous = true;
}
- _ => {
- candidates.vec.push(AutoImplCandidate(def_id.clone()))
- }
+ _ => candidates.vec.push(AutoImplCandidate(def_id.clone())),
}
}
}
/// Search for impls that might apply to `obligation`.
- fn assemble_candidates_from_object_ty(&mut self,
- obligation: &TraitObligation<'tcx>,
- candidates: &mut SelectionCandidateSet<'tcx>)
- {
- debug!("assemble_candidates_from_object_ty(self_ty={:?})",
- obligation.self_ty().skip_binder());
+ fn assemble_candidates_from_object_ty(
+ &mut self,
+ obligation: &TraitObligation<'tcx>,
+ candidates: &mut SelectionCandidateSet<'tcx>,
+ ) {
+ debug!(
+ "assemble_candidates_from_object_ty(self_ty={:?})",
+ obligation.self_ty().skip_binder()
+ );
// Object-safety candidates are only applicable to object-safe
// traits. Including this check is useful because it helps
let self_ty = this.tcx().erase_late_bound_regions(&obligation.self_ty());
let poly_trait_ref = match self_ty.sty {
ty::Dynamic(ref data, ..) => {
- if data.auto_traits().any(|did| did == obligation.predicate.def_id()) {
- debug!("assemble_candidates_from_object_ty: matched builtin bound, \
- pushing candidate");
+ if data.auto_traits()
+ .any(|did| did == obligation.predicate.def_id())
+ {
+ debug!(
+ "assemble_candidates_from_object_ty: matched builtin bound, \
+ pushing candidate"
+ );
candidates.vec.push(BuiltinObjectCandidate);
return;
}
candidates.ambiguous = true; // could wind up being an object type
return;
}
- _ => return
+ _ => return,
};
- debug!("assemble_candidates_from_object_ty: poly_trait_ref={:?}",
- poly_trait_ref);
+ debug!(
+ "assemble_candidates_from_object_ty: poly_trait_ref={:?}",
+ poly_trait_ref
+ );
// Count only those upcast versions that match the trait-ref
// we are looking for. Specifically, do not only check for the
// correct trait, but also the correct type parameters.
// For example, we may be trying to upcast `Foo` to `Bar<i32>`,
// but `Foo` is declared as `trait Foo : Bar<u32>`.
- let upcast_trait_refs =
- util::supertraits(this.tcx(), poly_trait_ref)
- .filter(|upcast_trait_ref|
+ let upcast_trait_refs = util::supertraits(this.tcx(), poly_trait_ref)
+ .filter(|upcast_trait_ref| {
this.probe(|this, _| {
let upcast_trait_ref = upcast_trait_ref.clone();
- this.match_poly_trait_ref(obligation, upcast_trait_ref).is_ok()
+ this.match_poly_trait_ref(obligation, upcast_trait_ref)
+ .is_ok()
})
- )
+ })
.count();
if upcast_trait_refs > 1 {
}
/// Search for unsizing that might apply to `obligation`.
- fn assemble_candidates_for_unsizing(&mut self,
- obligation: &TraitObligation<'tcx>,
- candidates: &mut SelectionCandidateSet<'tcx>) {
+ fn assemble_candidates_for_unsizing(
+ &mut self,
+ obligation: &TraitObligation<'tcx>,
+ candidates: &mut SelectionCandidateSet<'tcx>,
+ ) {
// We currently never consider higher-ranked obligations e.g.
// `for<'a> &'a T: Unsize<Trait+'a>` to be implemented. This is not
// because they are a priori invalid, and we could potentially add support
return;
}
};
- let target = obligation.predicate.skip_binder().trait_ref.substs.type_at(1);
+ let target = obligation
+ .predicate
+ .skip_binder()
+ .trait_ref
+ .substs
+ .type_at(1);
- debug!("assemble_candidates_for_unsizing(source={:?}, target={:?})",
- source, target);
+ debug!(
+ "assemble_candidates_for_unsizing(source={:?}, target={:?})",
+ source, target
+ );
let may_apply = match (&source.sty, &target.sty) {
// Trait+Kx+'a -> Trait+Ky+'b (upcasts).
// We always upcast when we can because of reason
// #2 (region bounds).
match (data_a.principal(), data_b.principal()) {
- (Some(a), Some(b)) => a.def_id() == b.def_id() &&
- data_b.auto_traits()
+ (Some(a), Some(b)) => {
+ a.def_id() == b.def_id()
+ && data_b.auto_traits()
// All of a's auto traits need to be in b's auto traits.
- .all(|b| data_a.auto_traits().any(|a| a == b)),
- _ => false
+ .all(|b| data_a.auto_traits().any(|a| a == b))
+ }
+ _ => false,
}
}
// Ambiguous handling is below T -> Trait, because inference
// variables can still implement Unsize<Trait> and nested
// obligations will have the final say (likely deferred).
- (&ty::Infer(ty::TyVar(_)), _) |
- (_, &ty::Infer(ty::TyVar(_))) => {
+ (&ty::Infer(ty::TyVar(_)), _) | (_, &ty::Infer(ty::TyVar(_))) => {
debug!("assemble_candidates_for_unsizing: ambiguous");
candidates.ambiguous = true;
false
}
// (.., T) -> (.., U).
- (&ty::Tuple(tys_a), &ty::Tuple(tys_b)) => {
- tys_a.len() == tys_b.len()
- }
+ (&ty::Tuple(tys_a), &ty::Tuple(tys_b)) => tys_a.len() == tys_b.len(),
- _ => false
+ _ => false,
};
if may_apply {
//
// Winnowing is the process of attempting to resolve ambiguity by
// probing further. During the winnowing process, we unify all
- // type variables (ignoring skolemization) and then we also
- // attempt to evaluate recursive bounds to see if they are
- // satisfied.
+ // type variables and then we also attempt to evaluate recursive
+ // bounds to see if they are satisfied.
/// Returns true if `victim` should be dropped in favor of
/// `other`. Generally speaking we will drop duplicate
fn candidate_should_be_dropped_in_favor_of<'o>(
&mut self,
victim: &EvaluatedCandidate<'tcx>,
- other: &EvaluatedCandidate<'tcx>)
- -> bool
- {
+ other: &EvaluatedCandidate<'tcx>,
+ ) -> bool {
if victim.candidate == other.candidate {
return true;
}
// Check if a bound would previously have been removed when normalizing
// the param_env so that it can be given the lowest priority. See
// #50825 for the motivation for this.
- let is_global = |cand: &ty::PolyTraitRef<'_>| {
- cand.is_global() && !cand.has_late_bound_regions()
- };
+ let is_global =
+ |cand: &ty::PolyTraitRef<'_>| cand.is_global() && !cand.has_late_bound_regions();
match other.candidate {
// Prefer BuiltinCandidate { has_nested: false } to anything else.
BuiltinCandidate { has_nested: false } => true,
ParamCandidate(ref cand) => match victim.candidate {
AutoImplCandidate(..) => {
- bug!("default implementations shouldn't be recorded \
- when there are other valid candidates");
+ bug!(
+ "default implementations shouldn't be recorded \
+ when there are other valid candidates"
+ );
}
// Prefer BuiltinCandidate { has_nested: false } to anything else.
// This is a fix for #53123 and prevents winnowing from accidentally extending the
// lifetime of a variable.
BuiltinCandidate { has_nested: false } => false,
- ImplCandidate(..) |
- ClosureCandidate |
- GeneratorCandidate |
- FnPointerCandidate |
- BuiltinObjectCandidate |
- BuiltinUnsizeCandidate |
- BuiltinCandidate { .. } => {
+ ImplCandidate(..)
+ | ClosureCandidate
+ | GeneratorCandidate
+ | FnPointerCandidate
+ | BuiltinObjectCandidate
+ | BuiltinUnsizeCandidate
+ | BuiltinCandidate { .. } => {
// Global bounds from the where clause should be ignored
// here (see issue #50825). Otherwise, we have a where
// clause so don't go around looking for impls.
!is_global(cand)
}
- ObjectCandidate |
- ProjectionCandidate => {
+ ObjectCandidate | ProjectionCandidate => {
// Arbitrarily give param candidates priority
// over projection and object candidates.
!is_global(cand)
- },
+ }
ParamCandidate(..) => false,
},
- ObjectCandidate |
- ProjectionCandidate => match victim.candidate {
+ ObjectCandidate | ProjectionCandidate => match victim.candidate {
AutoImplCandidate(..) => {
- bug!("default implementations shouldn't be recorded \
- when there are other valid candidates");
+ bug!(
+ "default implementations shouldn't be recorded \
+ when there are other valid candidates"
+ );
}
// Prefer BuiltinCandidate { has_nested: false } to anything else.
// This is a fix for #53123 and prevents winnowing from accidentally extending the
// lifetime of a variable.
BuiltinCandidate { has_nested: false } => false,
- ImplCandidate(..) |
- ClosureCandidate |
- GeneratorCandidate |
- FnPointerCandidate |
- BuiltinObjectCandidate |
- BuiltinUnsizeCandidate |
- BuiltinCandidate { .. } => {
- true
- }
- ObjectCandidate |
- ProjectionCandidate => {
+ ImplCandidate(..)
+ | ClosureCandidate
+ | GeneratorCandidate
+ | FnPointerCandidate
+ | BuiltinObjectCandidate
+ | BuiltinUnsizeCandidate
+ | BuiltinCandidate { .. } => true,
+ ObjectCandidate | ProjectionCandidate => {
// Arbitrarily give param candidates priority
// over projection and object candidates.
true
- },
+ }
ParamCandidate(ref cand) => is_global(cand),
},
ImplCandidate(other_def) => {
match victim.candidate {
ImplCandidate(victim_def) => {
let tcx = self.tcx().global_tcx();
- return tcx.specializes((other_def, victim_def)) ||
- tcx.impls_are_allowed_to_overlap(other_def, victim_def);
+ return tcx.specializes((other_def, victim_def))
+ || tcx.impls_are_allowed_to_overlap(other_def, victim_def);
}
ParamCandidate(ref cand) => {
// Prefer the impl to a global where clause candidate.
return is_global(cand);
}
- _ => ()
+ _ => (),
}
}
false
- },
- ClosureCandidate |
- GeneratorCandidate |
- FnPointerCandidate |
- BuiltinObjectCandidate |
- BuiltinUnsizeCandidate |
- BuiltinCandidate { has_nested: true } => {
+ }
+ ClosureCandidate
+ | GeneratorCandidate
+ | FnPointerCandidate
+ | BuiltinObjectCandidate
+ | BuiltinUnsizeCandidate
+ | BuiltinCandidate { has_nested: true } => {
match victim.candidate {
ParamCandidate(ref cand) => {
// Prefer these to a global where-clause bound
_ => false,
}
}
- _ => false
+ _ => false,
}
}
// These cover the traits that are built-in to the language
// itself: `Copy`, `Clone` and `Sized`.
- fn assemble_builtin_bound_candidates<'o>(&mut self,
- conditions: BuiltinImplConditions<'tcx>,
- candidates: &mut SelectionCandidateSet<'tcx>)
- -> Result<(), SelectionError<'tcx>>
- {
+ fn assemble_builtin_bound_candidates<'o>(
+ &mut self,
+ conditions: BuiltinImplConditions<'tcx>,
+ candidates: &mut SelectionCandidateSet<'tcx>,
+ ) -> Result<(), SelectionError<'tcx>> {
match conditions {
BuiltinImplConditions::Where(nested) => {
debug!("builtin_bound: nested={:?}", nested);
candidates.vec.push(BuiltinCandidate {
- has_nested: nested.skip_binder().len() > 0
+ has_nested: nested.skip_binder().len() > 0,
});
}
BuiltinImplConditions::None => {}
Ok(())
}
- fn sized_conditions(&mut self,
- obligation: &TraitObligation<'tcx>)
- -> BuiltinImplConditions<'tcx>
- {
+ fn sized_conditions(
+ &mut self,
+ obligation: &TraitObligation<'tcx>,
+ ) -> BuiltinImplConditions<'tcx> {
use self::BuiltinImplConditions::{Ambiguous, None, Where};
// NOTE: binder moved to (*)
- let self_ty = self.infcx.shallow_resolve(
- obligation.predicate.skip_binder().self_ty());
+ let self_ty = self.infcx
+ .shallow_resolve(obligation.predicate.skip_binder().self_ty());
match self_ty.sty {
- ty::Infer(ty::IntVar(_)) | ty::Infer(ty::FloatVar(_)) |
- ty::Uint(_) | ty::Int(_) | ty::Bool | ty::Float(_) |
- ty::FnDef(..) | ty::FnPtr(_) | ty::RawPtr(..) |
- ty::Char | ty::Ref(..) | ty::Generator(..) |
- ty::GeneratorWitness(..) | ty::Array(..) | ty::Closure(..) |
- ty::Never | ty::Error => {
+ ty::Infer(ty::IntVar(_))
+ | ty::Infer(ty::FloatVar(_))
+ | ty::Uint(_)
+ | ty::Int(_)
+ | ty::Bool
+ | ty::Float(_)
+ | ty::FnDef(..)
+ | ty::FnPtr(_)
+ | ty::RawPtr(..)
+ | ty::Char
+ | ty::Ref(..)
+ | ty::Generator(..)
+ | ty::GeneratorWitness(..)
+ | ty::Array(..)
+ | ty::Closure(..)
+ | ty::Never
+ | ty::Error => {
// safe for everything
Where(ty::Binder::dummy(Vec::new()))
}
ty::Str | ty::Slice(_) | ty::Dynamic(..) | ty::Foreign(..) => None,
- ty::Tuple(tys) => {
- Where(ty::Binder::bind(tys.last().into_iter().cloned().collect()))
- }
+ ty::Tuple(tys) => Where(ty::Binder::bind(tys.last().into_iter().cloned().collect())),
ty::Adt(def, substs) => {
let sized_crit = def.sized_constraint(self.tcx());
// (*) binder moved here
Where(ty::Binder::bind(
- sized_crit.iter().map(|ty| ty.subst(self.tcx(), substs)).collect()
+ sized_crit
+ .iter()
+ .map(|ty| ty.subst(self.tcx(), substs))
+ .collect(),
))
}
ty::Projection(_) | ty::Param(_) | ty::Opaque(..) => None,
ty::Infer(ty::TyVar(_)) => Ambiguous,
- ty::Infer(ty::CanonicalTy(_)) |
- ty::Infer(ty::FreshTy(_)) |
- ty::Infer(ty::FreshIntTy(_)) |
- ty::Infer(ty::FreshFloatTy(_)) => {
- bug!("asked to assemble builtin bounds of unexpected type: {:?}",
- self_ty);
+ ty::UnnormalizedProjection(..)
+ | ty::Infer(ty::CanonicalTy(_))
+ | ty::Infer(ty::FreshTy(_))
+ | ty::Infer(ty::FreshIntTy(_))
+ | ty::Infer(ty::FreshFloatTy(_)) => {
+ bug!(
+ "asked to assemble builtin bounds of unexpected type: {:?}",
+ self_ty
+ );
}
}
}
- fn copy_clone_conditions(&mut self,
- obligation: &TraitObligation<'tcx>)
- -> BuiltinImplConditions<'tcx>
- {
+ fn copy_clone_conditions(
+ &mut self,
+ obligation: &TraitObligation<'tcx>,
+ ) -> BuiltinImplConditions<'tcx> {
// NOTE: binder moved to (*)
- let self_ty = self.infcx.shallow_resolve(
- obligation.predicate.skip_binder().self_ty());
+ let self_ty = self.infcx
+ .shallow_resolve(obligation.predicate.skip_binder().self_ty());
use self::BuiltinImplConditions::{Ambiguous, None, Where};
match self_ty.sty {
- ty::Infer(ty::IntVar(_)) | ty::Infer(ty::FloatVar(_)) |
- ty::FnDef(..) | ty::FnPtr(_) | ty::Error => {
- Where(ty::Binder::dummy(Vec::new()))
- }
-
- ty::Uint(_) | ty::Int(_) | ty::Bool | ty::Float(_) |
- ty::Char | ty::RawPtr(..) | ty::Never |
- ty::Ref(_, _, hir::MutImmutable) => {
+ ty::Infer(ty::IntVar(_))
+ | ty::Infer(ty::FloatVar(_))
+ | ty::FnDef(..)
+ | ty::FnPtr(_)
+ | ty::Error => Where(ty::Binder::dummy(Vec::new())),
+
+ ty::Uint(_)
+ | ty::Int(_)
+ | ty::Bool
+ | ty::Float(_)
+ | ty::Char
+ | ty::RawPtr(..)
+ | ty::Never
+ | ty::Ref(_, _, hir::MutImmutable) => {
// Implementations provided in libcore
None
}
- ty::Dynamic(..) | ty::Str | ty::Slice(..) |
- ty::Generator(..) | ty::GeneratorWitness(..) | ty::Foreign(..) |
- ty::Ref(_, _, hir::MutMutable) => {
- None
- }
+ ty::Dynamic(..)
+ | ty::Str
+ | ty::Slice(..)
+ | ty::Generator(..)
+ | ty::GeneratorWitness(..)
+ | ty::Foreign(..)
+ | ty::Ref(_, _, hir::MutMutable) => None,
ty::Array(element_ty, _) => {
// (*) binder moved here
let is_copy_trait = Some(trait_id) == self.tcx().lang_items().copy_trait();
let is_clone_trait = Some(trait_id) == self.tcx().lang_items().clone_trait();
if is_copy_trait || is_clone_trait {
- Where(ty::Binder::bind(substs.upvar_tys(def_id, self.tcx()).collect()))
+ Where(ty::Binder::bind(
+ substs.upvar_tys(def_id, self.tcx()).collect(),
+ ))
} else {
None
}
Ambiguous
}
- ty::Infer(ty::CanonicalTy(_)) |
- ty::Infer(ty::FreshTy(_)) |
- ty::Infer(ty::FreshIntTy(_)) |
- ty::Infer(ty::FreshFloatTy(_)) => {
- bug!("asked to assemble builtin bounds of unexpected type: {:?}",
- self_ty);
+ ty::UnnormalizedProjection(..)
+ | ty::Infer(ty::CanonicalTy(_))
+ | ty::Infer(ty::FreshTy(_))
+ | ty::Infer(ty::FreshIntTy(_))
+ | ty::Infer(ty::FreshFloatTy(_)) => {
+ bug!(
+ "asked to assemble builtin bounds of unexpected type: {:?}",
+ self_ty
+ );
}
}
}
/// ```
fn constituent_types_for_ty(&self, t: Ty<'tcx>) -> Vec<Ty<'tcx>> {
match t.sty {
- ty::Uint(_) |
- ty::Int(_) |
- ty::Bool |
- ty::Float(_) |
- ty::FnDef(..) |
- ty::FnPtr(_) |
- ty::Str |
- ty::Error |
- ty::Infer(ty::IntVar(_)) |
- ty::Infer(ty::FloatVar(_)) |
- ty::Never |
- ty::Char => {
- Vec::new()
- }
-
- ty::Dynamic(..) |
- ty::Param(..) |
- ty::Foreign(..) |
- ty::Projection(..) |
- ty::Infer(ty::CanonicalTy(_)) |
- ty::Infer(ty::TyVar(_)) |
- ty::Infer(ty::FreshTy(_)) |
- ty::Infer(ty::FreshIntTy(_)) |
- ty::Infer(ty::FreshFloatTy(_)) => {
- bug!("asked to assemble constituent types of unexpected type: {:?}",
- t);
- }
-
- ty::RawPtr(ty::TypeAndMut { ty: element_ty, ..}) |
- ty::Ref(_, element_ty, _) => {
- vec![element_ty]
- },
+ ty::Uint(_)
+ | ty::Int(_)
+ | ty::Bool
+ | ty::Float(_)
+ | ty::FnDef(..)
+ | ty::FnPtr(_)
+ | ty::Str
+ | ty::Error
+ | ty::Infer(ty::IntVar(_))
+ | ty::Infer(ty::FloatVar(_))
+ | ty::Never
+ | ty::Char => Vec::new(),
+
+ ty::UnnormalizedProjection(..)
+ | ty::Dynamic(..)
+ | ty::Param(..)
+ | ty::Foreign(..)
+ | ty::Projection(..)
+ | ty::Infer(ty::CanonicalTy(_))
+ | ty::Infer(ty::TyVar(_))
+ | ty::Infer(ty::FreshTy(_))
+ | ty::Infer(ty::FreshIntTy(_))
+ | ty::Infer(ty::FreshFloatTy(_)) => {
+ bug!(
+ "asked to assemble constituent types of unexpected type: {:?}",
+ t
+ );
+ }
- ty::Array(element_ty, _) | ty::Slice(element_ty) => {
+ ty::RawPtr(ty::TypeAndMut { ty: element_ty, .. }) | ty::Ref(_, element_ty, _) => {
vec![element_ty]
}
+ ty::Array(element_ty, _) | ty::Slice(element_ty) => vec![element_ty],
+
ty::Tuple(ref tys) => {
// (T1, ..., Tn) -- meets any bound that all of T1...Tn meet
tys.to_vec()
}
- ty::Closure(def_id, ref substs) => {
- substs.upvar_tys(def_id, self.tcx()).collect()
- }
+ ty::Closure(def_id, ref substs) => substs.upvar_tys(def_id, self.tcx()).collect(),
ty::Generator(def_id, ref substs, _) => {
let witness = substs.witness(def_id, self.tcx());
- substs.upvar_tys(def_id, self.tcx()).chain(iter::once(witness)).collect()
+ substs
+ .upvar_tys(def_id, self.tcx())
+ .chain(iter::once(witness))
+ .collect()
}
ty::GeneratorWitness(types) => {
}
// for `PhantomData<T>`, we pass `T`
- ty::Adt(def, substs) if def.is_phantom_data() => {
- substs.types().collect()
- }
+ ty::Adt(def, substs) if def.is_phantom_data() => substs.types().collect(),
- ty::Adt(def, substs) => {
- def.all_fields()
- .map(|f| f.ty(self.tcx(), substs))
- .collect()
- }
+ ty::Adt(def, substs) => def.all_fields().map(|f| f.ty(self.tcx(), substs)).collect(),
ty::Opaque(def_id, substs) => {
// We can resolve the `impl Trait` to its concrete type,
}
}
- fn collect_predicates_for_types(&mut self,
- param_env: ty::ParamEnv<'tcx>,
- cause: ObligationCause<'tcx>,
- recursion_depth: usize,
- trait_def_id: DefId,
- types: ty::Binder<Vec<Ty<'tcx>>>)
- -> Vec<PredicateObligation<'tcx>>
- {
+ fn collect_predicates_for_types(
+ &mut self,
+ param_env: ty::ParamEnv<'tcx>,
+ cause: ObligationCause<'tcx>,
+ recursion_depth: usize,
+ trait_def_id: DefId,
+ types: ty::Binder<Vec<Ty<'tcx>>>,
+ ) -> Vec<PredicateObligation<'tcx>> {
// Because the types were potentially derived from
// higher-ranked obligations they may reference late-bound
// regions. For example, `for<'a> Foo<&'a int> : Copy` would
//
// The strategy is to:
//
- // 1. Instantiate those regions to skolemized regions (e.g.,
+ // 1. Instantiate those regions to placeholder regions (e.g.,
// `for<'a> &'a int` becomes `&0 int`.
// 2. Produce something like `&'0 int : Copy`
// 3. Re-bind the regions back to `for<'a> &'a int : Copy`
- types.skip_binder().into_iter().flat_map(|ty| { // binder moved -\
- let ty: ty::Binder<Ty<'tcx>> = ty::Binder::bind(ty); // <----/
-
- self.in_snapshot(|this, snapshot| {
- let (skol_ty, skol_map) =
- this.infcx().skolemize_late_bound_regions(&ty);
- let Normalized { value: normalized_ty, mut obligations } =
- project::normalize_with_depth(this,
- param_env,
- cause.clone(),
- recursion_depth,
- &skol_ty);
- let skol_obligation =
- this.tcx().predicate_for_trait_def(param_env,
- cause.clone(),
- trait_def_id,
- recursion_depth,
- normalized_ty,
- &[]);
- obligations.push(skol_obligation);
- this.infcx().plug_leaks(skol_map, snapshot, obligations)
+ types
+ .skip_binder()
+ .into_iter()
+ .flat_map(|ty| {
+ // binder moved -\
+ let ty: ty::Binder<Ty<'tcx>> = ty::Binder::bind(ty); // <----/
+
+ self.in_snapshot(|this, snapshot| {
+ let (skol_ty, placeholder_map) = this.infcx()
+ .replace_late_bound_regions_with_placeholders(&ty);
+ let Normalized {
+ value: normalized_ty,
+ mut obligations,
+ } = project::normalize_with_depth(
+ this,
+ param_env,
+ cause.clone(),
+ recursion_depth,
+ &skol_ty,
+ );
+ let skol_obligation = this.tcx().predicate_for_trait_def(
+ param_env,
+ cause.clone(),
+ trait_def_id,
+ recursion_depth,
+ normalized_ty,
+ &[],
+ );
+ obligations.push(skol_obligation);
+ this.infcx()
+ .plug_leaks(placeholder_map, snapshot, obligations)
+ })
})
- }).collect()
+ .collect()
}
///////////////////////////////////////////////////////////////////////////
// [rustc guide]:
// https://rust-lang-nursery.github.io/rustc-guide/traits/resolution.html#confirmation
- fn confirm_candidate(&mut self,
- obligation: &TraitObligation<'tcx>,
- candidate: SelectionCandidate<'tcx>)
- -> Result<Selection<'tcx>, SelectionError<'tcx>>
- {
- debug!("confirm_candidate({:?}, {:?})",
- obligation,
- candidate);
+ fn confirm_candidate(
+ &mut self,
+ obligation: &TraitObligation<'tcx>,
+ candidate: SelectionCandidate<'tcx>,
+ ) -> Result<Selection<'tcx>, SelectionError<'tcx>> {
+ debug!("confirm_candidate({:?}, {:?})", obligation, candidate);
match candidate {
BuiltinCandidate { has_nested } => {
Ok(VtableAutoImpl(data))
}
- ImplCandidate(impl_def_id) => {
- Ok(VtableImpl(self.confirm_impl_candidate(obligation, impl_def_id)))
- }
+ ImplCandidate(impl_def_id) => Ok(VtableImpl(self.confirm_impl_candidate(
+ obligation,
+ impl_def_id,
+ ))),
ClosureCandidate => {
let vtable_closure = self.confirm_closure_candidate(obligation)?;
}
FnPointerCandidate => {
- let data =
- self.confirm_fn_pointer_candidate(obligation)?;
+ let data = self.confirm_fn_pointer_candidate(obligation)?;
Ok(VtableFnPointer(data))
}
}
}
- fn confirm_projection_candidate(&mut self,
- obligation: &TraitObligation<'tcx>)
- {
+ fn confirm_projection_candidate(&mut self, obligation: &TraitObligation<'tcx>) {
self.in_snapshot(|this, snapshot| {
let result =
- this.match_projection_obligation_against_definition_bounds(obligation,
- snapshot);
+ this.match_projection_obligation_against_definition_bounds(obligation, snapshot);
assert!(result);
})
}
- fn confirm_param_candidate(&mut self,
- obligation: &TraitObligation<'tcx>,
- param: ty::PolyTraitRef<'tcx>)
- -> Vec<PredicateObligation<'tcx>>
- {
- debug!("confirm_param_candidate({:?},{:?})",
- obligation,
- param);
+ fn confirm_param_candidate(
+ &mut self,
+ obligation: &TraitObligation<'tcx>,
+ param: ty::PolyTraitRef<'tcx>,
+ ) -> Vec<PredicateObligation<'tcx>> {
+ debug!("confirm_param_candidate({:?},{:?})", obligation, param);
// During evaluation, we already checked that this
// where-clause trait-ref could be unified with the obligation
match self.match_where_clause_trait_ref(obligation, param.clone()) {
Ok(obligations) => obligations,
Err(()) => {
- bug!("Where clause `{:?}` was applicable to `{:?}` but now is not",
- param,
- obligation);
+ bug!(
+ "Where clause `{:?}` was applicable to `{:?}` but now is not",
+ param,
+ obligation
+ );
}
}
}
- fn confirm_builtin_candidate(&mut self,
- obligation: &TraitObligation<'tcx>,
- has_nested: bool)
- -> VtableBuiltinData<PredicateObligation<'tcx>>
- {
- debug!("confirm_builtin_candidate({:?}, {:?})",
- obligation, has_nested);
+ fn confirm_builtin_candidate(
+ &mut self,
+ obligation: &TraitObligation<'tcx>,
+ has_nested: bool,
+ ) -> VtableBuiltinData<PredicateObligation<'tcx>> {
+ debug!(
+ "confirm_builtin_candidate({:?}, {:?})",
+ obligation, has_nested
+ );
let lang_items = self.tcx().lang_items();
let obligations = if has_nested {
let trait_def = obligation.predicate.def_id();
- let conditions =
- if Some(trait_def) == lang_items.sized_trait() {
- self.sized_conditions(obligation)
- } else if Some(trait_def) == lang_items.copy_trait() {
- self.copy_clone_conditions(obligation)
- } else if Some(trait_def) == lang_items.clone_trait() {
- self.copy_clone_conditions(obligation)
- } else {
- bug!("unexpected builtin trait {:?}", trait_def)
+ let conditions = if Some(trait_def) == lang_items.sized_trait() {
+ self.sized_conditions(obligation)
+ } else if Some(trait_def) == lang_items.copy_trait() {
+ self.copy_clone_conditions(obligation)
+ } else if Some(trait_def) == lang_items.clone_trait() {
+ self.copy_clone_conditions(obligation)
+ } else {
+ bug!("unexpected builtin trait {:?}", trait_def)
};
let nested = match conditions {
BuiltinImplConditions::Where(nested) => nested,
- _ => bug!("obligation {:?} had matched a builtin impl but now doesn't",
- obligation)
+ _ => bug!(
+ "obligation {:?} had matched a builtin impl but now doesn't",
+ obligation
+ ),
};
let cause = obligation.derived_cause(BuiltinDerivedObligation);
- self.collect_predicates_for_types(obligation.param_env,
- cause,
- obligation.recursion_depth+1,
- trait_def,
- nested)
+ self.collect_predicates_for_types(
+ obligation.param_env,
+ cause,
+ obligation.recursion_depth + 1,
+ trait_def,
+ nested,
+ )
} else {
vec![]
};
- debug!("confirm_builtin_candidate: obligations={:?}",
- obligations);
+ debug!("confirm_builtin_candidate: obligations={:?}", obligations);
- VtableBuiltinData { nested: obligations }
+ VtableBuiltinData {
+ nested: obligations,
+ }
}
/// This handles the case where a `auto trait Foo` impl is being used.
///
/// 1. For each constituent type `Y` in `X`, `Y : Foo` holds
/// 2. For each where-clause `C` declared on `Foo`, `[Self => X] C` holds.
- fn confirm_auto_impl_candidate(&mut self,
- obligation: &TraitObligation<'tcx>,
- trait_def_id: DefId)
- -> VtableAutoImplData<PredicateObligation<'tcx>>
- {
- debug!("confirm_auto_impl_candidate({:?}, {:?})",
- obligation,
- trait_def_id);
+ fn confirm_auto_impl_candidate(
+ &mut self,
+ obligation: &TraitObligation<'tcx>,
+ trait_def_id: DefId,
+ ) -> VtableAutoImplData<PredicateObligation<'tcx>> {
+ debug!(
+ "confirm_auto_impl_candidate({:?}, {:?})",
+ obligation, trait_def_id
+ );
let types = obligation.predicate.map_bound(|inner| {
let self_ty = self.infcx.shallow_resolve(inner.self_ty());
}
/// See `confirm_auto_impl_candidate`
- fn vtable_auto_impl(&mut self,
- obligation: &TraitObligation<'tcx>,
- trait_def_id: DefId,
- nested: ty::Binder<Vec<Ty<'tcx>>>)
- -> VtableAutoImplData<PredicateObligation<'tcx>>
- {
+ fn vtable_auto_impl(
+ &mut self,
+ obligation: &TraitObligation<'tcx>,
+ trait_def_id: DefId,
+ nested: ty::Binder<Vec<Ty<'tcx>>>,
+ ) -> VtableAutoImplData<PredicateObligation<'tcx>> {
debug!("vtable_auto_impl: nested={:?}", nested);
let cause = obligation.derived_cause(BuiltinDerivedObligation);
cause,
obligation.recursion_depth + 1,
trait_def_id,
- nested);
+ nested,
+ );
let trait_obligations: Vec<PredicateObligation<'_>> = self.in_snapshot(|this, snapshot| {
let poly_trait_ref = obligation.predicate.to_poly_trait_ref();
- let (trait_ref, skol_map) =
- this.infcx().skolemize_late_bound_regions(&poly_trait_ref);
+ let (trait_ref, placeholder_map) = this.infcx()
+ .replace_late_bound_regions_with_placeholders(&poly_trait_ref);
let cause = obligation.derived_cause(ImplDerivedObligation);
- this.impl_or_trait_obligations(cause,
- obligation.recursion_depth + 1,
- obligation.param_env,
- trait_def_id,
- &trait_ref.substs,
- skol_map,
- snapshot)
+ this.impl_or_trait_obligations(
+ cause,
+ obligation.recursion_depth + 1,
+ obligation.param_env,
+ trait_def_id,
+ &trait_ref.substs,
+ placeholder_map,
+ snapshot,
+ )
});
// Adds the predicates from the trait. Note that this contains a `Self: Trait`
VtableAutoImplData {
trait_def_id,
- nested: obligations
+ nested: obligations,
}
}
- fn confirm_impl_candidate(&mut self,
- obligation: &TraitObligation<'tcx>,
- impl_def_id: DefId)
- -> VtableImplData<'tcx, PredicateObligation<'tcx>>
- {
- debug!("confirm_impl_candidate({:?},{:?})",
- obligation,
- impl_def_id);
+ fn confirm_impl_candidate(
+ &mut self,
+ obligation: &TraitObligation<'tcx>,
+ impl_def_id: DefId,
+ ) -> VtableImplData<'tcx, PredicateObligation<'tcx>> {
+ debug!("confirm_impl_candidate({:?},{:?})", obligation, impl_def_id);
// First, create the substitutions by matching the impl again,
// this time not in a probe.
self.in_snapshot(|this, snapshot| {
- let (substs, skol_map) =
- this.rematch_impl(impl_def_id, obligation,
- snapshot);
+ let (substs, placeholder_map) = this.rematch_impl(impl_def_id, obligation, snapshot);
debug!("confirm_impl_candidate substs={:?}", substs);
let cause = obligation.derived_cause(ImplDerivedObligation);
- this.vtable_impl(impl_def_id,
- substs,
- cause,
- obligation.recursion_depth + 1,
- obligation.param_env,
- skol_map,
- snapshot)
+ this.vtable_impl(
+ impl_def_id,
+ substs,
+ cause,
+ obligation.recursion_depth + 1,
+ obligation.param_env,
+ placeholder_map,
+ snapshot,
+ )
})
}
- fn vtable_impl(&mut self,
- impl_def_id: DefId,
- mut substs: Normalized<'tcx, &'tcx Substs<'tcx>>,
- cause: ObligationCause<'tcx>,
- recursion_depth: usize,
- param_env: ty::ParamEnv<'tcx>,
- skol_map: infer::SkolemizationMap<'tcx>,
- snapshot: &infer::CombinedSnapshot<'cx, 'tcx>)
- -> VtableImplData<'tcx, PredicateObligation<'tcx>>
- {
- debug!("vtable_impl(impl_def_id={:?}, substs={:?}, recursion_depth={}, skol_map={:?})",
- impl_def_id,
- substs,
- recursion_depth,
- skol_map);
-
- let mut impl_obligations =
- self.impl_or_trait_obligations(cause,
- recursion_depth,
- param_env,
- impl_def_id,
- &substs.value,
- skol_map,
- snapshot);
-
- debug!("vtable_impl: impl_def_id={:?} impl_obligations={:?}",
- impl_def_id,
- impl_obligations);
+ fn vtable_impl(
+ &mut self,
+ impl_def_id: DefId,
+ mut substs: Normalized<'tcx, &'tcx Substs<'tcx>>,
+ cause: ObligationCause<'tcx>,
+ recursion_depth: usize,
+ param_env: ty::ParamEnv<'tcx>,
+ placeholder_map: infer::PlaceholderMap<'tcx>,
+ snapshot: &infer::CombinedSnapshot<'cx, 'tcx>,
+ ) -> VtableImplData<'tcx, PredicateObligation<'tcx>> {
+ debug!(
+ "vtable_impl(impl_def_id={:?}, substs={:?}, recursion_depth={}, placeholder_map={:?})",
+ impl_def_id, substs, recursion_depth, placeholder_map
+ );
+
+ let mut impl_obligations = self.impl_or_trait_obligations(
+ cause,
+ recursion_depth,
+ param_env,
+ impl_def_id,
+ &substs.value,
+ placeholder_map,
+ snapshot,
+ );
+
+ debug!(
+ "vtable_impl: impl_def_id={:?} impl_obligations={:?}",
+ impl_def_id, impl_obligations
+ );
// Because of RFC447, the impl-trait-ref and obligations
// are sufficient to determine the impl substs, without
// e.g. `impl<U: Tr, V: Iterator<Item=U>> Foo<<U as Tr>::T> for V`
impl_obligations.append(&mut substs.obligations);
- VtableImplData { impl_def_id,
- substs: substs.value,
- nested: impl_obligations }
+ VtableImplData {
+ impl_def_id,
+ substs: substs.value,
+ nested: impl_obligations,
+ }
}
- fn confirm_object_candidate(&mut self,
- obligation: &TraitObligation<'tcx>)
- -> VtableObjectData<'tcx, PredicateObligation<'tcx>>
- {
- debug!("confirm_object_candidate({:?})",
- obligation);
+ fn confirm_object_candidate(
+ &mut self,
+ obligation: &TraitObligation<'tcx>,
+ ) -> VtableObjectData<'tcx, PredicateObligation<'tcx>> {
+ debug!("confirm_object_candidate({:?})", obligation);
// FIXME skipping binder here seems wrong -- we should
// probably flatten the binder from the obligation and the
// binder from the object. Have to try to make a broken test
// case that results. -nmatsakis
- let self_ty = self.infcx.shallow_resolve(*obligation.self_ty().skip_binder());
+ let self_ty = self.infcx
+ .shallow_resolve(*obligation.self_ty().skip_binder());
let poly_trait_ref = match self_ty.sty {
ty::Dynamic(ref data, ..) => {
data.principal().unwrap().with_self_ty(self.tcx(), self_ty)
}
- _ => span_bug!(obligation.cause.span,
- "object candidate with non-object")
+ _ => span_bug!(obligation.cause.span, "object candidate with non-object"),
};
let mut upcast_trait_ref = None;
// where we can unify because otherwise select would have
// reported an ambiguity. (When we do find a match, also
// record it for later.)
- let nonmatching =
- util::supertraits(tcx, poly_trait_ref)
- .take_while(|&t|
- match self.commit_if_ok(|this, _|
- this.match_poly_trait_ref(obligation, t))
- {
- Ok(obligations) => {
- upcast_trait_ref = Some(t);
- nested.extend(obligations);
- false
- }
- Err(_) => { true }
+ let nonmatching = util::supertraits(tcx, poly_trait_ref).take_while(
+ |&t| match self.commit_if_ok(|this, _| this.match_poly_trait_ref(obligation, t)) {
+ Ok(obligations) => {
+ upcast_trait_ref = Some(t);
+ nested.extend(obligations);
+ false
}
- );
+ Err(_) => true,
+ },
+ );
// Additionally, for each of the nonmatching predicates that
// we pass over, we sum up the set of number of vtable
}
}
- fn confirm_fn_pointer_candidate(&mut self, obligation: &TraitObligation<'tcx>)
- -> Result<VtableFnPointerData<'tcx, PredicateObligation<'tcx>>, SelectionError<'tcx>>
- {
- debug!("confirm_fn_pointer_candidate({:?})",
- obligation);
+ fn confirm_fn_pointer_candidate(
+ &mut self,
+ obligation: &TraitObligation<'tcx>,
+ ) -> Result<VtableFnPointerData<'tcx, PredicateObligation<'tcx>>, SelectionError<'tcx>> {
+ debug!("confirm_fn_pointer_candidate({:?})", obligation);
// ok to skip binder; it is reintroduced below
- let self_ty = self.infcx.shallow_resolve(*obligation.self_ty().skip_binder());
+ let self_ty = self.infcx
+ .shallow_resolve(*obligation.self_ty().skip_binder());
let sig = self_ty.fn_sig(self.tcx());
- let trait_ref =
- self.tcx().closure_trait_ref_and_return_type(obligation.predicate.def_id(),
- self_ty,
- sig,
- util::TupleArgumentsFlag::Yes)
+ let trait_ref = self.tcx()
+ .closure_trait_ref_and_return_type(
+ obligation.predicate.def_id(),
+ self_ty,
+ sig,
+ util::TupleArgumentsFlag::Yes,
+ )
.map_bound(|(trait_ref, _)| trait_ref);
- let Normalized { value: trait_ref, obligations } =
- project::normalize_with_depth(self,
- obligation.param_env,
- obligation.cause.clone(),
- obligation.recursion_depth + 1,
- &trait_ref);
+ let Normalized {
+ value: trait_ref,
+ obligations,
+ } = project::normalize_with_depth(
+ self,
+ obligation.param_env,
+ obligation.cause.clone(),
+ obligation.recursion_depth + 1,
+ &trait_ref,
+ );
- self.confirm_poly_trait_refs(obligation.cause.clone(),
- obligation.param_env,
- obligation.predicate.to_poly_trait_ref(),
- trait_ref)?;
- Ok(VtableFnPointerData { fn_ty: self_ty, nested: obligations })
+ self.confirm_poly_trait_refs(
+ obligation.cause.clone(),
+ obligation.param_env,
+ obligation.predicate.to_poly_trait_ref(),
+ trait_ref,
+ )?;
+ Ok(VtableFnPointerData {
+ fn_ty: self_ty,
+ nested: obligations,
+ })
}
- fn confirm_generator_candidate(&mut self,
- obligation: &TraitObligation<'tcx>)
- -> Result<VtableGeneratorData<'tcx, PredicateObligation<'tcx>>,
- SelectionError<'tcx>>
- {
+ fn confirm_generator_candidate(
+ &mut self,
+ obligation: &TraitObligation<'tcx>,
+ ) -> Result<VtableGeneratorData<'tcx, PredicateObligation<'tcx>>, SelectionError<'tcx>> {
// ok to skip binder because the substs on generator types never
// touch bound regions, they just capture the in-scope
// type/region parameters
- let self_ty = self.infcx.shallow_resolve(obligation.self_ty().skip_binder());
+ let self_ty = self.infcx
+ .shallow_resolve(obligation.self_ty().skip_binder());
let (generator_def_id, substs) = match self_ty.sty {
ty::Generator(id, substs, _) => (id, substs),
- _ => bug!("closure candidate for non-closure {:?}", obligation)
+ _ => bug!("closure candidate for non-closure {:?}", obligation),
};
- debug!("confirm_generator_candidate({:?},{:?},{:?})",
- obligation,
- generator_def_id,
- substs);
+ debug!(
+ "confirm_generator_candidate({:?},{:?},{:?})",
+ obligation, generator_def_id, substs
+ );
- let trait_ref =
- self.generator_trait_ref_unnormalized(obligation, generator_def_id, substs);
+ let trait_ref = self.generator_trait_ref_unnormalized(obligation, generator_def_id, substs);
let Normalized {
value: trait_ref,
- mut obligations
- } = normalize_with_depth(self,
- obligation.param_env,
- obligation.cause.clone(),
- obligation.recursion_depth+1,
- &trait_ref);
-
- debug!("confirm_generator_candidate(generator_def_id={:?}, \
- trait_ref={:?}, obligations={:?})",
- generator_def_id,
- trait_ref,
- obligations);
-
- obligations.extend(
- self.confirm_poly_trait_refs(obligation.cause.clone(),
- obligation.param_env,
- obligation.predicate.to_poly_trait_ref(),
- trait_ref)?);
+ mut obligations,
+ } = normalize_with_depth(
+ self,
+ obligation.param_env,
+ obligation.cause.clone(),
+ obligation.recursion_depth + 1,
+ &trait_ref,
+ );
+
+ debug!(
+ "confirm_generator_candidate(generator_def_id={:?}, \
+ trait_ref={:?}, obligations={:?})",
+ generator_def_id, trait_ref, obligations
+ );
+
+ obligations.extend(self.confirm_poly_trait_refs(
+ obligation.cause.clone(),
+ obligation.param_env,
+ obligation.predicate.to_poly_trait_ref(),
+ trait_ref,
+ )?);
Ok(VtableGeneratorData {
generator_def_id: generator_def_id,
substs: substs.clone(),
- nested: obligations
+ nested: obligations,
})
}
- fn confirm_closure_candidate(&mut self,
- obligation: &TraitObligation<'tcx>)
- -> Result<VtableClosureData<'tcx, PredicateObligation<'tcx>>,
- SelectionError<'tcx>>
- {
+ fn confirm_closure_candidate(
+ &mut self,
+ obligation: &TraitObligation<'tcx>,
+ ) -> Result<VtableClosureData<'tcx, PredicateObligation<'tcx>>, SelectionError<'tcx>> {
debug!("confirm_closure_candidate({:?})", obligation);
let kind = self.tcx()
- .lang_items()
- .fn_trait_kind(obligation.predicate.def_id())
- .unwrap_or_else(|| bug!("closure candidate for non-fn trait {:?}",
- obligation));
+ .lang_items()
+ .fn_trait_kind(obligation.predicate.def_id())
+ .unwrap_or_else(|| bug!("closure candidate for non-fn trait {:?}", obligation));
// ok to skip binder because the substs on closure types never
// touch bound regions, they just capture the in-scope
// type/region parameters
- let self_ty = self.infcx.shallow_resolve(obligation.self_ty().skip_binder());
+ let self_ty = self.infcx
+ .shallow_resolve(obligation.self_ty().skip_binder());
let (closure_def_id, substs) = match self_ty.sty {
ty::Closure(id, substs) => (id, substs),
- _ => bug!("closure candidate for non-closure {:?}", obligation)
+ _ => bug!("closure candidate for non-closure {:?}", obligation),
};
- let trait_ref =
- self.closure_trait_ref_unnormalized(obligation, closure_def_id, substs);
+ let trait_ref = self.closure_trait_ref_unnormalized(obligation, closure_def_id, substs);
let Normalized {
value: trait_ref,
- mut obligations
- } = normalize_with_depth(self,
- obligation.param_env,
- obligation.cause.clone(),
- obligation.recursion_depth+1,
- &trait_ref);
-
- debug!("confirm_closure_candidate(closure_def_id={:?}, trait_ref={:?}, obligations={:?})",
- closure_def_id,
- trait_ref,
- obligations);
-
- obligations.extend(
- self.confirm_poly_trait_refs(obligation.cause.clone(),
- obligation.param_env,
- obligation.predicate.to_poly_trait_ref(),
- trait_ref)?);
+ mut obligations,
+ } = normalize_with_depth(
+ self,
+ obligation.param_env,
+ obligation.cause.clone(),
+ obligation.recursion_depth + 1,
+ &trait_ref,
+ );
+
+ debug!(
+ "confirm_closure_candidate(closure_def_id={:?}, trait_ref={:?}, obligations={:?})",
+ closure_def_id, trait_ref, obligations
+ );
+
+ obligations.extend(self.confirm_poly_trait_refs(
+ obligation.cause.clone(),
+ obligation.param_env,
+ obligation.predicate.to_poly_trait_ref(),
+ trait_ref,
+ )?);
obligations.push(Obligation::new(
obligation.cause.clone(),
obligation.param_env,
- ty::Predicate::ClosureKind(closure_def_id, substs, kind)));
+ ty::Predicate::ClosureKind(closure_def_id, substs, kind),
+ ));
Ok(VtableClosureData {
closure_def_id,
substs: substs.clone(),
- nested: obligations
+ nested: obligations,
})
}
/// because these output type parameters should not affect the
/// selection of the impl. Therefore, if there is a mismatch, we
/// report an error to the user.
- fn confirm_poly_trait_refs(&mut self,
- obligation_cause: ObligationCause<'tcx>,
- obligation_param_env: ty::ParamEnv<'tcx>,
- obligation_trait_ref: ty::PolyTraitRef<'tcx>,
- expected_trait_ref: ty::PolyTraitRef<'tcx>)
- -> Result<Vec<PredicateObligation<'tcx>>, SelectionError<'tcx>>
- {
+ fn confirm_poly_trait_refs(
+ &mut self,
+ obligation_cause: ObligationCause<'tcx>,
+ obligation_param_env: ty::ParamEnv<'tcx>,
+ obligation_trait_ref: ty::PolyTraitRef<'tcx>,
+ expected_trait_ref: ty::PolyTraitRef<'tcx>,
+ ) -> Result<Vec<PredicateObligation<'tcx>>, SelectionError<'tcx>> {
let obligation_trait_ref = obligation_trait_ref.clone();
self.infcx
.at(&obligation_cause, obligation_param_env)
.map_err(|e| OutputTypeParameterMismatch(expected_trait_ref, obligation_trait_ref, e))
}
- fn confirm_builtin_unsize_candidate(&mut self,
- obligation: &TraitObligation<'tcx>,)
- -> Result<VtableBuiltinData<PredicateObligation<'tcx>>, SelectionError<'tcx>>
- {
+ fn confirm_builtin_unsize_candidate(
+ &mut self,
+ obligation: &TraitObligation<'tcx>,
+ ) -> Result<VtableBuiltinData<PredicateObligation<'tcx>>, SelectionError<'tcx>> {
let tcx = self.tcx();
// assemble_candidates_for_unsizing should ensure there are no late bound
// regions here. See the comment there for more details.
- let source = self.infcx.shallow_resolve(
- obligation.self_ty().no_late_bound_regions().unwrap());
- let target = obligation.predicate.skip_binder().trait_ref.substs.type_at(1);
+ let source = self.infcx
+ .shallow_resolve(obligation.self_ty().no_late_bound_regions().unwrap());
+ let target = obligation
+ .predicate
+ .skip_binder()
+ .trait_ref
+ .substs
+ .type_at(1);
let target = self.infcx.shallow_resolve(target);
- debug!("confirm_builtin_unsize_candidate(source={:?}, target={:?})",
- source, target);
+ debug!(
+ "confirm_builtin_unsize_candidate(source={:?}, target={:?})",
+ source, target
+ );
let mut nested = vec![];
match (&source.sty, &target.sty) {
// See assemble_candidates_for_unsizing for more info.
let existential_predicates = data_a.map_bound(|data_a| {
let principal = data_a.principal();
- let iter = principal.into_iter().map(ty::ExistentialPredicate::Trait)
- .chain(data_a.projection_bounds()
- .map(|x| ty::ExistentialPredicate::Projection(x)))
- .chain(data_b.auto_traits().map(ty::ExistentialPredicate::AutoTrait));
+ let iter = principal
+ .into_iter()
+ .map(ty::ExistentialPredicate::Trait)
+ .chain(
+ data_a
+ .projection_bounds()
+ .map(|x| ty::ExistentialPredicate::Projection(x)),
+ )
+ .chain(
+ data_b
+ .auto_traits()
+ .map(ty::ExistentialPredicate::AutoTrait),
+ );
tcx.mk_existential_predicates(iter)
});
let new_trait = tcx.mk_dynamic(existential_predicates, r_b);
- let InferOk { obligations, .. } =
- self.infcx.at(&obligation.cause, obligation.param_env)
- .eq(target, new_trait)
- .map_err(|_| Unimplemented)?;
+ let InferOk { obligations, .. } = self.infcx
+ .at(&obligation.cause, obligation.param_env)
+ .eq(target, new_trait)
+ .map_err(|_| Unimplemented)?;
nested.extend(obligations);
// Register one obligation for 'a: 'b.
- let cause = ObligationCause::new(obligation.cause.span,
- obligation.cause.body_id,
- ObjectCastObligation(target));
+ let cause = ObligationCause::new(
+ obligation.cause.span,
+ obligation.cause.body_id,
+ ObjectCastObligation(target),
+ );
let outlives = ty::OutlivesPredicate(r_a, r_b);
- nested.push(Obligation::with_depth(cause,
- obligation.recursion_depth + 1,
- obligation.param_env,
- ty::Binder::bind(outlives).to_predicate()));
+ nested.push(Obligation::with_depth(
+ cause,
+ obligation.recursion_depth + 1,
+ obligation.param_env,
+ ty::Binder::bind(outlives).to_predicate(),
+ ));
}
// T -> Trait.
(_, &ty::Dynamic(ref data, r)) => {
- let mut object_dids =
- data.auto_traits().chain(data.principal().map(|p| p.def_id()));
+ let mut object_dids = data.auto_traits()
+ .chain(data.principal().map(|p| p.def_id()));
if let Some(did) = object_dids.find(|did| !tcx.is_object_safe(*did)) {
- return Err(TraitNotObjectSafe(did))
+ return Err(TraitNotObjectSafe(did));
}
- let cause = ObligationCause::new(obligation.cause.span,
- obligation.cause.body_id,
- ObjectCastObligation(target));
+ let cause = ObligationCause::new(
+ obligation.cause.span,
+ obligation.cause.body_id,
+ ObjectCastObligation(target),
+ );
let predicate_to_obligation = |predicate| {
- Obligation::with_depth(cause.clone(),
- obligation.recursion_depth + 1,
- obligation.param_env,
- predicate)
+ Obligation::with_depth(
+ cause.clone(),
+ obligation.recursion_depth + 1,
+ obligation.param_env,
+ predicate,
+ )
};
// Create obligations:
// words, if the object type is Foo+Send, this would create an obligation for the
// Send check.)
// - Projection predicates
- nested.extend(data.iter().map(|d|
- predicate_to_obligation(d.with_self_ty(tcx, source))
- ));
+ nested.extend(
+ data.iter()
+ .map(|d| predicate_to_obligation(d.with_self_ty(tcx, source))),
+ );
// We can only make objects from sized types.
let tr = ty::TraitRef {
// being cast to `Foo+'a` outlives `'a`:
let outlives = ty::OutlivesPredicate(source, r);
nested.push(predicate_to_obligation(
- ty::Binder::dummy(outlives).to_predicate()));
+ ty::Binder::dummy(outlives).to_predicate(),
+ ));
}
// [T; n] -> [T].
(&ty::Array(a, _), &ty::Slice(b)) => {
- let InferOk { obligations, .. } =
- self.infcx.at(&obligation.cause, obligation.param_env)
- .eq(b, a)
- .map_err(|_| Unimplemented)?;
+ let InferOk { obligations, .. } = self.infcx
+ .at(&obligation.cause, obligation.param_env)
+ .eq(b, a)
+ .map_err(|_| Unimplemented)?;
nested.extend(obligations);
}
// Struct<T> -> Struct<U>.
(&ty::Adt(def, substs_a), &ty::Adt(_, substs_b)) => {
- let fields = def
- .all_fields()
+ let fields = def.all_fields()
.map(|f| tcx.type_of(f.did))
.collect::<Vec<_>>();
// Check that the source struct with the target's
// unsized parameters is equal to the target.
- let params = substs_a.iter().enumerate().map(|(i, &k)|
+ let params = substs_a.iter().enumerate().map(|(i, &k)| {
if ty_params.contains(i) {
substs_b.type_at(i).into()
} else {
k
}
- );
+ });
let new_struct = tcx.mk_adt(def, tcx.mk_substs(params));
- let InferOk { obligations, .. } =
- self.infcx.at(&obligation.cause, obligation.param_env)
- .eq(target, new_struct)
- .map_err(|_| Unimplemented)?;
+ let InferOk { obligations, .. } = self.infcx
+ .at(&obligation.cause, obligation.param_env)
+ .eq(target, new_struct)
+ .map_err(|_| Unimplemented)?;
nested.extend(obligations);
// Construct the nested Field<T>: Unsize<Field<U>> predicate.
obligation.predicate.def_id(),
obligation.recursion_depth + 1,
inner_source,
- &[inner_target.into()]));
+ &[inner_target.into()],
+ ));
}
// (.., T) -> (.., U).
// Check that the source tuple with the target's
// last element is equal to the target.
let new_tuple = tcx.mk_tup(a_mid.iter().cloned().chain(iter::once(b_last)));
- let InferOk { obligations, .. } =
- self.infcx.at(&obligation.cause, obligation.param_env)
- .eq(target, new_tuple)
- .map_err(|_| Unimplemented)?;
+ let InferOk { obligations, .. } = self.infcx
+ .at(&obligation.cause, obligation.param_env)
+ .eq(target, new_tuple)
+ .map_err(|_| Unimplemented)?;
nested.extend(obligations);
// Construct the nested T: Unsize<U> predicate.
obligation.predicate.def_id(),
obligation.recursion_depth + 1,
a_last,
- &[b_last.into()]));
+ &[b_last.into()],
+ ));
}
- _ => bug!()
+ _ => bug!(),
};
Ok(VtableBuiltinData { nested: nested })
// run inside of a `probe()` so that their side-effects are
// contained.
- fn rematch_impl(&mut self,
- impl_def_id: DefId,
- obligation: &TraitObligation<'tcx>,
- snapshot: &infer::CombinedSnapshot<'cx, 'tcx>)
- -> (Normalized<'tcx, &'tcx Substs<'tcx>>,
- infer::SkolemizationMap<'tcx>)
- {
+ fn rematch_impl(
+ &mut self,
+ impl_def_id: DefId,
+ obligation: &TraitObligation<'tcx>,
+ snapshot: &infer::CombinedSnapshot<'cx, 'tcx>,
+ ) -> (
+ Normalized<'tcx, &'tcx Substs<'tcx>>,
+ infer::PlaceholderMap<'tcx>,
+ ) {
match self.match_impl(impl_def_id, obligation, snapshot) {
- Ok((substs, skol_map)) => (substs, skol_map),
+ Ok((substs, placeholder_map)) => (substs, placeholder_map),
Err(()) => {
- bug!("Impl {:?} was matchable against {:?} but now is not",
- impl_def_id,
- obligation);
+ bug!(
+ "Impl {:?} was matchable against {:?} but now is not",
+ impl_def_id,
+ obligation
+ );
}
}
}
- fn match_impl(&mut self,
- impl_def_id: DefId,
- obligation: &TraitObligation<'tcx>,
- snapshot: &infer::CombinedSnapshot<'cx, 'tcx>)
- -> Result<(Normalized<'tcx, &'tcx Substs<'tcx>>,
- infer::SkolemizationMap<'tcx>), ()>
- {
+ fn match_impl(
+ &mut self,
+ impl_def_id: DefId,
+ obligation: &TraitObligation<'tcx>,
+ snapshot: &infer::CombinedSnapshot<'cx, 'tcx>,
+ ) -> Result<
+ (
+ Normalized<'tcx, &'tcx Substs<'tcx>>,
+ infer::PlaceholderMap<'tcx>,
+ ),
+ (),
+ > {
let impl_trait_ref = self.tcx().impl_trait_ref(impl_def_id).unwrap();
// Before we create the substitutions and everything, first
return Err(());
}
- let (skol_obligation, skol_map) = self.infcx().skolemize_late_bound_regions(
- &obligation.predicate);
+ let (skol_obligation, placeholder_map) = self.infcx()
+ .replace_late_bound_regions_with_placeholders(&obligation.predicate);
let skol_obligation_trait_ref = skol_obligation.trait_ref;
- let impl_substs = self.infcx.fresh_substs_for_item(obligation.cause.span,
- impl_def_id);
-
- let impl_trait_ref = impl_trait_ref.subst(self.tcx(),
- impl_substs);
-
- let Normalized { value: impl_trait_ref, obligations: mut nested_obligations } =
- project::normalize_with_depth(self,
- obligation.param_env,
- obligation.cause.clone(),
- obligation.recursion_depth + 1,
- &impl_trait_ref);
-
- debug!("match_impl(impl_def_id={:?}, obligation={:?}, \
- impl_trait_ref={:?}, skol_obligation_trait_ref={:?})",
- impl_def_id,
- obligation,
- impl_trait_ref,
- skol_obligation_trait_ref);
-
- let InferOk { obligations, .. } =
- self.infcx.at(&obligation.cause, obligation.param_env)
- .eq(skol_obligation_trait_ref, impl_trait_ref)
- .map_err(|e|
- debug!("match_impl: failed eq_trait_refs due to `{}`", e)
- )?;
+ let impl_substs = self.infcx
+ .fresh_substs_for_item(obligation.cause.span, impl_def_id);
+
+ let impl_trait_ref = impl_trait_ref.subst(self.tcx(), impl_substs);
+
+ let Normalized {
+ value: impl_trait_ref,
+ obligations: mut nested_obligations,
+ } = project::normalize_with_depth(
+ self,
+ obligation.param_env,
+ obligation.cause.clone(),
+ obligation.recursion_depth + 1,
+ &impl_trait_ref,
+ );
+
+ debug!(
+ "match_impl(impl_def_id={:?}, obligation={:?}, \
+ impl_trait_ref={:?}, skol_obligation_trait_ref={:?})",
+ impl_def_id, obligation, impl_trait_ref, skol_obligation_trait_ref
+ );
+
+ let InferOk { obligations, .. } = self.infcx
+ .at(&obligation.cause, obligation.param_env)
+ .eq(skol_obligation_trait_ref, impl_trait_ref)
+ .map_err(|e| debug!("match_impl: failed eq_trait_refs due to `{}`", e))?;
nested_obligations.extend(obligations);
- if let Err(e) = self.infcx.leak_check(false,
- obligation.cause.span,
- &skol_map,
- snapshot) {
+ if let Err(e) =
+ self.infcx
+ .leak_check(false, obligation.cause.span, &placeholder_map, snapshot)
+ {
debug!("match_impl: failed leak check due to `{}`", e);
return Err(());
}
debug!("match_impl: success impl_substs={:?}", impl_substs);
- Ok((Normalized {
- value: impl_substs,
- obligations: nested_obligations
- }, skol_map))
+ Ok((
+ Normalized {
+ value: impl_substs,
+ obligations: nested_obligations,
+ },
+ placeholder_map,
+ ))
}
- fn fast_reject_trait_refs(&mut self,
- obligation: &TraitObligation<'_>,
- impl_trait_ref: &ty::TraitRef<'_>)
- -> bool
- {
+ fn fast_reject_trait_refs(
+ &mut self,
+ obligation: &TraitObligation<'_>,
+ impl_trait_ref: &ty::TraitRef<'_>,
+ ) -> bool {
// We can avoid creating type variables and doing the full
// substitution if we find that any of the input types, when
// simplified, do not match.
- obligation.predicate.skip_binder().input_types()
+ obligation
+ .predicate
+ .skip_binder()
+ .input_types()
.zip(impl_trait_ref.input_types())
.any(|(obligation_ty, impl_ty)| {
let simplified_obligation_ty =
fast_reject::simplify_type(self.tcx(), obligation_ty, true);
- let simplified_impl_ty =
- fast_reject::simplify_type(self.tcx(), impl_ty, false);
+ let simplified_impl_ty = fast_reject::simplify_type(self.tcx(), impl_ty, false);
- simplified_obligation_ty.is_some() &&
- simplified_impl_ty.is_some() &&
- simplified_obligation_ty != simplified_impl_ty
+ simplified_obligation_ty.is_some()
+ && simplified_impl_ty.is_some()
+ && simplified_obligation_ty != simplified_impl_ty
})
}
/// result from the normalization. Normalization is necessary
/// because where-clauses are stored in the parameter environment
/// unnormalized.
- fn match_where_clause_trait_ref(&mut self,
- obligation: &TraitObligation<'tcx>,
- where_clause_trait_ref: ty::PolyTraitRef<'tcx>)
- -> Result<Vec<PredicateObligation<'tcx>>, ()>
- {
+ fn match_where_clause_trait_ref(
+ &mut self,
+ obligation: &TraitObligation<'tcx>,
+ where_clause_trait_ref: ty::PolyTraitRef<'tcx>,
+ ) -> Result<Vec<PredicateObligation<'tcx>>, ()> {
self.match_poly_trait_ref(obligation, where_clause_trait_ref)
}
/// Returns `Ok` if `poly_trait_ref` being true implies that the
/// obligation is satisfied.
- fn match_poly_trait_ref(&mut self,
- obligation: &TraitObligation<'tcx>,
- poly_trait_ref: ty::PolyTraitRef<'tcx>)
- -> Result<Vec<PredicateObligation<'tcx>>, ()>
- {
- debug!("match_poly_trait_ref: obligation={:?} poly_trait_ref={:?}",
- obligation,
- poly_trait_ref);
+ fn match_poly_trait_ref(
+ &mut self,
+ obligation: &TraitObligation<'tcx>,
+ poly_trait_ref: ty::PolyTraitRef<'tcx>,
+ ) -> Result<Vec<PredicateObligation<'tcx>>, ()> {
+ debug!(
+ "match_poly_trait_ref: obligation={:?} poly_trait_ref={:?}",
+ obligation, poly_trait_ref
+ );
- self.infcx.at(&obligation.cause, obligation.param_env)
- .sup(obligation.predicate.to_poly_trait_ref(), poly_trait_ref)
- .map(|InferOk { obligations, .. }| obligations)
- .map_err(|_| ())
+ self.infcx
+ .at(&obligation.cause, obligation.param_env)
+ .sup(obligation.predicate.to_poly_trait_ref(), poly_trait_ref)
+ .map(|InferOk { obligations, .. }| obligations)
+ .map_err(|_| ())
}
///////////////////////////////////////////////////////////////////////////
// Miscellany
- fn match_fresh_trait_refs(&self,
- previous: &ty::PolyTraitRef<'tcx>,
- current: &ty::PolyTraitRef<'tcx>)
- -> bool
- {
+ fn match_fresh_trait_refs(
+ &self,
+ previous: &ty::PolyTraitRef<'tcx>,
+ current: &ty::PolyTraitRef<'tcx>,
+ ) -> bool {
let mut matcher = ty::_match::Match::new(self.tcx());
matcher.relate(previous, current).is_ok()
}
- fn push_stack<'o,'s:'o>(&mut self,
- previous_stack: TraitObligationStackList<'s, 'tcx>,
- obligation: &'o TraitObligation<'tcx>)
- -> TraitObligationStack<'o, 'tcx>
- {
- let fresh_trait_ref =
- obligation.predicate.to_poly_trait_ref().fold_with(&mut self.freshener);
+ fn push_stack<'o, 's: 'o>(
+ &mut self,
+ previous_stack: TraitObligationStackList<'s, 'tcx>,
+ obligation: &'o TraitObligation<'tcx>,
+ ) -> TraitObligationStack<'o, 'tcx> {
+ let fresh_trait_ref = obligation
+ .predicate
+ .to_poly_trait_ref()
+ .fold_with(&mut self.freshener);
TraitObligationStack {
obligation,
}
}
- fn closure_trait_ref_unnormalized(&mut self,
- obligation: &TraitObligation<'tcx>,
- closure_def_id: DefId,
- substs: ty::ClosureSubsts<'tcx>)
- -> ty::PolyTraitRef<'tcx>
- {
+ fn closure_trait_ref_unnormalized(
+ &mut self,
+ obligation: &TraitObligation<'tcx>,
+ closure_def_id: DefId,
+ substs: ty::ClosureSubsts<'tcx>,
+ ) -> ty::PolyTraitRef<'tcx> {
let closure_type = self.infcx.closure_sig(closure_def_id, substs);
// (1) Feels icky to skip the binder here, but OTOH we know
// in fact unparameterized (or at least does not reference any
// regions bound in the obligation). Still probably some
// refactoring could make this nicer.
- self.tcx().closure_trait_ref_and_return_type(obligation.predicate.def_id(),
- obligation.predicate
- .skip_binder()
- .self_ty(), // (1)
- closure_type,
- util::TupleArgumentsFlag::No)
+ self.tcx()
+ .closure_trait_ref_and_return_type(
+ obligation.predicate.def_id(),
+ obligation.predicate.skip_binder().self_ty(), // (1)
+ closure_type,
+ util::TupleArgumentsFlag::No,
+ )
.map_bound(|(trait_ref, _)| trait_ref)
}
- fn generator_trait_ref_unnormalized(&mut self,
- obligation: &TraitObligation<'tcx>,
- closure_def_id: DefId,
- substs: ty::GeneratorSubsts<'tcx>)
- -> ty::PolyTraitRef<'tcx>
- {
+ fn generator_trait_ref_unnormalized(
+ &mut self,
+ obligation: &TraitObligation<'tcx>,
+ closure_def_id: DefId,
+ substs: ty::GeneratorSubsts<'tcx>,
+ ) -> ty::PolyTraitRef<'tcx> {
let gen_sig = substs.poly_sig(closure_def_id, self.tcx());
// (1) Feels icky to skip the binder here, but OTOH we know
// regions bound in the obligation). Still probably some
// refactoring could make this nicer.
- self.tcx().generator_trait_ref_and_outputs(obligation.predicate.def_id(),
- obligation.predicate
- .skip_binder()
- .self_ty(), // (1)
- gen_sig)
+ self.tcx()
+ .generator_trait_ref_and_outputs(
+ obligation.predicate.def_id(),
+ obligation.predicate.skip_binder().self_ty(), // (1)
+ gen_sig,
+ )
.map_bound(|(trait_ref, ..)| trait_ref)
}
/// impl or trait. The obligations are substituted and fully
/// normalized. This is used when confirming an impl or default
/// impl.
- fn impl_or_trait_obligations(&mut self,
- cause: ObligationCause<'tcx>,
- recursion_depth: usize,
- param_env: ty::ParamEnv<'tcx>,
- def_id: DefId, // of impl or trait
- substs: &Substs<'tcx>, // for impl or trait
- skol_map: infer::SkolemizationMap<'tcx>,
- snapshot: &infer::CombinedSnapshot<'cx, 'tcx>)
- -> Vec<PredicateObligation<'tcx>>
- {
+ fn impl_or_trait_obligations(
+ &mut self,
+ cause: ObligationCause<'tcx>,
+ recursion_depth: usize,
+ param_env: ty::ParamEnv<'tcx>,
+ def_id: DefId, // of impl or trait
+ substs: &Substs<'tcx>, // for impl or trait
+ placeholder_map: infer::PlaceholderMap<'tcx>,
+ snapshot: &infer::CombinedSnapshot<'cx, 'tcx>,
+ ) -> Vec<PredicateObligation<'tcx>> {
debug!("impl_or_trait_obligations(def_id={:?})", def_id);
let tcx = self.tcx();
// that order.
let predicates = tcx.predicates_of(def_id);
assert_eq!(predicates.parent, None);
- let mut predicates: Vec<_> = predicates.predicates.iter().flat_map(|(predicate, _)| {
- let predicate = normalize_with_depth(self, param_env, cause.clone(), recursion_depth,
- &predicate.subst(tcx, substs));
- predicate.obligations.into_iter().chain(
- Some(Obligation {
+ let mut predicates: Vec<_> = predicates
+ .predicates
+ .iter()
+ .flat_map(|(predicate, _)| {
+ let predicate = normalize_with_depth(
+ self,
+ param_env,
+ cause.clone(),
+ recursion_depth,
+ &predicate.subst(tcx, substs),
+ );
+ predicate.obligations.into_iter().chain(Some(Obligation {
cause: cause.clone(),
recursion_depth,
param_env,
- predicate: predicate.value
+ predicate: predicate.value,
}))
- }).collect();
+ })
+ .collect();
// We are performing deduplication here to avoid exponential blowups
// (#38528) from happening, but the real cause of the duplication is
let mut seen = FxHashSet();
predicates.retain(|i| seen.insert(i.clone()));
}
- self.infcx().plug_leaks(skol_map, snapshot, predicates)
+ self.infcx()
+ .plug_leaks(placeholder_map, snapshot, predicates)
}
}
impl<'tcx> TraitObligation<'tcx> {
#[allow(unused_comparisons)]
- pub fn derived_cause(&self,
- variant: fn(DerivedObligationCause<'tcx>) -> ObligationCauseCode<'tcx>)
- -> ObligationCause<'tcx>
- {
+ pub fn derived_cause(
+ &self,
+ variant: fn(DerivedObligationCause<'tcx>) -> ObligationCauseCode<'tcx>,
+ ) -> ObligationCause<'tcx> {
/*!
* Creates a cause for obligations that are derived from
* `obligation` by a recursive search (e.g., for a builtin
if obligation.recursion_depth >= 0 {
let derived_cause = DerivedObligationCause {
parent_trait_ref: obligation.predicate.to_poly_trait_ref(),
- parent_code: Rc::new(obligation.cause.code.clone())
+ parent_code: Rc::new(obligation.cause.code.clone()),
};
let derived_code = variant(derived_cause);
- ObligationCause::new(obligation.cause.span, obligation.cause.body_id, derived_code)
+ ObligationCause::new(
+ obligation.cause.span,
+ obligation.cause.body_id,
+ derived_code,
+ )
} else {
obligation.cause.clone()
}
impl<'tcx> SelectionCache<'tcx> {
pub fn new() -> SelectionCache<'tcx> {
SelectionCache {
- hashmap: Lock::new(FxHashMap())
+ hashmap: Lock::new(FxHashMap()),
}
}
impl<'tcx> EvaluationCache<'tcx> {
pub fn new() -> EvaluationCache<'tcx> {
EvaluationCache {
- hashmap: Lock::new(FxHashMap())
+ hashmap: Lock::new(FxHashMap()),
}
}
}
}
-impl<'o,'tcx> TraitObligationStack<'o,'tcx> {
- fn list(&'o self) -> TraitObligationStackList<'o,'tcx> {
+impl<'o, 'tcx> TraitObligationStack<'o, 'tcx> {
+ fn list(&'o self) -> TraitObligationStackList<'o, 'tcx> {
TraitObligationStackList::with(self)
}
- fn iter(&'o self) -> TraitObligationStackList<'o,'tcx> {
+ fn iter(&'o self) -> TraitObligationStackList<'o, 'tcx> {
self.list()
}
}
#[derive(Copy, Clone)]
-struct TraitObligationStackList<'o,'tcx:'o> {
- head: Option<&'o TraitObligationStack<'o,'tcx>>
+struct TraitObligationStackList<'o, 'tcx: 'o> {
+ head: Option<&'o TraitObligationStack<'o, 'tcx>>,
}
-impl<'o,'tcx> TraitObligationStackList<'o,'tcx> {
- fn empty() -> TraitObligationStackList<'o,'tcx> {
+impl<'o, 'tcx> TraitObligationStackList<'o, 'tcx> {
+ fn empty() -> TraitObligationStackList<'o, 'tcx> {
TraitObligationStackList { head: None }
}
- fn with(r: &'o TraitObligationStack<'o,'tcx>) -> TraitObligationStackList<'o,'tcx> {
+ fn with(r: &'o TraitObligationStack<'o, 'tcx>) -> TraitObligationStackList<'o, 'tcx> {
TraitObligationStackList { head: Some(r) }
}
}
-impl<'o,'tcx> Iterator for TraitObligationStackList<'o,'tcx>{
- type Item = &'o TraitObligationStack<'o,'tcx>;
+impl<'o, 'tcx> Iterator for TraitObligationStackList<'o, 'tcx> {
+ type Item = &'o TraitObligationStack<'o, 'tcx>;
- fn next(&mut self) -> Option<&'o TraitObligationStack<'o,'tcx>> {
+ fn next(&mut self) -> Option<&'o TraitObligationStack<'o, 'tcx>> {
match self.head {
Some(o) => {
*self = o.previous;
Some(o)
}
- None => None
+ None => None,
}
}
}
-impl<'o,'tcx> fmt::Debug for TraitObligationStack<'o,'tcx> {
+impl<'o, 'tcx> fmt::Debug for TraitObligationStack<'o, 'tcx> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "TraitObligationStack({:?})", self.obligation)
}
#[derive(Clone, Eq, PartialEq)]
pub struct WithDepNode<T> {
dep_node: DepNodeIndex,
- cached_value: T
+ cached_value: T,
}
impl<T: Clone> WithDepNode<T> {
pub fn new(dep_node: DepNodeIndex, cached_value: T) -> Self {
- WithDepNode { dep_node, cached_value }
+ WithDepNode {
+ dep_node,
+ cached_value,
+ }
}
pub fn get(&self, tcx: TyCtxt<'_, '_, '_>) -> T {
return false;
}
- // create a parameter environment corresponding to a (skolemized) instantiation of impl1
+ // create a parameter environment corresponding to a (placeholder) instantiation of impl1
let penv = tcx.param_env(impl1_def_id);
let impl1_trait_ref = tcx.impl_trait_ref(impl1_def_id).unwrap();
--- /dev/null
+use ty::query::Providers;
+use hir::def_id::DefId;
+use hir;
+use ty::TyCtxt;
+use syntax_pos::symbol::Symbol;
+use hir::map::blocks::FnLikeNode;
+use syntax::attr;
+use rustc_target::spec::abi;
+
+impl<'a, 'tcx> TyCtxt<'a, 'tcx, 'tcx> {
+ /// Whether the `def_id` counts as const fn in your current crate, considering all active
+ /// feature gates
+ pub fn is_const_fn(self, def_id: DefId) -> bool {
+ self.is_const_fn_raw(def_id) && match self.lookup_stability(def_id) {
+ Some(stab) => match stab.const_stability {
+ // has a `rustc_const_unstable` attribute, check whether the user enabled the
+ // corresponding feature gate
+ Some(feature_name) => self.features()
+ .declared_lib_features
+ .iter()
+ .any(|&(sym, _)| sym == feature_name),
+ // the function has no stability attribute, it is stable as const fn or the user
+ // needs to use feature gates to use the function at all
+ None => true,
+ },
+ // functions without stability are either stable user written const fn or the user is
+ // using feature gates and we thus don't care what they do
+ None => true,
+ }
+ }
+
+ /// Whether the `def_id` is an unstable const fn and what feature gate is necessary to enable it
+ pub fn is_unstable_const_fn(self, def_id: DefId) -> Option<Symbol> {
+ if self.is_const_fn_raw(def_id) {
+ self.lookup_stability(def_id)?.const_stability
+ } else {
+ None
+ }
+ }
+
+ /// Returns true if this function must conform to `min_const_fn`
+ pub fn is_min_const_fn(self, def_id: DefId) -> bool {
+ if self.features().staged_api {
+ // some intrinsics are waved through if called inside the
+ // standard library. Users never need to call them directly
+ if let abi::Abi::RustIntrinsic = self.fn_sig(def_id).abi() {
+ assert!(!self.is_const_fn(def_id));
+ match &self.item_name(def_id).as_str()[..] {
+ | "size_of"
+ | "min_align_of"
+ | "needs_drop"
+ => return true,
+ _ => {},
+ }
+ }
+ // in order for a libstd function to be considered min_const_fn
+ // it needs to be stable and have no `rustc_const_unstable` attribute
+ match self.lookup_stability(def_id) {
+ // stable functions with unstable const fn aren't `min_const_fn`
+ Some(&attr::Stability { const_stability: Some(_), .. }) => false,
+ // unstable functions don't need to conform
+ Some(&attr::Stability { ref level, .. }) if level.is_unstable() => false,
+ // everything else needs to conform, because it would be callable from
+ // other `min_const_fn` functions
+ _ => true,
+ }
+ } else {
+ // users enabling the `const_fn` can do what they want
+ !self.sess.features_untracked().const_fn
+ }
+ }
+}
+
+
+pub fn provide<'tcx>(providers: &mut Providers<'tcx>) {
+ /// only checks whether the function has a `const` modifier
+ fn is_const_fn_raw<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> bool {
+ let node_id = tcx.hir.as_local_node_id(def_id)
+ .expect("Non-local call to local provider is_const_fn");
+
+ if let Some(fn_like) = FnLikeNode::from_node(tcx.hir.get(node_id)) {
+ fn_like.constness() == hir::Constness::Const
+ } else {
+ false
+ }
+ }
+
+ fn is_promotable_const_fn<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> bool {
+ tcx.is_const_fn(def_id) && match tcx.lookup_stability(def_id) {
+ Some(stab) => {
+ if cfg!(debug_assertions) && stab.promotable {
+ let sig = tcx.fn_sig(def_id);
+ assert_eq!(
+ sig.unsafety(),
+ hir::Unsafety::Normal,
+ "don't mark const unsafe fns as promotable",
+ // https://github.com/rust-lang/rust/pull/53851#issuecomment-418760682
+ );
+ }
+ stab.promotable
+ },
+ None => false,
+ }
+ }
+
+ *providers = Providers {
+ is_const_fn_raw,
+ is_promotable_const_fn,
+ ..*providers
+ };
+}
local as usize == global as usize
}
- /// Returns true if this function must conform to `min_const_fn`
- pub fn is_min_const_fn(self, def_id: DefId) -> bool {
- if self.features().staged_api {
- // some intrinsics are waved through if called inside the
- // standard library. Users never need to call them directly
- if let abi::Abi::RustIntrinsic = self.fn_sig(def_id).abi() {
- assert!(!self.is_const_fn(def_id));
- match &self.item_name(def_id).as_str()[..] {
- | "size_of"
- | "min_align_of"
- | "needs_drop"
- => return true,
- _ => {},
- }
- }
- // in order for a libstd function to be considered min_const_fn
- // it needs to be stable and have no `rustc_const_unstable` attribute
- match self.lookup_stability(def_id) {
- // stable functions with unstable const fn aren't `min_const_fn`
- Some(&attr::Stability { const_stability: Some(_), .. }) => false,
- // unstable functions don't need to conform
- Some(&attr::Stability { ref level, .. }) if level.is_unstable() => false,
- // everything else needs to conform, because it would be callable from
- // other `min_const_fn` functions
- _ => true,
- }
- } else {
- // users enabling the `const_fn` can do what they want
- !self.sess.features_untracked().const_fn
- }
- }
-
/// Create a type context and call the closure with a `TyCtxt` reference
/// to the context. The closure enforces that the type context and any interned
/// value (types, substs, etc.) can only be used while `ty::tls` has a valid
self,
Adt, Array, Slice, RawPtr, Ref, FnDef, FnPtr,
Generator, GeneratorWitness, Dynamic, Closure, Tuple,
- Param, Infer, Projection, Opaque, Foreign);
+ Param, Infer, UnnormalizedProjection, Projection, Opaque, Foreign);
println!("Substs interner: #{}", self.interners.substs.borrow().len());
println!("Region interner: #{}", self.interners.region.borrow().len());
ty::Infer(ty::IntVar(_)) => "integral variable".to_string(),
ty::Infer(ty::FloatVar(_)) => "floating-point variable".to_string(),
ty::Infer(ty::CanonicalTy(_)) |
- ty::Infer(ty::FreshTy(_)) => "skolemized type".to_string(),
- ty::Infer(ty::FreshIntTy(_)) => "skolemized integral type".to_string(),
- ty::Infer(ty::FreshFloatTy(_)) => "skolemized floating-point type".to_string(),
+ ty::Infer(ty::FreshTy(_)) => "fresh type".to_string(),
+ ty::Infer(ty::FreshIntTy(_)) => "fresh integral type".to_string(),
+ ty::Infer(ty::FreshFloatTy(_)) => "fresh floating-point type".to_string(),
ty::Projection(_) => "associated type".to_string(),
+ ty::UnnormalizedProjection(_) => "non-normalized associated type".to_string(),
ty::Param(ref p) => {
if p.is_self() {
"Self".to_string()
ty::FnPtr(ref f) => {
Some(FunctionSimplifiedType(f.skip_binder().inputs().len()))
}
+ ty::UnnormalizedProjection(..) => bug!("only used with chalk-engine"),
ty::Projection(_) | ty::Param(_) => {
if can_simplify_params {
// In normalized types, projections don't unify with
self.add_projection_ty(data);
}
+ &ty::UnnormalizedProjection(..) => bug!("only used with chalk-engine"),
+
&ty::Opaque(_, substs) => {
self.add_flags(TypeFlags::HAS_PROJECTION);
self.add_substs(substs);
/// we already use the term "free region". It refers to the regions that we use to represent bound
/// regions on a fn definition while we are typechecking its body.
///
-/// To clarify, conceptually there is no particular difference between an "escaping" region and a
-/// "free" region. However, there is a big difference in practice. Basically, when "entering" a
-/// binding level, one is generally required to do some sort of processing to a bound region, such
-/// as replacing it with a fresh/skolemized region, or making an entry in the environment to
-/// represent the scope to which it is attached, etc. An escaping region represents a bound region
-/// for which this processing has not yet been done.
+/// To clarify, conceptually there is no particular difference between
+/// an "escaping" region and a "free" region. However, there is a big
+/// difference in practice. Basically, when "entering" a binding
+/// level, one is generally required to do some sort of processing to
+/// a bound region, such as replacing it with a fresh/placeholder
+/// region, or making an entry in the environment to represent the
+/// scope to which it is attached, etc. An escaping region represents
+/// a bound region for which this processing has not yet been done.
struct HasEscapingRegionsVisitor {
/// Anything bound by `outer_index` or "above" is escaping
outer_index: ty::DebruijnIndex,
return true
}
let codegen_fn_attrs = tcx.codegen_fn_attrs(self.def_id());
- codegen_fn_attrs.requests_inline() || tcx.is_const_fn(self.def_id())
+ // need to use `is_const_fn_raw` since we don't really care if the user can use it as a
+ // const fn, just whether the function should be inlined
+ codegen_fn_attrs.requests_inline() || tcx.is_const_fn_raw(self.def_id())
}
}
ty::Str |
ty::FnPtr(_) |
ty::Projection(_) |
+ ty::UnnormalizedProjection(..) |
ty::Param(_) |
ty::Opaque(..) |
ty::Infer(_) |
}
tcx.layout_raw(param_env.and(normalized))?
}
- ty::GeneratorWitness(..) | ty::Infer(_) => {
+ ty::UnnormalizedProjection(..) | ty::GeneratorWitness(..) | ty::Infer(_) => {
bug!("LayoutDetails::compute: unexpected type `{}`", ty)
}
ty::Param(_) | ty::Error => {
}
}
- ty::Projection(_) | ty::Opaque(..) | ty::Param(_) |
- ty::Infer(_) | ty::Error => {
+ ty::Projection(_) | ty::UnnormalizedProjection(..) |
+ ty::Opaque(..) | ty::Param(_) | ty::Infer(_) | ty::Error => {
bug!("TyLayout::field_type: unexpected type `{}`", this.ty)
}
})
pub mod cast;
#[macro_use]
pub mod codec;
+mod constness;
pub mod error;
mod erase_regions;
pub mod fast_reject;
/// region `'a` is in a subuniverse U2 of U1, because we can name it
/// inside the fn type but not outside.
///
-/// Universes are related to **skolemization** -- which is a way of
-/// doing type- and trait-checking around these "forall" binders (also
-/// called **universal quantification**). The idea is that when, in
-/// the body of `bar`, we refer to `T` as a type, we aren't referring
-/// to any type in particular, but rather a kind of "fresh" type that
-/// is distinct from all other types we have actually declared. This
-/// is called a **skolemized** type, and we use universes to talk
-/// about this. In other words, a type name in universe 0 always
-/// corresponds to some "ground" type that the user declared, but a
-/// type name in a non-zero universe is a skolemized type -- an
-/// idealized representative of "types in general" that we use for
-/// checking generic functions.
+/// Universes are used to do type- and trait-checking around these
+/// "forall" binders (also called **universal quantification**). The
+/// idea is that when, in the body of `bar`, we refer to `T` as a
+/// type, we aren't referring to any type in particular, but rather a
+/// kind of "fresh" type that is distinct from all other types we have
+/// actually declared. This is called a **placeholder** type, and we
+/// use universes to talk about this. In other words, a type name in
+/// universe 0 always corresponds to some "ground" type that the user
+/// declared, but a type name in a non-zero universe is a placeholder
+/// type -- an idealized representative of "types in general" that we
+/// use for checking generic functions.
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, RustcEncodable, RustcDecodable)]
pub struct UniverseIndex(u32);
}
}
+/// The "placeholder index" fully defines a placeholder region.
+/// Placeholder regions are identified by both a **universe** as well
+/// as a "bound-region" within that universe. The `bound_region` is
+/// basically a name -- distinct bound regions within the same
+/// universe are just two regions with an unknown relationship to one
+/// another.
+#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable, PartialOrd, Ord)]
+pub struct Placeholder {
+ pub universe: UniverseIndex,
+ pub name: BoundRegion,
+}
+
/// When type checking, we use the `ParamEnv` to track
/// details about the set of where-clauses that are in scope at this
/// particular point.
const IS_FUNDAMENTAL = 1 << 2;
const IS_UNION = 1 << 3;
const IS_BOX = 1 << 4;
+ /// Indicates whether the type is an `Arc`.
+ const IS_ARC = 1 << 5;
+ /// Indicates whether the type is an `Rc`.
+ const IS_RC = 1 << 6;
/// Indicates whether the variant list of this ADT is `#[non_exhaustive]`.
/// (i.e., this flag is never set unless this ADT is an enum).
- const IS_VARIANT_LIST_NON_EXHAUSTIVE = 1 << 5;
+ const IS_VARIANT_LIST_NON_EXHAUSTIVE = 1 << 7;
}
}
if Some(did) == tcx.lang_items().owned_box() {
flags = flags | AdtFlags::IS_BOX;
}
+ if Some(did) == tcx.lang_items().arc() {
+ flags = flags | AdtFlags::IS_ARC;
+ }
+ if Some(did) == tcx.lang_items().rc() {
+ flags = flags | AdtFlags::IS_RC;
+ }
if kind == AdtKind::Enum && tcx.has_attr(did, "non_exhaustive") {
debug!("found non-exhaustive variant list for {:?}", did);
flags = flags | AdtFlags::IS_VARIANT_LIST_NON_EXHAUSTIVE;
self.flags.intersects(AdtFlags::IS_PHANTOM_DATA)
}
+ /// Returns `true` if this is `Arc<T>`.
+ pub fn is_arc(&self) -> bool {
+ self.flags.intersects(AdtFlags::IS_ARC)
+ }
+
+ /// Returns `true` if this is `Rc<T>`.
+ pub fn is_rc(&self) -> bool {
+ self.flags.intersects(AdtFlags::IS_RC)
+ }
+
/// Returns true if this is Box<T>.
#[inline]
pub fn is_box(&self) -> bool {
vec![ty]
}
+ UnnormalizedProjection(..) => bug!("only used with chalk-engine"),
+
Param(..) => {
// perf hack: if there is a `T: Sized` bound, then
// we know that `T` is Sized and do not need to check
erase_regions::provide(providers);
layout::provide(providers);
util::provide(providers);
+ constness::provide(providers);
*providers = ty::query::Providers {
associated_item,
associated_item_def_ids,
}
}
+ ty::UnnormalizedProjection(..) => bug!("only used with chalk-engine"),
+
// We assume that inference variables are fully resolved.
// So, if we encounter an inference variable, just record
// the unresolved variable as a component.
}
}
-impl<'tcx> QueryDescription<'tcx> for queries::is_const_fn<'tcx> {
+impl<'tcx> QueryDescription<'tcx> for queries::is_const_fn_raw<'tcx> {
fn describe(tcx: TyCtxt<'_, '_, '_>, def_id: DefId) -> String {
format!("checking if item is const fn: `{}`", tcx.item_path_str(def_id))
}
DefId
) -> Result<DtorckConstraint<'tcx>, NoSolution>,
- /// True if this is a const fn
- [] fn is_const_fn: IsConstFn(DefId) -> bool,
+ /// True if this is a const fn, use the `is_const_fn` to know whether your crate actually
+ /// sees it as const fn (e.g. the const-fn-ness might be unstable and you might not have
+ /// the feature gate active)
+ ///
+ /// DO NOT CALL MANUALLY, it is only meant to cache the base data for the `is_const_fn`
+ /// function
+ [] fn is_const_fn_raw: IsConstFn(DefId) -> bool,
+
+
+ /// Returns true if calls to the function may be promoted
+ ///
+ /// This is either because the function is e.g. a tuple-struct or tuple-variant constructor,
+ /// or because it has the `#[rustc_promotable]` attribute. The attribute should be removed
+ /// in the future in favour of some form of check which figures out whether the function
+ /// does not inspect the bits of any of its arguments (so is essentially just a constructor
+ /// function)
+ [] fn is_promotable_const_fn: IsPromotableConstFn(DefId) -> bool,
/// True if this is a foreign item (i.e., linked via `extern { ... }`).
[] fn is_foreign_item: IsForeignItem(DefId) -> bool,
DepKind::FnSignature => { force!(fn_sig, def_id!()); }
DepKind::CoerceUnsizedInfo => { force!(coerce_unsized_info, def_id!()); }
DepKind::ItemVariances => { force!(variances_of, def_id!()); }
- DepKind::IsConstFn => { force!(is_const_fn, def_id!()); }
+ DepKind::IsConstFn => { force!(is_const_fn_raw, def_id!()); }
+ DepKind::IsPromotableConstFn => { force!(is_promotable_const_fn, def_id!()); }
DepKind::IsForeignItem => { force!(is_foreign_item, def_id!()); }
DepKind::SizedConstraint => { force!(adt_sized_constraint, def_id!()); }
DepKind::DtorckConstraint => { force!(adt_dtorck_constraint, def_id!()); }
ty::GeneratorWitness(types) => ty::GeneratorWitness(types.fold_with(folder)),
ty::Closure(did, substs) => ty::Closure(did, substs.fold_with(folder)),
ty::Projection(ref data) => ty::Projection(data.fold_with(folder)),
+ ty::UnnormalizedProjection(ref data) => {
+ ty::UnnormalizedProjection(data.fold_with(folder))
+ }
ty::Opaque(did, substs) => ty::Opaque(did, substs.fold_with(folder)),
ty::Bool | ty::Char | ty::Str | ty::Int(_) |
ty::Uint(_) | ty::Float(_) | ty::Error | ty::Infer(_) |
}
ty::GeneratorWitness(ref types) => types.visit_with(visitor),
ty::Closure(_did, ref substs) => substs.visit_with(visitor),
- ty::Projection(ref data) => data.visit_with(visitor),
+ ty::Projection(ref data) | ty::UnnormalizedProjection(ref data) => {
+ data.visit_with(visitor)
+ }
ty::Opaque(_, ref substs) => substs.visit_with(visitor),
ty::Bool | ty::Char | ty::Str | ty::Int(_) |
ty::Uint(_) | ty::Float(_) | ty::Error | ty::Infer(_) |
/// `<T as Trait<..>>::N`.
Projection(ProjectionTy<'tcx>),
+ /// A placeholder type used when we do not have enough information
+ /// to normalize the projection of an associated type to an
+ /// existing concrete type. Currently only used with chalk-engine.
+ UnnormalizedProjection(ProjectionTy<'tcx>),
+
/// Opaque (`impl Trait`) type found in a return type.
/// The `DefId` comes either from
/// * the `impl Trait` ast::Ty node,
/// Object types don't have a self-type specified. Therefore, when
/// we convert the principal trait-ref into a normal trait-ref,
/// you must give *some* self-type. A common choice is `mk_err()`
- /// or some skolemized type.
+ /// or some placeholder type.
pub fn with_self_ty(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>, self_ty: Ty<'tcx>)
-> ty::TraitRef<'tcx> {
// otherwise the escaping regions would be captured by the binder
/// Object types don't have a self-type specified. Therefore, when
/// we convert the principal trait-ref into a normal trait-ref,
/// you must give *some* self-type. A common choice is `mk_err()`
- /// or some skolemized type.
+ /// or some placeholder type.
pub fn with_self_ty(&self, tcx: TyCtxt<'_, '_, 'tcx>,
self_ty: Ty<'tcx>)
-> ty::PolyTraitRef<'tcx> {
/// Binder is a binder for higher-ranked lifetimes. It is part of the
/// compiler's representation for things like `for<'a> Fn(&'a isize)`
/// (which would be represented by the type `PolyTraitRef ==
-/// Binder<TraitRef>`). Note that when we skolemize, instantiate,
+/// Binder<TraitRef>`). Note that when we instantiate,
/// erase, or otherwise "discharge" these bound regions, we change the
/// type from `Binder<T>` to just `T` (see
/// e.g. `liberate_late_bound_regions`).
///
/// Unlike Param-s, bound regions are not supposed to exist "in the wild"
/// outside their binder, e.g. in types passed to type inference, and
-/// should first be substituted (by skolemized regions, free regions,
+/// should first be substituted (by placeholder regions, free regions,
/// or region variables).
///
-/// ## Skolemized and Free Regions
+/// ## Placeholder and Free Regions
///
/// One often wants to work with bound regions without knowing their precise
/// identity. For example, when checking a function, the lifetime of a borrow
/// it must be ensured that bounds on the region can't be accidentally
/// assumed without being checked.
///
-/// The process of doing that is called "skolemization". The bound regions
-/// are replaced by skolemized markers, which don't satisfy any relation
-/// not explicitly provided.
+/// To do this, we replace the bound regions with placeholder markers,
+/// which don't satisfy any relation not explicitly provided.
///
-/// There are 2 kinds of skolemized regions in rustc: `ReFree` and
-/// `ReSkolemized`. When checking an item's body, `ReFree` is supposed
+/// There are 2 kinds of placeholder regions in rustc: `ReFree` and
+/// `RePlaceholder`. When checking an item's body, `ReFree` is supposed
/// to be used. These also support explicit bounds: both the internally-stored
/// *scope*, which the region is assumed to outlive, as well as other
/// relations stored in the `FreeRegionMap`. Note that these relations
///
/// When working with higher-ranked types, some region relations aren't
/// yet known, so you can't just call `resolve_regions_and_report_errors`.
-/// `ReSkolemized` is designed for this purpose. In these contexts,
+/// `RePlaceholder` is designed for this purpose. In these contexts,
/// there's also the risk that some inference variable laying around will
-/// get unified with your skolemized region: if you want to check whether
+/// get unified with your placeholder region: if you want to check whether
/// `for<'a> Foo<'_>: 'a`, and you substitute your bound region `'a`
-/// with a skolemized region `'%a`, the variable `'_` would just be
-/// instantiated to the skolemized region `'%a`, which is wrong because
+/// with a placeholder region `'%a`, the variable `'_` would just be
+/// instantiated to the placeholder region `'%a`, which is wrong because
/// the inference variable is supposed to satisfy the relation
-/// *for every value of the skolemized region*. To ensure that doesn't
+/// *for every value of the placeholder region*. To ensure that doesn't
/// happen, you can use `leak_check`. This is more clearly explained
/// by the [rustc guide].
///
/// A region variable. Should not exist after typeck.
ReVar(RegionVid),
- /// A skolemized region - basically the higher-ranked version of ReFree.
+ /// A placeholder region - basically the higher-ranked version of ReFree.
/// Should not exist after typeck.
- ReSkolemized(ty::UniverseIndex, BoundRegion),
+ RePlaceholder(ty::Placeholder),
/// Empty lifetime is for data that is never accessed.
/// Bottom in the region lattice. We treat ReEmpty somewhat
RegionKind::ReScope(..) => false,
RegionKind::ReStatic => true,
RegionKind::ReVar(..) => false,
- RegionKind::ReSkolemized(_, br) => br.is_named(),
+ RegionKind::RePlaceholder(placeholder) => placeholder.name.is_named(),
RegionKind::ReEmpty => false,
RegionKind::ReErased => false,
RegionKind::ReClosureBound(..) => false,
flags = flags | TypeFlags::HAS_FREE_REGIONS;
flags = flags | TypeFlags::HAS_RE_INFER;
}
- ty::ReSkolemized(..) => {
+ ty::RePlaceholder(..) => {
flags = flags | TypeFlags::HAS_FREE_REGIONS;
flags = flags | TypeFlags::HAS_RE_SKOL;
}
}
}
+ /// Returns `true` if this type is an `Arc<T>`.
+ pub fn is_arc(&self) -> bool {
+ match self.sty {
+ Adt(def, _) => def.is_arc(),
+ _ => false,
+ }
+ }
+
+ /// Returns `true` if this type is an `Rc<T>`.
+ pub fn is_rc(&self) -> bool {
+ match self.sty {
+ Adt(def, _) => def.is_rc(),
+ _ => false,
+ }
+ }
+
pub fn is_box(&self) -> bool {
match self.sty {
Adt(def, _) => def.is_box(),
Generator(_, GeneratorSubsts { ref substs }, _) => {
substs.regions().collect()
}
- Projection(ref data) => {
+ Projection(ref data) | UnnormalizedProjection(ref data) => {
data.substs.regions().collect()
}
FnDef(..) |
ty::Projection(_) | ty::Param(_) | ty::Opaque(..) => false,
+ ty::UnnormalizedProjection(..) => bug!("only used with chalk-engine"),
+
ty::Infer(ty::TyVar(_)) => false,
ty::Infer(ty::CanonicalTy(_)) |
ty::Dynamic(..) | ty::Projection(..) | ty::Param(_) |
ty::Opaque(..) | ty::Infer(_) | ty::Error => true,
+ ty::UnnormalizedProjection(..) => bug!("only used with chalk-engine"),
+
// Structural recursion.
ty::Array(ty, _) | ty::Slice(ty) => needs_drop(ty),
ty::Ref(_, ty, _) => {
stack.push(ty);
}
- ty::Projection(ref data) => {
+ ty::Projection(ref data) | ty::UnnormalizedProjection(ref data) => {
stack.extend(data.substs.types().rev());
}
ty::Dynamic(ref obj, ..) => {
self.compute_projection(data);
}
+ ty::UnnormalizedProjection(..) => bug!("only used with chalk-engine"),
+
ty::Adt(def, substs) => {
// WfNominalType
let obligations = self.nominal_obligations(def.did, substs);
{
// Since we don't actually *know* the self type for an object,
// this "open(err)" serves as a kind of dummy standin -- basically
- // a skolemized type.
+ // a placeholder type.
let open_ty = tcx.mk_infer(ty::FreshTy(0));
let predicates = existential_predicates.iter().filter_map(|predicate| {
use ty::{Error, Str, Array, Slice, Float, FnDef, FnPtr};
use ty::{Param, RawPtr, Ref, Never, Tuple};
use ty::{Closure, Generator, GeneratorWitness, Foreign, Projection, Opaque};
-use ty::{Dynamic, Int, Uint, Infer};
+use ty::{UnnormalizedProjection, Dynamic, Int, Uint, Infer};
use ty::{self, RegionVid, Ty, TyCtxt, TypeFoldable, GenericParamCount, GenericParamDefKind};
use util::nodemap::FxHashSet;
}
ty::ReLateBound(_, br) |
ty::ReFree(ty::FreeRegion { bound_region: br, .. }) |
- ty::ReSkolemized(_, br) => {
+ ty::RePlaceholder(ty::Placeholder { name: br, .. }) => {
write!(f, "{}", br)
}
ty::ReScope(scope) if cx.identify_regions => {
write!(f, "'?{}", c.index())
}
- ty::ReSkolemized(universe, ref bound_region) => {
- write!(f, "ReSkolemized({:?}, {:?})", universe, bound_region)
+ ty::RePlaceholder(placeholder) => {
+ write!(f, "RePlaceholder({:?})", placeholder)
}
ty::ReEmpty => write!(f, "ReEmpty"),
}
Foreign(def_id) => parameterized(f, subst::Substs::empty(), def_id, &[]),
Projection(ref data) => data.print(f, cx),
+ UnnormalizedProjection(ref data) => {
+ write!(f, "Unnormalized(")?;
+ data.print(f, cx)?;
+ write!(f, ")")
+ }
Opaque(def_id, substs) => {
if cx.is_verbose {
return write!(f, "Opaque({:?}, {:?})", def_id, substs);
// These cannot exist in borrowck
RegionKind::ReVar(..) |
RegionKind::ReCanonical(..) |
- RegionKind::ReSkolemized(..) |
+ RegionKind::RePlaceholder(..) |
RegionKind::ReClosureBound(..) |
RegionKind::ReErased => span_bug!(borrow_span,
"unexpected region in borrowck {:?}",
ty::ReClosureBound(..) |
ty::ReLateBound(..) |
ty::ReVar(..) |
- ty::ReSkolemized(..) |
+ ty::RePlaceholder(..) |
ty::ReErased => {
span_bug!(
cmt.span,
if let Some(i) = arg_pos {
// The argument's `Ty`
(Some(&fn_like.decl().inputs[i]),
- i == 0 && fn_like.decl().has_implicit_self)
+ i == 0 && fn_like.decl().implicit_self.has_implicit_self())
} else {
(None, false)
}
}
ty::Error |
ty::Infer(_) |
+ ty::UnnormalizedProjection(..) |
ty::Projection(..) |
ty::Opaque(..) |
ty::GeneratorWitness(..) |
bug!("undesugared DropAndReplace in codegen: {:?}", terminator);
}
- mir::TerminatorKind::Call { ref func, ref args, ref destination, cleanup } => {
+ mir::TerminatorKind::Call {
+ ref func,
+ ref args,
+ ref destination,
+ cleanup,
+ from_hir_call: _
+ } => {
// Create the callee. This is a fn ptr or zero-sized and hence a kind of scalar.
let callee = self.codegen_operand(&bx, func);
ty::Closure(..) |
ty::Generator(..) |
ty::GeneratorWitness(..) |
+ ty::UnnormalizedProjection(..) |
ty::Projection(..) |
ty::Opaque(..) |
ty::FnDef(..) => bug!("Unexpected type in foreign function"),
ty::Adt(def, _) => {
if def.variants.is_empty() {
return;
- } else {
- check_must_use(cx, def.did, s.span, "")
}
+ check_must_use(cx, def.did, s.span, "")
},
_ => false,
};
AssignOp(.., ref value) => (value, "assigned value", false),
// either function/method call, or something this lint doesn't care about
ref call_or_other => {
- let args_to_check;
- let call_kind;
- match *call_or_other {
- Call(_, ref args) => {
- call_kind = "function";
- args_to_check = &args[..];
- },
- MethodCall(_, ref args) => {
- call_kind = "method";
- // first "argument" is self (which sometimes needs parens)
- args_to_check = &args[1..];
- }
+ let (args_to_check, call_kind) = match *call_or_other {
+ Call(_, ref args) => (&args[..], "function"),
+ // first "argument" is self (which sometimes needs parens)
+ MethodCall(_, ref args) => (&args[1..], "method"),
// actual catch-all arm
_ => { return; }
- }
+ };
// Don't lint if this is a nested macro expansion: otherwise, the lint could
// trigger in situations that macro authors shouldn't have to care about, e.g.,
// when a parenthesized token tree matched in one macro expansion is matched as
}
fn check_stmt(&mut self, cx: &EarlyContext, s: &ast::Stmt) {
- let (value, msg) = match s.node {
- ast::StmtKind::Local(ref local) => {
- match local.init {
- Some(ref value) => (value, "assigned value"),
- None => return,
- }
+ if let ast::StmtKind::Local(ref local) = s.node {
+ if let Some(ref value) = local.init {
+ self.check_unused_parens_core(cx, &value, "assigned value", false);
}
- _ => return,
- };
- self.check_unused_parens_core(cx, &value, msg, false);
+ }
}
}
let orig_ident = items[0].0.prefix.segments.last().unwrap().ident;
if orig_ident.name == keywords::SelfValue.name() {
return;
- } else {
- node_ident = rename.unwrap_or(orig_ident);
}
+ node_ident = rename.unwrap_or(orig_ident);
}
ast::UseTreeKind::Glob => {
node_ident = ast::Ident::from_str("*");
use rustc::ty::query::Providers;
use rustc::hir::def_id::{CrateNum, DefId, LOCAL_CRATE, CRATE_DEF_INDEX};
use rustc::hir::map::{DefKey, DefPath, DefPathHash};
-use rustc::hir::map::blocks::FnLikeNode;
use rustc::hir::map::definitions::DefPathTable;
use rustc::util::nodemap::DefIdMap;
use rustc_data_structures::svh::Svh;
use syntax::symbol::Symbol;
use syntax_pos::{Span, NO_EXPANSION, FileName};
use rustc_data_structures::bit_set::BitSet;
-use rustc::hir;
macro_rules! provide {
(<$lt:tt> $tcx:ident, $def_id:ident, $other:ident, $cdata:ident,
}
fn_sig => { cdata.fn_sig(def_id.index, tcx) }
inherent_impls => { Lrc::new(cdata.get_inherent_implementations_for_type(def_id.index)) }
- is_const_fn => { cdata.is_const_fn(def_id.index) }
+ is_const_fn_raw => { cdata.is_const_fn_raw(def_id.index) }
is_foreign_item => { cdata.is_foreign_item(def_id.index) }
describe_def => { cdata.get_def(def_id.index) }
def_span => { cdata.get_span(def_id.index, &tcx.sess) }
}
pub fn provide<'tcx>(providers: &mut Providers<'tcx>) {
- fn is_const_fn<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> bool {
- let node_id = tcx.hir.as_local_node_id(def_id)
- .expect("Non-local call to local provider is_const_fn");
-
- if let Some(fn_like) = FnLikeNode::from_node(tcx.hir.get(node_id)) {
- fn_like.constness() == hir::Constness::Const
- } else {
- false
- }
- }
-
// FIXME(#44234) - almost all of these queries have no sub-queries and
// therefore no actual inputs, they're just reading tables calculated in
// resolve! Does this work? Unsure! That's what the issue is about
*providers = Providers {
- is_const_fn,
is_dllimport_foreign_item: |tcx, id| {
tcx.native_library_kind(id) == Some(NativeLibraryKind::NativeUnknown)
},
}
}
- pub fn is_const_fn(&self, id: DefIndex) -> bool {
+ crate fn is_const_fn_raw(&self, id: DefIndex) -> bool {
let constness = match self.entry(id).kind {
EntryKind::Method(data) => data.decode(self).fn_data.constness,
EntryKind::Fn(data) => data.decode(self).constness,
use rustc::hir::def_id::DefId;
use rustc::middle::region::ScopeTree;
use rustc::mir::{
- self, AggregateKind, BindingForm, BorrowKind, ClearCrossCrate, FakeReadCause, Field, Local,
- LocalDecl, LocalKind, Location, Operand, Place, PlaceProjection, ProjectionElem, Rvalue,
- Statement, StatementKind, TerminatorKind, VarBindingForm,
+ self, AggregateKind, BindingForm, BorrowKind, ClearCrossCrate, Field, Local,
+ LocalDecl, LocalKind, Location, Operand, Place, PlaceProjection, ProjectionElem,
+ Rvalue, Statement, StatementKind, TerminatorKind, VarBindingForm,
};
use rustc::ty;
use rustc::util::ppaux::with_highlight_region_for_bound_region;
move_spans.var_span_label(&mut err, "move occurs due to use in closure");
self.explain_why_borrow_contains_point(context, borrow, None)
- .emit(self.infcx.tcx, &mut err);
+ .emit(self.infcx.tcx, &mut err, String::new());
err.buffer(&mut self.errors_buffer);
}
});
self.explain_why_borrow_contains_point(context, borrow, None)
- .emit(self.infcx.tcx, &mut err);
+ .emit(self.infcx.tcx, &mut err, String::new());
err.buffer(&mut self.errors_buffer);
}
let desc_place = self.describe_place(place).unwrap_or("_".to_owned());
let tcx = self.infcx.tcx;
+ let first_borrow_desc;
+
// FIXME: supply non-"" `opt_via` when appropriate
let mut err = match (
gen_borrow_kind,
"immutable",
"mutable",
) {
- (BorrowKind::Shared, lft, _, BorrowKind::Mut { .. }, _, rgt)
- | (BorrowKind::Mut { .. }, _, lft, BorrowKind::Shared, rgt, _) => {
+ (BorrowKind::Shared, lft, _, BorrowKind::Mut { .. }, _, rgt) => {
+ first_borrow_desc = "mutable ";
+ tcx.cannot_reborrow_already_borrowed(
+ span,
+ &desc_place,
+ "",
+ lft,
+ issued_span,
+ "it",
+ rgt,
+ "",
+ None,
+ Origin::Mir,
+ )
+ }
+ (BorrowKind::Mut { .. }, _, lft, BorrowKind::Shared, rgt, _) => {
+ first_borrow_desc = "immutable ";
tcx.cannot_reborrow_already_borrowed(
span,
&desc_place,
}
(BorrowKind::Mut { .. }, _, _, BorrowKind::Mut { .. }, _, _) => {
+ first_borrow_desc = "first ";
tcx.cannot_mutably_borrow_multiply(
span,
&desc_place,
}
(BorrowKind::Unique, _, _, BorrowKind::Unique, _, _) => {
+ first_borrow_desc = "first ";
tcx.cannot_uniquely_borrow_by_two_closures(
span,
&desc_place,
return;
}
- (BorrowKind::Unique, _, _, _, _, _) => tcx.cannot_uniquely_borrow_by_one_closure(
- span,
- &desc_place,
- "",
- issued_span,
- "it",
- "",
- None,
- Origin::Mir,
- ),
+ (BorrowKind::Unique, _, _, _, _, _) => {
+ first_borrow_desc = "first ";
+ tcx.cannot_uniquely_borrow_by_one_closure(
+ span,
+ &desc_place,
+ "",
+ issued_span,
+ "it",
+ "",
+ None,
+ Origin::Mir,
+ )
+ },
(BorrowKind::Shared, lft, _, BorrowKind::Unique, _, _) => {
+ first_borrow_desc = "first ";
tcx.cannot_reborrow_already_uniquely_borrowed(
span,
&desc_place,
}
(BorrowKind::Mut { .. }, _, lft, BorrowKind::Unique, _, _) => {
+ first_borrow_desc = "first ";
tcx.cannot_reborrow_already_uniquely_borrowed(
span,
&desc_place,
}
self.explain_why_borrow_contains_point(context, issued_borrow, None)
- .emit(self.infcx.tcx, &mut err);
+ .emit(self.infcx.tcx, &mut err, first_borrow_desc.to_string());
err.buffer(&mut self.errors_buffer);
}
if let BorrowExplanation::MustBeValidFor(..) = explanation {
} else {
- explanation.emit(self.infcx.tcx, &mut err);
+ explanation.emit(self.infcx.tcx, &mut err, String::new());
}
} else {
err.span_label(borrow_span, "borrowed value does not live long enough");
borrow_spans.args_span_label(&mut err, "value captured here");
- explanation.emit(self.infcx.tcx, &mut err);
+ explanation.emit(self.infcx.tcx, &mut err, String::new());
}
err
_ => {}
}
- explanation.emit(self.infcx.tcx, &mut err);
+ explanation.emit(self.infcx.tcx, &mut err, String::new());
err.buffer(&mut self.errors_buffer);
}
}
_ => {}
}
- explanation.emit(self.infcx.tcx, &mut err);
+ explanation.emit(self.infcx.tcx, &mut err, String::new());
borrow_spans.args_span_label(&mut err, "value captured here");
loan_spans.var_span_label(&mut err, "borrow occurs due to use in closure");
self.explain_why_borrow_contains_point(context, loan, None)
- .emit(self.infcx.tcx, &mut err);
+ .emit(self.infcx.tcx, &mut err, String::new());
err.buffer(&mut self.errors_buffer);
}
}
}
- /// Returns the `FakeReadCause` at this location if it is a `FakeRead` statement.
- pub(super) fn retrieve_fake_read_cause_for_location(
- &self,
- location: &Location,
- ) -> Option<FakeReadCause> {
- let stmt = self.mir.basic_blocks()[location.block]
- .statements
- .get(location.statement_index)?;
- if let StatementKind::FakeRead(cause, _) = stmt.kind {
- Some(cause)
- } else {
- None
- }
- }
-
fn classify_drop_access_kind(&self, place: &Place<'tcx>) -> StorageDeadOrDrop<'tcx> {
let tcx = self.infcx.tcx;
match place {
// lifetimes without names with the value `'0`.
match ty.sty {
ty::TyKind::Ref(ty::RegionKind::ReLateBound(_, br), _, _)
- | ty::TyKind::Ref(ty::RegionKind::ReSkolemized(_, br), _, _) => {
- with_highlight_region_for_bound_region(*br, counter, || format!("{}", ty))
- }
+ | ty::TyKind::Ref(
+ ty::RegionKind::RePlaceholder(ty::Placeholder { name: br, .. }),
+ _,
+ _,
+ ) => with_highlight_region_for_bound_region(*br, counter, || format!("{}", ty)),
_ => format!("{}", ty),
}
}
fn get_region_name_for_ty(&self, ty: ty::Ty<'tcx>, counter: usize) -> String {
match ty.sty {
ty::TyKind::Ref(region, _, _) => match region {
- ty::RegionKind::ReLateBound(_, br) | ty::RegionKind::ReSkolemized(_, br) => {
+ ty::RegionKind::ReLateBound(_, br)
+ | ty::RegionKind::RePlaceholder(ty::Placeholder { name: br, .. }) => {
with_highlight_region_for_bound_region(*br, counter, || format!("{}", region))
}
_ => format!("{}", region),
ref args,
ref destination,
cleanup: _,
+ from_hir_call: _,
} => {
self.consume_operand(ContextKind::CallOperator.new(loc), (func, span), flow_state);
for arg in args {
// except according to those terms.
use core::unicode::property::Pattern_White_Space;
+use std::fmt::{self, Display};
+
use rustc::mir::*;
use rustc::ty;
use rustc_errors::{DiagnosticBuilder,Applicability};
use borrow_check::MirBorrowckCtxt;
use borrow_check::prefixes::PrefixSet;
-use dataflow::move_paths::{IllegalMoveOrigin, IllegalMoveOriginKind};
-use dataflow::move_paths::{LookupResult, MoveError, MovePathIndex};
+use dataflow::move_paths::{
+ IllegalMoveOrigin, IllegalMoveOriginKind, InitLocation,
+ LookupResult, MoveError, MovePathIndex,
+};
use util::borrowck_errors::{BorrowckErrors, Origin};
// Often when desugaring a pattern match we may have many individual moves in
},
}
+enum BorrowedContentSource {
+ Arc,
+ Rc,
+ Other,
+}
+
+impl Display for BorrowedContentSource {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ match *self {
+ BorrowedContentSource::Arc => write!(f, "an `Arc`"),
+ BorrowedContentSource::Rc => write!(f, "an `Rc`"),
+ BorrowedContentSource::Other => write!(f, "borrowed content"),
+ }
+ }
+}
+
impl<'a, 'gcx, 'tcx> MirBorrowckCtxt<'a, 'gcx, 'tcx> {
pub(crate) fn report_move_errors(&mut self, move_errors: Vec<(Place<'tcx>, MoveError<'tcx>)>) {
let grouped_errors = self.group_move_errors(move_errors);
diag
}
- _ => self.infcx.tcx.cannot_move_out_of(
- span, "borrowed content", origin
- ),
+ _ => {
+ let source = self.borrowed_content_source(place);
+ self.infcx.tcx.cannot_move_out_of(
+ span, &format!("{}", source), origin
+ )
+ },
}
}
IllegalMoveOriginKind::InteriorOfTypeWithDestructor { container_ty: ty } => {
);
}
}
+
+ fn borrowed_content_source(&self, place: &Place<'tcx>) -> BorrowedContentSource {
+ // Look up the provided place and work out the move path index for it,
+ // we'll use this to work back through where this value came from and check whether it
+ // was originally part of an `Rc` or `Arc`.
+ let initial_mpi = match self.move_data.rev_lookup.find(place) {
+ LookupResult::Exact(mpi) | LookupResult::Parent(Some(mpi)) => mpi,
+ _ => return BorrowedContentSource::Other,
+ };
+
+ let mut queue = vec![initial_mpi];
+ let mut visited = Vec::new();
+ debug!("borrowed_content_source: queue={:?}", queue);
+ while let Some(mpi) = queue.pop() {
+ debug!(
+ "borrowed_content_source: mpi={:?} queue={:?} visited={:?}",
+ mpi, queue, visited
+ );
+
+ // Don't visit the same path twice.
+ if visited.contains(&mpi) {
+ continue;
+ }
+ visited.push(mpi);
+
+ for i in &self.move_data.init_path_map[mpi] {
+ let init = &self.move_data.inits[*i];
+ debug!("borrowed_content_source: init={:?}", init);
+ // We're only interested in statements that initialized a value, not the
+ // initializations from arguments.
+ let loc = match init.location {
+ InitLocation::Statement(stmt) => stmt,
+ _ => continue,
+ };
+
+ let bbd = &self.mir[loc.block];
+ let is_terminator = bbd.statements.len() == loc.statement_index;
+ debug!("borrowed_content_source: loc={:?} is_terminator={:?}", loc, is_terminator);
+ if !is_terminator {
+ let stmt = &bbd.statements[loc.statement_index];
+ debug!("borrowed_content_source: stmt={:?}", stmt);
+ // We're only interested in assignments (in particular, where the
+ // assignment came from - was it an `Rc` or `Arc`?).
+ if let StatementKind::Assign(_, box Rvalue::Ref(_, _, source)) = &stmt.kind {
+ let ty = source.ty(self.mir, self.infcx.tcx).to_ty(self.infcx.tcx);
+ let ty = match ty.sty {
+ ty::TyKind::Ref(_, ty, _) => ty,
+ _ => ty,
+ };
+ debug!("borrowed_content_source: ty={:?}", ty);
+
+ if ty.is_arc() {
+ return BorrowedContentSource::Arc;
+ } else if ty.is_rc() {
+ return BorrowedContentSource::Rc;
+ } else {
+ queue.push(init.path);
+ }
+ }
+ } else if let Some(Terminator {
+ kind: TerminatorKind::Call { args, .. },
+ ..
+ }) = &bbd.terminator {
+ for arg in args {
+ let source = match arg {
+ Operand::Copy(place) | Operand::Move(place) => place,
+ _ => continue,
+ };
+
+ let ty = source.ty(self.mir, self.infcx.tcx).to_ty(self.infcx.tcx);
+ let ty = match ty.sty {
+ ty::TyKind::Ref(_, ty, _) => ty,
+ _ => ty,
+ };
+ debug!("borrowed_content_source: ty={:?}", ty);
+
+ if ty.is_arc() {
+ return BorrowedContentSource::Arc;
+ } else if ty.is_rc() {
+ return BorrowedContentSource::Rc;
+ } else {
+ queue.push(init.path);
+ }
+ }
+ }
+ }
+ }
+
+ BorrowedContentSource::Other
+ }
}
use rustc::ty::{self, Const, DefIdTree, TyS, TyKind, TyCtxt};
use rustc_data_structures::indexed_vec::Idx;
use syntax_pos::Span;
+use syntax_pos::symbol::keywords;
use dataflow::move_paths::InitLocation;
use borrow_check::MirBorrowckCtxt;
debug!("report_mutability_error: act={:?}, acted_on={:?}", act, acted_on);
match the_place_err {
+ // Suggest removing a `&mut` from the use of a mutable reference.
+ Place::Local(local)
+ if {
+ self.mir.local_decls.get(*local).map(|local_decl| {
+ if let ClearCrossCrate::Set(
+ mir::BindingForm::ImplicitSelf(kind)
+ ) = local_decl.is_user_variable.as_ref().unwrap() {
+ // Check if the user variable is a `&mut self` and we can therefore
+ // suggest removing the `&mut`.
+ //
+ // Deliberately fall into this case for all implicit self types,
+ // so that we don't fall in to the next case with them.
+ *kind == mir::ImplicitSelfKind::MutRef
+ } else if Some(keywords::SelfValue.name()) == local_decl.name {
+ // Otherwise, check if the name is the self kewyord - in which case
+ // we have an explicit self. Do the same thing in this case and check
+ // for a `self: &mut Self` to suggest removing the `&mut`.
+ if let ty::TyKind::Ref(
+ _, _, hir::Mutability::MutMutable
+ ) = local_decl.ty.sty {
+ true
+ } else {
+ false
+ }
+ } else {
+ false
+ }
+ }).unwrap_or(false)
+ } =>
+ {
+ err.span_label(span, format!("cannot {ACT}", ACT = act));
+ err.span_label(span, "try removing `&mut` here");
+ },
+
// We want to suggest users use `let mut` for local (user
// variable) mutations...
Place::Local(local) if self.mir.local_decls[*local].can_be_made_mutable() => {
{
let local_decl = &self.mir.local_decls[*local];
let suggestion = match local_decl.is_user_variable.as_ref().unwrap() {
- ClearCrossCrate::Set(mir::BindingForm::ImplicitSelf) => {
+ ClearCrossCrate::Set(mir::BindingForm::ImplicitSelf(_)) => {
Some(suggest_ampmut_self(self.infcx.tcx, local_decl))
}
// except according to those terms.
use borrow_check::borrow_set::BorrowData;
+use borrow_check::error_reporting::UseSpans;
use borrow_check::nll::region_infer::Cause;
use borrow_check::{Context, MirBorrowckCtxt, WriteKind};
use rustc::ty::{Region, TyCtxt};
-use rustc::mir::{FakeReadCause, Location, Place, TerminatorKind};
+use rustc::mir::{FakeReadCause, Location, Operand, Place, StatementKind, TerminatorKind};
use rustc_errors::DiagnosticBuilder;
use syntax_pos::Span;
use syntax_pos::symbol::Symbol;
mod find_use;
pub(in borrow_check) enum BorrowExplanation<'tcx> {
- UsedLater(bool, Option<FakeReadCause>, Span),
- UsedLaterInLoop(bool, Span),
+ UsedLater(LaterUseKind, Span),
+ UsedLaterInLoop(LaterUseKind, Span),
UsedLaterWhenDropped(Span, Symbol, bool),
MustBeValidFor(Region<'tcx>),
Unexplained,
}
+#[derive(Clone, Copy)]
+pub(in borrow_check) enum LaterUseKind {
+ ClosureCapture,
+ Call,
+ FakeLetRead,
+ Other,
+}
+
impl<'tcx> BorrowExplanation<'tcx> {
pub(in borrow_check) fn emit<'cx, 'gcx>(
&self,
tcx: TyCtxt<'cx, 'gcx, 'tcx>,
- err: &mut DiagnosticBuilder<'_>
+ err: &mut DiagnosticBuilder<'_>,
+ borrow_desc: String,
) {
match *self {
- BorrowExplanation::UsedLater(is_in_closure, fake_read_cause, var_or_use_span) => {
- let message = if is_in_closure {
- "borrow later captured here by closure"
- } else if let Some(FakeReadCause::ForLet) = fake_read_cause {
- "borrow later stored here"
- } else {
- "borrow later used here"
+ BorrowExplanation::UsedLater(later_use_kind, var_or_use_span) => {
+ let message = borrow_desc + match later_use_kind {
+ LaterUseKind::ClosureCapture => "borrow later captured here by closure",
+ LaterUseKind::Call => "borrow later used by call",
+ LaterUseKind::FakeLetRead => "borrow later stored here",
+ LaterUseKind::Other => "borrow later used here",
};
err.span_label(var_or_use_span, message);
},
- BorrowExplanation::UsedLaterInLoop(is_in_closure, var_or_use_span) => {
- let message = if is_in_closure {
- "borrow captured here by closure, in later iteration of loop"
- } else {
- "borrow used here, in later iteration of loop"
+ BorrowExplanation::UsedLaterInLoop(later_use_kind, var_or_use_span) => {
+ let message = borrow_desc + match later_use_kind {
+ LaterUseKind::ClosureCapture => {
+ "borrow captured here by closure, in later iteration of loop"
+ },
+ LaterUseKind::Call => "borrow used by call, in later iteration of loop",
+ LaterUseKind::FakeLetRead => "borrow later stored here",
+ LaterUseKind::Other => "borrow used here, in later iteration of loop",
};
err.span_label(var_or_use_span, message);
},
BorrowExplanation::UsedLaterWhenDropped(span, local_name, should_note_order) => {
err.span_label(
span,
- format!("borrow later used here, when `{}` is dropped", local_name),
+ format!(
+ "{}borrow later used here, when `{}` is dropped",
+ borrow_desc,
+ local_name,
+ ),
);
if should_note_order {
BorrowExplanation::MustBeValidFor(region) => {
tcx.note_and_explain_free_region(
err,
- "borrowed value must be valid for ",
+ &(borrow_desc + "borrowed value must be valid for "),
region,
"...",
);
.or_else(|| self.borrow_spans(span, location));
if self.is_borrow_location_in_loop(context.loc) {
- BorrowExplanation::UsedLaterInLoop(spans.for_closure(), spans.var_or_use())
+ let later_use = self.later_use_kind(spans, location);
+ BorrowExplanation::UsedLaterInLoop(later_use.0, later_use.1)
} else {
// Check if the location represents a `FakeRead`, and adapt the error
// message to the `FakeReadCause` it is from: in particular,
// the ones inserted in optimized `let var = <expr>` patterns.
- BorrowExplanation::UsedLater(
- spans.for_closure(),
- self.retrieve_fake_read_cause_for_location(&location),
- spans.var_or_use()
- )
+ let later_use = self.later_use_kind(spans, location);
+ BorrowExplanation::UsedLater(later_use.0, later_use.1)
}
}
false
}
+
+ fn later_use_kind(&self, use_spans: UseSpans, location: Location) -> (LaterUseKind, Span) {
+ use self::LaterUseKind::*;
+
+ let block = &self.mir.basic_blocks()[location.block];
+ match use_spans {
+ UseSpans::ClosureUse { var_span, .. } => (LaterUseKind::ClosureCapture, var_span),
+ UseSpans::OtherUse(span) => {
+ (if let Some(stmt) = block.statements.get(location.statement_index) {
+ match stmt.kind {
+ StatementKind::FakeRead(FakeReadCause::ForLet, _) => FakeLetRead,
+ _ => Other,
+ }
+ } else {
+ assert_eq!(location.statement_index, block.statements.len());
+ match block.terminator().kind {
+ TerminatorKind::Call { ref func, from_hir_call: true, .. } => {
+ // Just point to the function, to reduce the chance
+ // of overlapping spans.
+ let function_span = match func {
+ Operand::Constant(c) => c.span,
+ Operand::Copy(Place::Local(l)) | Operand::Move(Place::Local(l)) => {
+ let local_decl = &self.mir.local_decls[*l];
+ if local_decl.name.is_none() {
+ local_decl.source_info.span
+ } else {
+ span
+ }
+ },
+ _ => span,
+ };
+ return (Call, function_span);
+ },
+ _ => Other,
+ }
+ }, span)
+ }
+ }
+ }
}
ref args,
ref destination,
cleanup: _,
+ from_hir_call: _,
} => {
self.consume_operand(ContextKind::CallOperator.new(location), func);
for arg in args {
// Run the MIR type-checker.
let MirTypeckResults {
constraints,
+ placeholder_indices,
universal_region_relations,
} = type_check::type_check(
infcx,
elements,
);
+ let placeholder_indices = Rc::new(placeholder_indices);
+
if let Some(all_facts) = &mut all_facts {
all_facts
.universal_region
let mut regioncx = RegionInferenceContext::new(
var_origins,
universal_regions,
+ placeholder_indices,
universal_region_relations,
mir,
outlives_constraints,
ty::ReLateBound(..)
| ty::ReScope(..)
| ty::ReVar(..)
- | ty::ReSkolemized(..)
+ | ty::RePlaceholder(..)
| ty::ReEmpty
| ty::ReErased
| ty::ReClosureBound(..)
use super::universal_regions::UniversalRegions;
use borrow_check::nll::constraints::graph::NormalConstraintGraph;
use borrow_check::nll::constraints::{ConstraintSccIndex, ConstraintSet, OutlivesConstraint};
-use borrow_check::nll::region_infer::values::{RegionElement, ToElementIndex};
+use borrow_check::nll::region_infer::values::{PlaceholderIndices, RegionElement, ToElementIndex};
use borrow_check::nll::type_check::free_region_relations::UniversalRegionRelations;
use borrow_check::nll::type_check::Locations;
use rustc::hir::def_id::DefId;
pub(crate) fn new(
var_infos: VarInfos,
universal_regions: Rc<UniversalRegions<'tcx>>,
+ placeholder_indices: Rc<PlaceholderIndices>,
universal_region_relations: Rc<UniversalRegionRelations<'tcx>>,
_mir: &Mir<'tcx>,
outlives_constraints: ConstraintSet,
.map(|info| RegionDefinition::new(info.universe, info.origin))
.collect();
- // Compute the max universe used anywhere amongst the regions.
- let max_universe = definitions
- .iter()
- .map(|d| d.universe)
- .max()
- .unwrap_or(ty::UniverseIndex::ROOT);
-
let constraints = Rc::new(outlives_constraints); // freeze constraints
let constraint_graph = Rc::new(constraints.graph(definitions.len()));
let fr_static = universal_regions.fr_static;
let constraint_sccs = Rc::new(constraints.compute_sccs(&constraint_graph, fr_static));
- let mut scc_values = RegionValues::new(elements, universal_regions.len(), max_universe);
+ let mut scc_values =
+ RegionValues::new(elements, universal_regions.len(), &placeholder_indices);
for region in liveness_constraints.rows() {
let scc = constraint_sccs.scc(region);
self.scc_values.add_element(scc, variable);
}
- NLLRegionVariableOrigin::BoundRegion(ui) => {
- // Each placeholder region X outlives its
- // associated universe but nothing else. Every
- // placeholder region is always in a universe that
- // contains `ui` -- but when placeholder regions
- // are placed into an SCC, that SCC may include
- // things from other universes that do not include
- // `ui`.
+ NLLRegionVariableOrigin::Placeholder(placeholder) => {
+ // Each placeholder region is only visible from
+ // its universe `ui` and its superuniverses. So we
+ // can't just add it into `scc` unless the
+ // universe of the scc can name this region.
let scc_universe = self.scc_universes[scc];
- if ui.is_subset_of(scc_universe) {
- self.scc_values.add_element(scc, ui);
+ if placeholder.universe.is_subset_of(scc_universe) {
+ self.scc_values.add_element(scc, placeholder);
} else {
self.add_incompatible_universe(scc);
}
// B's value, and check whether all of them are nameable
// from universe_a
self.scc_values
- .subuniverses_contained_in(scc_b)
- .all(|u| u.is_subset_of(universe_a))
+ .placeholders_contained_in(scc_b)
+ .all(|p| p.universe.is_subset_of(universe_a))
}
/// Extend `scc` so that it can outlive some placeholder region
);
}
- NLLRegionVariableOrigin::BoundRegion(universe) => {
- self.check_bound_universal_region(infcx, mir, mir_def_id, fr, universe);
+ NLLRegionVariableOrigin::Placeholder(placeholder) => {
+ self.check_bound_universal_region(infcx, mir, mir_def_id, fr, placeholder);
}
NLLRegionVariableOrigin::Existential => {
assert!(self.scc_universes[longer_fr_scc] == ty::UniverseIndex::ROOT);
debug_assert!(
self.scc_values
- .subuniverses_contained_in(longer_fr_scc)
+ .placeholders_contained_in(longer_fr_scc)
.next()
.is_none()
);
mir: &Mir<'tcx>,
_mir_def_id: DefId,
longer_fr: RegionVid,
- universe: ty::UniverseIndex,
+ placeholder: ty::Placeholder,
) {
- debug!("check_bound_universal_region(fr={:?})", longer_fr);
+ debug!(
+ "check_bound_universal_region(fr={:?}, placeholder={:?})",
+ longer_fr, placeholder,
+ );
let longer_fr_scc = self.constraint_sccs.scc(longer_fr);
.find(|element| match element {
RegionElement::Location(_) => true,
RegionElement::RootUniversalRegion(_) => true,
- RegionElement::SubUniversalRegion(ui) => *ui != universe,
+ RegionElement::PlaceholderRegion(placeholder1) => placeholder != *placeholder1,
})
} {
Some(v) => v,
let error_region = match error_element {
RegionElement::Location(l) => self.find_sub_region_live_at(longer_fr, l),
RegionElement::RootUniversalRegion(r) => r,
- RegionElement::SubUniversalRegion(error_ui) => self.definitions
+ RegionElement::PlaceholderRegion(error_placeholder) => self.definitions
.iter_enumerated()
.filter_map(|(r, definition)| match definition.origin {
- NLLRegionVariableOrigin::BoundRegion(ui) if error_ui == ui => Some(r),
+ NLLRegionVariableOrigin::Placeholder(p) if p == error_placeholder => Some(r),
_ => None,
})
.next()
use rustc::mir::{BasicBlock, Location, Mir};
use rustc::ty::{self, RegionVid};
use rustc_data_structures::bit_set::{HybridBitSet, SparseBitMatrix};
+use rustc_data_structures::fx::FxHashMap;
use rustc_data_structures::indexed_vec::Idx;
use rustc_data_structures::indexed_vec::IndexVec;
use std::fmt::Debug;
impl RegionValueElements {
crate fn new(mir: &Mir<'_>) -> Self {
let mut num_points = 0;
- let statements_before_block: IndexVec<BasicBlock, usize> = mir
- .basic_blocks()
+ let statements_before_block: IndexVec<BasicBlock, usize> = mir.basic_blocks()
.iter()
.map(|block_data| {
let v = num_points;
let mut basic_blocks = IndexVec::with_capacity(num_points);
for (bb, bb_data) in mir.basic_blocks().iter_enumerated() {
- basic_blocks.extend((0 .. bb_data.statements.len() + 1).map(|_| bb));
+ basic_blocks.extend((0..bb_data.statements.len() + 1).map(|_| bb));
}
Self {
let block = self.basic_blocks[index];
let start_index = self.statements_before_block[block];
let statement_index = index.index() - start_index;
- Location { block, statement_index }
+ Location {
+ block,
+ statement_index,
+ }
}
/// Sometimes we get point-indices back from bitsets that may be
index: PointIndex,
stack: &mut Vec<PointIndex>,
) {
- let Location { block, statement_index } = self.to_location(index);
+ let Location {
+ block,
+ statement_index,
+ } = self.to_location(index);
if statement_index == 0 {
// If this is a basic block head, then the predecessors are
// the the terminators of other basic blocks
stack.extend(
- mir
- .predecessors_for(block)
+ mir.predecessors_for(block)
.iter()
.map(|&pred_bb| mir.terminator_loc(pred_bb))
.map(|pred_loc| self.point_from_location(pred_loc)),
pub struct PointIndex { DEBUG_FORMAT = "PointIndex({})" }
}
-/// A single integer representing a (non-zero) `UniverseIndex`.
-/// Computed just by subtracting one from `UniverseIndex`; this is
-/// because the `0` value for `UniverseIndex` represents the root
-/// universe, and we don't need/want a bit for that one.
+/// A single integer representing a `ty::Placeholder`.
newtype_index! {
pub struct PlaceholderIndex { DEBUG_FORMAT = "PlaceholderIndex({})" }
}
/// A subuniverse from a subuniverse (e.g., instantiated from a
/// `for<'a> fn(&'a u32)` type).
- SubUniversalRegion(ty::UniverseIndex),
+ PlaceholderRegion(ty::Placeholder),
}
/// When we initially compute liveness, we use a bit matrix storing
/// Adds all the elements in the given bit array into the given
/// region. Returns true if any of them are newly added.
crate fn add_elements(&mut self, row: N, locations: &HybridBitSet<PointIndex>) -> bool {
- debug!("LivenessValues::add_elements(row={:?}, locations={:?})", row, locations);
+ debug!(
+ "LivenessValues::add_elements(row={:?}, locations={:?})",
+ row, locations
+ );
self.points.union_into_row(row, locations)
}
}
}
+/// Maps from `ty::Placeholder` values that are used in the rest of
+/// rustc to the internal `PlaceholderIndex` values that are used in
+/// NLL.
+#[derive(Default)]
+crate struct PlaceholderIndices {
+ to_index: FxHashMap<ty::Placeholder, PlaceholderIndex>,
+ from_index: IndexVec<PlaceholderIndex, ty::Placeholder>,
+}
+
+impl PlaceholderIndices {
+ crate fn insert(&mut self, placeholder: ty::Placeholder) -> PlaceholderIndex {
+ let PlaceholderIndices {
+ to_index,
+ from_index,
+ } = self;
+ *to_index
+ .entry(placeholder)
+ .or_insert_with(|| from_index.push(placeholder))
+ }
+
+ crate fn lookup_index(&self, placeholder: ty::Placeholder) -> PlaceholderIndex {
+ self.to_index[&placeholder]
+ }
+
+ crate fn lookup_placeholder(&self, placeholder: PlaceholderIndex) -> ty::Placeholder {
+ self.from_index[placeholder]
+ }
+
+ crate fn len(&self) -> usize {
+ self.from_index.len()
+ }
+}
+
+impl ::std::iter::FromIterator<ty::Placeholder> for PlaceholderIndices {
+ fn from_iter<I>(iter: I) -> Self
+ where
+ I: IntoIterator<Item = ty::Placeholder>,
+ {
+ let mut result = Self::default();
+ iter.into_iter().for_each(|p| {
+ result.insert(p);
+ });
+ result
+ }
+}
+
/// Stores the full values for a set of regions (in contrast to
/// `LivenessValues`, which only stores those points in the where a
/// region is live). The full value for a region may contain points in
#[derive(Clone)]
crate struct RegionValues<N: Idx> {
elements: Rc<RegionValueElements>,
+ placeholder_indices: Rc<PlaceholderIndices>,
points: SparseBitMatrix<N, PointIndex>,
free_regions: SparseBitMatrix<N, RegionVid>,
crate fn new(
elements: &Rc<RegionValueElements>,
num_universal_regions: usize,
- max_universe: ty::UniverseIndex,
+ placeholder_indices: &Rc<PlaceholderIndices>,
) -> Self {
- let num_placeholders = max_universe.as_usize();
+ let num_placeholders = placeholder_indices.len();
Self {
elements: elements.clone(),
points: SparseBitMatrix::new(elements.num_points),
+ placeholder_indices: placeholder_indices.clone(),
free_regions: SparseBitMatrix::new(num_universal_regions),
placeholders: SparseBitMatrix::new(num_placeholders),
}
/// Returns the locations contained within a given region `r`.
crate fn locations_outlived_by<'a>(&'a self, r: N) -> impl Iterator<Item = Location> + 'a {
- self.points
- .row(r)
- .into_iter()
- .flat_map(move |set| {
- set.iter()
- .take_while(move |&p| self.elements.point_in_range(p))
- .map(move |p| self.elements.to_location(p))
- })
+ self.points.row(r).into_iter().flat_map(move |set| {
+ set.iter()
+ .take_while(move |&p| self.elements.point_in_range(p))
+ .map(move |p| self.elements.to_location(p))
+ })
}
/// Returns just the universal regions that are contained in a given region's value.
}
/// Returns all the elements contained in a given region's value.
- crate fn subuniverses_contained_in<'a>(
+ crate fn placeholders_contained_in<'a>(
&'a self,
r: N,
- ) -> impl Iterator<Item = ty::UniverseIndex> + 'a {
+ ) -> impl Iterator<Item = ty::Placeholder> + 'a {
self.placeholders
.row(r)
.into_iter()
.flat_map(|set| set.iter())
- .map(|p| ty::UniverseIndex::from_u32((p.index() + 1) as u32))
+ .map(move |p| self.placeholder_indices.lookup_placeholder(p))
}
/// Returns all the elements contained in a given region's value.
crate fn elements_contained_in<'a>(&'a self, r: N) -> impl Iterator<Item = RegionElement> + 'a {
let points_iter = self.locations_outlived_by(r).map(RegionElement::Location);
- let free_regions_iter = self
- .universal_regions_outlived_by(r)
+ let free_regions_iter = self.universal_regions_outlived_by(r)
.map(RegionElement::RootUniversalRegion);
- let subuniverses_iter = self
- .subuniverses_contained_in(r)
- .map(RegionElement::SubUniversalRegion);
+ let placeholder_universes_iter = self.placeholders_contained_in(r)
+ .map(RegionElement::PlaceholderRegion);
points_iter
.chain(free_regions_iter)
- .chain(subuniverses_iter)
+ .chain(placeholder_universes_iter)
}
/// Returns a "pretty" string value of the region. Meant for debugging.
}
}
-impl ToElementIndex for ty::UniverseIndex {
+impl ToElementIndex for ty::Placeholder {
fn add_to_row<N: Idx>(self, values: &mut RegionValues<N>, row: N) -> bool {
- let index = PlaceholderIndex::new(self.as_usize() - 1);
+ let index = values.placeholder_indices.lookup_index(self);
values.placeholders.insert(row, index)
}
fn contained_in_row<N: Idx>(self, values: &RegionValues<N>, row: N) -> bool {
- let index = PlaceholderIndex::new(self.as_usize() - 1);
+ let index = values.placeholder_indices.lookup_index(self);
values.placeholders.contains(row, index)
}
}
result.push_str(&format!("{:?}", fr));
}
- RegionElement::SubUniversalRegion(ur) => {
+ RegionElement::PlaceholderRegion(placeholder) => {
if let Some((location1, location2)) = open_location {
push_sep(&mut result);
push_location_range(&mut result, location1, location2);
}
push_sep(&mut result);
- result.push_str(&format!("{:?}", ur));
+ result.push_str(&format!("{:?}", placeholder));
}
}
}
use borrow_check::location::LocationTable;
use borrow_check::nll::constraints::{ConstraintCategory, ConstraintSet, OutlivesConstraint};
use borrow_check::nll::facts::AllFacts;
-use borrow_check::nll::region_infer::values::{LivenessValues, RegionValueElements};
+use borrow_check::nll::region_infer::values::LivenessValues;
+use borrow_check::nll::region_infer::values::PlaceholderIndices;
+use borrow_check::nll::region_infer::values::RegionValueElements;
use borrow_check::nll::region_infer::{ClosureRegionRequirementsExt, TypeTest};
use borrow_check::nll::renumber;
use borrow_check::nll::type_check::free_region_relations::{
use rustc::ty::fold::TypeFoldable;
use rustc::ty::subst::Subst;
use rustc::ty::{self, CanonicalTy, RegionVid, ToPolyTraitRef, Ty, TyCtxt, TyKind};
-use std::{fmt, iter};
use std::rc::Rc;
+use std::{fmt, iter};
use syntax_pos::{Span, DUMMY_SP};
use transform::{MirPass, MirSource};
-use rustc_data_structures::fx::FxHashSet;
use either::Either;
+use rustc_data_structures::fx::FxHashSet;
macro_rules! span_mirbug {
($context:expr, $elem:expr, $($message:tt)*) => ({
outlives_constraints: ConstraintSet::default(),
type_tests: Vec::default(),
};
+ let mut placeholder_indices = PlaceholderIndices::default();
let CreateResult {
universal_region_relations,
borrow_set,
all_facts,
constraints: &mut constraints,
+ placeholder_indices: &mut placeholder_indices,
};
type_check_internal(
cx.equate_inputs_and_outputs(mir, universal_regions, &normalized_inputs_and_output);
liveness::generate(cx, mir, elements, flow_inits, move_data, location_table);
- cx.borrowck_context.as_mut().map(|bcx| translate_outlives_facts(bcx));
+ cx.borrowck_context
+ .as_mut()
+ .map(|bcx| translate_outlives_facts(bcx));
},
);
MirTypeckResults {
constraints,
+ placeholder_indices,
universal_region_relations,
}
}
fn translate_outlives_facts(cx: &mut BorrowCheckContext) {
if let Some(facts) = cx.all_facts {
let location_table = cx.location_table;
- facts.outlives.extend(
- cx.constraints.outlives_constraints.iter().flat_map(|constraint: &OutlivesConstraint| {
- if let Some(from_location) = constraint.locations.from_location() {
- Either::Left(iter::once((
- constraint.sup,
- constraint.sub,
- location_table.mid_index(from_location),
- )))
- } else {
- Either::Right(location_table.all_points().map(move |location| {
- (constraint.sup, constraint.sub, location)
- }))
- }
- })
- );
+ facts
+ .outlives
+ .extend(cx.constraints.outlives_constraints.iter().flat_map(
+ |constraint: &OutlivesConstraint| {
+ if let Some(from_location) = constraint.locations.from_location() {
+ Either::Left(iter::once((
+ constraint.sup,
+ constraint.sub,
+ location_table.mid_index(from_location),
+ )))
+ } else {
+ Either::Right(
+ location_table
+ .all_points()
+ .map(move |location| (constraint.sup, constraint.sub, location)),
+ )
+ }
+ },
+ ));
}
}
all_facts: &'a mut Option<AllFacts>,
borrow_set: &'a BorrowSet<'tcx>,
constraints: &'a mut MirTypeckRegionConstraints<'tcx>,
+ placeholder_indices: &'a mut PlaceholderIndices,
}
crate struct MirTypeckResults<'tcx> {
crate constraints: MirTypeckRegionConstraints<'tcx>,
+ crate placeholder_indices: PlaceholderIndices,
crate universal_region_relations: Rc<UniversalRegionRelations<'tcx>>,
}
/// delegate.
fn push_outlives(&mut self, sup: ty::Region<'tcx>, sub: ty::Region<'tcx>);
- /// Creates a new region variable representing an instantiated
- /// higher-ranked region; this will be either existential or
- /// universal depending on the context. So e.g. if you have
- /// `for<'a> fn(..) <: for<'b> fn(..)`, then we will first
- /// instantiate `'b` with a universally quantitifed region and
- /// then `'a` with an existentially quantified region (the order
- /// is important so that the existential region `'a` can see the
- /// universal one).
- fn next_region_var(
- &mut self,
- universally_quantified: UniversallyQuantified,
- ) -> ty::Region<'tcx>;
+ /// Creates a new universe index. Used when instantiating placeholders.
+ fn next_subuniverse(&mut self) -> ty::UniverseIndex;
+
+ /// Creates a new region variable representing a higher-ranked
+ /// region that is instantiated existentially. This creates an
+ /// inference variable, typically.
+ ///
+ /// So e.g. if you have `for<'a> fn(..) <: for<'b> fn(..)`, then
+ /// we will invoke this method to instantiate `'a` with an
+ /// inference variable (though `'b` would be instantiated first,
+ /// as a placeholder).
+ fn next_existential_region_var(&mut self) -> ty::Region<'tcx>;
+
+ /// Creates a new region variable representing a
+ /// higher-ranked region that is instantiated universally.
+ /// This creates a new region placeholder, typically.
+ ///
+ /// So e.g. if you have `for<'a> fn(..) <: for<'b> fn(..)`, then
+ /// we will invoke this method to instantiate `'b` with a
+ /// placeholder region.
+ fn next_placeholder_region(&mut self, placeholder: ty::Placeholder) -> ty::Region<'tcx>;
/// Creates a new existential region in the given universe. This
/// is used when handling subtyping and type variables -- if we
}
impl TypeRelatingDelegate<'tcx> for NllTypeRelatingDelegate<'_, '_, '_, 'tcx> {
- fn next_region_var(
- &mut self,
- universally_quantified: UniversallyQuantified,
- ) -> ty::Region<'tcx> {
- let origin = if universally_quantified.0 {
- NLLRegionVariableOrigin::BoundRegion(self.infcx.create_subuniverse())
- } else {
- NLLRegionVariableOrigin::Existential
- };
+ fn next_subuniverse(&mut self) -> ty::UniverseIndex {
+ self.infcx.create_subuniverse()
+ }
+
+ fn next_existential_region_var(&mut self) -> ty::Region<'tcx> {
+ let origin = NLLRegionVariableOrigin::Existential;
+ self.infcx.next_nll_region_var(origin)
+ }
+
+ fn next_placeholder_region(&mut self, placeholder: ty::Placeholder) -> ty::Region<'tcx> {
+ let origin = NLLRegionVariableOrigin::Placeholder(placeholder);
+ if let Some(borrowck_context) = &mut self.borrowck_context {
+ borrowck_context.placeholder_indices.insert(placeholder);
+ }
self.infcx.next_nll_region_var(origin)
}
universally_quantified: UniversallyQuantified,
) -> BoundRegionScope<'tcx> {
let mut scope = BoundRegionScope::default();
+
+ // Create a callback that creates (via the delegate) either an
+ // existential or placeholder region as needed.
+ let mut next_region = {
+ let delegate = &mut self.delegate;
+ let mut lazy_universe = None;
+ move |br: ty::BoundRegion| {
+ if universally_quantified.0 {
+ // The first time this closure is called, create a
+ // new universe for the placeholders we will make
+ // from here out.
+ let universe = lazy_universe.unwrap_or_else(|| {
+ let universe = delegate.next_subuniverse();
+ lazy_universe = Some(universe);
+ universe
+ });
+
+ let placeholder = ty::Placeholder { universe, name: br };
+ delegate.next_placeholder_region(placeholder)
+ } else {
+ delegate.next_existential_region_var()
+ }
+ }
+ };
+
value.skip_binder().visit_with(&mut ScopeInstantiator {
- delegate: &mut self.delegate,
+ next_region: &mut next_region,
target_index: ty::INNERMOST,
- universally_quantified,
bound_region_scope: &mut scope,
});
+
scope
}
/// binder depth, and finds late-bound regions targeting the
/// `for<..`>. For each of those, it creates an entry in
/// `bound_region_scope`.
-struct ScopeInstantiator<'me, 'tcx: 'me, D>
-where
- D: TypeRelatingDelegate<'tcx> + 'me,
-{
- delegate: &'me mut D,
+struct ScopeInstantiator<'me, 'tcx: 'me> {
+ next_region: &'me mut dyn FnMut(ty::BoundRegion) -> ty::Region<'tcx>,
// The debruijn index of the scope we are instantiating.
target_index: ty::DebruijnIndex,
- universally_quantified: UniversallyQuantified,
bound_region_scope: &'me mut BoundRegionScope<'tcx>,
}
-impl<'me, 'tcx, D> TypeVisitor<'tcx> for ScopeInstantiator<'me, 'tcx, D>
-where
- D: TypeRelatingDelegate<'tcx>,
-{
+impl<'me, 'tcx> TypeVisitor<'tcx> for ScopeInstantiator<'me, 'tcx> {
fn visit_binder<T: TypeFoldable<'tcx>>(&mut self, t: &ty::Binder<T>) -> bool {
self.target_index.shift_in(1);
t.super_visit_with(self);
fn visit_region(&mut self, r: ty::Region<'tcx>) -> bool {
let ScopeInstantiator {
- universally_quantified,
bound_region_scope,
- delegate,
+ next_region,
..
} = self;
bound_region_scope
.map
.entry(*br)
- .or_insert_with(|| delegate.next_region_var(*universally_quantified));
+ .or_insert_with(|| next_region(*br));
}
_ => {}
use hair::*;
use rustc::mir::interpret::EvalErrorKind::BoundsCheck;
use rustc::mir::*;
+use rustc::ty::Variance;
use rustc_data_structures::indexed_vec::Idx;
ty: expr.ty,
}))),
+ ExprKind::PlaceTypeAscription { source, user_ty } => {
+ let place = unpack!(block = this.as_place(block, source));
+ this.cfg.push(
+ block,
+ Statement {
+ source_info,
+ kind: StatementKind::AscribeUserType(
+ place.clone(),
+ Variance::Invariant,
+ user_ty,
+ ),
+ },
+ );
+ block.and(place)
+ }
+ ExprKind::ValueTypeAscription { source, user_ty } => {
+ let source = this.hir.mirror(source);
+ let temp = unpack!(
+ block = this.as_temp(block, source.temp_lifetime, source, mutability)
+ );
+ this.cfg.push(
+ block,
+ Statement {
+ source_info,
+ kind: StatementKind::AscribeUserType(
+ Place::Local(temp.clone()),
+ Variance::Invariant,
+ user_ty,
+ ),
+ },
+ );
+ block.and(Place::Local(temp))
+ }
+
ExprKind::Array { .. }
| ExprKind::Tuple { .. }
| ExprKind::Adt { .. }
| ExprKind::Continue { .. }
| ExprKind::Return { .. }
| ExprKind::InlineAsm { .. }
- | ExprKind::StaticRef { .. } => {
+ | ExprKind::StaticRef { .. }
+ | ExprKind::PlaceTypeAscription { .. }
+ | ExprKind::ValueTypeAscription { .. } => {
// these do not have corresponding `Rvalue` variants,
// so make an operand and then return that
debug_assert!(match Category::of(&expr.kind) {
| ExprKind::Index { .. }
| ExprKind::SelfRef
| ExprKind::VarRef { .. }
- | ExprKind::StaticRef { .. } => Some(Category::Place),
+ | ExprKind::StaticRef { .. }
+ | ExprKind::PlaceTypeAscription { .. }
+ | ExprKind::ValueTypeAscription { .. } => Some(Category::Place),
ExprKind::LogicalOp { .. }
| ExprKind::If { .. }
);
exit_block.unit()
}
- ExprKind::Call { ty, fun, args } => {
+ ExprKind::Call { ty, fun, args, from_hir_call } => {
// FIXME(canndrew): This is_never should probably be an is_uninhabited
let diverges = expr.ty.is_never();
let intrinsic = match ty.sty {
} else {
Some((destination.clone(), success))
},
+ from_hir_call,
},
);
success.unit()
}
// Avoid creating a temporary
- ExprKind::VarRef { .. } | ExprKind::SelfRef | ExprKind::StaticRef { .. } => {
+ ExprKind::VarRef { .. } |
+ ExprKind::SelfRef |
+ ExprKind::StaticRef { .. } |
+ ExprKind::PlaceTypeAscription { .. } |
+ ExprKind::ValueTypeAscription { .. } => {
debug_assert!(Category::of(&expr.kind) == Some(Category::Place));
let place = unpack!(block = this.as_place(block, expr));
| ExprKind::Literal { .. }
| ExprKind::Yield { .. } => {
debug_assert!(match Category::of(&expr.kind).unwrap() {
+ // should be handled above
Category::Rvalue(RvalueFunc::Into) => false,
+
+ // must be handled above or else we get an
+ // infinite loop in the builder; see
+ // e.g. `ExprKind::VarRef` above
+ Category::Place => false,
+
_ => true,
});
args: vec![val, expect],
destination: Some((eq_result.clone(), eq_block)),
cleanup: Some(cleanup),
+ from_hir_call: false,
});
// check the result
let ty_hir_id = fn_decl.inputs[index].hir_id;
let ty_span = tcx.hir.span(tcx.hir.hir_to_node_id(ty_hir_id));
opt_ty_info = Some(ty_span);
- self_arg = if index == 0 && fn_decl.has_implicit_self {
- Some(ImplicitSelfBinding)
+ self_arg = if index == 0 && fn_decl.implicit_self.has_implicit_self() {
+ match fn_decl.implicit_self {
+ hir::ImplicitSelfKind::Imm => Some(ImplicitSelfKind::Imm),
+ hir::ImplicitSelfKind::Mut => Some(ImplicitSelfKind::Mut),
+ hir::ImplicitSelfKind::ImmRef => Some(ImplicitSelfKind::ImmRef),
+ hir::ImplicitSelfKind::MutRef => Some(ImplicitSelfKind::MutRef),
+ _ => None,
+ }
} else {
None
};
///////////////////////////////////////////////////////////////////////////
/// the main entry point for building MIR for a function
-struct ImplicitSelfBinding;
-
struct ArgInfo<'gcx>(Ty<'gcx>,
Option<Span>,
Option<&'gcx hir::Pat>,
- Option<ImplicitSelfBinding>);
+ Option<ImplicitSelfKind>);
fn construct_fn<'a, 'gcx, 'tcx, A>(hir: Cx<'a, 'gcx, 'tcx>,
fn_id: ast::NodeId,
PatternKind::Binding { mutability, var, mode: BindingMode::ByValue, .. } => {
self.local_decls[local].mutability = mutability;
self.local_decls[local].is_user_variable =
- if let Some(ImplicitSelfBinding) = self_binding {
- Some(ClearCrossCrate::Set(BindingForm::ImplicitSelf))
+ if let Some(kind) = self_binding {
+ Some(ClearCrossCrate::Set(BindingForm::ImplicitSelf(*kind)))
} else {
let binding_mode = ty::BindingMode::BindByValue(mutability.into());
Some(ClearCrossCrate::Set(BindingForm::Var(VarBindingForm {
#[derive(Clone, Debug)]
enum ConstEvalError {
NeedsRfc(String),
- NotConst(String),
}
impl fmt::Display for ConstEvalError {
msg
)
}
- NotConst(ref msg) => write!(f, "{}", msg),
}
}
}
use self::ConstEvalError::*;
match *self {
NeedsRfc(_) => "this feature needs an rfc before being allowed inside constants",
- NotConst(_) => "this feature is not compatible with constant evaluation",
}
}
ecx.goto_block(ret)?; // fully evaluated and done
return Ok(None);
}
- return Err(
- ConstEvalError::NotConst(format!("calling non-const fn `{}`", instance)).into(),
- );
}
// This is a const fn. Call it.
Ok(Some(match ecx.load_mir(instance.def) {
self.propagate_bits_into_entry_set_for(in_out, *target, dirty_list);
}
}
- mir::TerminatorKind::Call { cleanup, ref destination, func: _, args: _ } => {
+ mir::TerminatorKind::Call { cleanup, ref destination, .. } => {
if let Some(unwind) = cleanup {
if !self.dead_unwinds.contains(bb) {
self.propagate_bits_into_entry_set_for(in_out, unwind, dirty_list);
self.gather_operand(value);
self.gather_init(location, InitKind::Deep);
}
- TerminatorKind::Call { ref func, ref args, ref destination, cleanup: _ } => {
+ TerminatorKind::Call {
+ ref func,
+ ref args,
+ ref destination,
+ cleanup: _,
+ from_hir_call: _,
+ } => {
self.gather_operand(func);
for arg in args {
self.gather_operand(arg);
use rustc::hir;
use rustc::hir::def_id::LocalDefId;
use rustc::mir::{BorrowKind};
+use syntax_pos::Span;
impl<'tcx> Mirror<'tcx> for &'tcx hir::Expr {
type Output = Expr<'tcx>;
let kind = match expr.node {
// Here comes the interesting stuff:
- hir::ExprKind::MethodCall(.., ref args) => {
+ hir::ExprKind::MethodCall(_, method_span, ref args) => {
// Rewrite a.b(c) into UFCS form like Trait::b(a, c)
- let expr = method_callee(cx, expr, None);
+ let expr = method_callee(cx, expr, method_span,None);
let args = args.iter()
.map(|e| e.to_ref())
.collect();
ty: expr.ty,
fun: expr.to_ref(),
args,
+ from_hir_call: true,
}
}
// rewrite f(u, v) into FnOnce::call_once(f, (u, v))
- let method = method_callee(cx, expr, None);
+ let method = method_callee(cx, expr, fun.span,None);
let arg_tys = args.iter().map(|e| cx.tables().expr_ty_adjusted(e));
let tupled_args = Expr {
ty: method.ty,
fun: method.to_ref(),
args: vec![fun.to_ref(), tupled_args.to_ref()],
+ from_hir_call: true,
}
} else {
let adt_data = if let hir::ExprKind::Path(hir::QPath::Resolved(_, ref path)) =
ty: cx.tables().node_id_to_type(fun.hir_id),
fun: fun.to_ref(),
args: args.to_ref(),
+ from_hir_call: true,
}
}
}
ExprKind::Cast { source }
}
}
- hir::ExprKind::Type(ref source, _) => return source.make_mirror(cx),
+ hir::ExprKind::Type(ref source, ref ty) => {
+ let user_provided_tys = cx.tables.user_provided_tys();
+ let user_ty = *user_provided_tys
+ .get(ty.hir_id)
+ .expect(&format!("{:?} not found in user_provided_tys, source: {:?}", ty, source));
+ if source.is_place_expr() {
+ ExprKind::PlaceTypeAscription {
+ source: source.to_ref(),
+ user_ty,
+ }
+ } else {
+ ExprKind::ValueTypeAscription {
+ source: source.to_ref(),
+ user_ty,
+ }
+ }
+ }
hir::ExprKind::Box(ref value) => {
ExprKind::Box {
value: value.to_ref(),
fn method_callee<'a, 'gcx, 'tcx>(
cx: &mut Cx<'a, 'gcx, 'tcx>,
expr: &hir::Expr,
+ span: Span,
overloaded_callee: Option<(DefId, &'tcx Substs<'tcx>)>,
) -> Expr<'tcx> {
let temp_lifetime = cx.region_scope_tree.temporary_scope(expr.hir_id.local_id);
Expr {
temp_lifetime,
ty,
- span: expr.span,
+ span,
kind: ExprKind::Literal {
literal: ty::Const::zero_sized(cx.tcx(), ty),
user_ty,
expr: &'tcx hir::Expr,
args: Vec<ExprRef<'tcx>>)
-> ExprKind<'tcx> {
- let fun = method_callee(cx, expr, None);
+ let fun = method_callee(cx, expr, expr.span, None);
ExprKind::Call {
ty: fun.ty,
fun: fun.to_ref(),
args,
+ from_hir_call: false,
}
}
// construct the complete expression `foo()` for the overloaded call,
// which will yield the &T type
let temp_lifetime = cx.region_scope_tree.temporary_scope(expr.hir_id.local_id);
- let fun = method_callee(cx, expr, overloaded_callee);
+ let fun = method_callee(cx, expr, expr.span, overloaded_callee);
let ref_expr = Expr {
temp_lifetime,
ty: ref_ty,
ty: fun.ty,
fun: fun.to_ref(),
args,
+ from_hir_call: false,
},
};
ty: Ty<'tcx>,
fun: ExprRef<'tcx>,
args: Vec<ExprRef<'tcx>>,
+ // Whether this is from a call in HIR, rather than from an overloaded
+ // operator. True for overloaded function call.
+ from_hir_call: bool,
},
Deref {
arg: ExprRef<'tcx>,
fields: Vec<FieldExprRef<'tcx>>,
base: Option<FruInfo<'tcx>>
},
+ PlaceTypeAscription {
+ source: ExprRef<'tcx>,
+ /// Type that the user gave to this expression
+ user_ty: CanonicalTy<'tcx>,
+ },
+ ValueTypeAscription {
+ source: ExprRef<'tcx>,
+ /// Type that the user gave to this expression
+ user_ty: CanonicalTy<'tcx>,
+ },
Closure {
closure_id: DefId,
substs: UpvarSubsts<'tcx>,
/// Undefined bytes
impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> Memory<'a, 'mir, 'tcx, M> {
- // FIXME(solson): This is a very naive, slow version.
+ // FIXME: Add a fast version for the common, nonoverlapping case
fn copy_undef_mask(
&mut self,
src: Pointer,
}
ty::Error |
ty::Infer(_) |
+ ty::UnnormalizedProjection(..) |
ty::Projection(..) |
ty::Param(_) |
ty::GeneratorWitness(_) |
args: vec![Operand::Move(ref_loc)],
destination: Some((dest, next)),
cleanup: Some(cleanup),
+ from_hir_call: true,
}, false);
}
Some(BasicBlock::new(3))
} else {
None
- }
+ },
+ from_hir_call: true,
}, false);
if let Adjustment::RefMut = rcvr_adjustment {
args: vec![lhs, rhs],
destination: Some((place, bb)),
cleanup: None,
+ from_hir_call: false,
},
});
}
};
match terminator.kind {
- TerminatorKind::Call { mut func, mut args, .. } => {
+ TerminatorKind::Call { mut func, mut args, from_hir_call, .. } => {
self.visit_operand(&mut func, loc);
for arg in &mut args {
self.visit_operand(arg, loc);
func,
args,
cleanup: None,
- destination: Some((Place::Local(new_temp), new_target))
+ destination: Some((Place::Local(new_temp), new_target)),
+ from_hir_call,
},
..terminator
};
use rustc::mir::visit::{PlaceContext, Visitor};
use rustc::middle::lang_items;
use rustc_target::spec::abi::Abi;
-use syntax::attr;
use syntax::ast::LitKind;
use syntax::feature_gate::{UnstableFeatures, feature_err, emit_feature_err, GateIssue};
use syntax_pos::{Span, DUMMY_SP};
let fn_ty = func.ty(self.mir, self.tcx);
let mut callee_def_id = None;
- let (mut is_shuffle, mut is_const_fn) = (false, None);
+ let (mut is_shuffle, mut is_const_fn) = (false, false);
if let ty::FnDef(def_id, _) = fn_ty.sty {
callee_def_id = Some(def_id);
match self.tcx.fn_sig(def_id).abi() {
| "unchecked_shr"
| "add_with_overflow"
| "sub_with_overflow"
- | "mul_with_overflow" => is_const_fn = Some(def_id),
+ | "mul_with_overflow"
+ // no need to check feature gates, intrinsics are only callable from the
+ // libstd or with forever unstable feature gates
+ => is_const_fn = true,
+ // special intrinsic that can be called diretly without an intrinsic
+ // feature gate needs a language feature gate
"transmute" => {
+ // never promote transmute calls
if self.mode != Mode::Fn {
- is_const_fn = Some(def_id);
+ is_const_fn = true;
+ // const eval transmute calls only with the feature gate
if !self.tcx.sess.features_untracked().const_transmute {
emit_feature_err(
&self.tcx.sess.parse_sess, "const_transmute",
}
}
_ => {
- if self.tcx.is_const_fn(def_id) || self.is_const_panic_fn(def_id) {
- is_const_fn = Some(def_id);
+ // in normal functions we only care about promotion
+ if self.mode == Mode::Fn {
+ // never promote const fn calls of
+ // functions without #[rustc_promotable]
+ if self.tcx.is_promotable_const_fn(def_id) {
+ is_const_fn = true;
+ }
+ } else {
+ // stable const fn or unstable const fns with their feature gate
+ // active
+ if self.tcx.is_const_fn(def_id) {
+ is_const_fn = true;
+ } else if self.is_const_panic_fn(def_id) {
+ // check the const_panic feature gate
+ // FIXME: cannot allow this inside `allow_internal_unstable` because
+ // that would make `panic!` insta stable in constants, since the
+ // macro is marked with the attr
+ if self.tcx.sess.features_untracked().const_panic {
+ is_const_fn = true;
+ } else {
+ // don't allow panics in constants without the feature gate
+ emit_feature_err(
+ &self.tcx.sess.parse_sess,
+ "const_panic",
+ self.span,
+ GateIssue::Language,
+ &format!("panicking in {}s is unstable", self.mode),
+ );
+ }
+ } else if let Some(feature) = self.tcx.is_unstable_const_fn(def_id) {
+ // check `#[unstable]` const fns or `#[rustc_const_unstable]`
+ // functions without the feature gate active in this crate to report
+ // a better error message than the one below
+ if self.span.allows_unstable() {
+ // `allow_internal_unstable` can make such calls stable
+ is_const_fn = true;
+ } else {
+ let mut err = self.tcx.sess.struct_span_err(self.span,
+ &format!("`{}` is not yet stable as a const fn",
+ self.tcx.item_path_str(def_id)));
+ help!(&mut err,
+ "in Nightly builds, add `#![feature({})]` \
+ to the crate attributes to enable",
+ feature);
+ err.emit();
+ }
+ } else {
+ // FIXME(#24111) Remove this check when const fn stabilizes
+ let (msg, note) = if let UnstableFeatures::Disallow =
+ self.tcx.sess.opts.unstable_features {
+ (format!("calls in {}s are limited to \
+ tuple structs and tuple variants",
+ self.mode),
+ Some("a limited form of compile-time function \
+ evaluation is available on a nightly \
+ compiler via `const fn`"))
+ } else {
+ (format!("calls in {}s are limited \
+ to constant functions, \
+ tuple structs and tuple variants",
+ self.mode),
+ None)
+ };
+ let mut err = struct_span_err!(
+ self.tcx.sess,
+ self.span,
+ E0015,
+ "{}",
+ msg,
+ );
+ if let Some(note) = note {
+ err.span_note(self.span, note);
+ }
+ err.emit();
+ }
}
}
}
});
}
- // Const fn calls.
- if let Some(def_id) = is_const_fn {
- // check the const_panic feature gate or
- // find corresponding rustc_const_unstable feature
- // FIXME: cannot allow this inside `allow_internal_unstable` because that would make
- // `panic!` insta stable in constants, since the macro is marked with the attr
- if self.is_const_panic_fn(def_id) {
- if self.mode == Mode::Fn {
- // never promote panics
- self.qualif = Qualif::NOT_CONST;
- } else if !self.tcx.sess.features_untracked().const_panic {
- // don't allow panics in constants without the feature gate
- emit_feature_err(
- &self.tcx.sess.parse_sess,
- "const_panic",
- self.span,
- GateIssue::Language,
- &format!("panicking in {}s is unstable", self.mode),
- );
- }
- } else if let Some(&attr::Stability {
- const_stability: Some(ref feature_name),
- .. }) = self.tcx.lookup_stability(def_id) {
- if
- // feature-gate is not enabled,
- !self.tcx.features()
- .declared_lib_features
- .iter()
- .any(|&(ref sym, _)| sym == feature_name) &&
-
- // this doesn't come from a macro that has #[allow_internal_unstable]
- !self.span.allows_unstable()
- {
- self.qualif = Qualif::NOT_CONST;
- if self.mode != Mode::Fn {
- // inside a constant environment, not having the feature gate is
- // an error
- let mut err = self.tcx.sess.struct_span_err(self.span,
- &format!("`{}` is not yet stable as a const fn",
- self.tcx.item_path_str(def_id)));
- help!(&mut err,
- "in Nightly builds, add `#![feature({})]` \
- to the crate attributes to enable",
- feature_name);
- err.emit();
- }
- }
- }
- } else {
+ // non-const fn calls.
+ if !is_const_fn {
self.qualif = Qualif::NOT_CONST;
if self.mode != Mode::Fn {
- // FIXME(#24111) Remove this check when const fn stabilizes
- let (msg, note) = if let UnstableFeatures::Disallow =
- self.tcx.sess.opts.unstable_features {
- (format!("calls in {}s are limited to \
- tuple structs and tuple variants",
- self.mode),
- Some("a limited form of compile-time function \
- evaluation is available on a nightly \
- compiler via `const fn`"))
- } else {
- (format!("calls in {}s are limited \
- to constant functions, \
- tuple structs and tuple variants",
- self.mode),
- None)
- };
- let mut err = struct_span_err!(self.tcx.sess, self.span, E0015, "{}", msg);
- if let Some(note) = note {
- err.span_note(self.span, note);
- }
- err.emit();
+ self.tcx.sess.delay_span_bug(
+ self.span,
+ "should have reported an error about non-const fn calls in constants",
+ )
}
}
TerminatorKind::Call {
func,
args,
+ from_hir_call: _,
destination: _,
cleanup: _,
} => {
args: vec![Operand::Move(Place::Local(ref_place))],
destination: Some((unit_temp, succ)),
cleanup: unwind.into_option(),
+ from_hir_call: true,
},
- source_info: self.source_info
+ source_info: self.source_info,
}),
is_cleanup: unwind.is_cleanup(),
};
func: Operand::function_handle(tcx, free_func, substs, self.source_info.span),
args: args,
destination: Some((unit_temp, target)),
- cleanup: None
+ cleanup: None,
+ from_hir_call: false,
}; // FIXME(#43234)
let free_block = self.new_block(unwind, call);
use rustc::ty::cast::CastKind;
use rustc::hir::def::{Def, CtorKind};
use rustc::hir::def_id::DefId;
-use rustc::hir::map::blocks::FnLikeNode;
use rustc::middle::expr_use_visitor as euv;
use rustc::middle::mem_categorization as mc;
use rustc::middle::mem_categorization::Categorization;
use rustc::hir;
use rustc_data_structures::sync::Lrc;
use syntax::ast;
-use syntax::attr;
use syntax_pos::{Span, DUMMY_SP};
use self::Promotability::*;
use std::ops::{BitAnd, BitAndAssign, BitOr};
}
}
- fn handle_const_fn_call(&mut self, def_id: DefId,
- ret_ty: Ty<'gcx>, span: Span) -> Promotability {
- if self.type_promotability(ret_ty) == NotPromotable {
- return NotPromotable;
- }
-
- let node_check = if let Some(fn_id) = self.tcx.hir.as_local_node_id(def_id) {
- FnLikeNode::from_node(self.tcx.hir.get(fn_id)).map_or(false, |fn_like| {
- fn_like.constness() == hir::Constness::Const
- })
+ fn handle_const_fn_call(
+ &mut self,
+ def_id: DefId,
+ ) -> Promotability {
+ if self.tcx.is_promotable_const_fn(def_id) {
+ Promotable
} else {
- self.tcx.is_const_fn(def_id)
- };
-
- if !node_check {
- return NotPromotable
+ NotPromotable
}
-
- if let Some(&attr::Stability {
- const_stability: Some(ref feature_name),
- .. }) = self.tcx.lookup_stability(def_id) {
- let stable_check =
- // feature-gate is enabled,
- self.tcx.features()
- .declared_lib_features
- .iter()
- .any(|&(ref sym, _)| sym == feature_name) ||
-
- // this comes from a macro that has #[allow_internal_unstable]
- span.allows_unstable();
- if !stable_check {
- return NotPromotable
- }
- };
- Promotable
}
/// While the `ExprUseVisitor` walks, we will identify which
Def::StructCtor(_, CtorKind::Fn) |
Def::VariantCtor(_, CtorKind::Fn) |
Def::SelfCtor(..) => Promotable,
- Def::Fn(did) => {
- v.handle_const_fn_call(did, node_ty, e.span)
- }
+ Def::Fn(did) => v.handle_const_fn_call(did),
Def::Method(did) => {
match v.tcx.associated_item(did).container {
- ty::ImplContainer(_) => {
- v.handle_const_fn_call(did, node_ty, e.span)
- }
+ ty::ImplContainer(_) => v.handle_const_fn_call(did),
ty::TraitContainer(_) => NotPromotable,
}
}
if let Some(def) = v.tables.type_dependent_defs().get(e.hir_id) {
let def_id = def.def_id();
match v.tcx.associated_item(def_id).container {
- ty::ImplContainer(_) => {
- method_call_result = method_call_result
- & v.handle_const_fn_call(def_id, node_ty, e.span);
- }
- ty::TraitContainer(_) => return NotPromotable,
- };
+ ty::ImplContainer(_) => method_call_result & v.handle_const_fn_call(def_id),
+ ty::TraitContainer(_) => NotPromotable,
+ }
} else {
v.tcx.sess.delay_span_bug(e.span, "no type-dependent def for method call");
+ NotPromotable
}
- method_call_result
}
hir::ExprKind::Struct(ref _qpath, ref hirvec, ref option_expr) => {
let mut struct_result = Promotable;
test = false
[dependencies]
+bitflags = "1.0"
log = "0.4"
syntax = { path = "../libsyntax" }
rustc = { path = "../librustc" }
--- /dev/null
+// Copyright 2012-2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use {CrateLint, PathResult};
+
+use std::collections::BTreeSet;
+
+use syntax::ast::Ident;
+use syntax::symbol::{keywords, Symbol};
+use syntax_pos::Span;
+
+use resolve_imports::ImportResolver;
+
+impl<'a, 'b:'a, 'c: 'b> ImportResolver<'a, 'b, 'c> {
+ /// Add suggestions for a path that cannot be resolved.
+ pub(crate) fn make_path_suggestion(
+ &mut self,
+ span: Span,
+ path: Vec<Ident>
+ ) -> Option<Vec<Ident>> {
+ debug!("make_path_suggestion: span={:?} path={:?}", span, path);
+ // If we don't have a path to suggest changes to, then return.
+ if path.is_empty() {
+ return None;
+ }
+
+ // Check whether a ident is a path segment that is not root.
+ let is_special = |ident: Ident| ident.is_path_segment_keyword() &&
+ ident.name != keywords::CrateRoot.name();
+
+ match (path.get(0), path.get(1)) {
+ // Make suggestions that require at least two non-special path segments.
+ (Some(fst), Some(snd)) if !is_special(*fst) && !is_special(*snd) => {
+ debug!("make_path_suggestion: fst={:?} snd={:?}", fst, snd);
+
+ self.make_missing_self_suggestion(span, path.clone())
+ .or_else(|| self.make_missing_crate_suggestion(span, path.clone()))
+ .or_else(|| self.make_missing_super_suggestion(span, path.clone()))
+ .or_else(|| self.make_external_crate_suggestion(span, path.clone()))
+ },
+ _ => None,
+ }
+ }
+
+ /// Suggest a missing `self::` if that resolves to an correct module.
+ ///
+ /// ```
+ /// |
+ /// LL | use foo::Bar;
+ /// | ^^^ Did you mean `self::foo`?
+ /// ```
+ fn make_missing_self_suggestion(
+ &mut self,
+ span: Span,
+ mut path: Vec<Ident>
+ ) -> Option<Vec<Ident>> {
+ // Replace first ident with `self` and check if that is valid.
+ path[0].name = keywords::SelfValue.name();
+ let result = self.resolve_path(None, &path, None, false, span, CrateLint::No);
+ debug!("make_missing_self_suggestion: path={:?} result={:?}", path, result);
+ if let PathResult::Module(..) = result {
+ Some(path)
+ } else {
+ None
+ }
+ }
+
+ /// Suggest a missing `crate::` if that resolves to an correct module.
+ ///
+ /// ```
+ /// |
+ /// LL | use foo::Bar;
+ /// | ^^^ Did you mean `crate::foo`?
+ /// ```
+ fn make_missing_crate_suggestion(
+ &mut self,
+ span: Span,
+ mut path: Vec<Ident>
+ ) -> Option<Vec<Ident>> {
+ // Replace first ident with `crate` and check if that is valid.
+ path[0].name = keywords::Crate.name();
+ let result = self.resolve_path(None, &path, None, false, span, CrateLint::No);
+ debug!("make_missing_crate_suggestion: path={:?} result={:?}", path, result);
+ if let PathResult::Module(..) = result {
+ Some(path)
+ } else {
+ None
+ }
+ }
+
+ /// Suggest a missing `super::` if that resolves to an correct module.
+ ///
+ /// ```
+ /// |
+ /// LL | use foo::Bar;
+ /// | ^^^ Did you mean `super::foo`?
+ /// ```
+ fn make_missing_super_suggestion(
+ &mut self,
+ span: Span,
+ mut path: Vec<Ident>
+ ) -> Option<Vec<Ident>> {
+ // Replace first ident with `crate` and check if that is valid.
+ path[0].name = keywords::Super.name();
+ let result = self.resolve_path(None, &path, None, false, span, CrateLint::No);
+ debug!("make_missing_super_suggestion: path={:?} result={:?}", path, result);
+ if let PathResult::Module(..) = result {
+ Some(path)
+ } else {
+ None
+ }
+ }
+
+ /// Suggest a missing external crate name if that resolves to an correct module.
+ ///
+ /// ```
+ /// |
+ /// LL | use foobar::Baz;
+ /// | ^^^^^^ Did you mean `baz::foobar`?
+ /// ```
+ ///
+ /// Used when importing a submodule of an external crate but missing that crate's
+ /// name as the first part of path.
+ fn make_external_crate_suggestion(
+ &mut self,
+ span: Span,
+ mut path: Vec<Ident>
+ ) -> Option<Vec<Ident>> {
+ // Need to clone else we can't call `resolve_path` without a borrow error. We also store
+ // into a `BTreeMap` so we can get consistent ordering (and therefore the same diagnostic)
+ // each time.
+ let external_crate_names: BTreeSet<Symbol> = self.resolver.session.extern_prelude
+ .clone().drain().collect();
+
+ // Insert a new path segment that we can replace.
+ let new_path_segment = path[0].clone();
+ path.insert(1, new_path_segment);
+
+ // Iterate in reverse so that we start with crates at the end of the alphabet. This means
+ // that we'll always get `std` before `core`.
+ for name in external_crate_names.iter().rev() {
+ let ident = Ident::with_empty_ctxt(*name);
+ // Calling `maybe_process_path_extern` ensures that we're only running `resolve_path`
+ // on a crate name that won't ICE.
+ if let Some(_) = self.crate_loader.maybe_process_path_extern(*name, ident.span) {
+ // Replace the first after root (a placeholder we inserted) with a crate name
+ // and check if that is valid.
+ path[1].name = *name;
+ let result = self.resolve_path(None, &path, None, false, span, CrateLint::No);
+ debug!("make_external_crate_suggestion: name={:?} path={:?} result={:?}",
+ name, path, result);
+ if let PathResult::Module(..) = result {
+ return Some(path)
+ }
+ }
+ }
+
+ // Remove our placeholder segment.
+ path.remove(1);
+ None
+ }
+}
#![feature(rustc_diagnostic_macros)]
#![feature(slice_sort_by_cached_key)]
+#[macro_use]
+extern crate bitflags;
#[macro_use]
extern crate log;
#[macro_use]
use errors::{Applicability, DiagnosticBuilder, DiagnosticId};
use std::cell::{Cell, RefCell};
-use std::cmp;
+use std::{cmp, fmt, iter, ptr};
use std::collections::BTreeSet;
-use std::fmt;
-use std::iter;
use std::mem::replace;
+use rustc_data_structures::ptr_key::PtrKey;
use rustc_data_structures::sync::Lrc;
use resolve_imports::{ImportDirective, ImportDirectiveSubclass, NameResolution, ImportResolver};
// NB: This module needs to be declared first so diagnostics are
// registered before they are used.
mod diagnostics;
-
+mod error_reporting;
mod macros;
mod check_unused;
mod build_reduced_graph;
normal_ancestor_id: DefId,
resolutions: RefCell<FxHashMap<(Ident, Namespace), &'a RefCell<NameResolution<'a>>>>,
- legacy_macro_resolutions: RefCell<Vec<(Ident, MacroKind, ParentScope<'a>, Option<Def>)>>,
+ legacy_macro_resolutions: RefCell<Vec<(Ident, MacroKind, ParentScope<'a>,
+ Option<&'a NameBinding<'a>>)>>,
macro_resolutions: RefCell<Vec<(Box<[Ident]>, Span)>>,
builtin_attrs: RefCell<Vec<(Ident, ParentScope<'a>)>>,
fn nearest_item_scope(&'a self) -> Module<'a> {
if self.is_trait() { self.parent.unwrap() } else { self }
}
+
+ fn is_ancestor_of(&self, mut other: &Self) -> bool {
+ while !ptr::eq(self, other) {
+ if let Some(parent) = other.parent {
+ other = parent;
+ } else {
+ return false;
+ }
+ }
+ true
+ }
}
impl<'a> fmt::Debug for ModuleData<'a> {
}
}
- fn get_macro<'b: 'a>(&self, resolver: &mut Resolver<'a, 'b>) -> Lrc<SyntaxExtension> {
- resolver.get_macro(self.def_ignoring_ambiguity())
- }
-
// We sometimes need to treat variants as `pub` for backwards compatibility
fn pseudo_vis(&self) -> ty::Visibility {
if self.is_variant() && self.def().def_id().is_local() {
block_map: NodeMap<Module<'a>>,
module_map: FxHashMap<DefId, Module<'a>>,
extern_module_map: FxHashMap<(DefId, bool /* MacrosOnly? */), Module<'a>>,
+ binding_parent_modules: FxHashMap<PtrKey<'a, NameBinding<'a>>, Module<'a>>,
pub make_glob_map: bool,
/// Maps imports to the names of items actually imported (this actually maps
module_map,
block_map: NodeMap(),
extern_module_map: FxHashMap(),
+ binding_parent_modules: FxHashMap(),
make_glob_map: make_glob_map == MakeGlobMap::Yes,
glob_map: NodeMap(),
self.resolve_ident_in_module(module, ident, ns, record_used, path_span)
} else if opt_ns == Some(MacroNS) {
assert!(ns == TypeNS);
- self.resolve_lexical_macro_path_segment(ident, ns, None, parent_scope, record_used,
- record_used, path_span).map(|(b, _)| b)
+ self.early_resolve_ident_in_lexical_scope(ident, ns, None, parent_scope,
+ record_used, record_used, path_span)
} else {
let record_used_id =
if record_used { crate_lint.node_id().or(Some(CRATE_NODE_ID)) } else { None };
vis.is_accessible_from(module.normal_ancestor_id, self)
}
+ fn set_binding_parent_module(&mut self, binding: &'a NameBinding<'a>, module: Module<'a>) {
+ if let Some(old_module) = self.binding_parent_modules.insert(PtrKey(binding), module) {
+ if !ptr::eq(module, old_module) {
+ span_bug!(binding.span, "parent module is reset for binding");
+ }
+ }
+ }
+
+ fn disambiguate_legacy_vs_modern(
+ &self,
+ legacy: &'a NameBinding<'a>,
+ modern: &'a NameBinding<'a>,
+ ) -> bool {
+ // Some non-controversial subset of ambiguities "modern macro name" vs "macro_rules"
+ // is disambiguated to mitigate regressions from macro modularization.
+ // Scoping for `macro_rules` behaves like scoping for `let` at module level, in general.
+ match (self.binding_parent_modules.get(&PtrKey(legacy)),
+ self.binding_parent_modules.get(&PtrKey(modern))) {
+ (Some(legacy), Some(modern)) =>
+ legacy.normal_ancestor_id == modern.normal_ancestor_id &&
+ modern.is_ancestor_of(legacy),
+ _ => false,
+ }
+ }
+
fn report_ambiguity_error(&self, ident: Ident, b1: &NameBinding, b2: &NameBinding) {
let participle = |is_import: bool| if is_import { "imported" } else { "defined" };
let msg1 =
use {AmbiguityError, CrateLint, Resolver, ResolutionError, is_known_tool, resolve_error};
use {Module, ModuleKind, NameBinding, NameBindingKind, PathResult, ToNameBinding};
use ModuleOrUniformRoot;
-use Namespace::{self, TypeNS, MacroNS};
+use Namespace::{self, *};
use build_reduced_graph::{BuildReducedGraphVisitor, IsMacroExport};
use resolve_imports::ImportResolver;
use rustc::hir::def_id::{DefId, CRATE_DEF_INDEX, DefIndex,
use syntax::ast::{self, Name, Ident};
use syntax::attr;
use syntax::errors::DiagnosticBuilder;
-use syntax::ext::base::{self, Determinacy, MultiModifier, MultiDecorator};
+use syntax::ext::base::{self, Determinacy};
use syntax::ext::base::{MacroKind, SyntaxExtension, Resolver as SyntaxResolver};
-use syntax::ext::expand::{AstFragment, Invocation, InvocationKind, TogetherWith};
+use syntax::ext::expand::{AstFragment, Invocation, InvocationKind};
use syntax::ext::hygiene::{self, Mark};
use syntax::ext::tt::macro_rules;
use syntax::feature_gate::{self, feature_err, emit_feature_err, is_builtin_attr_name, GateIssue};
use std::mem;
use rustc_data_structures::sync::Lrc;
-#[derive(Clone, Copy)]
-crate struct FromPrelude(bool);
-
#[derive(Clone)]
pub struct InvocationData<'a> {
def_index: DefIndex,
// Resolves attribute and derive legacy macros from `#![plugin(..)]`.
fn find_legacy_attr_invoc(&mut self, attrs: &mut Vec<ast::Attribute>, allow_derive: bool)
-> Option<ast::Attribute> {
- for i in 0..attrs.len() {
- let name = attrs[i].name();
-
- if self.session.plugin_attributes.borrow().iter()
- .any(|&(ref attr_nm, _)| name == &**attr_nm) {
- attr::mark_known(&attrs[i]);
- }
-
- match self.builtin_macros.get(&name).cloned() {
- Some(binding) => match *binding.get_macro(self) {
- MultiModifier(..) | MultiDecorator(..) | SyntaxExtension::AttrProcMacro(..) => {
- return Some(attrs.remove(i))
- }
- _ => {}
- },
- None => {}
- }
+ if !allow_derive {
+ return None;
}
- if !allow_derive { return None }
-
// Check for legacy derives
for i in 0..attrs.len() {
let name = attrs[i].name();
fn resolve_macro_invocation(&mut self, invoc: &Invocation, invoc_id: Mark, force: bool)
-> Result<Option<Lrc<SyntaxExtension>>, Determinacy> {
- let (path, kind, derives_in_scope, together_with) = match invoc.kind {
+ let (path, kind, derives_in_scope, after_derive) = match invoc.kind {
InvocationKind::Attr { attr: None, .. } =>
return Ok(None),
- InvocationKind::Attr { attr: Some(ref attr), ref traits, together_with, .. } =>
- (&attr.path, MacroKind::Attr, traits.clone(), together_with),
+ InvocationKind::Attr { attr: Some(ref attr), ref traits, after_derive, .. } =>
+ (&attr.path, MacroKind::Attr, traits.clone(), after_derive),
InvocationKind::Bang { ref mac, .. } =>
- (&mac.node.path, MacroKind::Bang, Vec::new(), TogetherWith::None),
+ (&mac.node.path, MacroKind::Bang, Vec::new(), false),
InvocationKind::Derive { ref path, .. } =>
- (path, MacroKind::Derive, Vec::new(), TogetherWith::None),
+ (path, MacroKind::Derive, Vec::new(), false),
};
let parent_scope = self.invoc_parent_scope(invoc_id, derives_in_scope);
let (def, ext) = self.resolve_macro_to_def(path, kind, &parent_scope, force)?;
if let Def::Macro(def_id, _) = def {
- match together_with {
- TogetherWith::Derive =>
- self.session.span_err(invoc.span(),
- "macro attributes must be placed before `#[derive]`"),
- TogetherWith::TestBench if !self.session.features_untracked().plugin =>
- self.session.span_err(invoc.span(),
- "macro attributes cannot be used together with `#[test]` or `#[bench]`"),
- _ => {}
+ if after_derive {
+ self.session.span_err(invoc.span(),
+ "macro attributes must be placed before `#[derive]`");
}
self.macro_defs.insert(invoc.expansion_data.mark, def_id);
let normal_module_def_id =
Err(Determinacy::Determined)
},
};
+
parent_scope.module.macro_resolutions.borrow_mut()
.push((path.into_boxed_slice(), span));
- return def;
- }
- let result = if let Some(legacy_binding) = self.resolve_legacy_scope(path[0], Some(kind),
- parent_scope, false) {
- Ok(legacy_binding.def())
+ def
} else {
- match self.resolve_lexical_macro_path_segment(path[0], MacroNS, Some(kind),
- parent_scope, false, force, span) {
- Ok((binding, _)) => Ok(binding.def_ignoring_ambiguity()),
+ let binding = self.early_resolve_ident_in_lexical_scope(
+ path[0], MacroNS, Some(kind), parent_scope, false, force, span
+ );
+ match binding {
+ Ok(..) => {}
+ Err(Determinacy::Determined) => self.found_unresolved_macro = true,
Err(Determinacy::Undetermined) => return Err(Determinacy::Undetermined),
- Err(Determinacy::Determined) => {
- self.found_unresolved_macro = true;
- Err(Determinacy::Determined)
- }
}
- };
- parent_scope.module.legacy_macro_resolutions.borrow_mut()
- .push((path[0], kind, parent_scope.clone(), result.ok()));
+ parent_scope.module.legacy_macro_resolutions.borrow_mut()
+ .push((path[0], kind, parent_scope.clone(), binding.ok()));
- result
+ binding.map(|binding| binding.def_ignoring_ambiguity())
+ }
}
- // Resolve the initial segment of a non-global macro path
- // (e.g. `foo` in `foo::bar!(); or `foo!();`).
+ // Resolve an identifier in lexical scope.
// This is a variation of `fn resolve_ident_in_lexical_scope` that can be run during
// expansion and import resolution (perhaps they can be merged in the future).
- crate fn resolve_lexical_macro_path_segment(
+ // The function is used for resolving initial segments of macro paths (e.g. `foo` in
+ // `foo::bar!(); or `foo!();`) and can be used for "uniform path" imports in the future.
+ crate fn early_resolve_ident_in_lexical_scope(
&mut self,
mut ident: Ident,
ns: Namespace,
record_used: bool,
force: bool,
path_span: Span,
- ) -> Result<(&'a NameBinding<'a>, FromPrelude), Determinacy> {
+ ) -> Result<&'a NameBinding<'a>, Determinacy> {
// General principles:
// 1. Not controlled (user-defined) names should have higher priority than controlled names
// built into the language or standard library. This way we can add new names into the
// language or standard library without breaking user code.
- // 2. "Closed set" below means new names can appear after the current resolution attempt.
+ // 2. "Closed set" below means new names cannot appear after the current resolution attempt.
// Places to search (in order of decreasing priority):
// (Type NS)
// 1. FIXME: Ribs (type parameters), there's no necessary infrastructure yet
// 4. Tool modules (closed, controlled right now, but not in the future).
// 5. Standard library prelude (de-facto closed, controlled).
// 6. Language prelude (closed, controlled).
+ // (Value NS)
+ // 1. FIXME: Ribs (local variables), there's no necessary infrastructure yet
+ // (open set, not controlled).
+ // 2. Names in modules (both normal `mod`ules and blocks), loop through hygienic parents
+ // (open, not controlled).
+ // 3. Standard library prelude (de-facto closed, controlled).
// (Macro NS)
- // 0. Derive helpers (open, not controlled). All ambiguities with other names
+ // 1-3. Derive helpers (open, not controlled). All ambiguities with other names
// are currently reported as errors. They should be higher in priority than preludes
// and probably even names in modules according to the "general principles" above. They
// also should be subject to restricted shadowing because are effectively produced by
// derives (you need to resolve the derive first to add helpers into scope), but they
// should be available before the derive is expanded for compatibility.
// It's mess in general, so we are being conservative for now.
- // 1. Names in modules (both normal `mod`ules and blocks), loop through hygienic parents
- // (open, not controlled).
- // 2. `macro_use` prelude (open, the open part is from macro expansions, not controlled).
- // 2a. User-defined prelude from macro-use
+ // 1-3. `macro_rules` (open, not controlled), loop through legacy scopes. Have higher
+ // priority than prelude macros, but create ambiguities with macros in modules.
+ // 1-3. Names in modules (both normal `mod`ules and blocks), loop through hygienic parents
+ // (open, not controlled). Have higher priority than prelude macros, but create
+ // ambiguities with `macro_rules`.
+ // 4. `macro_use` prelude (open, the open part is from macro expansions, not controlled).
+ // 4a. User-defined prelude from macro-use
// (open, the open part is from macro expansions, not controlled).
- // 2b. Standard library prelude is currently implemented as `macro-use` (closed, controlled)
- // 3. Language prelude: builtin macros (closed, controlled, except for legacy plugins).
- // 4. Language prelude: builtin attributes (closed, controlled).
+ // 4b. Standard library prelude is currently implemented as `macro-use` (closed, controlled)
+ // 5. Language prelude: builtin macros (closed, controlled, except for legacy plugins).
+ // 6. Language prelude: builtin attributes (closed, controlled).
+ // 4-6. Legacy plugin helpers (open, not controlled). Similar to derive helpers,
+ // but introduced by legacy plugins using `register_attribute`. Priority is somewhere
+ // in prelude, not sure where exactly (creates ambiguities with any other prelude names).
+
+ enum WhereToResolve<'a> {
+ DeriveHelpers,
+ MacroRules(LegacyScope<'a>),
+ Module(Module<'a>),
+ MacroUsePrelude,
+ BuiltinMacros,
+ BuiltinAttrs,
+ LegacyPluginHelpers,
+ ExternPrelude,
+ ToolPrelude,
+ StdLibPrelude,
+ BuiltinTypes,
+ }
+
+ bitflags! {
+ struct Flags: u8 {
+ const DERIVE_HELPERS = 1 << 0;
+ const MACRO_RULES = 1 << 1;
+ const MODULE = 1 << 2;
+ const PRELUDE = 1 << 3;
+ }
+ }
- assert!(ns == TypeNS || ns == MacroNS);
assert!(force || !record_used); // `record_used` implies `force`
ident = ident.modern();
// }
// So we have to save the innermost solution and continue searching in outer scopes
// to detect potential ambiguities.
- let mut innermost_result: Option<(&NameBinding, FromPrelude)> = None;
-
- enum WhereToResolve<'a> {
- Module(Module<'a>),
- MacroUsePrelude,
- BuiltinMacros,
- BuiltinAttrs,
- DeriveHelpers,
- ExternPrelude,
- ToolPrelude,
- StdLibPrelude,
- BuiltinTypes,
- }
+ let mut innermost_result: Option<(&NameBinding, Flags, /* conflicts with */ Flags)> = None;
// Go through all the scopes and try to resolve the name.
let mut where_to_resolve = WhereToResolve::DeriveHelpers;
let mut use_prelude = !parent_scope.module.no_implicit_prelude;
loop {
let result = match where_to_resolve {
+ WhereToResolve::DeriveHelpers => {
+ let mut result = Err(Determinacy::Determined);
+ for derive in &parent_scope.derives {
+ let parent_scope = ParentScope { derives: Vec::new(), ..*parent_scope };
+ if let Ok((_, ext)) = self.resolve_macro_to_def(derive, MacroKind::Derive,
+ &parent_scope, force) {
+ if let SyntaxExtension::ProcMacroDerive(_, helper_attrs, _) = &*ext {
+ if helper_attrs.contains(&ident.name) {
+ let binding =
+ (Def::NonMacroAttr(NonMacroAttrKind::DeriveHelper),
+ ty::Visibility::Public, derive.span, Mark::root())
+ .to_name_binding(self.arenas);
+ result = Ok((binding, Flags::DERIVE_HELPERS, Flags::all()));
+ break;
+ }
+ }
+ }
+ }
+ result
+ }
+ WhereToResolve::MacroRules(legacy_scope) => match legacy_scope {
+ LegacyScope::Binding(legacy_binding) if ident == legacy_binding.ident =>
+ Ok((legacy_binding.binding, Flags::MACRO_RULES, Flags::empty())),
+ _ => Err(Determinacy::Determined),
+ }
WhereToResolve::Module(module) => {
let orig_current_module = mem::replace(&mut self.current_module, module);
let binding = self.resolve_ident_in_module_unadjusted(
path_span,
);
self.current_module = orig_current_module;
- binding.map(|binding| (binding, FromPrelude(false)))
+ binding.map(|binding| (binding, Flags::MODULE, Flags::empty()))
}
WhereToResolve::MacroUsePrelude => {
match self.macro_use_prelude.get(&ident.name).cloned() {
- Some(binding) => Ok((binding, FromPrelude(true))),
+ Some(binding) => Ok((binding, Flags::PRELUDE, Flags::empty())),
None => Err(Determinacy::Determined),
}
}
WhereToResolve::BuiltinMacros => {
match self.builtin_macros.get(&ident.name).cloned() {
- Some(binding) => Ok((binding, FromPrelude(true))),
+ Some(binding) => Ok((binding, Flags::PRELUDE, Flags::empty())),
None => Err(Determinacy::Determined),
}
}
let binding = (Def::NonMacroAttr(NonMacroAttrKind::Builtin),
ty::Visibility::Public, ident.span, Mark::root())
.to_name_binding(self.arenas);
- Ok((binding, FromPrelude(true)))
+ Ok((binding, Flags::PRELUDE, Flags::empty()))
} else {
Err(Determinacy::Determined)
}
}
- WhereToResolve::DeriveHelpers => {
- let mut result = Err(Determinacy::Determined);
- for derive in &parent_scope.derives {
- let parent_scope = ParentScope { derives: Vec::new(), ..*parent_scope };
- if let Ok((_, ext)) = self.resolve_macro_to_def(derive, MacroKind::Derive,
- &parent_scope, force) {
- if let SyntaxExtension::ProcMacroDerive(_, helper_attrs, _) = &*ext {
- if helper_attrs.contains(&ident.name) {
- let binding =
- (Def::NonMacroAttr(NonMacroAttrKind::DeriveHelper),
- ty::Visibility::Public, derive.span, Mark::root())
- .to_name_binding(self.arenas);
- result = Ok((binding, FromPrelude(false)));
- break;
- }
- }
- }
+ WhereToResolve::LegacyPluginHelpers => {
+ if self.session.plugin_attributes.borrow().iter()
+ .any(|(name, _)| ident.name == &**name) {
+ let binding = (Def::NonMacroAttr(NonMacroAttrKind::LegacyPluginHelper),
+ ty::Visibility::Public, ident.span, Mark::root())
+ .to_name_binding(self.arenas);
+ Ok((binding, Flags::PRELUDE, Flags::PRELUDE))
+ } else {
+ Err(Determinacy::Determined)
}
- result
}
WhereToResolve::ExternPrelude => {
if use_prelude && self.session.extern_prelude.contains(&ident.name) {
let binding = (crate_root, ty::Visibility::Public,
ident.span, Mark::root()).to_name_binding(self.arenas);
- Ok((binding, FromPrelude(true)))
+ Ok((binding, Flags::PRELUDE, Flags::empty()))
} else {
Err(Determinacy::Determined)
}
if use_prelude && is_known_tool(ident.name) {
let binding = (Def::ToolMod, ty::Visibility::Public,
ident.span, Mark::root()).to_name_binding(self.arenas);
- Ok((binding, FromPrelude(true)))
+ Ok((binding, Flags::PRELUDE, Flags::empty()))
} else {
Err(Determinacy::Determined)
}
false,
path_span,
) {
- result = Ok((binding, FromPrelude(true)));
+ result = Ok((binding, Flags::PRELUDE, Flags::empty()));
}
}
}
result
}
WhereToResolve::BuiltinTypes => {
- if let Some(prim_ty) =
- self.primitive_type_table.primitive_types.get(&ident.name).cloned() {
- let binding = (Def::PrimTy(prim_ty), ty::Visibility::Public,
- ident.span, Mark::root()).to_name_binding(self.arenas);
- Ok((binding, FromPrelude(true)))
- } else {
- Err(Determinacy::Determined)
+ match self.primitive_type_table.primitive_types.get(&ident.name).cloned() {
+ Some(prim_ty) => {
+ let binding = (Def::PrimTy(prim_ty), ty::Visibility::Public,
+ ident.span, Mark::root()).to_name_binding(self.arenas);
+ Ok((binding, Flags::PRELUDE, Flags::empty()))
+ }
+ None => Err(Determinacy::Determined)
}
}
};
macro_rules! continue_search { () => {
where_to_resolve = match where_to_resolve {
+ WhereToResolve::DeriveHelpers =>
+ WhereToResolve::MacroRules(parent_scope.legacy),
+ WhereToResolve::MacroRules(legacy_scope) => match legacy_scope {
+ LegacyScope::Binding(binding) =>
+ WhereToResolve::MacroRules(binding.parent_legacy_scope),
+ LegacyScope::Invocation(invocation) =>
+ WhereToResolve::MacroRules(invocation.output_legacy_scope.get()),
+ LegacyScope::Empty => WhereToResolve::Module(parent_scope.module),
+ LegacyScope::Uninitialized => unreachable!(),
+ }
WhereToResolve::Module(module) => {
match self.hygienic_lexical_parent(module, &mut ident.span) {
Some(parent_module) => WhereToResolve::Module(parent_module),
None => {
use_prelude = !module.no_implicit_prelude;
- if ns == MacroNS {
- WhereToResolve::MacroUsePrelude
- } else {
- WhereToResolve::ExternPrelude
+ match ns {
+ TypeNS => WhereToResolve::ExternPrelude,
+ ValueNS => WhereToResolve::StdLibPrelude,
+ MacroNS => WhereToResolve::MacroUsePrelude,
}
}
}
}
WhereToResolve::MacroUsePrelude => WhereToResolve::BuiltinMacros,
WhereToResolve::BuiltinMacros => WhereToResolve::BuiltinAttrs,
- WhereToResolve::BuiltinAttrs => break, // nowhere else to search
- WhereToResolve::DeriveHelpers => WhereToResolve::Module(parent_scope.module),
+ WhereToResolve::BuiltinAttrs => WhereToResolve::LegacyPluginHelpers,
+ WhereToResolve::LegacyPluginHelpers => break, // nowhere else to search
WhereToResolve::ExternPrelude => WhereToResolve::ToolPrelude,
WhereToResolve::ToolPrelude => WhereToResolve::StdLibPrelude,
- WhereToResolve::StdLibPrelude => WhereToResolve::BuiltinTypes,
+ WhereToResolve::StdLibPrelude => match ns {
+ TypeNS => WhereToResolve::BuiltinTypes,
+ ValueNS => break, // nowhere else to search
+ MacroNS => unreachable!(),
+ }
WhereToResolve::BuiltinTypes => break, // nowhere else to search
};
}}
match result {
- Ok(result) => {
- if sub_namespace_mismatch(kind, result.0.macro_kind()) {
+ Ok((binding, flags, ambig_flags)) => {
+ if sub_namespace_mismatch(kind, binding.macro_kind()) {
continue_search!();
}
if !record_used {
- return Ok(result);
+ return Ok(binding);
}
- if let Some(innermost_result) = innermost_result {
+ if let Some((innermost_binding, innermost_flags, innermost_ambig_flags))
+ = innermost_result {
// Found another solution, if the first one was "weak", report an error.
- let (def, innermost_def) = (result.0.def(), innermost_result.0.def());
- if def != innermost_def &&
- (innermost_result.0.is_glob_import() ||
- innermost_result.0.may_appear_after(parent_scope.expansion, result.0) ||
- innermost_def == Def::NonMacroAttr(NonMacroAttrKind::DeriveHelper) ||
- def == Def::NonMacroAttr(NonMacroAttrKind::DeriveHelper)) {
+ if binding.def() != innermost_binding.def() &&
+ (innermost_binding.is_glob_import() ||
+ innermost_binding.may_appear_after(parent_scope.expansion, binding) ||
+ innermost_flags.intersects(ambig_flags) ||
+ flags.intersects(innermost_ambig_flags) ||
+ (innermost_flags.contains(Flags::MACRO_RULES) &&
+ flags.contains(Flags::MODULE) &&
+ !self.disambiguate_legacy_vs_modern(innermost_binding, binding))) {
self.ambiguity_errors.push(AmbiguityError {
ident,
- b1: innermost_result.0,
- b2: result.0,
+ b1: innermost_binding,
+ b2: binding,
});
- return Ok(innermost_result);
+ return Ok(innermost_binding);
}
} else {
// Found the first solution.
- innermost_result = Some(result);
+ innermost_result = Some((binding, flags, ambig_flags));
}
continue_search!();
}
// The first found solution was the only one, return it.
- if let Some(innermost_result) = innermost_result {
- return Ok(innermost_result);
+ if let Some((binding, ..)) = innermost_result {
+ return Ok(binding);
}
let determinacy = Determinacy::determined(force);
let binding = (Def::NonMacroAttr(NonMacroAttrKind::Custom),
ty::Visibility::Public, ident.span, Mark::root())
.to_name_binding(self.arenas);
- Ok((binding, FromPrelude(true)))
+ Ok(binding)
} else {
Err(determinacy)
}
}
- fn resolve_legacy_scope(
- &mut self,
- ident: Ident,
- kind: Option<MacroKind>,
- parent_scope: &ParentScope<'a>,
- record_used: bool,
- ) -> Option<&'a NameBinding<'a>> {
- if sub_namespace_mismatch(kind, Some(MacroKind::Bang)) {
- return None;
- }
-
- let ident = ident.modern();
-
- // This is *the* result, resolution from the scope closest to the resolved identifier.
- // However, sometimes this result is "weak" because it comes from a macro expansion,
- // and in this case it cannot shadow names from outer scopes, e.g.
- // macro_rules! m { ... } // solution in outer scope
- // {
- // define_m!(); // generates another `macro_rules! m` - innermost solution
- // // weak, cannot shadow the outer `m`, need to report ambiguity error
- // m!();
- // }
- // So we have to save the innermost solution and continue searching in outer scopes
- // to detect potential ambiguities.
- let mut innermost_result: Option<&NameBinding> = None;
-
- // Go through all the scopes and try to resolve the name.
- let mut where_to_resolve = parent_scope.legacy;
- loop {
- let result = match where_to_resolve {
- LegacyScope::Binding(legacy_binding) if ident == legacy_binding.ident =>
- Some(legacy_binding.binding),
- _ => None,
- };
-
- macro_rules! continue_search { () => {
- where_to_resolve = match where_to_resolve {
- LegacyScope::Empty => break, // nowhere else to search
- LegacyScope::Binding(binding) => binding.parent_legacy_scope,
- LegacyScope::Invocation(invocation) => invocation.output_legacy_scope.get(),
- LegacyScope::Uninitialized => unreachable!(),
- };
-
- continue;
- }}
-
- match result {
- Some(result) => {
- if !record_used {
- return Some(result);
- }
-
- if let Some(innermost_result) = innermost_result {
- // Found another solution, if the first one was "weak", report an error.
- if result.def() != innermost_result.def() &&
- innermost_result.may_appear_after(parent_scope.expansion, result) {
- self.ambiguity_errors.push(AmbiguityError {
- ident,
- b1: innermost_result,
- b2: result,
- });
- return Some(innermost_result);
- }
- } else {
- // Found the first solution.
- innermost_result = Some(result);
- }
-
- continue_search!();
- }
- None => {
- continue_search!();
- }
- }
- }
-
- // The first found solution was the only one (or there was no solution at all), return it.
- innermost_result
- }
-
pub fn finalize_current_module_macro_resolutions(&mut self) {
let module = self.current_module;
for &(ref path, span) in module.macro_resolutions.borrow().iter() {
let legacy_macro_resolutions =
mem::replace(&mut *module.legacy_macro_resolutions.borrow_mut(), Vec::new());
- for (ident, kind, parent_scope, def) in legacy_macro_resolutions {
- let span = ident.span;
- let legacy_resolution = self.resolve_legacy_scope(
- ident, Some(kind), &parent_scope, true
+ for (ident, kind, parent_scope, initial_binding) in legacy_macro_resolutions {
+ let binding = self.early_resolve_ident_in_lexical_scope(
+ ident, MacroNS, Some(kind), &parent_scope, true, true, ident.span
);
- let resolution = self.resolve_lexical_macro_path_segment(
- ident, MacroNS, Some(kind), &parent_scope, true, true, span
- );
-
- let check_consistency = |this: &Self, new_def: Def| {
- if let Some(def) = def {
- if this.ambiguity_errors.is_empty() && new_def != def && new_def != Def::Err {
- // Make sure compilation does not succeed if preferred macro resolution
- // has changed after the macro had been expanded. In theory all such
- // situations should be reported as ambiguity errors, so this is span-bug.
- span_bug!(span, "inconsistent resolution for a macro");
+ match binding {
+ Ok(binding) => {
+ let def = binding.def_ignoring_ambiguity();
+ if let Some(initial_binding) = initial_binding {
+ self.record_use(ident, MacroNS, initial_binding);
+ let initial_def = initial_binding.def_ignoring_ambiguity();
+ if self.ambiguity_errors.is_empty() &&
+ def != initial_def && def != Def::Err {
+ // Make sure compilation does not succeed if preferred macro resolution
+ // has changed after the macro had been expanded. In theory all such
+ // situations should be reported as ambiguity errors, so this is a bug.
+ span_bug!(ident.span, "inconsistent resolution for a macro");
+ }
+ } else {
+ // It's possible that the macro was unresolved (indeterminate) and silently
+ // expanded into a dummy fragment for recovery during expansion.
+ // Now, post-expansion, the resolution may succeed, but we can't change the
+ // past and need to report an error.
+ let msg = format!("cannot determine resolution for the {} `{}`",
+ kind.descr(), ident);
+ let msg_note = "import resolution is stuck, try simplifying macro imports";
+ self.session.struct_span_err(ident.span, &msg).note(msg_note).emit();
}
- } else {
- // It's possible that the macro was unresolved (indeterminate) and silently
- // expanded into a dummy fragment for recovery during expansion.
- // Now, post-expansion, the resolution may succeed, but we can't change the
- // past and need to report an error.
- let msg =
- format!("cannot determine resolution for the {} `{}`", kind.descr(), ident);
- let msg_note = "import resolution is stuck, try simplifying macro imports";
- this.session.struct_span_err(span, &msg).note(msg_note).emit();
}
- };
-
- match (legacy_resolution, resolution) {
- (None, Err(_)) => {
- assert!(def.is_none());
+ Err(..) => {
+ assert!(initial_binding.is_none());
let bang = if kind == MacroKind::Bang { "!" } else { "" };
let msg =
format!("cannot find {} `{}{}` in this scope", kind.descr(), ident, bang);
- let mut err = self.session.struct_span_err(span, &msg);
- self.suggest_macro_name(&ident.as_str(), kind, &mut err, span);
+ let mut err = self.session.struct_span_err(ident.span, &msg);
+ self.suggest_macro_name(&ident.as_str(), kind, &mut err, ident.span);
err.emit();
- },
- (Some(legacy_binding), Ok((binding, FromPrelude(from_prelude))))
- if legacy_binding.def() != binding.def_ignoring_ambiguity() &&
- (!from_prelude ||
- legacy_binding.may_appear_after(parent_scope.expansion, binding)) => {
- self.report_ambiguity_error(ident, legacy_binding, binding);
- },
- // OK, non-macro-expanded legacy wins over prelude even if defs are different
- // Also, legacy and modern can co-exist if their defs are same
- (Some(legacy_binding), Ok(_)) |
- // OK, unambiguous resolution
- (Some(legacy_binding), Err(_)) => {
- check_consistency(self, legacy_binding.def());
- }
- // OK, unambiguous resolution
- (None, Ok((binding, FromPrelude(from_prelude)))) => {
- check_consistency(self, binding.def_ignoring_ambiguity());
- if from_prelude {
- self.record_use(ident, MacroNS, binding);
- }
}
- };
+ }
}
let builtin_attrs = mem::replace(&mut *module.builtin_attrs.borrow_mut(), Vec::new());
for (ident, parent_scope) in builtin_attrs {
- let resolve_legacy = |this: &mut Self| this.resolve_legacy_scope(
- ident, Some(MacroKind::Attr), &parent_scope, true
- );
- let resolve_modern = |this: &mut Self| this.resolve_lexical_macro_path_segment(
+ let binding = self.early_resolve_ident_in_lexical_scope(
ident, MacroNS, Some(MacroKind::Attr), &parent_scope, true, true, ident.span
- ).map(|(binding, _)| binding).ok();
-
- if let Some(binding) = resolve_legacy(self).or_else(|| resolve_modern(self)) {
+ );
+ if let Ok(binding) = binding {
if binding.def_ignoring_ambiguity() !=
Def::NonMacroAttr(NonMacroAttrKind::Builtin) {
let builtin_binding = (Def::NonMacroAttr(NonMacroAttrKind::Builtin),
let def = Def::Macro(def_id, MacroKind::Bang);
let vis = ty::Visibility::Invisible; // Doesn't matter for legacy bindings
let binding = (def, vis, item.span, expansion).to_name_binding(self.arenas);
+ self.set_binding_parent_module(binding, self.current_module);
let legacy_binding = self.arenas.alloc_legacy_binding(LegacyBinding {
parent_legacy_scope: *current_legacy_scope, binding, ident
});
// expansion. With restricted shadowing names from globs and macro expansions cannot
// shadow names from outer scopes, so we can freely fallback from module search to search
// in outer scopes. To continue search in outer scopes we have to lie a bit and return
- // `Determined` to `resolve_lexical_macro_path_segment` even if the correct answer
+ // `Determined` to `early_resolve_ident_in_lexical_scope` even if the correct answer
// for in-module resolution could be `Undetermined`.
if restricted_shadowing {
return Err(Determined);
binding: &'a NameBinding<'a>)
-> Result<(), &'a NameBinding<'a>> {
self.check_reserved_macro_name(ident, ns);
+ self.set_binding_parent_module(binding, module);
self.update_resolution(module, ident, ns, |this, resolution| {
if let Some(old_binding) = resolution.binding {
if binding.is_glob_import() {
return None;
}
PathResult::Failed(span, msg, true) => {
- let (mut self_path, mut self_result) = (module_path.clone(), None);
- let is_special = |ident: Ident| ident.is_path_segment_keyword() &&
- ident.name != keywords::CrateRoot.name();
- if !self_path.is_empty() && !is_special(self_path[0]) &&
- !(self_path.len() > 1 && is_special(self_path[1])) {
- self_path[0].name = keywords::SelfValue.name();
- self_result = Some(self.resolve_path(None, &self_path, None, false,
- span, CrateLint::No));
- }
- return if let Some(PathResult::Module(..)) = self_result {
- Some((span, format!("Did you mean `{}`?", names_to_string(&self_path[..]))))
+ return if let Some(suggested_path) = self.make_path_suggestion(
+ span, module_path.clone()
+ ) {
+ Some((
+ span,
+ format!("Did you mean `{}`?", names_to_string(&suggested_path[..]))
+ ))
} else {
Some((span, msg))
};
overflows: vec![],
}),
+ ty::UnnormalizedProjection(..) => bug!("only used with chalk-engine"),
+
ty::Infer(..) | ty::Error => {
// By the time this code runs, all type variables ought to
// be fully resolved.
match path.def {
Def::Existential(did) => {
// check for desugared impl trait
- if ty::is_impl_trait_defn(tcx, did).is_some() {
- let lifetimes = &path.segments[0].args.as_ref().unwrap().args;
- return self.impl_trait_ty_to_ty(did, lifetimes);
- }
+ assert!(ty::is_impl_trait_defn(tcx, did).is_none());
let item_segment = path.segments.split_last().unwrap();
self.prohibit_generics(item_segment.1);
let substs = self.ast_path_substs_for_ty(span, did, item_segment.0);
});
self.def_to_ty(opt_self_ty, path, false)
}
+ hir::TyKind::Def(item_id, ref lifetimes) => {
+ let did = tcx.hir.local_def_id(item_id.id);
+ self.impl_trait_ty_to_ty(did, lifetimes)
+ },
hir::TyKind::Path(hir::QPath::TypeRelative(ref qself, ref segment)) => {
debug!("ast_ty_to_ty: qself={:?} segment={:?}", qself, segment);
let ty = self.ast_ty_to_ty(qself);
ty::Foreign(..) => Some(PointerKind::Thin),
// We should really try to normalize here.
ty::Projection(ref pi) => Some(PointerKind::OfProjection(pi)),
+ ty::UnnormalizedProjection(..) => bug!("only used with chalk-engine"),
ty::Opaque(def_id, substs) => Some(PointerKind::OfOpaque(def_id, substs)),
ty::Param(ref p) => Some(PointerKind::OfParam(p)),
// Insufficient type information.
// We create a mapping `dummy_substs` that maps from the impl type
// parameters to fresh types and regions. For type parameters,
// this is the identity transform, but we could as well use any
- // skolemized types. For regions, we convert from bound to free
+ // placeholder types. For regions, we convert from bound to free
// regions (Note: but only early-bound regions, i.e., those
// declared on the impl or used in type parameter bounds).
//
// impl_to_skol_substs = {'i => 'i0, U => U0, N => N0 }
//
// Now we can apply skol_substs to the type of the impl method
- // to yield a new function type in terms of our fresh, skolemized
+ // to yield a new function type in terms of our fresh, placeholder
// types:
//
// <'b> fn(t: &'i0 U0, m: &'b) -> Foo
// We do this by creating a parameter environment which contains a
// substitution corresponding to impl_to_skol_substs. We then build
// trait_to_skol_substs and use it to convert the predicates contained
- // in the trait_m.generics to the skolemized form.
+ // in the trait_m.generics to the placeholder form.
//
// Finally we register each of these predicates as an obligation in
// a fresh FulfillmentCtxt, and invoke select_all_or_error.
- // Create mapping from impl to skolemized.
+ // Create mapping from impl to placeholder.
let impl_to_skol_substs = Substs::identity_for_item(tcx, impl_m.def_id);
- // Create mapping from trait to skolemized.
+ // Create mapping from trait to placeholder.
let trait_to_skol_substs = impl_to_skol_substs.rebase_onto(tcx,
impl_m.container.id(),
trait_to_impl_substs);
hybrid_preds.predicates.extend(
trait_m_predicates.instantiate_own(tcx, trait_to_skol_substs).predicates);
- // Construct trait parameter environment and then shift it into the skolemized viewpoint.
+ // Construct trait parameter environment and then shift it into the placeholder viewpoint.
// The key step here is to update the caller_bounds's predicates to be
// the new hybrid bounds we computed.
let normalize_cause = traits::ObligationCause::misc(impl_m_span, impl_m_node_id);
// any associated types appearing in the fn arguments or return
// type.
- // Compute skolemized form of impl and trait method tys.
+ // Compute placeholder form of impl and trait method tys.
let tcx = infcx.tcx;
let (impl_sig, _) =
// method.
let impl_c_node_id = tcx.hir.as_local_node_id(impl_c.def_id).unwrap();
- // Compute skolemized form of impl and trait const tys.
+ // Compute placeholder form of impl and trait const tys.
let impl_ty = tcx.type_of(impl_c.def_id);
let trait_ty = tcx.type_of(trait_c.def_id).subst(tcx, trait_to_impl_substs);
let mut cause = ObligationCause::misc(impl_c_span, impl_c_node_id);
}
}
- fn is_place_expr(&self, expr: &hir::Expr) -> bool {
- match expr.node {
- hir::ExprKind::Path(hir::QPath::Resolved(_, ref path)) => {
- match path.def {
- Def::Local(..) | Def::Upvar(..) | Def::Static(..) | Def::Err => true,
- _ => false,
- }
- }
-
- hir::ExprKind::Type(ref e, _) => {
- self.is_place_expr(e)
- }
-
- hir::ExprKind::Unary(hir::UnDeref, _) |
- hir::ExprKind::Field(..) |
- hir::ExprKind::Index(..) => {
- true
- }
-
- // Partially qualified paths in expressions can only legally
- // refer to associated items which are always rvalues.
- hir::ExprKind::Path(hir::QPath::TypeRelative(..)) |
-
- hir::ExprKind::Call(..) |
- hir::ExprKind::MethodCall(..) |
- hir::ExprKind::Struct(..) |
- hir::ExprKind::Tup(..) |
- hir::ExprKind::If(..) |
- hir::ExprKind::Match(..) |
- hir::ExprKind::Closure(..) |
- hir::ExprKind::Block(..) |
- hir::ExprKind::Repeat(..) |
- hir::ExprKind::Array(..) |
- hir::ExprKind::Break(..) |
- hir::ExprKind::Continue(..) |
- hir::ExprKind::Ret(..) |
- hir::ExprKind::While(..) |
- hir::ExprKind::Loop(..) |
- hir::ExprKind::Assign(..) |
- hir::ExprKind::InlineAsm(..) |
- hir::ExprKind::AssignOp(..) |
- hir::ExprKind::Lit(_) |
- hir::ExprKind::Unary(..) |
- hir::ExprKind::Box(..) |
- hir::ExprKind::AddrOf(..) |
- hir::ExprKind::Binary(..) |
- hir::ExprKind::Yield(..) |
- hir::ExprKind::Cast(..) => {
- false
- }
- }
- }
-
/// For the overloaded place expressions (`*x`, `x[3]`), the trait
/// returns a type of `&T`, but the actual type we assign to the
/// *expression* is `T`. So this function just peels off the return
ty
}
- fn check_expr_kind(&self,
- expr: &'gcx hir::Expr,
- expected: Expectation<'tcx>,
- needs: Needs) -> Ty<'tcx> {
+ fn check_expr_kind(
+ &self,
+ expr: &'gcx hir::Expr,
+ expected: Expectation<'tcx>,
+ needs: Needs
+ ) -> Ty<'tcx> {
let tcx = self.tcx;
let id = expr.id;
match expr.node {
let hint = expected.only_has_type(self).map_or(NoExpectation, |ty| {
match ty.sty {
ty::Ref(_, ty, _) | ty::RawPtr(ty::TypeAndMut { ty, .. }) => {
- if self.is_place_expr(&oprnd) {
+ if oprnd.is_place_expr() {
// Places may legitimately have unsized types.
// For example, dereferences of a fat pointer and
// the last field of a struct can be unsized.
_ => {
// Only check this if not in an `if` condition, as the
// mistyped comparison help is more appropriate.
- if !self.is_place_expr(&lhs) {
+ if !lhs.is_place_expr() {
struct_span_err!(self.tcx.sess, expr.span, E0070,
"invalid left-hand side expression")
.span_label(expr.span, "left-hand of expression not valid")
hir::ExprKind::Type(ref e, ref t) => {
let ty = self.to_ty(&t);
self.check_expr_eq_type(&e, ty);
+ let c_ty = self.infcx.canonicalize_response(&ty);
+ self.tables.borrow_mut().user_provided_tys_mut().insert(t.hir_id, c_ty);
ty
}
hir::ExprKind::Array(ref args) => {
return_ty
};
- if !self.is_place_expr(lhs_expr) {
+ if !lhs_expr.is_place_expr() {
struct_span_err!(
self.tcx.sess, lhs_expr.span,
E0067, "invalid left-hand side expression")
def_id: DefId,
) -> ty::GenericPredicates<'tcx> {
use rustc::hir::*;
+ use rustc_data_structures::fx::FxHashSet;
debug!("explicit_predicates_of(def_id={:?})", def_id);
+ /// A data structure with unique elements, which preserves order of insertion.
+ /// Preserving the order of insertion is important here so as not to break
+ /// compile-fail UI tests.
+ struct UniquePredicates<'tcx> {
+ predicates: Vec<(ty::Predicate<'tcx>, Span)>,
+ uniques: FxHashSet<(ty::Predicate<'tcx>, Span)>,
+ }
+
+ impl<'tcx> UniquePredicates<'tcx> {
+ fn new() -> Self {
+ UniquePredicates {
+ predicates: vec![],
+ uniques: FxHashSet::default(),
+ }
+ }
+
+ fn push(&mut self, value: (ty::Predicate<'tcx>, Span)) {
+ if self.uniques.insert(value) {
+ self.predicates.push(value);
+ }
+ }
+
+ fn extend<I: IntoIterator<Item = (ty::Predicate<'tcx>, Span)>>(&mut self, iter: I) {
+ for value in iter {
+ self.push(value);
+ }
+ }
+ }
+
let node_id = tcx.hir.as_local_node_id(def_id).unwrap();
let node = tcx.hir.get(node_id);
let icx = ItemCtxt::new(tcx, def_id);
let no_generics = hir::Generics::empty();
- let mut predicates = vec![];
+ let mut predicates = UniquePredicates::new();
let ast_generics = match node {
Node::TraitItem(item) => &item.generics,
// on a trait we need to add in the supertrait bounds and bounds found on
// associated types.
if let Some((_trait_ref, _)) = is_trait {
- predicates = tcx.super_predicates_of(def_id).predicates;
+ predicates.extend(tcx.super_predicates_of(def_id).predicates);
}
// In default impls, we can assume that the self type implements
}))
}
+ let mut predicates = predicates.predicates;
+
// Subtle: before we store the predicates into the tcx, we
// sort them so that predicates like `T: Foo<Item=U>` come
// before uses of `U`. This avoids false ambiguity errors
| RegionKind::ReCanonical(..)
| RegionKind::ReScope(..)
| RegionKind::ReVar(..)
- | RegionKind::ReSkolemized(..)
+ | RegionKind::RePlaceholder(..)
| RegionKind::ReFree(..) => {
bug!("unexpected region in outlives inference: {:?}", region);
}
// types, where we use Error as the Self type
}
+ ty::UnnormalizedProjection(..) |
ty::GeneratorWitness(..) |
ty::Infer(..) => {
bug!("unexpected type encountered in \
ty::ReClosureBound(..) |
ty::ReScope(..) |
ty::ReVar(..) |
- ty::ReSkolemized(..) |
+ ty::RePlaceholder(..) |
ty::ReEmpty |
ty::ReErased => {
// We don't expect to see anything but 'static or bound
ty::ReFree(..) |
ty::ReScope(..) |
ty::ReVar(..) |
- ty::ReSkolemized(..) |
+ ty::RePlaceholder(..) |
ty::ReEmpty |
ty::ReClosureBound(_) |
ty::ReCanonical(_) |
Array(box ty.clean(cx), length)
},
TyKind::Tup(ref tys) => Tuple(tys.clean(cx)),
+ TyKind::Def(item_id, _) => {
+ let item = cx.tcx.hir.expect_item(item_id.id);
+ if let hir::ItemKind::Existential(ref ty) = item.node {
+ ImplTrait(ty.bounds.clean(cx))
+ } else {
+ unreachable!()
+ }
+ }
TyKind::Path(hir::QPath::Resolved(None, ref path)) => {
if let Some(new_ty) = cx.ty_substs.borrow().get(&path.def).cloned() {
return new_ty;
if let Some(bounds) = cx.impl_trait_bounds.borrow_mut().remove(&did) {
return ImplTrait(bounds);
}
- } else if let Def::Existential(did) = path.def {
- // This block is for returned impl trait only.
- if let Some(node_id) = cx.tcx.hir.as_local_node_id(did) {
- let item = cx.tcx.hir.expect_item(node_id);
- if let hir::ItemKind::Existential(ref ty) = item.node {
- return ImplTrait(ty.bounds.clean(cx));
- }
- }
}
let mut alias = None;
ty::Closure(..) | ty::Generator(..) => Tuple(vec![]), // FIXME(pcwalton)
+ ty::UnnormalizedProjection(..) => panic!("UnnormalizedProjection"),
ty::GeneratorWitness(..) => panic!("GeneratorWitness"),
ty::Infer(..) => panic!("Infer"),
ty::Error => panic!("Error"),
#[stable(feature = "rust1", since = "1.0.0")]
impl<'a, E: Error + 'a> From<E> for Box<dyn Error + 'a> {
+ /// Converts a type of [`Error`] into a box of dyn [`Error`].
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::error::Error;
+ /// use std::fmt;
+ /// use std::mem;
+ ///
+ /// #[derive(Debug)]
+ /// struct AnError;
+ ///
+ /// impl fmt::Display for AnError {
+ /// fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ /// write!(f , "An error")
+ /// }
+ /// }
+ ///
+ /// impl Error for AnError {
+ /// fn description(&self) -> &str {
+ /// "Description of an error"
+ /// }
+ /// }
+ ///
+ /// let an_error = AnError;
+ /// assert!(0 == mem::size_of_val(&an_error));
+ /// let a_boxed_error = Box::<Error>::from(an_error);
+ /// assert!(mem::size_of::<Box<dyn Error>>() == mem::size_of_val(&a_boxed_error))
+ /// ```
fn from(err: E) -> Box<dyn Error + 'a> {
Box::new(err)
}
#[stable(feature = "rust1", since = "1.0.0")]
impl<'a, E: Error + Send + Sync + 'a> From<E> for Box<dyn Error + Send + Sync + 'a> {
+ /// Converts a type of [`Error`] + [`Send`] + [`Sync`] into a box of dyn [`Error`] +
+ /// [`Send`] + [`Sync`].
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::error::Error;
+ /// use std::fmt;
+ /// use std::mem;
+ ///
+ /// #[derive(Debug)]
+ /// struct AnError;
+ ///
+ /// impl fmt::Display for AnError {
+ /// fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ /// write!(f , "An error")
+ /// }
+ /// }
+ ///
+ /// impl Error for AnError {
+ /// fn description(&self) -> &str {
+ /// "Description of an error"
+ /// }
+ /// }
+ ///
+ /// unsafe impl Send for AnError {}
+ ///
+ /// unsafe impl Sync for AnError {}
+ ///
+ /// let an_error = AnError;
+ /// assert!(0 == mem::size_of_val(&an_error));
+ /// let a_boxed_error = Box::<Error + Send + Sync>::from(an_error);
+ /// assert!(
+ /// mem::size_of::<Box<dyn Error + Send + Sync>>() == mem::size_of_val(&a_boxed_error))
+ /// ```
fn from(err: E) -> Box<dyn Error + Send + Sync + 'a> {
Box::new(err)
}
#[stable(feature = "rust1", since = "1.0.0")]
impl From<String> for Box<dyn Error + Send + Sync> {
+ /// Converts a [`String`] into a box of dyn [`Error`] + [`Send`] + [`Sync`].
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::error::Error;
+ /// use std::mem;
+ ///
+ /// let a_string_error = "a string error".to_string();
+ /// let a_boxed_error = Box::<Error + Send + Sync>::from(a_string_error);
+ /// assert!(
+ /// mem::size_of::<Box<dyn Error + Send + Sync>>() == mem::size_of_val(&a_boxed_error))
+ /// ```
fn from(err: String) -> Box<dyn Error + Send + Sync> {
#[derive(Debug)]
struct StringError(String);
#[stable(feature = "string_box_error", since = "1.6.0")]
impl From<String> for Box<dyn Error> {
+ /// Converts a [`String`] into a box of dyn [`Error`].
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::error::Error;
+ /// use std::mem;
+ ///
+ /// let a_string_error = "a string error".to_string();
+ /// let a_boxed_error = Box::<Error>::from(a_string_error);
+ /// assert!(mem::size_of::<Box<dyn Error>>() == mem::size_of_val(&a_boxed_error))
+ /// ```
fn from(str_err: String) -> Box<dyn Error> {
let err1: Box<dyn Error + Send + Sync> = From::from(str_err);
let err2: Box<dyn Error> = err1;
#[stable(feature = "rust1", since = "1.0.0")]
impl<'a, 'b> From<&'b str> for Box<dyn Error + Send + Sync + 'a> {
+ /// Converts a [`str`] into a box of dyn [`Error`] + [`Send`] + [`Sync`].
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::error::Error;
+ /// use std::mem;
+ ///
+ /// let a_str_error = "a str error";
+ /// let a_boxed_error = Box::<Error + Send + Sync>::from(a_str_error);
+ /// assert!(
+ /// mem::size_of::<Box<dyn Error + Send + Sync>>() == mem::size_of_val(&a_boxed_error))
+ /// ```
fn from(err: &'b str) -> Box<dyn Error + Send + Sync + 'a> {
From::from(String::from(err))
}
#[stable(feature = "string_box_error", since = "1.6.0")]
impl<'a> From<&'a str> for Box<dyn Error> {
+ /// Converts a [`str`] into a box of dyn [`Error`].
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::error::Error;
+ /// use std::mem;
+ ///
+ /// let a_str_error = "a str error";
+ /// let a_boxed_error = Box::<Error>::from(a_str_error);
+ /// assert!(mem::size_of::<Box<dyn Error>>() == mem::size_of_val(&a_boxed_error))
+ /// ```
fn from(err: &'a str) -> Box<dyn Error> {
From::from(String::from(err))
}
#[stable(feature = "cow_box_error", since = "1.22.0")]
impl<'a, 'b> From<Cow<'b, str>> for Box<dyn Error + Send + Sync + 'a> {
+ /// Converts a [`Cow`] into a box of dyn [`Error`] + [`Send`] + [`Sync`].
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::error::Error;
+ /// use std::mem;
+ /// use std::borrow::Cow;
+ ///
+ /// let a_cow_str_error = Cow::from("a str error");
+ /// let a_boxed_error = Box::<Error + Send + Sync>::from(a_cow_str_error);
+ /// assert!(
+ /// mem::size_of::<Box<dyn Error + Send + Sync>>() == mem::size_of_val(&a_boxed_error))
+ /// ```
fn from(err: Cow<'b, str>) -> Box<dyn Error + Send + Sync + 'a> {
From::from(String::from(err))
}
#[stable(feature = "cow_box_error", since = "1.22.0")]
impl<'a> From<Cow<'a, str>> for Box<dyn Error> {
+ /// Converts a [`Cow`] into a box of dyn [`Error`].
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::error::Error;
+ /// use std::mem;
+ /// use std::borrow::Cow;
+ ///
+ /// let a_cow_str_error = Cow::from("a str error");
+ /// let a_boxed_error = Box::<Error>::from(a_cow_str_error);
+ /// assert!(mem::size_of::<Box<dyn Error>>() == mem::size_of_val(&a_boxed_error))
+ /// ```
fn from(err: Cow<'a, str>) -> Box<dyn Error> {
From::from(String::from(err))
}
#![feature(const_cstr_unchecked)]
#![feature(core_intrinsics)]
#![feature(dropck_eyepatch)]
+#![feature(duration_as_u128)]
#![feature(exact_size_is_empty)]
#![feature(external_doc)]
#![feature(fixed_size_array)]
--- /dev/null
+// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use arch::wasm32::atomic;
+use cmp;
+use mem;
+use sync::atomic::{AtomicUsize, Ordering::SeqCst};
+use sys::mutex::Mutex;
+use time::Duration;
+
+pub struct Condvar {
+ cnt: AtomicUsize,
+}
+
+// Condition variables are implemented with a simple counter internally that is
+// likely to cause spurious wakeups. Blocking on a condition variable will first
+// read the value of the internal counter, unlock the given mutex, and then
+// block if and only if the counter's value is still the same. Notifying a
+// condition variable will modify the counter (add one for now) and then wake up
+// a thread waiting on the address of the counter.
+//
+// A thread waiting on the condition variable will as a result avoid going to
+// sleep if it's notified after the lock is unlocked but before it fully goes to
+// sleep. A sleeping thread is guaranteed to be woken up at some point as it can
+// only be woken up with a call to `wake`.
+//
+// Note that it's possible for 2 or more threads to be woken up by a call to
+// `notify_one` with this implementation. That can happen where the modification
+// of `cnt` causes any threads in the middle of `wait` to avoid going to sleep,
+// and the subsequent `wake` may wake up a thread that's actually blocking. We
+// consider this a spurious wakeup, though, which all users of condition
+// variables must already be prepared to handle. As a result, this source of
+// spurious wakeups is currently though to be ok, although it may be problematic
+// later on if it causes too many spurious wakeups.
+
+impl Condvar {
+ pub const fn new() -> Condvar {
+ Condvar { cnt: AtomicUsize::new(0) }
+ }
+
+ #[inline]
+ pub unsafe fn init(&mut self) {
+ // nothing to do
+ }
+
+ pub unsafe fn notify_one(&self) {
+ self.cnt.fetch_add(1, SeqCst);
+ atomic::wake(self.ptr(), 1);
+ }
+
+ #[inline]
+ pub unsafe fn notify_all(&self) {
+ self.cnt.fetch_add(1, SeqCst);
+ atomic::wake(self.ptr(), -1); // -1 == "wake everyone"
+ }
+
+ pub unsafe fn wait(&self, mutex: &Mutex) {
+ // "atomically block and unlock" implemented by loading our current
+ // counter's value, unlocking the mutex, and blocking if the counter
+ // still has the same value.
+ //
+ // Notifications happen by incrementing the counter and then waking a
+ // thread. Incrementing the counter after we unlock the mutex will
+ // prevent us from sleeping and otherwise the call to `wake` will
+ // wake us up once we're asleep.
+ let ticket = self.cnt.load(SeqCst) as i32;
+ mutex.unlock();
+ let val = atomic::wait_i32(self.ptr(), ticket, -1);
+ // 0 == woken, 1 == not equal to `ticket`, 2 == timeout (shouldn't happen)
+ debug_assert!(val == 0 || val == 1);
+ mutex.lock();
+ }
+
+ pub unsafe fn wait_timeout(&self, mutex: &Mutex, dur: Duration) -> bool {
+ let ticket = self.cnt.load(SeqCst) as i32;
+ mutex.unlock();
+ let nanos = dur.as_nanos();
+ let nanos = cmp::min(i64::max_value() as u128, nanos);
+
+ // If the return value is 2 then a timeout happened, so we return
+ // `false` as we weren't actually notified.
+ let ret = atomic::wait_i32(self.ptr(), ticket, nanos as i64) != 2;
+ mutex.lock();
+ return ret
+ }
+
+ #[inline]
+ pub unsafe fn destroy(&self) {
+ // nothing to do
+ }
+
+ #[inline]
+ fn ptr(&self) -> *mut i32 {
+ assert_eq!(mem::size_of::<usize>(), mem::size_of::<i32>());
+ &self.cnt as *const AtomicUsize as *mut i32
+ }
+}
#[cfg(feature = "backtrace")]
pub mod backtrace;
pub mod cmath;
-pub mod condvar;
pub mod env;
pub mod fs;
pub mod memchr;
-pub mod mutex;
pub mod net;
pub mod os;
pub mod os_str;
pub mod path;
pub mod pipe;
pub mod process;
-pub mod rwlock;
pub mod stack_overflow;
pub mod thread;
-pub mod thread_local;
pub mod time;
pub mod stdio;
+cfg_if! {
+ if #[cfg(target_feature = "atomics")] {
+ #[path = "condvar_atomics.rs"]
+ pub mod condvar;
+ #[path = "mutex_atomics.rs"]
+ pub mod mutex;
+ #[path = "rwlock_atomics.rs"]
+ pub mod rwlock;
+ #[path = "thread_local_atomics.rs"]
+ pub mod thread_local;
+ } else {
+ pub mod condvar;
+ pub mod mutex;
+ pub mod rwlock;
+ pub mod thread_local;
+ }
+}
+
#[cfg(not(test))]
pub fn init() {
}
--- /dev/null
+// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use arch::wasm32::atomic;
+use cell::UnsafeCell;
+use mem;
+use sync::atomic::{AtomicUsize, AtomicU64, Ordering::SeqCst};
+
+pub struct Mutex {
+ locked: AtomicUsize,
+}
+
+// Mutexes have a pretty simple implementation where they contain an `i32`
+// internally that is 0 when unlocked and 1 when the mutex is locked.
+// Acquisition has a fast path where it attempts to cmpxchg the 0 to a 1, and
+// if it fails it then waits for a notification. Releasing a lock is then done
+// by swapping in 0 and then notifying any waiters, if present.
+
+impl Mutex {
+ pub const fn new() -> Mutex {
+ Mutex { locked: AtomicUsize::new(0) }
+ }
+
+ #[inline]
+ pub unsafe fn init(&mut self) {
+ // nothing to do
+ }
+
+ pub unsafe fn lock(&self) {
+ while !self.try_lock() {
+ let val = atomic::wait_i32(
+ self.ptr(),
+ 1, // we expect our mutex is locked
+ -1, // wait infinitely
+ );
+ // we should have either woke up (0) or got a not-equal due to a
+ // race (1). We should never time out (2)
+ debug_assert!(val == 0 || val == 1);
+ }
+ }
+
+ pub unsafe fn unlock(&self) {
+ let prev = self.locked.swap(0, SeqCst);
+ debug_assert_eq!(prev, 1);
+ atomic::wake(self.ptr(), 1); // wake up one waiter, if any
+ }
+
+ #[inline]
+ pub unsafe fn try_lock(&self) -> bool {
+ self.locked.compare_exchange(0, 1, SeqCst, SeqCst).is_ok()
+ }
+
+ #[inline]
+ pub unsafe fn destroy(&self) {
+ // nothing to do
+ }
+
+ #[inline]
+ fn ptr(&self) -> *mut i32 {
+ assert_eq!(mem::size_of::<usize>(), mem::size_of::<i32>());
+ &self.locked as *const AtomicUsize as *mut isize as *mut i32
+ }
+}
+
+pub struct ReentrantMutex {
+ owner: AtomicU64,
+ recursions: UnsafeCell<u32>,
+}
+
+unsafe impl Send for ReentrantMutex {}
+unsafe impl Sync for ReentrantMutex {}
+
+// Reentrant mutexes are similarly implemented to mutexs above except that
+// instead of "1" meaning unlocked we use the id of a thread to represent
+// whether it has locked a mutex. That way we have an atomic counter which
+// always holds the id of the thread that currently holds the lock (or 0 if the
+// lock is unlocked).
+//
+// Once a thread acquires a lock recursively, which it detects by looking at
+// the value that's already there, it will update a local `recursions` counter
+// in a nonatomic fashion (as we hold the lock). The lock is then fully
+// released when this recursion counter reaches 0.
+
+impl ReentrantMutex {
+ pub unsafe fn uninitialized() -> ReentrantMutex {
+ ReentrantMutex {
+ owner: AtomicU64::new(0),
+ recursions: UnsafeCell::new(0),
+ }
+ }
+
+ pub unsafe fn init(&mut self) {
+ // nothing to do...
+ }
+
+ pub unsafe fn lock(&self) {
+ let me = thread_id();
+ while let Err(owner) = self._try_lock(me) {
+ let val = atomic::wait_i64(self.ptr(), owner as i64, -1);
+ debug_assert!(val == 0 || val == 1);
+ }
+ }
+
+ #[inline]
+ pub unsafe fn try_lock(&self) -> bool {
+ self._try_lock(thread_id()).is_ok()
+ }
+
+ #[inline]
+ unsafe fn _try_lock(&self, id: u64) -> Result<(), u64> {
+ let id = id.checked_add(1).unwrap(); // make sure `id` isn't 0
+ match self.owner.compare_exchange(0, id, SeqCst, SeqCst) {
+ // we transitioned from unlocked to locked
+ Ok(_) => {
+ debug_assert_eq!(*self.recursions.get(), 0);
+ Ok(())
+ }
+
+ // we currently own this lock, so let's update our count and return
+ // true.
+ Err(n) if n == id => {
+ *self.recursions.get() += 1;
+ Ok(())
+ }
+
+ // Someone else owns the lock, let our caller take care of it
+ Err(other) => Err(other),
+ }
+ }
+
+ pub unsafe fn unlock(&self) {
+ // If we didn't ever recursively lock the lock then we fully unlock the
+ // mutex and wake up a waiter, if any. Otherwise we decrement our
+ // recursive counter and let some one else take care of the zero.
+ match *self.recursions.get() {
+ 0 => {
+ self.owner.swap(0, SeqCst);
+ atomic::wake(self.ptr() as *mut i32, 1); // wake up one waiter, if any
+ }
+ ref mut n => *n -= 1,
+ }
+ }
+
+ pub unsafe fn destroy(&self) {
+ // nothing to do...
+ }
+
+ #[inline]
+ fn ptr(&self) -> *mut i64 {
+ &self.owner as *const AtomicU64 as *mut i64
+ }
+}
+
+fn thread_id() -> u64 {
+ panic!("thread ids not implemented on wasm with atomics yet")
+}
--- /dev/null
+// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use cell::UnsafeCell;
+use sys::mutex::Mutex;
+use sys::condvar::Condvar;
+
+pub struct RWLock {
+ lock: Mutex,
+ cond: Condvar,
+ state: UnsafeCell<State>,
+}
+
+enum State {
+ Unlocked,
+ Reading(usize),
+ Writing,
+}
+
+unsafe impl Send for RWLock {}
+unsafe impl Sync for RWLock {}
+
+// This rwlock implementation is a relatively simple implementation which has a
+// condition variable for readers/writers as well as a mutex protecting the
+// internal state of the lock. A current downside of the implementation is that
+// unlocking the lock will notify *all* waiters rather than just readers or just
+// writers. This can cause lots of "thundering stampede" problems. While
+// hopefully correct this implementation is very likely to want to be changed in
+// the future.
+
+impl RWLock {
+ pub const fn new() -> RWLock {
+ RWLock {
+ lock: Mutex::new(),
+ cond: Condvar::new(),
+ state: UnsafeCell::new(State::Unlocked),
+ }
+ }
+
+ #[inline]
+ pub unsafe fn read(&self) {
+ self.lock.lock();
+ while !(*self.state.get()).inc_readers() {
+ self.cond.wait(&self.lock);
+ }
+ self.lock.unlock();
+ }
+
+ #[inline]
+ pub unsafe fn try_read(&self) -> bool {
+ self.lock.lock();
+ let ok = (*self.state.get()).inc_readers();
+ self.lock.unlock();
+ return ok
+ }
+
+ #[inline]
+ pub unsafe fn write(&self) {
+ self.lock.lock();
+ while !(*self.state.get()).inc_writers() {
+ self.cond.wait(&self.lock);
+ }
+ self.lock.unlock();
+ }
+
+ #[inline]
+ pub unsafe fn try_write(&self) -> bool {
+ self.lock.lock();
+ let ok = (*self.state.get()).inc_writers();
+ self.lock.unlock();
+ return ok
+ }
+
+ #[inline]
+ pub unsafe fn read_unlock(&self) {
+ self.lock.lock();
+ let notify = (*self.state.get()).dec_readers();
+ self.lock.unlock();
+ if notify {
+ // FIXME: should only wake up one of these some of the time
+ self.cond.notify_all();
+ }
+ }
+
+ #[inline]
+ pub unsafe fn write_unlock(&self) {
+ self.lock.lock();
+ (*self.state.get()).dec_writers();
+ self.lock.unlock();
+ // FIXME: should only wake up one of these some of the time
+ self.cond.notify_all();
+ }
+
+ #[inline]
+ pub unsafe fn destroy(&self) {
+ self.lock.destroy();
+ self.cond.destroy();
+ }
+}
+
+impl State {
+ fn inc_readers(&mut self) -> bool {
+ match *self {
+ State::Unlocked => {
+ *self = State::Reading(1);
+ true
+ }
+ State::Reading(ref mut cnt) => {
+ *cnt += 1;
+ true
+ }
+ State::Writing => false
+ }
+ }
+
+ fn inc_writers(&mut self) -> bool {
+ match *self {
+ State::Unlocked => {
+ *self = State::Writing;
+ true
+ }
+ State::Reading(_) |
+ State::Writing => false
+ }
+ }
+
+ fn dec_readers(&mut self) -> bool {
+ let zero = match *self {
+ State::Reading(ref mut cnt) => {
+ *cnt -= 1;
+ *cnt == 0
+ }
+ State::Unlocked |
+ State::Writing => invalid(),
+ };
+ if zero {
+ *self = State::Unlocked;
+ }
+ zero
+ }
+
+ fn dec_writers(&mut self) {
+ match *self {
+ State::Writing => {}
+ State::Unlocked |
+ State::Reading(_) => invalid(),
+ }
+ *self = State::Unlocked;
+ }
+}
+
+fn invalid() -> ! {
+ panic!("inconsistent rwlock");
+}
// nope
}
+ #[cfg(not(target_feature = "atomics"))]
pub fn sleep(_dur: Duration) {
panic!("can't sleep");
}
+ #[cfg(target_feature = "atomics")]
+ pub fn sleep(dur: Duration) {
+ use arch::wasm32::atomic;
+ use cmp;
+
+ // Use an atomic wait to block the current thread artificially with a
+ // timeout listed. Note that we should never be notified (return value
+ // of 0) or our comparison should never fail (return value of 1) so we
+ // should always only resume execution through a timeout (return value
+ // 2).
+ let mut nanos = dur.as_nanos();
+ while nanos > 0 {
+ let amt = cmp::min(i64::max_value() as u128, nanos);
+ let mut x = 0;
+ let val = unsafe { atomic::wait_i32(&mut x, 0, amt as i64) };
+ debug_assert_eq!(val, 2);
+ nanos -= amt;
+ }
+ }
+
pub fn join(self) {
match self.0 {}
}
--- /dev/null
+// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+pub type Key = usize;
+
+pub unsafe fn create(_dtor: Option<unsafe extern fn(*mut u8)>) -> Key {
+ panic!("TLS on wasm with atomics not implemented yet");
+}
+
+pub unsafe fn set(_key: Key, _value: *mut u8) {
+ panic!("TLS on wasm with atomics not implemented yet");
+}
+
+pub unsafe fn get(_key: Key) -> *mut u8 {
+ panic!("TLS on wasm with atomics not implemented yet");
+}
+
+pub unsafe fn destroy(_key: Key) {
+ panic!("TLS on wasm with atomics not implemented yet");
+}
+
+#[inline]
+pub fn requires_synchronized_create() -> bool {
+ false
+}
/// `Some` contains the feature gate required to be able to use the function
/// as const fn
pub const_stability: Option<Symbol>,
+ /// whether the function has a `#[rustc_promotable]` attribute
+ pub promotable: bool,
}
/// The available stability levels.
let mut stab: Option<Stability> = None;
let mut rustc_depr: Option<RustcDeprecation> = None;
let mut rustc_const_unstable: Option<Symbol> = None;
+ let mut promotable = false;
'outer: for attr in attrs_iter {
if ![
"rustc_const_unstable",
"unstable",
"stable",
+ "rustc_promotable",
].iter().any(|&s| attr.path == s) {
continue // not a stability level
}
mark_used(attr);
let meta = attr.meta();
+
+ if attr.path == "rustc_promotable" {
+ promotable = true;
+ }
// attributes with data
- if let Some(MetaItem { node: MetaItemKind::List(ref metas), .. }) = meta {
+ else if let Some(MetaItem { node: MetaItemKind::List(ref metas), .. }) = meta {
let meta = meta.as_ref().unwrap();
let get = |meta: &MetaItem, item: &mut Option<Symbol>| {
if item.is_some() {
feature,
rustc_depr: None,
const_stability: None,
+ promotable: false,
})
}
(None, _, _) => {
feature,
rustc_depr: None,
const_stability: None,
+ promotable: false,
})
}
(None, _) => {
}
}
+ // Merge the const-unstable info into the stability info
+ if promotable {
+ if let Some(ref mut stab) = stab {
+ stab.promotable = true;
+ } else {
+ span_err!(diagnostic, item_sp, E0717,
+ "rustc_promotable attribute must be paired with \
+ either stable or unstable attribute");
+ }
+ }
+
stab
}
E0694, // an unknown tool name found in scoped attributes
E0703, // invalid ABI
E0704, // incorrect visibility restriction
+ E0717, // rustc_promotable without stability attribute
}
pub expansion_data: ExpansionData,
}
-// Needed for feature-gating attributes used after derives or together with test/bench
-#[derive(Clone, Copy, PartialEq)]
-pub enum TogetherWith {
- None,
- Derive,
- TestBench,
-}
-
pub enum InvocationKind {
Bang {
mac: ast::Mac,
attr: Option<ast::Attribute>,
traits: Vec<Path>,
item: Annotatable,
- together_with: TogetherWith,
+ // We temporarily report errors for attribute macros placed after derives
+ after_derive: bool,
},
Derive {
path: Path,
let (kind, gate) = match *item {
Annotatable::Item(ref item) => {
match item.node {
- ItemKind::Mod(_) if self.cx.ecfg.proc_macro_mod() => return,
- ItemKind::Mod(_) => ("modules", "proc_macro_mod"),
+ ItemKind::Mod(_) if self.cx.ecfg.proc_macro_hygiene() => return,
+ ItemKind::Mod(_) => ("modules", "proc_macro_hygiene"),
_ => return,
}
}
Annotatable::ImplItem(_) => return,
Annotatable::ForeignItem(_) => return,
Annotatable::Stmt(_) |
- Annotatable::Expr(_) if self.cx.ecfg.proc_macro_expr() => return,
- Annotatable::Stmt(_) => ("statements", "proc_macro_expr"),
- Annotatable::Expr(_) => ("expressions", "proc_macro_expr"),
+ Annotatable::Expr(_) if self.cx.ecfg.proc_macro_hygiene() => return,
+ Annotatable::Stmt(_) => ("statements", "proc_macro_hygiene"),
+ Annotatable::Expr(_) => ("expressions", "proc_macro_hygiene"),
};
emit_feature_err(
self.cx.parse_sess,
}
fn gate_proc_macro_expansion(&self, span: Span, fragment: &Option<AstFragment>) {
- if self.cx.ecfg.proc_macro_gen() {
+ if self.cx.ecfg.proc_macro_hygiene() {
return
}
let fragment = match fragment {
if let ast::ItemKind::MacroDef(_) = i.node {
emit_feature_err(
self.parse_sess,
- "proc_macro_gen",
+ "proc_macro_hygiene",
self.span,
GateIssue::Language,
&format!("procedural macros cannot expand to macro definitions"),
AstFragmentKind::ImplItems => return,
AstFragmentKind::ForeignItems => return,
};
- if self.cx.ecfg.proc_macro_non_items() {
+ if self.cx.ecfg.proc_macro_hygiene() {
return
}
emit_feature_err(
self.cx.parse_sess,
- "proc_macro_non_items",
+ "proc_macro_hygiene",
span,
GateIssue::Language,
&format!("procedural macros cannot be expanded to {}", kind),
traits: Vec<Path>,
item: Annotatable,
kind: AstFragmentKind,
- together_with: TogetherWith)
+ after_derive: bool)
-> AstFragment {
- self.collect(kind, InvocationKind::Attr { attr, traits, item, together_with })
+ self.collect(kind, InvocationKind::Attr { attr, traits, item, after_derive })
}
- fn find_attr_invoc(&self, attrs: &mut Vec<ast::Attribute>, together_with: &mut TogetherWith)
+ fn find_attr_invoc(&self, attrs: &mut Vec<ast::Attribute>, after_derive: &mut bool)
-> Option<ast::Attribute> {
let attr = attrs.iter()
.position(|a| {
if a.path == "derive" {
- *together_with = TogetherWith::Derive
- } else if a.path == "rustc_test_marker2" {
- *together_with = TogetherWith::TestBench
+ *after_derive = true;
}
!attr::is_known(a) && !is_builtin_attr(a)
})
"non-builtin inner attributes are unstable");
}
}
- if together_with == &TogetherWith::None &&
- attrs.iter().any(|a| a.path == "rustc_test_marker2") {
- *together_with = TogetherWith::TestBench;
- }
attr
}
/// If `item` is an attr invocation, remove and return the macro attribute and derive traits.
fn classify_item<T>(&mut self, mut item: T)
- -> (Option<ast::Attribute>, Vec<Path>, T, TogetherWith)
+ -> (Option<ast::Attribute>, Vec<Path>, T, /* after_derive */ bool)
where T: HasAttrs,
{
- let (mut attr, mut traits, mut together_with) = (None, Vec::new(), TogetherWith::None);
+ let (mut attr, mut traits, mut after_derive) = (None, Vec::new(), false);
item = item.map_attrs(|mut attrs| {
if let Some(legacy_attr_invoc) = self.cx.resolver.find_legacy_attr_invoc(&mut attrs,
return attrs;
}
- attr = self.find_attr_invoc(&mut attrs, &mut together_with);
+ attr = self.find_attr_invoc(&mut attrs, &mut after_derive);
traits = collect_derives(&mut self.cx, &mut attrs);
attrs
});
- (attr, traits, item, together_with)
+ (attr, traits, item, after_derive)
}
/// Alternative of `classify_item()` that ignores `#[derive]` so invocations fallthrough
/// to the unused-attributes lint (making it an error on statements and expressions
/// is a breaking change)
fn classify_nonitem<T: HasAttrs>(&mut self, mut item: T)
- -> (Option<ast::Attribute>, T, TogetherWith) {
- let (mut attr, mut together_with) = (None, TogetherWith::None);
+ -> (Option<ast::Attribute>, T, /* after_derive */ bool) {
+ let (mut attr, mut after_derive) = (None, false);
item = item.map_attrs(|mut attrs| {
if let Some(legacy_attr_invoc) = self.cx.resolver.find_legacy_attr_invoc(&mut attrs,
return attrs;
}
- attr = self.find_attr_invoc(&mut attrs, &mut together_with);
+ attr = self.find_attr_invoc(&mut attrs, &mut after_derive);
attrs
});
- (attr, item, together_with)
+ (attr, item, after_derive)
}
fn configure<T: HasAttrs>(&mut self, node: T) -> Option<T> {
expr.node = self.cfg.configure_expr_kind(expr.node);
// ignore derives so they remain unused
- let (attr, expr, together_with) = self.classify_nonitem(expr);
+ let (attr, expr, after_derive) = self.classify_nonitem(expr);
if attr.is_some() {
// collect the invoc regardless of whether or not attributes are permitted here
// AstFragmentKind::Expr requires the macro to emit an expression
return self.collect_attr(attr, vec![], Annotatable::Expr(P(expr)),
- AstFragmentKind::Expr, together_with).make_expr();
+ AstFragmentKind::Expr, after_derive).make_expr();
}
if let ast::ExprKind::Mac(mac) = expr.node {
expr.node = self.cfg.configure_expr_kind(expr.node);
// ignore derives so they remain unused
- let (attr, expr, together_with) = self.classify_nonitem(expr);
+ let (attr, expr, after_derive) = self.classify_nonitem(expr);
if attr.is_some() {
attr.as_ref().map(|a| self.cfg.maybe_emit_expr_attr_err(a));
return self.collect_attr(attr, vec![], Annotatable::Expr(P(expr)),
- AstFragmentKind::OptExpr, together_with).make_opt_expr();
+ AstFragmentKind::OptExpr, after_derive).make_opt_expr();
}
if let ast::ExprKind::Mac(mac) = expr.node {
// we'll expand attributes on expressions separately
if !stmt.is_expr() {
- let (attr, derives, stmt_, together_with) = if stmt.is_item() {
+ let (attr, derives, stmt_, after_derive) = if stmt.is_item() {
self.classify_item(stmt)
} else {
// ignore derives on non-item statements so it falls through
// to the unused-attributes lint
- let (attr, stmt, together_with) = self.classify_nonitem(stmt);
- (attr, vec![], stmt, together_with)
+ let (attr, stmt, after_derive) = self.classify_nonitem(stmt);
+ (attr, vec![], stmt, after_derive)
};
if attr.is_some() || !derives.is_empty() {
return self.collect_attr(attr, derives, Annotatable::Stmt(P(stmt_)),
- AstFragmentKind::Stmts, together_with).make_stmts();
+ AstFragmentKind::Stmts, after_derive).make_stmts();
}
stmt = stmt_;
fn fold_item(&mut self, item: P<ast::Item>) -> SmallVec<[P<ast::Item>; 1]> {
let item = configure!(self, item);
- let (attr, traits, item, together_with) = self.classify_item(item);
+ let (attr, traits, item, after_derive) = self.classify_item(item);
if attr.is_some() || !traits.is_empty() {
return self.collect_attr(attr, traits, Annotatable::Item(item),
- AstFragmentKind::Items, together_with).make_items();
+ AstFragmentKind::Items, after_derive).make_items();
}
match item.node {
fn fold_trait_item(&mut self, item: ast::TraitItem) -> SmallVec<[ast::TraitItem; 1]> {
let item = configure!(self, item);
- let (attr, traits, item, together_with) = self.classify_item(item);
+ let (attr, traits, item, after_derive) = self.classify_item(item);
if attr.is_some() || !traits.is_empty() {
return self.collect_attr(attr, traits, Annotatable::TraitItem(P(item)),
- AstFragmentKind::TraitItems, together_with).make_trait_items()
+ AstFragmentKind::TraitItems, after_derive).make_trait_items()
}
match item.node {
fn fold_impl_item(&mut self, item: ast::ImplItem) -> SmallVec<[ast::ImplItem; 1]> {
let item = configure!(self, item);
- let (attr, traits, item, together_with) = self.classify_item(item);
+ let (attr, traits, item, after_derive) = self.classify_item(item);
if attr.is_some() || !traits.is_empty() {
return self.collect_attr(attr, traits, Annotatable::ImplItem(P(item)),
- AstFragmentKind::ImplItems, together_with).make_impl_items();
+ AstFragmentKind::ImplItems, after_derive).make_impl_items();
}
match item.node {
fn fold_foreign_item(&mut self, foreign_item: ast::ForeignItem)
-> SmallVec<[ast::ForeignItem; 1]>
{
- let (attr, traits, foreign_item, together_with) = self.classify_item(foreign_item);
+ let (attr, traits, foreign_item, after_derive) = self.classify_item(foreign_item);
if attr.is_some() || !traits.is_empty() {
return self.collect_attr(attr, traits, Annotatable::ForeignItem(P(foreign_item)),
- AstFragmentKind::ForeignItems, together_with)
+ AstFragmentKind::ForeignItems, after_derive)
.make_foreign_items();
}
fn enable_custom_derive = custom_derive,
fn enable_format_args_nl = format_args_nl,
fn macros_in_extern_enabled = macros_in_extern,
- fn proc_macro_mod = proc_macro_mod,
- fn proc_macro_gen = proc_macro_gen,
- fn proc_macro_expr = proc_macro_expr,
- fn proc_macro_non_items = proc_macro_non_items,
+ fn proc_macro_hygiene = proc_macro_hygiene,
}
fn enable_custom_inner_attributes(&self) -> bool {
// Allows macro invocations on modules expressions and statements and
// procedural macros to expand to non-items.
- (active, proc_macro_mod, "1.27.0", Some(54727), None),
- (active, proc_macro_expr, "1.27.0", Some(54727), None),
- (active, proc_macro_non_items, "1.27.0", Some(54727), None),
- (active, proc_macro_gen, "1.27.0", Some(54727), None),
+ (active, proc_macro_hygiene, "1.30.0", Some(54727), None),
// #[doc(alias = "...")]
(active, doc_alias, "1.27.0", Some(50146), None),
Some("merged into `#![feature(slice_patterns)]`")),
(removed, macro_reexport, "1.0.0", Some(29638), None,
Some("subsumed by `pub use`")),
+ (removed, proc_macro_mod, "1.27.0", Some(54727), None,
+ Some("subsumed by `#![feature(proc_macro_hygiene)]`")),
+ (removed, proc_macro_expr, "1.27.0", Some(54727), None,
+ Some("subsumed by `#![feature(proc_macro_hygiene)]`")),
+ (removed, proc_macro_non_items, "1.27.0", Some(54727), None,
+ Some("subsumed by `#![feature(proc_macro_hygiene)]`")),
+ (removed, proc_macro_gen, "1.27.0", Some(54727), None,
+ Some("subsumed by `#![feature(proc_macro_hygiene)]`")),
);
declare_features! (
"the `#[rustc_test_marker]` attribute \
is used internally to track tests",
cfg_fn!(rustc_attrs))),
- ("rustc_test_marker2", Normal, Gated(Stability::Unstable,
- "rustc_attrs",
- "temporarily used by rustc to report some errors",
- cfg_fn!(rustc_attrs))),
("rustc_transparent_macro", Whitelisted, Gated(Stability::Unstable,
"rustc_attrs",
"used internally for testing macro hygiene",
self.word_nbsp("async")?;
self.print_capture_clause(capture_clause)?;
self.s.space()?;
+ // cbox/ibox in analogy to the `ExprKind::Block` arm above
+ self.cbox(INDENT_UNIT)?;
+ self.ibox(0)?;
self.print_block_with_attrs(blk, attrs)?;
}
ast::ExprKind::Assign(ref lhs, ref rhs) => {
// If we're not in test configuration, remove the annotated item
if !cx.ecfg.should_test { return vec![]; }
- let mut item =
+ let item =
if let Annotatable::Item(i) = item { i }
else {
cx.parse_sess.span_diagnostic.span_fatal(item.span(),
debug!("Synthetic test item:\n{}\n", pprust::item_to_string(&test_const));
- // Temporarily add another marker to the original item for error reporting
- let marker2 = cx.attribute(
- attr_sp, cx.meta_word(attr_sp, Symbol::intern("rustc_test_marker2"))
- );
- item.attrs.push(marker2);
-
vec![
// Access to libtest under a gensymed name
Annotatable::Item(test_extern),
-Subproject commit 05c2f61c384e2097a3a4c648344114fc4ac983be
+Subproject commit fe825c93788c841ac1872e8351a62c37a5f78427
//! Attributes producing expressions in invalid locations
-#![feature(stmt_expr_attributes, proc_macro_expr)]
+#![feature(stmt_expr_attributes, proc_macro_hygiene)]
extern crate attr_stmt_expr;
use attr_stmt_expr::{duplicate, no_output};
// aux-build:attr-stmt-expr.rs
// ignore-stage1
-#![feature(proc_macro_expr)]
+#![feature(proc_macro_hygiene)]
extern crate attr_stmt_expr;
use attr_stmt_expr::{expect_let, expect_print_stmt, expect_expr, expect_print_expr};
// aux-build:bang_proc_macro2.rs
// ignore-stage1
-#![feature(proc_macro_non_items)]
+#![feature(proc_macro_hygiene)]
#![allow(unused_macros)]
extern crate bang_proc_macro2;
// except according to those terms.
// aux-build:proc-macro-gates.rs
-// gate-test-proc_macro_non_items
-// gate-test-proc_macro_mod line
-// gate-test-proc_macro_expr
-// gate-test-proc_macro_mod
-// gate-test-proc_macro_gen
+// gate-test-proc_macro_hygiene
#![feature(stmt_expr_attributes)]
--- /dev/null
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![feature(const_fn)]
+
+const X : usize = 2;
+
+const fn f(x: usize) -> usize {
+ let mut sum = 0;
+ //~^ let bindings in constant functions are unstable
+ //~| statements in constant functions are unstable
+ for i in 0..x {
+ //~^ ERROR E0015
+ //~| ERROR E0019
+ sum += i;
+ }
+ sum
+}
+
+#[allow(unused_variables)]
+fn main() {
+ let a : [i32; f(X)]; //~ ERROR E0080
+}
--- /dev/null
+// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+fn main() {
+ [(); & { loop { continue } } ]; //~ ERROR mismatched types
+ [(); loop { break }]; //~ ERROR mismatched types
+ [(); {while true {break}; 0}]; //~ ERROR constant contains unimplemented expression type
+ [(); { for _ in 0usize.. {}; 0}]; //~ ERROR calls in constants are limited to constant functions
+ //~^ ERROR constant contains unimplemented expression type
+ //~| ERROR could not evaluate repeat length
+}
#[rustc_clean(label="Hir", cfg="cfail2")]
#[rustc_clean(label="Hir", cfg="cfail3")]
trait TraitChangeModeSelfOwnToMut: Sized {
- #[rustc_clean(label="Hir", cfg="cfail2")]
+ #[rustc_dirty(label="Hir", cfg="cfail2")]
#[rustc_clean(label="Hir", cfg="cfail3")]
#[rustc_dirty(label="HirBody", cfg="cfail2")]
#[rustc_clean(label="HirBody", cfg="cfail3")]
--- /dev/null
+#![feature(async_await)]
+#![allow(unused_parens)]
+
+// edition:2018
+// pp-exact
+
+fn main() { let _a = (async { }); }
// no-prefer-dynamic
#![crate_type = "proc-macro"]
-#![feature(proc_macro_non_items)]
+#![feature(proc_macro_hygiene)]
extern crate proc_macro;
// no-prefer-dynamic
#![crate_type = "proc-macro"]
-#![feature(proc_macro_non_items, proc_macro_quote)]
+#![feature(proc_macro_hygiene, proc_macro_quote)]
extern crate proc_macro;
// no-prefer-dynamic
#![crate_type = "proc-macro"]
-#![feature(proc_macro_non_items)]
+#![feature(proc_macro_hygiene)]
extern crate proc_macro;
#[macro_use] #[no_link]
extern crate macro_crate_test;
-#[derive(PartialEq, Clone, Debug)]
#[rustc_into_multi_foo]
+#[derive(PartialEq, Clone, Debug)]
fn foo() -> AnotherFakeTypeThatHadBetterGoAway {}
// Check that the `#[into_multi_foo]`-generated `foo2` is configured away
// aux-build:cond_plugin.rs
// ignore-stage1
-#![feature(proc_macro_non_items)]
+#![feature(proc_macro_hygiene)]
extern crate cond_plugin;
// aux-build:hello_macro.rs
// ignore-stage1
-#![feature(proc_macro_non_items, proc_macro_gen)]
+#![feature(proc_macro_hygiene)]
extern crate hello_macro;
// aux-build:attr-stmt-expr.rs
// ignore-stage1
-#![feature(stmt_expr_attributes, proc_macro_expr)]
+#![feature(stmt_expr_attributes, proc_macro_hygiene)]
extern crate attr_stmt_expr;
use attr_stmt_expr::{expect_let, expect_print_stmt, expect_expr, expect_print_expr,
// no-prefer-dynamic
-#![feature(proc_macro_non_items, proc_macro_quote)]
+#![feature(proc_macro_hygiene, proc_macro_quote)]
#![crate_type = "proc-macro"]
extern crate proc_macro;
// no-prefer-dynamic
-#![feature(proc_macro_quote, proc_macro_non_items)]
+#![feature(proc_macro_quote, proc_macro_hygiene)]
#![crate_type = "proc-macro"]
extern crate proc_macro as proc_macro_renamed; // This does not break `quote!`
// aux-build:bang-macro.rs
// ignore-stage1
-#![feature(proc_macro_non_items)]
+#![feature(proc_macro_hygiene)]
extern crate bang_macro;
use bang_macro::rewrite;
// aux-build:call-site.rs
// ignore-stage1
-#![feature(proc_macro_non_items)]
+#![feature(proc_macro_hygiene)]
extern crate call_site;
use call_site::*;
// aux-build:count_compound_ops.rs
// ignore-stage1
-#![feature(proc_macro_non_items)]
+#![feature(proc_macro_hygiene)]
extern crate count_compound_ops;
use count_compound_ops::count_compound_ops;
// aux-build:hygiene_example.rs
// ignore-stage1
-#![feature(proc_macro_non_items)]
+#![feature(proc_macro_hygiene)]
extern crate hygiene_example;
use hygiene_example::hello;
// aux-build:negative-token.rs
// ignore-stage1
-#![feature(proc_macro_non_items)]
+#![feature(proc_macro_hygiene)]
extern crate negative_token;
// ignore-stage1
// ignore-cross-compile
-#![feature(proc_macro_non_items)]
+#![feature(proc_macro_hygiene)]
extern crate proc_macro_def;
// compile-flags: -C debug_assertions=yes
-#![feature(const_fn, libc)]
+#![stable(feature = "rustc", since = "1.0.0")]
+#![feature(const_fn, libc, staged_api, rustc_attrs)]
#![allow(const_err)]
extern crate libc;
use std::process::{Command, Stdio};
// this will panic in debug mode and overflow in release mode
+#[stable(feature = "rustc", since = "1.0.0")]
+#[rustc_promotable]
const fn bar() -> usize { 0 - 1 }
fn foo() {
use std::cell::Cell;
+const FIVE: Cell<i32> = Cell::new(5);
+
#[inline(never)]
fn tuple_field() -> &'static u32 {
// This test is MIR-borrowck-only because the old borrowck
// doesn't agree that borrows of "frozen" (i.e. without any
// interior mutability) fields of non-frozen temporaries,
// should be promoted, while MIR promotion does promote them.
- &(Cell::new(5), 42).1
+ &(FIVE, 42).1
}
fn main() {
#![allow(dead_code)]
// Regression test for #37154: the problem here was that the cache
-// results in a false error because it was caching skolemized results
-// even after those skolemized regions had been popped.
+// results in a false error because it was caching placeholder results
+// even after those placeholder regions had been popped.
trait Foo {
fn method(&self) {}
// aux-build:attr_proc_macro.rs
-// compile-flags:--test
-#![feature(test)]
-
-extern crate test;
extern crate attr_proc_macro;
use attr_proc_macro::*;
#[attr_proc_macro] //~ ERROR macro attributes must be placed before `#[derive]`
struct After;
-#[attr_proc_macro] //~ ERROR macro attributes cannot be used together with `#[test]` or `#[bench]`
-#[test]
-fn test_before() {}
-
-#[test]
-#[attr_proc_macro] //~ ERROR macro attributes cannot be used together with `#[test]` or `#[bench]`
-fn test_after() {}
-
-#[attr_proc_macro] //~ ERROR macro attributes cannot be used together with `#[test]` or `#[bench]`
-#[bench]
-fn bench_before(b: &mut test::Bencher) {}
-
-#[bench]
-#[attr_proc_macro] //~ ERROR macro attributes cannot be used together with `#[test]` or `#[bench]`
-fn bench_after(b: &mut test::Bencher) {}
+fn main() {}
error: macro attributes must be placed before `#[derive]`
- --> $DIR/attribute-order-restricted.rs:15:1
+ --> $DIR/attribute-order-restricted.rs:11:1
|
LL | #[attr_proc_macro] //~ ERROR macro attributes must be placed before `#[derive]`
| ^^^^^^^^^^^^^^^^^^
-error: macro attributes cannot be used together with `#[test]` or `#[bench]`
- --> $DIR/attribute-order-restricted.rs:18:1
- |
-LL | #[attr_proc_macro] //~ ERROR macro attributes cannot be used together with `#[test]` or `#[bench]`
- | ^^^^^^^^^^^^^^^^^^
-
-error: macro attributes cannot be used together with `#[test]` or `#[bench]`
- --> $DIR/attribute-order-restricted.rs:23:1
- |
-LL | #[attr_proc_macro] //~ ERROR macro attributes cannot be used together with `#[test]` or `#[bench]`
- | ^^^^^^^^^^^^^^^^^^
-
-error: macro attributes cannot be used together with `#[test]` or `#[bench]`
- --> $DIR/attribute-order-restricted.rs:26:1
- |
-LL | #[attr_proc_macro] //~ ERROR macro attributes cannot be used together with `#[test]` or `#[bench]`
- | ^^^^^^^^^^^^^^^^^^
-
-error: macro attributes cannot be used together with `#[test]` or `#[bench]`
- --> $DIR/attribute-order-restricted.rs:31:1
- |
-LL | #[attr_proc_macro] //~ ERROR macro attributes cannot be used together with `#[test]` or `#[bench]`
- | ^^^^^^^^^^^^^^^^^^
-
-error: aborting due to 5 previous errors
+error: aborting due to previous error
// aux-build:lifetimes.rs
-#![feature(proc_macro_non_items)]
+#![feature(proc_macro_hygiene)]
extern crate lifetimes;
// compile-pass
// aux-build:bang_proc_macro.rs
-#![feature(proc_macro_non_items)]
+#![feature(proc_macro_hygiene)]
#[macro_use]
extern crate bang_proc_macro;
// aux-build:multispan.rs
// ignore-stage1
-#![feature(proc_macro_non_items)]
+#![feature(proc_macro_hygiene)]
extern crate multispan;
// aux-build:parent-source-spans.rs
// ignore-stage1
-#![feature(decl_macro, proc_macro_non_items)]
+#![feature(decl_macro, proc_macro_hygiene)]
extern crate parent_source_spans;
// aux-build:three-equals.rs
// ignore-stage1
-#![feature(proc_macro_non_items)]
+#![feature(proc_macro_hygiene)]
extern crate three_equals;
| ^ borrow occurs here
...
LL | drop(bar);
- | --- borrow later used here
+ | --- first borrow later used here
error[E0501]: cannot borrow `*a` as immutable because previous closure requires unique access
--> $DIR/E0501.rs:31:23
| ^ borrow occurs here
...
LL | drop(bar);
- | --- borrow later used here
+ | --- first borrow later used here
error: aborting due to 2 previous errors
| ^ borrow occurs here
...
LL | drop(bar);
- | --- borrow later used here
+ | --- first borrow later used here
error[E0501]: cannot borrow `*a` as immutable because previous closure requires unique access
--> $DIR/E0501.rs:31:23
| ^ borrow occurs here
...
LL | drop(bar);
- | --- borrow later used here
+ | --- first borrow later used here
error: aborting due to 2 previous errors
LL | | &f; //~ ERROR: cannot borrow `f` as immutable because it is also borrowed as mutable
| | ^-
| |_____||
- | |borrow later used here
+ | |mutable borrow later used here
| immutable borrow occurs here
error[E0502]: cannot borrow `f` as mutable because it is also borrowed as immutable
LL | | &mut f; //~ ERROR: cannot borrow `f` as mutable because it is also borrowed as immutable
| | ^^^^^-
| |_____|____|
- | | borrow later used here
+ | | immutable borrow later used here
| mutable borrow occurs here
error: aborting due to 6 previous errors
LL | let b = &mut x.0; //~ ERROR cannot borrow `x.0` as mutable because it is also borrowed as
| ^^^^^^^^ mutable borrow occurs here
LL | a.use_ref();
- | - borrow later used here
+ | - immutable borrow later used here
error[E0499]: cannot borrow `x.0` as mutable more than once at a time
--> $DIR/borrow-tuple-fields.rs:33:13
LL | let b = &mut x.0; //~ ERROR cannot borrow `x.0` as mutable more than once at a time
| ^^^^^^^^ second mutable borrow occurs here
LL | a.use_ref();
- | - borrow later used here
+ | - first borrow later used here
error[E0505]: cannot move out of `x` because it is borrowed
--> $DIR/borrow-tuple-fields.rs:38:13
LL | let b = &mut x.0; //~ ERROR cannot borrow `x.0` as mutable because it is also borrowed as
| ^^^^^^^^ mutable borrow occurs here
LL | a.use_ref();
- | - borrow later used here
+ | - immutable borrow later used here
error[E0499]: cannot borrow `x.0` as mutable more than once at a time
--> $DIR/borrow-tuple-fields.rs:48:13
LL | let b = &mut x.0; //~ ERROR cannot borrow `x.0` as mutable more than once at a time
| ^^^^^^^^ second mutable borrow occurs here
LL | a.use_mut();
- | - borrow later used here
+ | - first borrow later used here
error: aborting due to 6 previous errors
| ^^^^^^^^^ second mutable borrow occurs here
...
LL | *a += 1;
- | ------- borrow later used here
+ | ------- first borrow later used here
error: aborting due to previous error
| ^^^^^^^^^ second mutable borrow occurs here
...
LL | *a += 1;
- | ------- borrow later used here
+ | ------- first borrow later used here
error: aborting due to previous error
| ^^^^^^^^^ second mutable borrow occurs here
...
LL | *a += 1;
- | ------- borrow later used here
+ | ------- first borrow later used here
error: aborting due to previous error
| ^ mutable borrow occurs here
LL |
LL | println!("{}", *q);
- | -- borrow later used here
+ | -- immutable borrow later used here
error[E0502]: cannot borrow `p` as mutable because it is also borrowed as immutable
--> $DIR/borrowck-assign-comp-idx.rs:37:9
|
-LL | / borrow(
-LL | | &p,
- | | -- immutable borrow occurs here
-LL | | || p[0] = 5); //~ ERROR cannot borrow `p` as mutable
- | |_________^^_-_______- borrow later used here
- | | |
- | | second borrow occurs due to use of `p` in closure
- | mutable borrow occurs here
+LL | borrow(
+ | ------ immutable borrow later used by call
+LL | &p,
+ | -- immutable borrow occurs here
+LL | || p[0] = 5); //~ ERROR cannot borrow `p` as mutable
+ | ^^ - second borrow occurs due to use of `p` in closure
+ | |
+ | mutable borrow occurs here
error: aborting due to 2 previous errors
error[E0499]: cannot borrow `x` as mutable more than once at a time
--> $DIR/borrowck-autoref-3261.rs:25:9
|
-LL | (&mut x).with(
- | --------
- | |
- | _____first mutable borrow occurs here
- | |
-LL | | |opt| { //~ ERROR cannot borrow `x` as mutable more than once at a time
- | | ^^^^^ second mutable borrow occurs here
-LL | | match opt {
-LL | | &Either::Right(ref f) => {
-LL | | x = X(Either::Left((0, 0)));
- | | - second borrow occurs due to use of `x` in closure
-... |
-LL | | }
-LL | | })
- | |__________- borrow later used here
+LL | (&mut x).with(
+ | -------- ---- first borrow later used by call
+ | |
+ | first mutable borrow occurs here
+LL | |opt| { //~ ERROR cannot borrow `x` as mutable more than once at a time
+ | ^^^^^ second mutable borrow occurs here
+...
+LL | x = X(Either::Left((0, 0)));
+ | - second borrow occurs due to use of `x` in closure
error: aborting due to previous error
error[E0502]: cannot borrow `a` as mutable because it is also borrowed as immutable
--> $DIR/borrowck-bad-nested-calls-free.rs:35:17
|
-LL | / add(
-LL | | &*a,
- | | --- immutable borrow occurs here
-LL | | rewrite(&mut a)); //~ ERROR cannot borrow
- | |_________________^^^^^^_- borrow later used here
- | |
- | mutable borrow occurs here
+LL | add(
+ | --- immutable borrow later used by call
+LL | &*a,
+ | --- immutable borrow occurs here
+LL | rewrite(&mut a)); //~ ERROR cannot borrow
+ | ^^^^^^ mutable borrow occurs here
error[E0502]: cannot borrow `a` as mutable because it is also borrowed as immutable
--> $DIR/borrowck-bad-nested-calls-free.rs:42:17
|
-LL | / add(
-LL | | &*a,
- | | --- immutable borrow occurs here
-LL | | rewrite(&mut a)); //~ ERROR cannot borrow
- | |_________________^^^^^^_- borrow later used here
- | |
- | mutable borrow occurs here
+LL | add(
+ | --- immutable borrow later used by call
+LL | &*a,
+ | --- immutable borrow occurs here
+LL | rewrite(&mut a)); //~ ERROR cannot borrow
+ | ^^^^^^ mutable borrow occurs here
error: aborting due to 2 previous errors
error[E0505]: cannot move out of `a` because it is borrowed
--> $DIR/borrowck-bad-nested-calls-move.rs:35:9
|
-LL | / add(
-LL | | &*a,
- | | --- borrow of `*a` occurs here
-LL | | a); //~ ERROR cannot move
- | |_________^- borrow later used here
- | |
- | move out of `a` occurs here
+LL | add(
+ | --- borrow later used by call
+LL | &*a,
+ | --- borrow of `*a` occurs here
+LL | a); //~ ERROR cannot move
+ | ^ move out of `a` occurs here
error[E0505]: cannot move out of `a` because it is borrowed
--> $DIR/borrowck-bad-nested-calls-move.rs:42:9
|
-LL | / add(
-LL | | &*a,
- | | --- borrow of `*a` occurs here
-LL | | a); //~ ERROR cannot move
- | |_________^- borrow later used here
- | |
- | move out of `a` occurs here
+LL | add(
+ | --- borrow later used by call
+LL | &*a,
+ | --- borrow of `*a` occurs here
+LL | a); //~ ERROR cannot move
+ | ^ move out of `a` occurs here
error: aborting due to 2 previous errors
LL | let _bar2 = &mut foo.bar1; //~ ERROR cannot borrow
| ^^^^^^^^^^^^^ second mutable borrow occurs here
LL | *bar1;
- | ----- borrow later used here
+ | ----- first borrow later used here
error[E0502]: cannot borrow `foo.bar1` as immutable because it is also borrowed as mutable
--> $DIR/borrowck-borrow-from-owned-ptr.rs:36:17
LL | let _bar2 = &foo.bar1; //~ ERROR cannot borrow
| ^^^^^^^^^ immutable borrow occurs here
LL | *bar1;
- | ----- borrow later used here
+ | ----- mutable borrow later used here
error[E0502]: cannot borrow `foo.bar1` as mutable because it is also borrowed as immutable
--> $DIR/borrowck-borrow-from-owned-ptr.rs:43:17
LL | let _bar2 = &mut foo.bar1; //~ ERROR cannot borrow
| ^^^^^^^^^^^^^ mutable borrow occurs here
LL | *bar1;
- | ----- borrow later used here
+ | ----- immutable borrow later used here
error[E0499]: cannot borrow `foo.bar1` as mutable more than once at a time
--> $DIR/borrowck-borrow-from-owned-ptr.rs:73:21
| ^^^^^^^^^^^^^ second mutable borrow occurs here
...
LL | *bar1;
- | ----- borrow later used here
+ | ----- first borrow later used here
error[E0502]: cannot borrow `foo.bar1` as immutable because it is also borrowed as mutable
--> $DIR/borrowck-borrow-from-owned-ptr.rs:82:17
| ^^^^^^^^^ immutable borrow occurs here
LL | let _foo2 = &*foo; //~ ERROR cannot borrow
LL | *bar1;
- | ----- borrow later used here
+ | ----- mutable borrow later used here
error[E0502]: cannot borrow `*foo` as immutable because it is also borrowed as mutable
--> $DIR/borrowck-borrow-from-owned-ptr.rs:83:17
LL | let _foo2 = &*foo; //~ ERROR cannot borrow
| ^^^^^ immutable borrow occurs here
LL | *bar1;
- | ----- borrow later used here
+ | ----- mutable borrow later used here
error[E0499]: cannot borrow `foo.bar1` as mutable more than once at a time
--> $DIR/borrowck-borrow-from-owned-ptr.rs:90:17
LL | let _foo1 = &mut foo.bar1; //~ ERROR cannot borrow
| ^^^^^^^^^^^^^ second mutable borrow occurs here
LL | *bar1;
- | ----- borrow later used here
+ | ----- first borrow later used here
error[E0499]: cannot borrow `*foo` as mutable more than once at a time
--> $DIR/borrowck-borrow-from-owned-ptr.rs:97:17
LL | let _foo2 = &mut *foo; //~ ERROR cannot borrow
| ^^^^^^^^^ second mutable borrow occurs here
LL | *bar1;
- | ----- borrow later used here
+ | ----- first borrow later used here
error[E0502]: cannot borrow `foo.bar1` as mutable because it is also borrowed as immutable
--> $DIR/borrowck-borrow-from-owned-ptr.rs:104:17
LL | let _foo1 = &mut foo.bar1; //~ ERROR cannot borrow
| ^^^^^^^^^^^^^ mutable borrow occurs here
LL | *bar1;
- | ----- borrow later used here
+ | ----- immutable borrow later used here
error[E0502]: cannot borrow `*foo` as mutable because it is also borrowed as immutable
--> $DIR/borrowck-borrow-from-owned-ptr.rs:111:17
LL | let _foo2 = &mut *foo; //~ ERROR cannot borrow
| ^^^^^^^^^ mutable borrow occurs here
LL | *bar1;
- | ----- borrow later used here
+ | ----- immutable borrow later used here
error[E0596]: cannot borrow `foo.bar1` as mutable, as `foo` is not declared as mutable
--> $DIR/borrowck-borrow-from-owned-ptr.rs:132:16
LL | let _bar2 = &mut foo.bar1; //~ ERROR cannot borrow
| ^^^^^^^^^^^^^ second mutable borrow occurs here
LL | *bar1;
- | ----- borrow later used here
+ | ----- first borrow later used here
error[E0502]: cannot borrow `foo.bar1` as immutable because it is also borrowed as mutable
--> $DIR/borrowck-borrow-from-stack-variable.rs:35:17
LL | let _bar2 = &foo.bar1; //~ ERROR cannot borrow
| ^^^^^^^^^ immutable borrow occurs here
LL | *bar1;
- | ----- borrow later used here
+ | ----- mutable borrow later used here
error[E0502]: cannot borrow `foo.bar1` as mutable because it is also borrowed as immutable
--> $DIR/borrowck-borrow-from-stack-variable.rs:42:17
LL | let _bar2 = &mut foo.bar1; //~ ERROR cannot borrow
| ^^^^^^^^^^^^^ mutable borrow occurs here
LL | *bar1;
- | ----- borrow later used here
+ | ----- immutable borrow later used here
error[E0499]: cannot borrow `foo.bar1` as mutable more than once at a time
--> $DIR/borrowck-borrow-from-stack-variable.rs:71:21
| ^^^^^^^^^^^^^ second mutable borrow occurs here
...
LL | *bar1;
- | ----- borrow later used here
+ | ----- first borrow later used here
error[E0502]: cannot borrow `foo.bar1` as immutable because it is also borrowed as mutable
--> $DIR/borrowck-borrow-from-stack-variable.rs:80:17
| ^^^^^^^^^ immutable borrow occurs here
LL | let _foo2 = &foo; //~ ERROR cannot borrow
LL | *bar1;
- | ----- borrow later used here
+ | ----- mutable borrow later used here
error[E0502]: cannot borrow `foo` as immutable because it is also borrowed as mutable
--> $DIR/borrowck-borrow-from-stack-variable.rs:81:17
LL | let _foo2 = &foo; //~ ERROR cannot borrow
| ^^^^ immutable borrow occurs here
LL | *bar1;
- | ----- borrow later used here
+ | ----- mutable borrow later used here
error[E0499]: cannot borrow `foo.bar1` as mutable more than once at a time
--> $DIR/borrowck-borrow-from-stack-variable.rs:88:17
LL | let _foo1 = &mut foo.bar1; //~ ERROR cannot borrow
| ^^^^^^^^^^^^^ second mutable borrow occurs here
LL | *bar1;
- | ----- borrow later used here
+ | ----- first borrow later used here
error[E0499]: cannot borrow `foo` as mutable more than once at a time
--> $DIR/borrowck-borrow-from-stack-variable.rs:95:17
LL | let _foo2 = &mut foo; //~ ERROR cannot borrow
| ^^^^^^^^ second mutable borrow occurs here
LL | *bar1;
- | ----- borrow later used here
+ | ----- first borrow later used here
error[E0502]: cannot borrow `foo.bar1` as mutable because it is also borrowed as immutable
--> $DIR/borrowck-borrow-from-stack-variable.rs:102:17
LL | let _foo1 = &mut foo.bar1; //~ ERROR cannot borrow
| ^^^^^^^^^^^^^ mutable borrow occurs here
LL | *bar1;
- | ----- borrow later used here
+ | ----- immutable borrow later used here
error[E0502]: cannot borrow `foo` as mutable because it is also borrowed as immutable
--> $DIR/borrowck-borrow-from-stack-variable.rs:109:17
LL | let _foo2 = &mut foo; //~ ERROR cannot borrow
| ^^^^^^^^ mutable borrow occurs here
LL | *bar1;
- | ----- borrow later used here
+ | ----- immutable borrow later used here
error[E0596]: cannot borrow `foo.bar1` as mutable, as `foo` is not declared as mutable
--> $DIR/borrowck-borrow-from-stack-variable.rs:130:16
LL | let p: &isize = &**t0; //~ ERROR cannot borrow
| ^^^^^ immutable borrow occurs here
LL | **t1 = 22;
- | --------- borrow later used here
+ | --------- mutable borrow later used here
error[E0596]: cannot borrow `**t0` as mutable, as it is behind a `&` reference
--> $DIR/borrowck-borrow-mut-base-ptr-in-aliasable-loc.rs:29:26
LL | x.f2(); //~ ERROR cannot borrow `*x` as mutable
| ^ second mutable borrow occurs here
LL | y.use_ref();
- | - borrow later used here
+ | - first borrow later used here
error: aborting due to previous error
| immutable borrow occurs here
LL | //[mir]~^ ERROR cannot borrow `x` as immutable because it is also borrowed as mutable
LL | drop(c1);
- | -- borrow later used here
+ | -- mutable borrow later used here
error[E0502]: cannot borrow `x` as immutable because it is also borrowed as mutable
--> $DIR/borrowck-closures-mut-and-imm.rs:39:14
| immutable borrow occurs here
LL | //[mir]~^ ERROR cannot borrow `x` as immutable because it is also borrowed as mutable
LL | drop(c1);
- | -- borrow later used here
+ | -- mutable borrow later used here
error[E0502]: cannot borrow `x` as immutable because it is also borrowed as mutable
--> $DIR/borrowck-closures-mut-and-imm.rs:47:14
| immutable borrow occurs here
LL | //[mir]~^ ERROR cannot borrow `x` as immutable because it is also borrowed as mutable
LL | drop(c1);
- | -- borrow later used here
+ | -- mutable borrow later used here
error[E0506]: cannot assign to `x` because it is borrowed
--> $DIR/borrowck-closures-mut-and-imm.rs:55:5
| mutable borrow occurs here
LL | //[mir]~^ ERROR cannot borrow `x` as mutable because it is also borrowed as immutable
LL | drop(c1);
- | -- borrow later used here
+ | -- immutable borrow later used here
error: aborting due to 8 previous errors
| immutable borrow occurs here
LL | //[mir]~^ ERROR cannot borrow `x` as immutable because it is also borrowed as mutable
LL | drop(c1);
- | -- borrow later used here
+ | -- mutable borrow later used here
error[E0502]: cannot borrow `x` as immutable because it is also borrowed as mutable
--> $DIR/borrowck-closures-mut-and-imm.rs:39:14
| immutable borrow occurs here
LL | //[mir]~^ ERROR cannot borrow `x` as immutable because it is also borrowed as mutable
LL | drop(c1);
- | -- borrow later used here
+ | -- mutable borrow later used here
error[E0502]: cannot borrow `x` as immutable because it is also borrowed as mutable
--> $DIR/borrowck-closures-mut-and-imm.rs:47:14
| immutable borrow occurs here
LL | //[mir]~^ ERROR cannot borrow `x` as immutable because it is also borrowed as mutable
LL | drop(c1);
- | -- borrow later used here
+ | -- mutable borrow later used here
error[E0506]: cannot assign to `x` because it is borrowed
--> $DIR/borrowck-closures-mut-and-imm.rs:55:5
| mutable borrow occurs here
LL | //[mir]~^ ERROR cannot borrow `x` as mutable because it is also borrowed as immutable
LL | drop(c1);
- | -- borrow later used here
+ | -- immutable borrow later used here
error: aborting due to 8 previous errors
| |
| second mutable borrow occurs here
LL | c1;
- | -- borrow later used here
+ | -- first borrow later used here
error[E0499]: cannot borrow `x` as mutable more than once at a time
--> $DIR/borrowck-closures-two-mut-fail.rs:37:24
| |
| second mutable borrow occurs here
LL | c1;
- | -- borrow later used here
+ | -- first borrow later used here
error[E0499]: cannot borrow `x` as mutable more than once at a time
--> $DIR/borrowck-closures-two-mut-fail.rs:44:24
| |
| second mutable borrow occurs here
LL | c1;
- | -- borrow later used here
+ | -- first borrow later used here
error[E0499]: cannot borrow `x` as mutable more than once at a time
--> $DIR/borrowck-closures-two-mut-fail.rs:51:24
| second mutable borrow occurs here
LL | //~^ ERROR cannot borrow `x` as mutable more than once
LL | c1;
- | -- borrow later used here
+ | -- first borrow later used here
error[E0499]: cannot borrow `x` as mutable more than once at a time
--> $DIR/borrowck-closures-two-mut-fail.rs:63:24
| second mutable borrow occurs here
LL | //~^ ERROR cannot borrow `x` as mutable more than once
LL | c1;
- | -- borrow later used here
+ | -- first borrow later used here
error: aborting due to 5 previous errors
| second mutable borrow occurs here
LL | //~| ERROR cannot borrow `x` as mutable more than once
LL | drop((c1, c2));
- | -- borrow later used here
+ | -- first borrow later used here
error[E0499]: cannot borrow `x` as mutable more than once at a time (Mir)
--> $DIR/borrowck-closures-two-mut.rs:36:24
| second mutable borrow occurs here
LL | //~| ERROR cannot borrow `x` as mutable more than once
LL | drop((c1, c2));
- | -- borrow later used here
+ | -- first borrow later used here
error[E0499]: cannot borrow `x` as mutable more than once at a time (Mir)
--> $DIR/borrowck-closures-two-mut.rs:44:24
| second mutable borrow occurs here
LL | //~| ERROR cannot borrow `x` as mutable more than once
LL | drop((c1, c2));
- | -- borrow later used here
+ | -- first borrow later used here
error[E0499]: cannot borrow `x` as mutable more than once at a time (Mir)
--> $DIR/borrowck-closures-two-mut.rs:52:24
| second mutable borrow occurs here
...
LL | drop((c1, c2));
- | -- borrow later used here
+ | -- first borrow later used here
error[E0499]: cannot borrow `x` as mutable more than once at a time (Mir)
--> $DIR/borrowck-closures-two-mut.rs:65:24
| second mutable borrow occurs here
...
LL | drop((c1, c2));
- | -- borrow later used here
+ | -- first borrow later used here
error: aborting due to 10 previous errors
LL | &mut this.x; //~ ERROR cannot borrow
| ^^^^^^^^^^^ mutable borrow occurs here
LL | p.use_ref();
- | - borrow later used here
+ | - immutable borrow later used here
error: aborting due to previous error
| |
| closure construction occurs here
LL | c1;
- | -- borrow later used here
+ | -- first borrow later used here
error[E0500]: closure requires unique access to `x` but it is already borrowed
--> $DIR/borrowck-closures-unique.rs:42:14
| |
| closure construction occurs here
LL | c1;
- | -- borrow later used here
+ | -- first borrow later used here
error[E0524]: two closures require unique access to `x` at the same time
--> $DIR/borrowck-closures-unique.rs:48:14
| |
| second closure is constructed here
LL | c1;
- | -- borrow later used here
+ | -- first borrow later used here
error[E0594]: cannot assign to `x`, as it is not declared as mutable
--> $DIR/borrowck-closures-unique.rs:57:38
| --- first borrow occurs due to use of `ptr` in closure
LL | };
LL | test(&*ptr); //~ ERROR cannot borrow `*ptr`
- | -----^^^^^-
- | | |
- | | immutable borrow occurs here
- | borrow later used here
+ | ---- ^^^^^ immutable borrow occurs here
+ | |
+ | mutable borrow later used by call
error: aborting due to previous error
| ^^^^^^ second mutable borrow occurs here
LL | //[mir]~^ ERROR cannot borrow `x` as mutable more than once at a time
LL | *y = 1;
- | ------ borrow later used here
+ | ------ first borrow later used here
error[E0499]: cannot borrow `x` as mutable more than once at a time
--> $DIR/borrowck-describe-lvalue.rs:307:20
| ^^^^^^ second mutable borrow occurs here
LL | //[mir]~^ ERROR cannot borrow `x` as mutable more than once at a time
LL | *y = 1;
- | ------ borrow later used here
+ | ------ first borrow later used here
error: unsatisfied lifetime constraints
--> $DIR/borrowck-describe-lvalue.rs:305:16
| ^^^^^^ immutable borrow occurs here
...
LL | drop(x);
- | - borrow later used here
+ | - mutable borrow later used here
error[E0502]: cannot borrow `e.x` as immutable because it is also borrowed as mutable
--> $DIR/borrowck-describe-lvalue.rs:207:23
| ^^^^^^ immutable borrow occurs here
...
LL | drop(x);
- | - borrow later used here
+ | - mutable borrow later used here
error[E0502]: cannot borrow `s.y.0` as immutable because it is also borrowed as mutable
--> $DIR/borrowck-describe-lvalue.rs:221:22
| ^^^^^^ immutable borrow occurs here
...
LL | drop(x);
- | - borrow later used here
+ | - mutable borrow later used here
error[E0502]: cannot borrow `s.x.y` as immutable because it is also borrowed as mutable
--> $DIR/borrowck-describe-lvalue.rs:228:28
| ^^^^^^ immutable borrow occurs here
...
LL | drop(x);
- | - borrow later used here
+ | - mutable borrow later used here
error[E0503]: cannot use `*v` because it was mutably borrowed
--> $DIR/borrowck-describe-lvalue.rs:271:9
| ^^^^^^ immutable borrow occurs here
...
LL | drop(x);
- | - borrow later used here
+ | - mutable borrow later used here
error[E0502]: cannot borrow `*block.current` as immutable because it is also borrowed as mutable
--> $DIR/borrowck-describe-lvalue.rs:245:29
| ^^^^^^^^^^^^^^^ immutable borrow occurs here
...
LL | drop(x);
- | - borrow later used here
+ | - mutable borrow later used here
error[E0502]: cannot borrow `*block.current` as immutable because it is also borrowed as mutable
--> $DIR/borrowck-describe-lvalue.rs:260:33
| ^^^^^^^^^^^^^^^^^^ immutable borrow occurs here
...
LL | drop(x);
- | - borrow later used here
+ | - mutable borrow later used here
error[E0382]: use of moved value: `x`
--> $DIR/borrowck-describe-lvalue.rs:318:22
| ^^^^^^ second mutable borrow occurs here
LL | //[mir]~^ ERROR cannot borrow `x` as mutable more than once at a time
LL | *y = 1;
- | ------ borrow later used here
+ | ------ first borrow later used here
error[E0499]: cannot borrow `x` as mutable more than once at a time
--> $DIR/borrowck-describe-lvalue.rs:307:20
| ^^^^^^ second mutable borrow occurs here
LL | //[mir]~^ ERROR cannot borrow `x` as mutable more than once at a time
LL | *y = 1;
- | ------ borrow later used here
+ | ------ first borrow later used here
error: unsatisfied lifetime constraints
--> $DIR/borrowck-describe-lvalue.rs:305:16
| ^^^^^^ immutable borrow occurs here
...
LL | drop(x);
- | - borrow later used here
+ | - mutable borrow later used here
error[E0502]: cannot borrow `e.x` as immutable because it is also borrowed as mutable
--> $DIR/borrowck-describe-lvalue.rs:207:23
| ^^^^^^ immutable borrow occurs here
...
LL | drop(x);
- | - borrow later used here
+ | - mutable borrow later used here
error[E0502]: cannot borrow `s.y.0` as immutable because it is also borrowed as mutable
--> $DIR/borrowck-describe-lvalue.rs:221:22
| ^^^^^^ immutable borrow occurs here
...
LL | drop(x);
- | - borrow later used here
+ | - mutable borrow later used here
error[E0502]: cannot borrow `s.x.y` as immutable because it is also borrowed as mutable
--> $DIR/borrowck-describe-lvalue.rs:228:28
| ^^^^^^ immutable borrow occurs here
...
LL | drop(x);
- | - borrow later used here
+ | - mutable borrow later used here
error[E0503]: cannot use `*v` because it was mutably borrowed
--> $DIR/borrowck-describe-lvalue.rs:271:9
| ^^^^^^ immutable borrow occurs here
...
LL | drop(x);
- | - borrow later used here
+ | - mutable borrow later used here
error[E0502]: cannot borrow `*block.current` as immutable because it is also borrowed as mutable
--> $DIR/borrowck-describe-lvalue.rs:245:29
| ^^^^^^^^^^^^^^^ immutable borrow occurs here
...
LL | drop(x);
- | - borrow later used here
+ | - mutable borrow later used here
error[E0502]: cannot borrow `*block.current` as immutable because it is also borrowed as mutable
--> $DIR/borrowck-describe-lvalue.rs:260:33
| ^^^^^^^^^^^^^^^^^^ immutable borrow occurs here
...
LL | drop(x);
- | - borrow later used here
+ | - mutable borrow later used here
error[E0382]: use of moved value: `x`
--> $DIR/borrowck-describe-lvalue.rs:318:22
LL | let q = &mut x.a; //~ ERROR cannot borrow `x.a` as mutable more than once at a time
| ^^^^^^^^ second mutable borrow occurs here
LL | drop(*p);
- | -- borrow later used here
+ | -- first borrow later used here
error[E0382]: use of moved value: `x.b`
--> $DIR/borrowck-field-sensitivity.rs:66:10
| -------
| |
| immutable borrow occurs here
- | borrow used here, in later iteration of loop
+ | immutable borrow used here, in later iteration of loop
LL | let cap = vector.capacity();
LL | vector.extend(repeat(0)); //~ ERROR cannot borrow
| ^^^^^^^^^^^^^^^^^^^^^^^^ mutable borrow occurs here
| -------
| |
| immutable borrow occurs here
- | borrow used here, in later iteration of loop
+ | immutable borrow used here, in later iteration of loop
...
LL | vector[1] = 5; //~ ERROR cannot borrow
| ^^^^^^ mutable borrow occurs here
error[E0501]: cannot borrow `*f` as mutable because previous closure requires unique access
--> $DIR/borrowck-insert-during-each.rs:26:3
|
-LL | f.foo(
- | ___^
- | |___|
- | ||
-LL | || |a| { //~ ERROR closure requires unique access to `f`
- | || --- closure construction occurs here
-LL | || f.n.insert(*a);
- | || - first borrow occurs due to use of `f` in closure
-LL | || })
- | || ^
- | ||__________|
- | |___________borrow occurs here
- | borrow later used here
-
-error[E0500]: closure requires unique access to `f` but it is already borrowed
- --> $DIR/borrowck-insert-during-each.rs:27:9
- |
LL | f.foo(
- | -
- | |
- | ___borrow occurs here
+ | ^ --- first borrow later used by call
+ | ___|
| |
LL | | |a| { //~ ERROR closure requires unique access to `f`
- | | ^^^ closure construction occurs here
+ | | --- closure construction occurs here
LL | | f.n.insert(*a);
- | | - second borrow occurs due to use of `f` in closure
+ | | - first borrow occurs due to use of `f` in closure
LL | | })
- | |__________- borrow later used here
+ | |__________^ borrow occurs here
+
+error[E0500]: closure requires unique access to `f` but it is already borrowed
+ --> $DIR/borrowck-insert-during-each.rs:27:9
+ |
+LL | f.foo(
+ | - --- first borrow later used by call
+ | |
+ | borrow occurs here
+LL | |a| { //~ ERROR closure requires unique access to `f`
+ | ^^^ closure construction occurs here
+LL | f.n.insert(*a);
+ | - second borrow occurs due to use of `f` in closure
error: aborting due to 2 previous errors
LL | borrow_mut(&mut *v); //~ ERROR cannot borrow
| ^^^^^^^ mutable borrow occurs here
LL | _w.use_ref();
- | -- borrow later used here
+ | -- immutable borrow later used here
error: aborting due to previous error
| ^^^ immutable borrow occurs here
LL | }
LL | *x = box 5;
- | -- borrow used here, in later iteration of loop
+ | -- mutable borrow used here, in later iteration of loop
error[E0502]: cannot borrow `*v` as immutable because it is also borrowed as mutable
--> $DIR/borrowck-lend-flow-loop.rs:109:16
|
LL | **x += 1;
- | -------- borrow used here, in later iteration of loop
+ | -------- mutable borrow used here, in later iteration of loop
LL | borrow(&*v); //~ ERROR cannot borrow
| ^^^ immutable borrow occurs here
LL | if cond2 {
LL | borrow_mut(&mut *v); //~ ERROR cannot borrow
| ^^^^^^^ mutable borrow occurs here
LL | _w.use_ref();
- | -- borrow later used here
+ | -- immutable borrow later used here
error: aborting due to previous error
error[E0502]: cannot borrow `v` as mutable because it is also borrowed as immutable
--> $DIR/borrowck-loan-blocks-mut-uniq.rs:20:12
|
-LL | borrow(&*v,
- | - --- immutable borrow occurs here
- | _____|
- | |
-LL | | |w| { //~ ERROR cannot borrow `v` as mutable
- | | ^^^ mutable borrow occurs here
-LL | | v = box 4;
- | | - second borrow occurs due to use of `v` in closure
-LL | | assert_eq!(*v, 3);
-LL | | assert_eq!(*w, 4);
-LL | | })
- | |__________- borrow later used here
+LL | borrow(&*v,
+ | ------ --- immutable borrow occurs here
+ | |
+ | immutable borrow later used by call
+LL | |w| { //~ ERROR cannot borrow `v` as mutable
+ | ^^^ mutable borrow occurs here
+LL | v = box 4;
+ | - second borrow occurs due to use of `v` in closure
error: aborting due to previous error
| ^ immutable borrow occurs here
LL |
LL | *q + 3; // OK to use the new alias `q`
- | -- borrow later used here
+ | -- mutable borrow later used here
error: aborting due to 2 previous errors
error[E0502]: cannot borrow `p` as mutable because it is also borrowed as immutable
--> $DIR/borrowck-loan-rcvr.rs:34:14
|
-LL | p.blockm(|| { //~ ERROR cannot borrow `p` as mutable
- | - ^^ mutable borrow occurs here
- | |
- | _____immutable borrow occurs here
- | |
-LL | | p.x = 10;
- | | - second borrow occurs due to use of `p` in closure
-LL | | })
- | |______- borrow later used here
+LL | p.blockm(|| { //~ ERROR cannot borrow `p` as mutable
+ | - ------ ^^ mutable borrow occurs here
+ | | |
+ | | immutable borrow later used by call
+ | immutable borrow occurs here
+LL | p.x = 10;
+ | - second borrow occurs due to use of `p` in closure
error[E0502]: cannot borrow `p` as immutable because it is also borrowed as mutable
--> $DIR/borrowck-loan-rcvr.rs:45:5
| ^ immutable borrow occurs here
LL |
LL | l.x += 1;
- | -------- borrow later used here
+ | -------- mutable borrow later used here
error: aborting due to 2 previous errors
error[E0502]: cannot borrow `v` as mutable because it is also borrowed as immutable
--> $DIR/borrowck-loan-vec-content.rs:28:9
|
-LL | / takes_imm_elt(
-LL | | &v[0],
- | | - immutable borrow occurs here
-LL | | || { //~ ERROR cannot borrow `v` as mutable
- | | ^^ mutable borrow occurs here
-LL | | v[1] = 4;
- | | - second borrow occurs due to use of `v` in closure
-LL | | })
- | |__________- borrow later used here
+LL | takes_imm_elt(
+ | ------------- immutable borrow later used by call
+LL | &v[0],
+ | - immutable borrow occurs here
+LL | || { //~ ERROR cannot borrow `v` as mutable
+ | ^^ mutable borrow occurs here
+LL | v[1] = 4;
+ | - second borrow occurs due to use of `v` in closure
error: aborting due to previous error
--- /dev/null
+error[E0507]: cannot move out of an `Rc`
+ --> $DIR/borrowck-move-out-of-overloaded-auto-deref.rs:17:14
+ |
+LL | let _x = Rc::new(vec![1, 2]).into_iter();
+ | ^^^^^^^^^^^^^^^^^^^ cannot move out of an `Rc`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0507`.
-error[E0507]: cannot move out of borrowed content
+error[E0507]: cannot move out of an `Rc`
--> $DIR/borrowck-move-out-of-overloaded-auto-deref.rs:17:14
|
LL | let _x = Rc::new(vec![1, 2]).into_iter();
- | ^^^^^^^^^^^^^^^^^^^ cannot move out of borrowed content
+ | ^^^^^^^^^^^^^^^^^^^ cannot move out of an `Rc`
error: aborting due to previous error
-error[E0507]: cannot move out of borrowed content
+error[E0507]: cannot move out of an `Rc`
--> $DIR/borrowck-move-out-of-overloaded-deref.rs:14:14
|
LL | let _x = *Rc::new("hi".to_string());
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
| |
- | cannot move out of borrowed content
+ | cannot move out of an `Rc`
| help: consider removing the `*`: `Rc::new("hi".to_string())`
error: aborting due to previous error
LL | 1 => { addr.push(&mut x); } //[ast]~ ERROR [E0499]
| ---- ^^^^^^ second mutable borrow occurs here
| |
- | borrow used here, in later iteration of loop
+ | first borrow used here, in later iteration of loop
...
LL | _ => { addr.push(&mut x); } //[ast]~ ERROR [E0499]
| ------ first mutable borrow occurs here
--> $DIR/borrowck-mut-borrow-linear-errors.rs:25:30
|
LL | 1 => { addr.push(&mut x); } //[ast]~ ERROR [E0499]
- | ---- borrow used here, in later iteration of loop
+ | ---- first borrow used here, in later iteration of loop
LL | //[mir]~^ ERROR [E0499]
LL | 2 => { addr.push(&mut x); } //[ast]~ ERROR [E0499]
| ^^^^^^ second mutable borrow occurs here
LL | 1 => { addr.push(&mut x); } //[ast]~ ERROR [E0499]
| ---- ^^^^^^ second mutable borrow occurs here
| |
- | borrow used here, in later iteration of loop
+ | first borrow used here, in later iteration of loop
...
LL | _ => { addr.push(&mut x); } //[ast]~ ERROR [E0499]
| ------ first mutable borrow occurs here
--> $DIR/borrowck-mut-borrow-linear-errors.rs:25:30
|
LL | 1 => { addr.push(&mut x); } //[ast]~ ERROR [E0499]
- | ---- borrow used here, in later iteration of loop
+ | ---- first borrow used here, in later iteration of loop
LL | //[mir]~^ ERROR [E0499]
LL | 2 => { addr.push(&mut x); } //[ast]~ ERROR [E0499]
| ^^^^^^ second mutable borrow occurs here
| ^^^^^^^ mutable borrow occurs here
LL | **t2 += 1; // Mutates `*t0`
LL | p.use_ref();
- | - borrow later used here
+ | - immutable borrow later used here
error[E0499]: cannot borrow `t0` as mutable more than once at a time
--> $DIR/borrowck-mut-borrow-of-mut-base-ptr.rs:29:18
| ^^^^^^^ second mutable borrow occurs here
LL | **t2 += 1; // Mutates `*t0` but not through `*p`
LL | p.use_mut();
- | - borrow later used here
+ | - first borrow later used here
error: aborting due to 2 previous errors
LL | let z = x.mut_borrowed(); //~ ERROR cannot borrow
| ^^^^^^^^^^^^^^^^ mutable borrow occurs here
LL | y.use_ref();
- | - borrow later used here
+ | - immutable borrow later used here
error[E0502]: cannot borrow `x` as mutable because it is also borrowed as immutable
--> $DIR/borrowck-object-lifetime.rs:36:13
LL | let z = &mut x; //~ ERROR cannot borrow
| ^^^^^^ mutable borrow occurs here
LL | y.use_ref();
- | - borrow later used here
+ | - immutable borrow later used here
error: aborting due to 2 previous errors
LL | let q = &f[&s]; //~ ERROR cannot borrow
| ^ immutable borrow occurs here
LL | p.use_mut();
- | - borrow later used here
+ | - mutable borrow later used here
error[E0499]: cannot borrow `*f` as mutable more than once at a time
--> $DIR/borrowck-overloaded-index-autoderef.rs:53:18
LL | let q = &mut f[&s]; //~ ERROR cannot borrow
| ^ second mutable borrow occurs here
LL | p.use_mut();
- | - borrow later used here
+ | - first borrow later used here
error[E0499]: cannot borrow `f.foo` as mutable more than once at a time
--> $DIR/borrowck-overloaded-index-autoderef.rs:63:18
LL | let q = &mut f.foo[&s]; //~ ERROR cannot borrow
| ^^^^^ second mutable borrow occurs here
LL | p.use_mut();
- | - borrow later used here
+ | - first borrow later used here
error[E0502]: cannot borrow `f.foo` as mutable because it is also borrowed as immutable
--> $DIR/borrowck-overloaded-index-autoderef.rs:75:18
LL | let q = &mut f.foo[&s]; //~ ERROR cannot borrow
| ^^^^^ mutable borrow occurs here
LL | p.use_ref();
- | - borrow later used here
+ | - immutable borrow later used here
error[E0506]: cannot assign to `f.foo` because it is borrowed
--> $DIR/borrowck-overloaded-index-autoderef.rs:81:5
| ^^ immutable borrow occurs here
...
LL | drop(rs);
- | -- borrow later used here
+ | -- mutable borrow later used here
error[E0502]: cannot borrow `s` as immutable because it is also borrowed as mutable
--> $DIR/borrowck-overloaded-index-ref-index.rs:65:7
| ^^ immutable borrow occurs here
...
LL | drop(rs);
- | -- borrow later used here
+ | -- mutable borrow later used here
error[E0594]: cannot assign to data in a `&` reference
--> $DIR/borrowck-overloaded-index-ref-index.rs:71:5
| ^^ immutable borrow occurs here
...
LL | drop(rs);
- | -- borrow later used here
+ | -- mutable borrow later used here
error[E0502]: cannot borrow `s` as immutable because it is also borrowed as mutable
--> $DIR/borrowck-overloaded-index-ref-index.rs:65:7
| ^^ immutable borrow occurs here
...
LL | drop(rs);
- | -- borrow later used here
+ | -- mutable borrow later used here
error[E0594]: cannot assign to data in a `&` reference
--> $DIR/borrowck-overloaded-index-ref-index.rs:71:5
| ^^ immutable borrow occurs here
...
LL | y.use_mut();
- | - borrow later used here
+ | - mutable borrow later used here
error[E0502]: cannot borrow `x` as mutable because it is also borrowed as immutable
--> $DIR/borrowck-report-with-custom-diagnostic.rs:30:21
| ^^^^^^ mutable borrow occurs here
...
LL | y.use_ref();
- | - borrow later used here
+ | - immutable borrow later used here
error[E0499]: cannot borrow `x` as mutable more than once at a time
--> $DIR/borrowck-report-with-custom-diagnostic.rs:45:17
| ^^^^^^ second mutable borrow occurs here
...
LL | y.use_mut();
- | - borrow later used here
+ | - first borrow later used here
error: aborting due to 3 previous errors
LL | if let [_, ref mut second2, ref mut third, ..] = *s { //~ERROR
| ^^^^^^^^^^^^^^^^ mutable borrow occurs here
LL | nop(&[first, second, second2, third]);
- | ------ borrow later used here
+ | ------ immutable borrow later used here
error[E0502]: cannot borrow `s[..]` as mutable because it is also borrowed as immutable
--> $DIR/borrowck-slice-pattern-element-loan.rs:44:21
LL | if let [.., ref mut third2, _, _] = *s { //~ERROR
| ^^^^^^^^^^^^^^ mutable borrow occurs here
LL | nop(&[first, third, third2, fourth]);
- | ----- borrow later used here
+ | ----- immutable borrow later used here
error[E0502]: cannot borrow `s[..]` as mutable because it is also borrowed as immutable
--> $DIR/borrowck-slice-pattern-element-loan.rs:55:20
LL | if let [_, ref mut from_begin1, ..] = *s { //~ERROR
| ^^^^^^^^^^^^^^^^^^^ mutable borrow occurs here
LL | nop(&[from_begin1, from_end1, from_end3, from_end4]);
- | --------- borrow later used here
+ | --------- immutable borrow later used here
error[E0502]: cannot borrow `s[..]` as mutable because it is also borrowed as immutable
--> $DIR/borrowck-slice-pattern-element-loan.rs:58:23
LL | if let [_, _, ref mut from_begin2, ..] = *s { //~ERROR
| ^^^^^^^^^^^^^^^^^^^ mutable borrow occurs here
LL | nop(&[from_begin2, from_end1, from_end3, from_end4]);
- | --------- borrow later used here
+ | --------- immutable borrow later used here
error[E0502]: cannot borrow `s[..]` as mutable because it is also borrowed as immutable
--> $DIR/borrowck-slice-pattern-element-loan.rs:61:26
LL | if let [_, _, _, ref mut from_begin3, ..] = *s { //~ERROR
| ^^^^^^^^^^^^^^^^^^^ mutable borrow occurs here
LL | nop(&[from_begin3, from_end1, from_end3, from_end4]);
- | --------- borrow later used here
+ | --------- immutable borrow later used here
error[E0502]: cannot borrow `s[..]` as mutable because it is also borrowed as immutable
--> $DIR/borrowck-slice-pattern-element-loan.rs:69:21
LL | if let [.., ref mut from_end2, _] = *s { //~ERROR
| ^^^^^^^^^^^^^^^^^ mutable borrow occurs here
LL | nop(&[from_begin0, from_begin1, from_begin3, from_end2]);
- | ----------- borrow later used here
+ | ----------- immutable borrow later used here
error[E0502]: cannot borrow `s[..]` as mutable because it is also borrowed as immutable
--> $DIR/borrowck-slice-pattern-element-loan.rs:72:21
LL | if let [.., ref mut from_end3, _, _] = *s { //~ERROR
| ^^^^^^^^^^^^^^^^^ mutable borrow occurs here
LL | nop(&[from_begin0, from_begin1, from_begin3, from_end3]);
- | ----------- borrow later used here
+ | ----------- immutable borrow later used here
error[E0502]: cannot borrow `s[..]` as mutable because it is also borrowed as immutable
--> $DIR/borrowck-slice-pattern-element-loan.rs:75:21
LL | if let [.., ref mut from_end4, _, _, _] = *s { //~ERROR
| ^^^^^^^^^^^^^^^^^ mutable borrow occurs here
LL | nop(&[from_begin0, from_begin1, from_begin3, from_end4]);
- | ----------- borrow later used here
+ | ----------- immutable borrow later used here
error[E0502]: cannot borrow `s[..]` as mutable because it is also borrowed as immutable
--> $DIR/borrowck-slice-pattern-element-loan.rs:92:20
LL | if let [_, ref mut tail..] = *s { //~ERROR
| ^^^^^^^^^^^^ mutable borrow occurs here
LL | nop(&[first, second]);
- | ------ borrow later used here
+ | ------ immutable borrow later used here
error[E0502]: cannot borrow `s[..]` as mutable because it is also borrowed as immutable
--> $DIR/borrowck-slice-pattern-element-loan.rs:110:17
LL | if let [ref mut tail.., _] = *s { //~ERROR
| ^^^^^^^^^^^^ mutable borrow occurs here
LL | nop(&[first, second]);
- | ------ borrow later used here
+ | ------ immutable borrow later used here
error[E0502]: cannot borrow `s[..]` as mutable because it is also borrowed as immutable
--> $DIR/borrowck-slice-pattern-element-loan.rs:119:17
LL | if let [ref mut s2.., _, _, _] = *s { //~ERROR
| ^^^^^^^^^^ mutable borrow occurs here
LL | nop_subslice(s1);
- | -- borrow later used here
+ | -- immutable borrow later used here
error: aborting due to 11 previous errors
| ^^^^^^^ mutable borrow occurs here
LL | *t1 = 22;
LL | p.use_ref();
- | - borrow later used here
+ | - immutable borrow later used here
error: aborting due to previous error
| ^^^^^^^^ mutable borrow occurs here
LL | //[mir]~^ ERROR cannot borrow `u.a` as mutable because it is also borrowed as immutable
LL | drop(ra);
- | -- borrow later used here
+ | -- immutable borrow later used here
error[E0506]: cannot assign to `u.a` because it is borrowed
--> $DIR/borrowck-union-borrow.rs:43:13
| ^^^^^^^^ mutable borrow occurs here
LL | //[mir]~^ ERROR cannot borrow `u.b` as mutable because it is also borrowed as immutable
LL | drop(ra);
- | -- borrow later used here
+ | -- immutable borrow later used here
error[E0506]: cannot assign to `u.b` because it is borrowed
--> $DIR/borrowck-union-borrow.rs:66:13
| ^^^^ immutable borrow occurs here
LL | //[mir]~^ ERROR cannot borrow `u.a` as immutable because it is also borrowed as mutable
LL | drop(rma);
- | --- borrow later used here
+ | --- mutable borrow later used here
error[E0503]: cannot use `u.a` because it was mutably borrowed
--> $DIR/borrowck-union-borrow.rs:79:21
| ^^^^^^^^ second mutable borrow occurs here
LL | //[mir]~^ ERROR cannot borrow `u.a` as mutable more than once at a time
LL | drop(rma);
- | --- borrow later used here
+ | --- first borrow later used here
error[E0506]: cannot assign to `u.a` because it is borrowed
--> $DIR/borrowck-union-borrow.rs:91:13
| ^^^^ immutable borrow occurs here
LL | //[mir]~^ ERROR cannot borrow `u.b` as immutable because it is also borrowed as mutable
LL | drop(rma);
- | --- borrow later used here
+ | --- mutable borrow later used here
error[E0503]: cannot use `u.b` because it was mutably borrowed
--> $DIR/borrowck-union-borrow.rs:104:21
| ^^^^^^^^ second mutable borrow occurs here
LL | //[mir]~^ ERROR cannot borrow `u.b` as mutable more than once at a time
LL | drop(rma);
- | --- borrow later used here
+ | --- first borrow later used here
error[E0506]: cannot assign to `u.b` because it is borrowed
--> $DIR/borrowck-union-borrow.rs:117:13
| ^^^^^^^^ mutable borrow occurs here
LL | //[mir]~^ ERROR cannot borrow `u.a` as mutable because it is also borrowed as immutable
LL | drop(ra);
- | -- borrow later used here
+ | -- immutable borrow later used here
error[E0506]: cannot assign to `u.a` because it is borrowed
--> $DIR/borrowck-union-borrow.rs:43:13
| ^^^^^^^^ mutable borrow occurs here
LL | //[mir]~^ ERROR cannot borrow `u.b` as mutable because it is also borrowed as immutable
LL | drop(ra);
- | -- borrow later used here
+ | -- immutable borrow later used here
error[E0506]: cannot assign to `u.b` because it is borrowed
--> $DIR/borrowck-union-borrow.rs:66:13
| ^^^^ immutable borrow occurs here
LL | //[mir]~^ ERROR cannot borrow `u.a` as immutable because it is also borrowed as mutable
LL | drop(rma);
- | --- borrow later used here
+ | --- mutable borrow later used here
error[E0503]: cannot use `u.a` because it was mutably borrowed
--> $DIR/borrowck-union-borrow.rs:79:21
| ^^^^^^^^ second mutable borrow occurs here
LL | //[mir]~^ ERROR cannot borrow `u.a` as mutable more than once at a time
LL | drop(rma);
- | --- borrow later used here
+ | --- first borrow later used here
error[E0506]: cannot assign to `u.a` because it is borrowed
--> $DIR/borrowck-union-borrow.rs:91:13
| ^^^^ immutable borrow occurs here
LL | //[mir]~^ ERROR cannot borrow `u.b` as immutable because it is also borrowed as mutable
LL | drop(rma);
- | --- borrow later used here
+ | --- mutable borrow later used here
error[E0503]: cannot use `u.b` because it was mutably borrowed
--> $DIR/borrowck-union-borrow.rs:104:21
| ^^^^^^^^ second mutable borrow occurs here
LL | //[mir]~^ ERROR cannot borrow `u.b` as mutable more than once at a time
LL | drop(rma);
- | --- borrow later used here
+ | --- first borrow later used here
error[E0506]: cannot assign to `u.b` because it is borrowed
--> $DIR/borrowck-union-borrow.rs:117:13
LL | borrow(&*v); //~ ERROR cannot borrow `*v`
| ^^^ immutable borrow occurs here
LL | w.use_mut();
- | - borrow later used here
+ | - mutable borrow later used here
error[E0502]: cannot borrow `*v` as immutable because it is also borrowed as mutable
--> $DIR/borrowck-uniq-via-lend.rs:63:12
LL | borrow(&*v); //~ ERROR cannot borrow `*v`
| ^^^ immutable borrow occurs here
LL | x.use_mut();
- | - borrow later used here
+ | - mutable borrow later used here
error: aborting due to 2 previous errors
| ------ first mutable borrow occurs here
...
LL | v.push(tail[0] + tail[1]); //~ ERROR cannot borrow
- | ^ ------- borrow later used here
+ | ^ ------- first borrow later used here
| |
| second mutable borrow occurs here
LL | bar.take(); //~ ERROR cannot borrow
| ^^^ second mutable borrow occurs here
LL | drop(baz);
- | --- borrow later used here
+ | --- first borrow later used here
error: aborting due to previous error
LL | (self.func)(arg) //~ ERROR cannot borrow
| ^^^ mutable borrow starts here in previous iteration of loop
|
-note: borrowed value must be valid for the lifetime 'a as defined on the impl at 17:6...
+note: first borrowed value must be valid for the lifetime 'a as defined on the impl at 17:6...
--> $DIR/mut-borrow-in-loop.rs:17:6
|
LL | impl<'a, T : 'a> FuncWrapper<'a, T> {
LL | (self.func)(arg) //~ ERROR cannot borrow
| ^^^ mutable borrow starts here in previous iteration of loop
|
-note: borrowed value must be valid for the lifetime 'a as defined on the impl at 17:6...
+note: first borrowed value must be valid for the lifetime 'a as defined on the impl at 17:6...
--> $DIR/mut-borrow-in-loop.rs:17:6
|
LL | impl<'a, T : 'a> FuncWrapper<'a, T> {
LL | (self.func)(arg) //~ ERROR cannot borrow
| ^^^ mutable borrow starts here in previous iteration of loop
|
-note: borrowed value must be valid for the lifetime 'a as defined on the impl at 17:6...
+note: first borrowed value must be valid for the lifetime 'a as defined on the impl at 17:6...
--> $DIR/mut-borrow-in-loop.rs:17:6
|
LL | impl<'a, T : 'a> FuncWrapper<'a, T> {
LL | let second = &mut void; //~ ERROR cannot borrow
| ^^^^^^^^^ second mutable borrow occurs here
LL | first.use_mut();
- | ----- borrow later used here
+ | ----- first borrow later used here
error[E0499]: cannot borrow `inner_void` as mutable more than once at a time
--> $DIR/mut-borrow-outside-loop.rs:25:28
| ^^^^^^^^^^^^^^^ second mutable borrow occurs here
LL | inner_second.use_mut();
LL | inner_first.use_mut();
- | ----------- borrow used here, in later iteration of loop
+ | ----------- first borrow used here, in later iteration of loop
error: aborting due to 2 previous errors
| ^^ immutable borrow occurs here
LL | //[nll_target]~^ ERROR cannot borrow `x` as immutable because it is also borrowed as mutable
LL | *y += 1;
- | ------- borrow later used here
+ | ------- mutable borrow later used here
error[E0502]: cannot borrow `x` as immutable because it is also borrowed as mutable
--> $DIR/two-phase-activation-sharing-interference.rs:50:13
| ^^ immutable borrow occurs here
LL | //[nll_target]~^ ERROR cannot borrow `x` as immutable because it is also borrowed as mutable
LL | *y += 1;
- | ------- borrow later used here
+ | ------- mutable borrow later used here
error[E0502]: cannot borrow `x` as immutable because it is also borrowed as mutable
--> $DIR/two-phase-activation-sharing-interference.rs:61:13
| ^^ immutable borrow occurs here
...
LL | *y += 1;
- | ------- borrow later used here
+ | ------- mutable borrow later used here
error[E0502]: cannot borrow `x` as immutable because it is also borrowed as mutable
--> $DIR/two-phase-activation-sharing-interference.rs:72:14
| ^^ immutable borrow occurs here
LL | //[nll_target]~^ ERROR cannot borrow `x` as immutable because it is also borrowed as mutable
LL | *y += 1;
- | ------- borrow later used here
+ | ------- mutable borrow later used here
error: aborting due to 4 previous errors
error[E0502]: cannot borrow `vec` as mutable because it is also borrowed as immutable
--> $DIR/two-phase-cannot-nest-mut-self-calls.rs:26:9
|
-LL | vec.get({
- | ---
- | |
- | _____immutable borrow occurs here
- | |
-LL | |
-LL | | vec.push(2);
- | | ^^^^^^^^^^^ mutable borrow occurs here
-LL | | //~^ ERROR cannot borrow `vec` as mutable because it is also borrowed as immutable
-LL | |
-LL | | 0
-LL | | });
- | |______- borrow later used here
+LL | vec.get({
+ | --- --- immutable borrow later used by call
+ | |
+ | immutable borrow occurs here
+LL |
+LL | vec.push(2);
+ | ^^^^^^^^^^^ mutable borrow occurs here
error: aborting due to previous error
--> $DIR/two-phase-multi-mut.rs:23:5
|
LL | foo.method(&mut foo);
- | ^^^^^^^^^^^--------^
- | | |
- | | first mutable borrow occurs here
+ | ^^^^------^--------^
+ | | | |
+ | | | first mutable borrow occurs here
+ | | first borrow later used by call
| second mutable borrow occurs here
- | borrow later used here
error[E0499]: cannot borrow `foo` as mutable more than once at a time
--> $DIR/two-phase-multi-mut.rs:23:16
|
LL | foo.method(&mut foo);
- | -----------^^^^^^^^-
- | | |
- | | second mutable borrow occurs here
+ | --- ------ ^^^^^^^^ second mutable borrow occurs here
+ | | |
+ | | first borrow later used by call
| first mutable borrow occurs here
- | borrow later used here
error: aborting due to 2 previous errors
--> $DIR/two-phase-nonrecv-autoref.rs:70:11
|
LL | f(f(10));
- | --^-----
- | | |
- | | second mutable borrow occurs here
+ | - ^ second mutable borrow occurs here
+ | |
| first mutable borrow occurs here
- | borrow later used here
+ | first borrow later used by call
error[E0382]: use of moved value: `*f`
--> $DIR/two-phase-nonrecv-autoref.rs:79:11
--> $DIR/two-phase-nonrecv-autoref.rs:86:11
|
LL | f(f(10));
- | --^-----
- | | |
- | | second mutable borrow occurs here
+ | - ^ second mutable borrow occurs here
+ | |
| first mutable borrow occurs here
- | borrow later used here
+ | first borrow later used by call
error[E0161]: cannot move a value of type dyn std::ops::FnOnce(i32) -> i32: the size of dyn std::ops::FnOnce(i32) -> i32 cannot be statically determined
--> $DIR/two-phase-nonrecv-autoref.rs:95:9
--> $DIR/two-phase-nonrecv-autoref.rs:139:27
|
LL | double_access(&mut a, &a);
- | ----------------------^^-
- | | | |
- | | | immutable borrow occurs here
+ | ------------- ------ ^^ immutable borrow occurs here
+ | | |
| | mutable borrow occurs here
- | borrow later used here
+ | mutable borrow later used by call
error[E0502]: cannot borrow `i` as immutable because it is also borrowed as mutable
--> $DIR/two-phase-nonrecv-autoref.rs:167:7
| | |
| | immutable borrow occurs here
| mutable borrow occurs here
- | borrow later used here
+ | mutable borrow later used here
error[E0502]: cannot borrow `i` as immutable because it is also borrowed as mutable
--> $DIR/two-phase-nonrecv-autoref.rs:173:7
| | |
| | immutable borrow occurs here
| mutable borrow occurs here
- | borrow later used here
+ | mutable borrow later used here
error: aborting due to 9 previous errors
--> $DIR/two-phase-nonrecv-autoref.rs:70:11
|
LL | f(f(10));
- | --^-----
- | | |
- | | second mutable borrow occurs here
+ | - ^ second mutable borrow occurs here
+ | |
| first mutable borrow occurs here
- | borrow later used here
+ | first borrow later used by call
error[E0382]: use of moved value: `*f`
--> $DIR/two-phase-nonrecv-autoref.rs:79:11
--> $DIR/two-phase-nonrecv-autoref.rs:86:11
|
LL | f(f(10));
- | --^-----
- | | |
- | | second mutable borrow occurs here
+ | - ^ second mutable borrow occurs here
+ | |
| first mutable borrow occurs here
- | borrow later used here
+ | first borrow later used by call
error[E0161]: cannot move a value of type dyn std::ops::FnOnce(i32) -> i32: the size of dyn std::ops::FnOnce(i32) -> i32 cannot be statically determined
--> $DIR/two-phase-nonrecv-autoref.rs:95:9
--> $DIR/two-phase-nonrecv-autoref.rs:139:27
|
LL | double_access(&mut a, &a);
- | ----------------------^^-
- | | | |
- | | | immutable borrow occurs here
+ | ------------- ------ ^^ immutable borrow occurs here
+ | | |
| | mutable borrow occurs here
- | borrow later used here
+ | mutable borrow later used by call
error[E0502]: cannot borrow `i` as immutable because it is also borrowed as mutable
--> $DIR/two-phase-nonrecv-autoref.rs:167:7
| | |
| | immutable borrow occurs here
| mutable borrow occurs here
- | borrow later used here
+ | mutable borrow later used here
error[E0502]: cannot borrow `i` as immutable because it is also borrowed as mutable
--> $DIR/two-phase-nonrecv-autoref.rs:173:7
| | |
| | immutable borrow occurs here
| mutable borrow occurs here
- | borrow later used here
+ | mutable borrow later used here
error: aborting due to 9 previous errors
| ^^^^^^^^ mutable borrow occurs here
...
LL | shared[0];
- | ------ borrow later used here
+ | ------ immutable borrow later used here
error: aborting due to previous error
error[E0499]: cannot borrow `v` as mutable more than once at a time
--> $DIR/two-phase-sneaky.rs:22:9
|
-LL | v[0].push_str({
- | -
- | |
- | _____first mutable borrow occurs here
- | |
-LL | |
-LL | | v.push(format!("foo"));
- | | ^ second mutable borrow occurs here
-LL | | //~^ ERROR cannot borrow `v` as mutable more than once at a time [E0499]
-LL | |
-LL | | "World!"
-LL | | });
- | |______- borrow later used here
+LL | v[0].push_str({
+ | - -------- first borrow later used by call
+ | |
+ | first mutable borrow occurs here
+LL |
+LL | v.push(format!("foo"));
+ | ^ second mutable borrow occurs here
error: aborting due to previous error
--> $DIR/two-phase-surprise-no-conflict.rs:79:17
|
LL | self.hash_expr(&self.cx_mut.body(eid).value);
- | ^^^^^^^^^^^^^^^^-----------^^^^^^^^^^^^^^^^^
- | | |
- | | immutable borrow occurs here
+ | ^^^^^---------^^-----------^^^^^^^^^^^^^^^^^
+ | | | |
+ | | | immutable borrow occurs here
+ | | immutable borrow later used by call
| mutable borrow occurs here
- | borrow later used here
error[E0499]: cannot borrow `reg.sess_mut` as mutable more than once at a time
--> $DIR/two-phase-surprise-no-conflict.rs:151:51
|
LL | reg.register_static(Box::new(TrivialPass::new(&mut reg.sess_mut)));
- | ----------------------------------------------^^^^^^^^^^^^^^^^^---
- | | |
- | | second mutable borrow occurs here
+ | --- --------------- ^^^^^^^^^^^^^^^^^ second mutable borrow occurs here
+ | | |
+ | | first borrow later used by call
| first mutable borrow occurs here
- | borrow later used here
error[E0499]: cannot borrow `reg.sess_mut` as mutable more than once at a time
--> $DIR/two-phase-surprise-no-conflict.rs:156:54
|
LL | reg.register_bound(Box::new(TrivialPass::new_mut(&mut reg.sess_mut)));
- | -------------------------------------------------^^^^^^^^^^^^^^^^^---
- | | |
- | | second mutable borrow occurs here
+ | --- -------------- ^^^^^^^^^^^^^^^^^ second mutable borrow occurs here
+ | | |
+ | | first borrow later used by call
| first mutable borrow occurs here
- | borrow later used here
error[E0499]: cannot borrow `reg.sess_mut` as mutable more than once at a time
--> $DIR/two-phase-surprise-no-conflict.rs:161:53
|
LL | reg.register_univ(Box::new(TrivialPass::new_mut(&mut reg.sess_mut)));
- | ------------------------------------------------^^^^^^^^^^^^^^^^^---
- | | |
- | | second mutable borrow occurs here
+ | --- ------------- ^^^^^^^^^^^^^^^^^ second mutable borrow occurs here
+ | | |
+ | | first borrow later used by call
| first mutable borrow occurs here
- | borrow later used here
error[E0499]: cannot borrow `reg.sess_mut` as mutable more than once at a time
--> $DIR/two-phase-surprise-no-conflict.rs:166:44
|
LL | reg.register_ref(&TrivialPass::new_mut(&mut reg.sess_mut));
- | ---------------------------------------^^^^^^^^^^^^^^^^^--
- | | |
- | | second mutable borrow occurs here
+ | --- ------------ ^^^^^^^^^^^^^^^^^ second mutable borrow occurs here
+ | | |
+ | | first borrow later used by call
| first mutable borrow occurs here
- | borrow later used here
error[E0502]: cannot borrow `*reg` as mutable because it is also borrowed as immutable
--> $DIR/two-phase-surprise-no-conflict.rs:178:5
|
LL | reg.register_bound(Box::new(CapturePass::new(®.sess_mut)));
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-------------^^^
- | | |
- | | immutable borrow occurs here
+ | ^^^^--------------^^^^^^^^^^^^^^^^^^^^^^^^^^^-------------^^^
+ | | | |
+ | | | immutable borrow occurs here
+ | | immutable borrow later used by call
| mutable borrow occurs here
- | borrow later used here
error[E0502]: cannot borrow `*reg` as mutable because it is also borrowed as immutable
--> $DIR/two-phase-surprise-no-conflict.rs:183:5
| | immutable borrow occurs here
| mutable borrow occurs here
|
-note: borrowed value must be valid for the lifetime 'a as defined on the function body at 122:21...
+note: immutable borrowed value must be valid for the lifetime 'a as defined on the function body at 122:21...
--> $DIR/two-phase-surprise-no-conflict.rs:122:21
|
LL | fn register_plugins<'a>(mk_reg: impl Fn() -> &'a mut Registry<'a>) {
--> $DIR/two-phase-surprise-no-conflict.rs:188:5
|
LL | reg.register_ref(&CapturePass::new(®.sess_mut));
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-------------^^
- | | |
- | | immutable borrow occurs here
+ | ^^^^------------^^^^^^^^^^^^^^^^^^^-------------^^
+ | | | |
+ | | | immutable borrow occurs here
+ | | immutable borrow later used by call
| mutable borrow occurs here
- | borrow later used here
error[E0499]: cannot borrow `*reg` as mutable more than once at a time
--> $DIR/two-phase-surprise-no-conflict.rs:200:5
|
LL | reg.register_bound(Box::new(CapturePass::new_mut(&mut reg.sess_mut)));
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-----------------^^^
- | | |
- | | first mutable borrow occurs here
+ | ^^^^--------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-----------------^^^
+ | | | |
+ | | | first mutable borrow occurs here
+ | | first borrow later used by call
| second mutable borrow occurs here
- | borrow later used here
error[E0499]: cannot borrow `reg.sess_mut` as mutable more than once at a time
--> $DIR/two-phase-surprise-no-conflict.rs:200:54
|
LL | reg.register_bound(Box::new(CapturePass::new_mut(&mut reg.sess_mut)));
- | -------------------------------------------------^^^^^^^^^^^^^^^^^---
- | | |
- | | second mutable borrow occurs here
+ | --- -------------- ^^^^^^^^^^^^^^^^^ second mutable borrow occurs here
+ | | |
+ | | first borrow later used by call
| first mutable borrow occurs here
- | borrow later used here
error[E0499]: cannot borrow `*reg` as mutable more than once at a time
--> $DIR/two-phase-surprise-no-conflict.rs:206:5
| | first mutable borrow occurs here
| second mutable borrow occurs here
|
-note: borrowed value must be valid for the lifetime 'a as defined on the function body at 122:21...
+note: first borrowed value must be valid for the lifetime 'a as defined on the function body at 122:21...
--> $DIR/two-phase-surprise-no-conflict.rs:122:21
|
LL | fn register_plugins<'a>(mk_reg: impl Fn() -> &'a mut Registry<'a>) {
--> $DIR/two-phase-surprise-no-conflict.rs:206:53
|
LL | reg.register_univ(Box::new(CapturePass::new_mut(&mut reg.sess_mut)));
- | ------------------------------------------------^^^^^^^^^^^^^^^^^---
- | | |
- | | second mutable borrow occurs here
+ | --- ------------- ^^^^^^^^^^^^^^^^^ second mutable borrow occurs here
+ | | |
+ | | first borrow later used by call
| first mutable borrow occurs here
- | borrow later used here
error[E0499]: cannot borrow `*reg` as mutable more than once at a time
--> $DIR/two-phase-surprise-no-conflict.rs:212:5
|
LL | reg.register_ref(&CapturePass::new_mut(&mut reg.sess_mut));
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-----------------^^
- | | |
- | | first mutable borrow occurs here
+ | ^^^^------------^^^^^^^^^^^^^^^^^^^^^^^-----------------^^
+ | | | |
+ | | | first mutable borrow occurs here
+ | | first borrow later used by call
| second mutable borrow occurs here
- | borrow later used here
error[E0499]: cannot borrow `reg.sess_mut` as mutable more than once at a time
--> $DIR/two-phase-surprise-no-conflict.rs:212:44
|
LL | reg.register_ref(&CapturePass::new_mut(&mut reg.sess_mut));
- | ---------------------------------------^^^^^^^^^^^^^^^^^--
- | | |
- | | second mutable borrow occurs here
+ | --- ------------ ^^^^^^^^^^^^^^^^^ second mutable borrow occurs here
+ | | |
+ | | first borrow later used by call
| first mutable borrow occurs here
- | borrow later used here
error: aborting due to 15 previous errors
--> $DIR/two-phase-surprise-no-conflict.rs:64:33
|
LL | self.hash_expr(&self.cx.body(eid).value);
- | ----------------^^^^^^^-----------------
- | | |
- | | immutable borrow occurs here
+ | ---- --------- ^^^^^^^ immutable borrow occurs here
+ | | |
+ | | mutable borrow later used by call
| mutable borrow occurs here
- | borrow later used here
error[E0502]: cannot borrow `*self.cx_mut` as immutable because it is also borrowed as mutable
--> $DIR/two-phase-surprise-no-conflict.rs:79:33
|
LL | self.hash_expr(&self.cx_mut.body(eid).value);
- | ----------------^^^^^^^^^^^-----------------
- | | |
- | | immutable borrow occurs here
+ | ---- --------- ^^^^^^^^^^^ immutable borrow occurs here
+ | | |
+ | | mutable borrow later used by call
| mutable borrow occurs here
- | borrow later used here
error[E0502]: cannot borrow `reg.sess_mut` as immutable because it is also borrowed as mutable
--> $DIR/two-phase-surprise-no-conflict.rs:131:51
|
LL | reg.register_static(Box::new(TrivialPass::new(®.sess_mut)));
- | ----------------------------------------------^^^^^^^^^^^^^---
- | | |
- | | immutable borrow occurs here
+ | --- --------------- ^^^^^^^^^^^^^ immutable borrow occurs here
+ | | |
+ | | mutable borrow later used by call
| mutable borrow occurs here
- | borrow later used here
error[E0502]: cannot borrow `reg.sess_mut` as immutable because it is also borrowed as mutable
--> $DIR/two-phase-surprise-no-conflict.rs:135:50
|
LL | reg.register_bound(Box::new(TrivialPass::new(®.sess_mut)));
- | ---------------------------------------------^^^^^^^^^^^^^---
- | | |
- | | immutable borrow occurs here
+ | --- -------------- ^^^^^^^^^^^^^ immutable borrow occurs here
+ | | |
+ | | mutable borrow later used by call
| mutable borrow occurs here
- | borrow later used here
error[E0502]: cannot borrow `reg.sess_mut` as immutable because it is also borrowed as mutable
--> $DIR/two-phase-surprise-no-conflict.rs:139:49
|
LL | reg.register_univ(Box::new(TrivialPass::new(®.sess_mut)));
- | --------------------------------------------^^^^^^^^^^^^^---
- | | |
- | | immutable borrow occurs here
+ | --- ------------- ^^^^^^^^^^^^^ immutable borrow occurs here
+ | | |
+ | | mutable borrow later used by call
| mutable borrow occurs here
- | borrow later used here
error[E0502]: cannot borrow `reg.sess_mut` as immutable because it is also borrowed as mutable
--> $DIR/two-phase-surprise-no-conflict.rs:143:40
|
LL | reg.register_ref(&TrivialPass::new(®.sess_mut));
- | -----------------------------------^^^^^^^^^^^^^--
- | | |
- | | immutable borrow occurs here
+ | --- ------------ ^^^^^^^^^^^^^ immutable borrow occurs here
+ | | |
+ | | mutable borrow later used by call
| mutable borrow occurs here
- | borrow later used here
error[E0499]: cannot borrow `reg.sess_mut` as mutable more than once at a time
--> $DIR/two-phase-surprise-no-conflict.rs:151:51
|
LL | reg.register_static(Box::new(TrivialPass::new(&mut reg.sess_mut)));
- | ----------------------------------------------^^^^^^^^^^^^^^^^^---
- | | |
- | | second mutable borrow occurs here
+ | --- --------------- ^^^^^^^^^^^^^^^^^ second mutable borrow occurs here
+ | | |
+ | | first borrow later used by call
| first mutable borrow occurs here
- | borrow later used here
error[E0499]: cannot borrow `reg.sess_mut` as mutable more than once at a time
--> $DIR/two-phase-surprise-no-conflict.rs:156:54
|
LL | reg.register_bound(Box::new(TrivialPass::new_mut(&mut reg.sess_mut)));
- | -------------------------------------------------^^^^^^^^^^^^^^^^^---
- | | |
- | | second mutable borrow occurs here
+ | --- -------------- ^^^^^^^^^^^^^^^^^ second mutable borrow occurs here
+ | | |
+ | | first borrow later used by call
| first mutable borrow occurs here
- | borrow later used here
error[E0499]: cannot borrow `reg.sess_mut` as mutable more than once at a time
--> $DIR/two-phase-surprise-no-conflict.rs:161:53
|
LL | reg.register_univ(Box::new(TrivialPass::new_mut(&mut reg.sess_mut)));
- | ------------------------------------------------^^^^^^^^^^^^^^^^^---
- | | |
- | | second mutable borrow occurs here
+ | --- ------------- ^^^^^^^^^^^^^^^^^ second mutable borrow occurs here
+ | | |
+ | | first borrow later used by call
| first mutable borrow occurs here
- | borrow later used here
error[E0499]: cannot borrow `reg.sess_mut` as mutable more than once at a time
--> $DIR/two-phase-surprise-no-conflict.rs:166:44
|
LL | reg.register_ref(&TrivialPass::new_mut(&mut reg.sess_mut));
- | ---------------------------------------^^^^^^^^^^^^^^^^^--
- | | |
- | | second mutable borrow occurs here
+ | --- ------------ ^^^^^^^^^^^^^^^^^ second mutable borrow occurs here
+ | | |
+ | | first borrow later used by call
| first mutable borrow occurs here
- | borrow later used here
error[E0502]: cannot borrow `reg.sess_mut` as immutable because it is also borrowed as mutable
--> $DIR/two-phase-surprise-no-conflict.rs:178:50
|
LL | reg.register_bound(Box::new(CapturePass::new(®.sess_mut)));
- | ---------------------------------------------^^^^^^^^^^^^^---
- | | |
- | | immutable borrow occurs here
+ | --- -------------- ^^^^^^^^^^^^^ immutable borrow occurs here
+ | | |
+ | | mutable borrow later used by call
| mutable borrow occurs here
- | borrow later used here
error[E0502]: cannot borrow `reg.sess_mut` as immutable because it is also borrowed as mutable
--> $DIR/two-phase-surprise-no-conflict.rs:183:49
|
LL | reg.register_univ(Box::new(CapturePass::new(®.sess_mut)));
- | --------------------------------------------^^^^^^^^^^^^^---
- | | |
- | | immutable borrow occurs here
+ | --- ------------- ^^^^^^^^^^^^^ immutable borrow occurs here
+ | | |
+ | | mutable borrow later used by call
| mutable borrow occurs here
- | borrow later used here
error[E0502]: cannot borrow `reg.sess_mut` as immutable because it is also borrowed as mutable
--> $DIR/two-phase-surprise-no-conflict.rs:188:40
|
LL | reg.register_ref(&CapturePass::new(®.sess_mut));
- | -----------------------------------^^^^^^^^^^^^^--
- | | |
- | | immutable borrow occurs here
+ | --- ------------ ^^^^^^^^^^^^^ immutable borrow occurs here
+ | | |
+ | | mutable borrow later used by call
| mutable borrow occurs here
- | borrow later used here
error[E0499]: cannot borrow `reg.sess_mut` as mutable more than once at a time
--> $DIR/two-phase-surprise-no-conflict.rs:200:54
|
LL | reg.register_bound(Box::new(CapturePass::new_mut(&mut reg.sess_mut)));
- | -------------------------------------------------^^^^^^^^^^^^^^^^^---
- | | |
- | | second mutable borrow occurs here
+ | --- -------------- ^^^^^^^^^^^^^^^^^ second mutable borrow occurs here
+ | | |
+ | | first borrow later used by call
| first mutable borrow occurs here
- | borrow later used here
error[E0499]: cannot borrow `reg.sess_mut` as mutable more than once at a time
--> $DIR/two-phase-surprise-no-conflict.rs:206:53
|
LL | reg.register_univ(Box::new(CapturePass::new_mut(&mut reg.sess_mut)));
- | ------------------------------------------------^^^^^^^^^^^^^^^^^---
- | | |
- | | second mutable borrow occurs here
+ | --- ------------- ^^^^^^^^^^^^^^^^^ second mutable borrow occurs here
+ | | |
+ | | first borrow later used by call
| first mutable borrow occurs here
- | borrow later used here
error[E0499]: cannot borrow `reg.sess_mut` as mutable more than once at a time
--> $DIR/two-phase-surprise-no-conflict.rs:212:44
|
LL | reg.register_ref(&CapturePass::new_mut(&mut reg.sess_mut));
- | ---------------------------------------^^^^^^^^^^^^^^^^^--
- | | |
- | | second mutable borrow occurs here
+ | --- ------------ ^^^^^^^^^^^^^^^^^ second mutable borrow occurs here
+ | | |
+ | | first borrow later used by call
| first mutable borrow occurs here
- | borrow later used here
error: aborting due to 17 previous errors
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: FromEnv(Self: Foo) :- FromEnv(Self: Bar).
- = note: FromEnv(Self: Foo) :- FromEnv(Self: Bar).
= note: Implemented(Self: Bar) :- FromEnv(Self: Bar).
- = note: WellFormed(Self: Bar) :- Implemented(Self: Bar), WellFormed(Self: Foo), WellFormed(Self: Foo).
+ = note: WellFormed(Self: Bar) :- Implemented(Self: Bar), WellFormed(Self: Foo).
error: program clause dump
--> $DIR/lower_env1.rs:19:1
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: FromEnv(Self: Foo) :- FromEnv(Self: Bar).
- = note: FromEnv(Self: Foo) :- FromEnv(Self: Bar).
= note: Implemented(Self: Bar) :- FromEnv(Self: Bar).
= note: Implemented(Self: Foo) :- FromEnv(Self: Foo).
= note: Implemented(Self: std::marker::Sized) :- FromEnv(Self: std::marker::Sized).
- = note: WellFormed(Self: Bar) :- Implemented(Self: Bar), WellFormed(Self: Foo), WellFormed(Self: Foo).
+ = note: WellFormed(Self: Bar) :- Implemented(Self: Bar), WellFormed(Self: Foo).
= note: WellFormed(Self: Foo) :- Implemented(Self: Foo).
= note: WellFormed(Self: std::marker::Sized) :- Implemented(Self: std::marker::Sized).
| ^^^^^^ second mutable borrow occurs here
LL | z.use_mut();
LL | y.use_mut();
- | - borrow later used here
+ | - first borrow later used here
error: aborting due to previous error
--> $DIR/one_line.rs:13:12
|
LL | v.push(v.pop().unwrap()); //~ ERROR cannot borrow
- | -------^----------------
- | | |
- | | second mutable borrow occurs here
+ | - ---- ^ second mutable borrow occurs here
+ | | |
+ | | first borrow later used by call
| first mutable borrow occurs here
- | borrow later used here
error: aborting due to previous error
| ^ second mutable borrow occurs here
...
LL | drop((y, z));
- | - borrow later used here
+ | - first borrow later used here
error[E0506]: cannot assign to `**x` because it is borrowed
--> $DIR/coerce-overloaded-autoderef.rs:31:5
--> $DIR/coerce-overloaded-autoderef.rs:38:20
|
LL | borrow_mut2(x, x);
- | ---------------^-
- | | | |
- | | | second mutable borrow occurs here
+ | ----------- - ^ second mutable borrow occurs here
+ | | |
| | first mutable borrow occurs here
- | borrow later used here
+ | first borrow later used by call
error[E0502]: cannot borrow `*x` as mutable because it is also borrowed as immutable
--> $DIR/coerce-overloaded-autoderef.rs:44:5
|
LL | borrow2(x, x);
- | ^^^^^^^^^^^-^
+ | -------^^^^-^
| | |
| | immutable borrow occurs here
| mutable borrow occurs here
- | borrow later used here
+ | immutable borrow later used by call
error: aborting due to 4 previous errors
| ^ second mutable borrow occurs here
...
LL | drop((y, z));
- | - borrow later used here
+ | - first borrow later used here
error[E0506]: cannot assign to `**x` because it is borrowed
--> $DIR/coerce-overloaded-autoderef.rs:31:5
--> $DIR/coerce-overloaded-autoderef.rs:38:20
|
LL | borrow_mut2(x, x);
- | ---------------^-
- | | | |
- | | | second mutable borrow occurs here
+ | ----------- - ^ second mutable borrow occurs here
+ | | |
| | first mutable borrow occurs here
- | borrow later used here
+ | first borrow later used by call
error[E0502]: cannot borrow `*x` as mutable because it is also borrowed as immutable
--> $DIR/coerce-overloaded-autoderef.rs:44:5
|
LL | borrow2(x, x);
- | ^^^^^^^^^^^-^
+ | -------^^^^-^
| | |
| | immutable borrow occurs here
| mutable borrow occurs here
- | borrow later used here
+ | immutable borrow later used by call
error: aborting due to 4 previous errors
| ^ second mutable borrow occurs here
...
LL | drop((y, z));
- | - borrow later used here
+ | - first borrow later used here
error[E0506]: cannot assign to `**x` because it is borrowed
--> $DIR/coerce-overloaded-autoderef.rs:31:5
--> $DIR/coerce-overloaded-autoderef.rs:38:20
|
LL | borrow_mut2(x, x);
- | ---------------^-
- | | | |
- | | | second mutable borrow occurs here
+ | ----------- - ^ second mutable borrow occurs here
+ | | |
| | first mutable borrow occurs here
- | borrow later used here
+ | first borrow later used by call
error[E0502]: cannot borrow `*x` as immutable because it is also borrowed as mutable
--> $DIR/coerce-overloaded-autoderef.rs:44:16
|
LL | borrow2(x, x);
- | -----------^-
- | | | |
- | | | immutable borrow occurs here
+ | ------- - ^ immutable borrow occurs here
+ | | |
| | mutable borrow occurs here
- | borrow later used here
+ | mutable borrow later used by call
error: aborting due to 4 previous errors
fn main() {
let _ = [0; f(2)];
//~^ ERROR calls in constants are limited to constant functions
- //~| E0080
}
LL | let _ = [0; f(2)];
| ^^^^
-error[E0080]: could not evaluate repeat length
- --> $DIR/const-call.rs:16:17
- |
-LL | let _ = [0; f(2)];
- | ^^^^ calling non-const fn `f`
-
-error: aborting due to 2 previous errors
+error: aborting due to previous error
-Some errors occurred: E0015, E0080.
-For more information about an error, try `rustc --explain E0015`.
+For more information about this error, try `rustc --explain E0015`.
|
LL | let x: &'static _ = &std::time::Duration::from_millis(42).subsec_millis();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ creates a temporary which is freed while still in use
-LL | //~^ does not live long enough
+LL | //~^ ERROR does not live long enough
LL | }
| - temporary value is freed at the end of this statement
|
fn main() {
let _: &'static u32 = &meh(); //~ ERROR does not live long enough
let x: &'static _ = &std::time::Duration::from_millis(42).subsec_millis();
- //~^ does not live long enough
+ //~^ ERROR does not live long enough
}
|
LL | let x: &'static _ = &std::time::Duration::from_millis(42).subsec_millis();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ temporary value does not live long enough
-LL | //~^ does not live long enough
+LL | //~^ ERROR does not live long enough
LL | }
| - temporary value only lives until here
|
+++ /dev/null
-// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-fn main() {
- [(); & { loop { continue } } ]; //~ ERROR mismatched types
- [(); loop { break }]; //~ ERROR mismatched types
- [(); {while true {break}; 0}]; //~ ERROR constant contains unimplemented expression type
- [(); { for _ in 0usize.. {}; 0}]; //~ ERROR calls in constants are limited to constant functions
- //~^ ERROR constant contains unimplemented expression type
- //~| ERROR could not evaluate repeat length
-}
+++ /dev/null
-error[E0308]: mismatched types
- --> $DIR/issue-52443.rs:12:10
- |
-LL | [(); & { loop { continue } } ]; //~ ERROR mismatched types
- | ^^^^^^^^^^^^^^^^^^^^^^^
- | |
- | expected usize, found reference
- | help: consider removing the borrow: `{ loop { continue } }`
- |
- = note: expected type `usize`
- found type `&_`
-
-error[E0308]: mismatched types
- --> $DIR/issue-52443.rs:13:17
- |
-LL | [(); loop { break }]; //~ ERROR mismatched types
- | ^^^^^ expected (), found usize
- |
- = note: expected type `()`
- found type `usize`
-
-error[E0019]: constant contains unimplemented expression type
- --> $DIR/issue-52443.rs:14:11
- |
-LL | [(); {while true {break}; 0}]; //~ ERROR constant contains unimplemented expression type
- | ^^^^^^^^^^^^^^^^^^
-
-error[E0015]: calls in constants are limited to constant functions, tuple structs and tuple variants
- --> $DIR/issue-52443.rs:15:21
- |
-LL | [(); { for _ in 0usize.. {}; 0}]; //~ ERROR calls in constants are limited to constant functions
- | ^^^^^^^^
-
-error[E0019]: constant contains unimplemented expression type
- --> $DIR/issue-52443.rs:15:21
- |
-LL | [(); { for _ in 0usize.. {}; 0}]; //~ ERROR calls in constants are limited to constant functions
- | ^^^^^^^^
-
-error[E0080]: could not evaluate repeat length
- --> $DIR/issue-52443.rs:15:10
- |
-LL | [(); { for _ in 0usize.. {}; 0}]; //~ ERROR calls in constants are limited to constant functions
- | ^^^^^^^^^^^--------^^^^^^^
- | |
- | calling non-const fn `<I as std::iter::IntoIterator><std::ops::RangeFrom<usize>>::into_iter`
-
-error: aborting due to 6 previous errors
-
-Some errors occurred: E0015, E0019, E0080, E0308.
-For more information about an error, try `rustc --explain E0015`.
--- /dev/null
+error[E0716]: temporary value dropped while borrowed
+ --> $DIR/promoted_const_fn_fail.rs:30:27
+ |
+LL | let x: &'static u8 = &(bar() + 1); //~ ERROR does not live long enough
+ | ^^^^^^^^^^^ creates a temporary which is freed while still in use
+...
+LL | }
+ | - temporary value is freed at the end of this statement
+ |
+ = note: borrowed value must be valid for the static lifetime...
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0716`.
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-// compile-pass
-
#![feature(const_fn, const_fn_union)]
#![deny(const_err)]
}
fn main() {
- // FIXME(oli-obk): this should panic at runtime
- // this will actually compile, but then
- // abort at runtime (not panic, hard abort).
- let x: &'static u8 = &(bar() + 1);
+ let x: &'static u8 = &(bar() + 1); //~ ERROR does not live long enough
let y = *x;
unreachable!();
}
--- /dev/null
+error[E0597]: borrowed value does not live long enough
+ --> $DIR/promoted_const_fn_fail.rs:30:27
+ |
+LL | let x: &'static u8 = &(bar() + 1); //~ ERROR does not live long enough
+ | ^^^^^^^^^^^ temporary value does not live long enough
+...
+LL | }
+ | - temporary value only lives until here
+ |
+ = note: borrowed value must be valid for the static lifetime...
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0597`.
+++ /dev/null
-// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-#![feature(const_fn)]
-
-const X : usize = 2;
-
-const fn f(x: usize) -> usize {
- let mut sum = 0;
- //~^ let bindings in constant functions are unstable
- //~| statements in constant functions are unstable
- for i in 0..x {
- //~^ ERROR E0015
- //~| ERROR E0019
- sum += i;
- }
- sum
-}
-
-#[allow(unused_variables)]
-fn main() {
- let a : [i32; f(X)]; //~ ERROR E0080
-}
+++ /dev/null
-error[E0658]: let bindings in constant functions are unstable (see issue #48821)
- --> $DIR/const-fn-error.rs:16:19
- |
-LL | let mut sum = 0;
- | ^
- |
- = help: add #![feature(const_let)] to the crate attributes to enable
-
-error[E0658]: statements in constant functions are unstable (see issue #48821)
- --> $DIR/const-fn-error.rs:16:19
- |
-LL | let mut sum = 0;
- | ^
- |
- = help: add #![feature(const_let)] to the crate attributes to enable
-
-error[E0015]: calls in constant functions are limited to constant functions, tuple structs and tuple variants
- --> $DIR/const-fn-error.rs:19:14
- |
-LL | for i in 0..x {
- | ^^^^
-
-error[E0019]: constant function contains unimplemented expression type
- --> $DIR/const-fn-error.rs:19:14
- |
-LL | for i in 0..x {
- | ^^^^
-
-error[E0080]: could not evaluate constant expression
- --> $DIR/const-fn-error.rs:29:13
- |
-LL | for i in 0..x {
- | ---- calling non-const fn `<I as std::iter::IntoIterator><std::ops::Range<usize>>::into_iter`
-...
-LL | let a : [i32; f(X)]; //~ ERROR E0080
- | ^^^^^^----^
- | |
- | inside call to `f`
-
-error: aborting due to 5 previous errors
-
-Some errors occurred: E0015, E0019, E0080, E0658.
-For more information about an error, try `rustc --explain E0015`.
--- /dev/null
+error[E0716]: temporary value dropped while borrowed
+ --> $DIR/promotion.rs:13:27
+ |
+LL | let x: &'static () = &foo1(); //~ ERROR does not live long enough
+ | ^^^^^^ creates a temporary which is freed while still in use
+...
+LL | }
+ | - temporary value is freed at the end of this statement
+ |
+ = note: borrowed value must be valid for the static lifetime...
+
+error[E0716]: temporary value dropped while borrowed
+ --> $DIR/promotion.rs:14:28
+ |
+LL | let y: &'static i32 = &foo2(42); //~ ERROR does not live long enough
+ | ^^^^^^^^ creates a temporary which is freed while still in use
+...
+LL | }
+ | - temporary value is freed at the end of this statement
+ |
+ = note: borrowed value must be valid for the static lifetime...
+
+error[E0716]: temporary value dropped while borrowed
+ --> $DIR/promotion.rs:15:28
+ |
+LL | let z: &'static i32 = &foo3(); //~ ERROR does not live long enough
+ | ^^^^^^ creates a temporary which is freed while still in use
+...
+LL | }
+ | - temporary value is freed at the end of this statement
+ |
+ = note: borrowed value must be valid for the static lifetime...
+
+error[E0716]: temporary value dropped while borrowed
+ --> $DIR/promotion.rs:16:34
+ |
+LL | let a: &'static Cell<i32> = &foo4(); //~ ERROR does not live long enough
+ | ^^^^^^ creates a temporary which is freed while still in use
+...
+LL | }
+ | - temporary value is freed at the end of this statement
+ |
+ = note: borrowed value must be valid for the static lifetime...
+
+error[E0716]: temporary value dropped while borrowed
+ --> $DIR/promotion.rs:17:42
+ |
+LL | let a: &'static Option<Cell<i32>> = &foo5(); //~ ERROR does not live long enough
+ | ^^^^^^ creates a temporary which is freed while still in use
+LL | let a: &'static Option<Cell<i32>> = &foo6(); //~ ERROR does not live long enough
+LL | }
+ | - temporary value is freed at the end of this statement
+ |
+ = note: borrowed value must be valid for the static lifetime...
+
+error[E0716]: temporary value dropped while borrowed
+ --> $DIR/promotion.rs:18:42
+ |
+LL | let a: &'static Option<Cell<i32>> = &foo6(); //~ ERROR does not live long enough
+ | ^^^^^^ creates a temporary which is freed while still in use
+LL | }
+ | - temporary value is freed at the end of this statement
+ |
+ = note: borrowed value must be valid for the static lifetime...
+
+error: aborting due to 6 previous errors
+
+For more information about this error, try `rustc --explain E0716`.
--- /dev/null
+#![feature(min_const_fn)]
+
+use std::cell::Cell;
+
+const fn foo1() {}
+const fn foo2(x: i32) -> i32 { x }
+const fn foo3() -> i32 { 42 }
+const fn foo4() -> Cell<i32> { Cell::new(42) }
+const fn foo5() -> Option<Cell<i32>> { Some(Cell::new(42)) }
+const fn foo6() -> Option<Cell<i32>> { None }
+
+fn main() {
+ let x: &'static () = &foo1(); //~ ERROR does not live long enough
+ let y: &'static i32 = &foo2(42); //~ ERROR does not live long enough
+ let z: &'static i32 = &foo3(); //~ ERROR does not live long enough
+ let a: &'static Cell<i32> = &foo4(); //~ ERROR does not live long enough
+ let a: &'static Option<Cell<i32>> = &foo5(); //~ ERROR does not live long enough
+ let a: &'static Option<Cell<i32>> = &foo6(); //~ ERROR does not live long enough
+}
--- /dev/null
+error[E0597]: borrowed value does not live long enough
+ --> $DIR/promotion.rs:13:27
+ |
+LL | let x: &'static () = &foo1(); //~ ERROR does not live long enough
+ | ^^^^^^ temporary value does not live long enough
+...
+LL | }
+ | - temporary value only lives until here
+ |
+ = note: borrowed value must be valid for the static lifetime...
+
+error[E0597]: borrowed value does not live long enough
+ --> $DIR/promotion.rs:14:28
+ |
+LL | let y: &'static i32 = &foo2(42); //~ ERROR does not live long enough
+ | ^^^^^^^^ temporary value does not live long enough
+...
+LL | }
+ | - temporary value only lives until here
+ |
+ = note: borrowed value must be valid for the static lifetime...
+
+error[E0597]: borrowed value does not live long enough
+ --> $DIR/promotion.rs:15:28
+ |
+LL | let z: &'static i32 = &foo3(); //~ ERROR does not live long enough
+ | ^^^^^^ temporary value does not live long enough
+...
+LL | }
+ | - temporary value only lives until here
+ |
+ = note: borrowed value must be valid for the static lifetime...
+
+error[E0597]: borrowed value does not live long enough
+ --> $DIR/promotion.rs:16:34
+ |
+LL | let a: &'static Cell<i32> = &foo4(); //~ ERROR does not live long enough
+ | ^^^^^^ temporary value does not live long enough
+...
+LL | }
+ | - temporary value only lives until here
+ |
+ = note: borrowed value must be valid for the static lifetime...
+
+error[E0597]: borrowed value does not live long enough
+ --> $DIR/promotion.rs:17:42
+ |
+LL | let a: &'static Option<Cell<i32>> = &foo5(); //~ ERROR does not live long enough
+ | ^^^^^^ temporary value does not live long enough
+LL | let a: &'static Option<Cell<i32>> = &foo6(); //~ ERROR does not live long enough
+LL | }
+ | - temporary value only lives until here
+ |
+ = note: borrowed value must be valid for the static lifetime...
+
+error[E0597]: borrowed value does not live long enough
+ --> $DIR/promotion.rs:18:42
+ |
+LL | let a: &'static Option<Cell<i32>> = &foo6(); //~ ERROR does not live long enough
+ | ^^^^^^ temporary value does not live long enough
+LL | }
+ | - temporary value only lives until here
+ |
+ = note: borrowed value must be valid for the static lifetime...
+
+error: aborting due to 6 previous errors
+
+For more information about this error, try `rustc --explain E0597`.
--> $DIR/issue-31424.rs:17:9
|
LL | (&mut self).bar(); //~ ERROR cannot borrow
- | ^^^^^^^^^^^ cannot borrow as mutable
+ | ^^^^^^^^^^^
+ | |
+ | cannot borrow as mutable
+ | try removing `&mut` here
error[E0596]: cannot borrow `self` as mutable, as it is not declared as mutable
--> $DIR/issue-31424.rs:23:9
|
-LL | fn bar(self: &mut Self) {
- | ---- help: consider changing this to be mutable: `mut self`
LL | (&mut self).bar(); //~ ERROR cannot borrow
- | ^^^^^^^^^^^ cannot borrow as mutable
+ | ^^^^^^^^^^^
+ | |
+ | cannot borrow as mutable
+ | try removing `&mut` here
error: aborting due to 2 previous errors
--> $DIR/issue-34126.rs:16:18
|
LL | self.run(&mut self); //~ ERROR cannot borrow
- | ---------^^^^^^^^^-
- | | |
- | | mutable borrow occurs here
+ | ---- --- ^^^^^^^^^ mutable borrow occurs here
+ | | |
+ | | immutable borrow later used by call
| immutable borrow occurs here
- | borrow later used here
error: aborting due to 2 previous errors
| ^^^^^^ second mutable borrow occurs here
LL | a.use_mut();
LL | x.use_mut();
- | - borrow later used here
+ | - first borrow later used here
error: aborting due to previous error
LL | bar(a); //~ ERROR E0502
| ^^^^^^ mutable borrow occurs here
LL | y.use_ref();
- | - borrow later used here
+ | - immutable borrow later used here
error: aborting due to previous error
LL | println!("{}", x[0]); //~ ERROR
| ^ immutable borrow occurs here
LL | b.resume();
- | - borrow later used here
+ | - mutable borrow later used here
error: aborting due to 2 previous errors
LL | println!("{}", x); //~ ERROR
| ^ borrow occurs here
LL | b.resume();
- | - borrow later used here
+ | - first borrow later used here
error: aborting due to previous error
| ^^^^^^^^^^^^^^^^ mutable borrow occurs here
LL |
LL | println!("{}", *thing);
- | ------ borrow later used here
+ | ------ immutable borrow later used here
error: aborting due to previous error
LL | my_stuff.insert(1, 43); //~ ERROR cannot borrow
| ^^^^^^^^^^^^^^^^^^^^^^ mutable borrow occurs here
LL | it;
- | -- borrow later used here
+ | -- immutable borrow later used here
error: aborting due to previous error
| ^^^
| |
| second mutable borrow occurs here
- | borrow later used here
+ | first borrow later used here
error: aborting due to previous error
| ^^^^^^^^^^^^^^^ second mutable borrow occurs here
...
LL | borrow1.use_mut();
- | ------- borrow later used here
+ | ------- first borrow later used here
error: aborting due to previous error
"##);
//~^^^ ERROR: there is no argument named `foo`
+
+ // bad syntax in format string with multiple newlines, #53836
+ format!("first number: {}
+second number: {}
+third number: {}
+fourth number: {}
+fifth number: {}
+sixth number: {}
+seventh number: {}
+eighth number: {}
+ninth number: {
+tenth number: {}",
+ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
+ //~^^ ERROR: invalid format string
}
LL | {foo}
| ^^^^^
-error: aborting due to 27 previous errors
+error: invalid format string: expected `'}'`, found `'t'`
+ --> $DIR/ifmt-bad-arg.rs:85:1
+ |
+LL | tenth number: {}",
+ | ^ expected `}` in format string
+
+error: aborting due to 28 previous errors
--- /dev/null
+// compile-pass
+
+#![deny(warnings)]
+
+#[deprecated]
+trait Deprecated {}
+
+#[deprecated]
+struct DeprecatedTy;
+
+#[allow(deprecated)]
+impl Deprecated for DeprecatedTy {}
+
+#[allow(deprecated)]
+fn foo() -> impl Deprecated { DeprecatedTy }
+
+fn main() {
+ foo();
+}
mod m4 {
macro_rules! m { () => {} }
use two_macros::m;
- m!(); //~ ERROR ambiguous
+ m!();
}
fn main() {}
-error[E0659]: `m` is ambiguous
- --> $DIR/macros.rs:48:5
- |
-LL | m!(); //~ ERROR ambiguous
- | ^ ambiguous name
- |
-note: `m` could refer to the name defined here
- --> $DIR/macros.rs:46:5
- |
-LL | macro_rules! m { () => {} }
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^
-note: `m` could also refer to the name imported here
- --> $DIR/macros.rs:47:9
- |
-LL | use two_macros::m;
- | ^^^^^^^^^^^^^
-
error[E0659]: `m` is ambiguous
--> $DIR/macros.rs:26:5
|
| ^^^^^^^^^^^^^
= note: macro-expanded macro imports do not shadow
-error: aborting due to 3 previous errors
+error: aborting due to 2 previous errors
For more information about this error, try `rustc --explain E0659`.
-error[E0659]: `panic` is ambiguous
- --> $DIR/shadow_builtin_macros.rs:43:5
- |
-LL | panic!(); //~ ERROR `panic` is ambiguous
- | ^^^^^ ambiguous name
- |
-note: `panic` could refer to the name defined here
- --> $DIR/shadow_builtin_macros.rs:40:9
- |
-LL | macro_rules! panic { () => {} }
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-LL | } }
-LL | m!();
- | ----- in this macro invocation
- = note: `panic` is also a builtin macro
- = note: macro-expanded macros do not shadow
-
error[E0659]: `panic` is ambiguous
--> $DIR/shadow_builtin_macros.rs:25:14
|
= note: `panic` is also a builtin macro
= note: macro-expanded macro imports do not shadow
+error[E0659]: `panic` is ambiguous
+ --> $DIR/shadow_builtin_macros.rs:43:5
+ |
+LL | panic!(); //~ ERROR `panic` is ambiguous
+ | ^^^^^ ambiguous name
+ |
+note: `panic` could refer to the name defined here
+ --> $DIR/shadow_builtin_macros.rs:40:9
+ |
+LL | macro_rules! panic { () => {} }
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL | } }
+LL | m!();
+ | ----- in this macro invocation
+ = note: `panic` is also a builtin macro
+ = note: macro-expanded macros do not shadow
+
error[E0659]: `n` is ambiguous
--> $DIR/shadow_builtin_macros.rs:59:5
|
--- /dev/null
+// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+trait Mirror {
+ type Image;
+ fn coerce(self) -> Self::Image;
+}
+
+impl<T> Mirror for T {
+ type Image = T;
+ fn coerce(self) -> Self { self }
+}
+
+trait Foo<'x, T> {
+ fn foo(self) -> &'x T;
+}
+
+impl<'s, 'x, T: 'x> Foo<'x, T> for &'s T where &'s T: Foo2<'x, T> {
+ fn foo(self) -> &'x T { self.foo2() }
+}
+
+trait Foo2<'x, T> {
+ fn foo2(self) -> &'x T;
+}
+
+// example 1 - fails leak check
+impl<'x> Foo2<'x, u32> for &'x u32
+{
+ fn foo2(self) -> &'x u32 { self }
+}
+
+// example 2 - OK with this issue
+impl<'x, 'a: 'x> Foo2<'x, i32> for &'a i32
+{
+ fn foo2(self) -> &'x i32 { self }
+}
+
+// example 3 - fails due to issue #XYZ + Leak-check
+impl<'x, T> Foo2<'x, u64> for T
+ where T: Mirror<Image=&'x u64>
+{
+ fn foo2(self) -> &'x u64 { self.coerce() }
+}
+
+// example 4 - fails due to issue #XYZ
+impl<'x, 'a: 'x, T> Foo2<'x, i64> for T
+ where T: Mirror<Image=&'a i64>
+{
+ fn foo2(self) -> &'x i64 { self.coerce() }
+}
+
+
+trait RefFoo<T> {
+ fn ref_foo(&self) -> &'static T;
+}
+
+impl<T> RefFoo<T> for T where for<'a> &'a T: Foo<'static, T> {
+ fn ref_foo(&self) -> &'static T {
+ self.foo()
+ }
+}
+
+
+fn coerce_lifetime1(a: &u32) -> &'static u32
+{
+ <u32 as RefFoo<u32>>::ref_foo(a)
+ //~^ ERROR the trait bound `for<'a> &'a u32: Foo2<'_, u32>` is not satisfied
+}
+
+fn coerce_lifetime2(a: &i32) -> &'static i32
+{
+ <i32 as RefFoo<i32>>::ref_foo(a)
+ //~^ ERROR the requirement `for<'a> 'a : ` is not satisfied
+}
+
+fn coerce_lifetime3(a: &u64) -> &'static u64
+{
+ <u64 as RefFoo<u64>>::ref_foo(a)
+ //~^ ERROR type mismatch resolving `for<'a> <&'a u64 as Mirror>::Image == &u64`
+}
+
+fn coerce_lifetime4(a: &i64) -> &'static i64
+{
+ <i64 as RefFoo<i64>>::ref_foo(a)
+ //~^ ERROR type mismatch resolving `for<'a> <&'a i64 as Mirror>::Image == &i64`
+}
+
+fn main() {}
--- /dev/null
+error[E0277]: the trait bound `for<'a> &'a u32: Foo2<'_, u32>` is not satisfied
+ --> $DIR/issue-54302-cases.rs:73:5
+ |
+LL | <u32 as RefFoo<u32>>::ref_foo(a)
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `for<'a> Foo2<'_, u32>` is not implemented for `&'a u32`
+ |
+ = help: the following implementations were found:
+ <&'x u32 as Foo2<'x, u32>>
+ = note: required because of the requirements on the impl of `for<'a> Foo<'static, u32>` for `&'a u32`
+ = note: required because of the requirements on the impl of `RefFoo<u32>` for `u32`
+note: required by `RefFoo::ref_foo`
+ --> $DIR/issue-54302-cases.rs:61:5
+ |
+LL | fn ref_foo(&self) -> &'static T;
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error[E0279]: the requirement `for<'a> 'a : ` is not satisfied (`expected bound lifetime parameter 'a, found concrete lifetime`)
+ --> $DIR/issue-54302-cases.rs:79:5
+ |
+LL | <i32 as RefFoo<i32>>::ref_foo(a)
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = note: required because of the requirements on the impl of `for<'a> Foo2<'_, i32>` for `&'a i32`
+ = note: required because of the requirements on the impl of `for<'a> Foo<'static, i32>` for `&'a i32`
+ = note: required because of the requirements on the impl of `RefFoo<i32>` for `i32`
+note: required by `RefFoo::ref_foo`
+ --> $DIR/issue-54302-cases.rs:61:5
+ |
+LL | fn ref_foo(&self) -> &'static T;
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error[E0271]: type mismatch resolving `for<'a> <&'a u64 as Mirror>::Image == &u64`
+ --> $DIR/issue-54302-cases.rs:85:5
+ |
+LL | <u64 as RefFoo<u64>>::ref_foo(a)
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected bound lifetime parameter 'a, found concrete lifetime
+ |
+ = note: required because of the requirements on the impl of `for<'a> Foo2<'_, u64>` for `&'a u64`
+ = note: required because of the requirements on the impl of `for<'a> Foo<'static, u64>` for `&'a u64`
+ = note: required because of the requirements on the impl of `RefFoo<u64>` for `u64`
+note: required by `RefFoo::ref_foo`
+ --> $DIR/issue-54302-cases.rs:61:5
+ |
+LL | fn ref_foo(&self) -> &'static T;
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error[E0271]: type mismatch resolving `for<'a> <&'a i64 as Mirror>::Image == &i64`
+ --> $DIR/issue-54302-cases.rs:91:5
+ |
+LL | <i64 as RefFoo<i64>>::ref_foo(a)
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected bound lifetime parameter 'a, found concrete lifetime
+ |
+ = note: required because of the requirements on the impl of `for<'a> Foo2<'_, i64>` for `&'a i64`
+ = note: required because of the requirements on the impl of `for<'a> Foo<'static, i64>` for `&'a i64`
+ = note: required because of the requirements on the impl of `RefFoo<i64>` for `i64`
+note: required by `RefFoo::ref_foo`
+ --> $DIR/issue-54302-cases.rs:61:5
+ |
+LL | fn ref_foo(&self) -> &'static T;
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 4 previous errors
+
+Some errors occurred: E0271, E0277, E0279.
+For more information about an error, try `rustc --explain E0271`.
--- /dev/null
+// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+trait Deserialize<'de> {}
+
+trait DeserializeOwned: for<'de> Deserialize<'de> {}
+impl<T> DeserializeOwned for T where T: for<'de> Deserialize<'de> {}
+
+// Based on this impl, `&'static str` only implements Deserialize<'static>.
+// It does not implement for<'de> Deserialize<'de>.
+impl<'de: 'a, 'a> Deserialize<'de> for &'a str {}
+
+fn main() {
+ // Then why does it implement DeserializeOwned? This compiles.
+ fn assert_deserialize_owned<T: DeserializeOwned>() {}
+ assert_deserialize_owned::<&'static str>();
+ //~^ ERROR the requirement `for<'de> 'de : ` is not satisfied
+
+ // It correctly does not implement for<'de> Deserialize<'de>.
+ //fn assert_hrtb<T: for<'de> Deserialize<'de>>() {}
+ //assert_hrtb::<&'static str>();
+}
--- /dev/null
+error[E0279]: the requirement `for<'de> 'de : ` is not satisfied (`expected bound lifetime parameter 'de, found concrete lifetime`)
+ --> $DIR/issue-54302.rs:23:5
+ |
+LL | assert_deserialize_owned::<&'static str>();
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = note: required because of the requirements on the impl of `for<'de> Deserialize<'de>` for `&'static str`
+ = note: required because of the requirements on the impl of `DeserializeOwned` for `&'static str`
+note: required by `main::assert_deserialize_owned`
+ --> $DIR/issue-54302.rs:22:5
+ |
+LL | fn assert_deserialize_owned<T: DeserializeOwned>() {}
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0279`.
| --- first borrow occurs due to use of `ptr` in closure
...
LL | test(&*ptr);
- | -----^^^^^-
- | | |
- | | immutable borrow occurs here
- | borrow later used here
+ | ---- ^^^^^ immutable borrow occurs here
+ | |
+ | mutable borrow later used by call
error: aborting due to previous error
--> $DIR/issue-18566.rs:33:19
|
LL | MyPtr(s).poke(s);
- | --------------^-
- | | | |
- | | | second mutable borrow occurs here
- | | first mutable borrow occurs here
- | borrow later used here
+ | - ---- ^ second mutable borrow occurs here
+ | | |
+ | | first borrow later used by call
+ | first mutable borrow occurs here
error: aborting due to previous error
| second mutable borrow occurs here
LL | //~^ ERROR cannot borrow `y` as mutable more than once at a time
LL | }
- | - borrow later used here, when `c` is dropped
+ | - first borrow later used here, when `c` is dropped
error[E0499]: cannot borrow `y` as mutable more than once at a time
--> $DIR/issue-18783.rs:26:29
| second mutable borrow occurs here
LL | //~^ ERROR cannot borrow `y` as mutable more than once at a time
LL | }
- | - borrow later used here, when `c` is dropped
+ | - first borrow later used here, when `c` is dropped
error: aborting due to 2 previous errors
LL | let r = &mut *self;
| ---------- borrow of `*self` occurs here
LL | r.get_size(width!(self))
- | ------------------------
- | | |
- | | in this macro invocation
- | borrow later used here
+ | -------- ------------ in this macro invocation
+ | |
+ | borrow later used by call
error: aborting due to previous error
fn main() {
let array: [usize; Dim3::dim()]
//~^ ERROR E0015
- //~| ERROR E0080
= [0; Dim3::dim()];
//~^ ERROR E0015
- //~| ERROR E0080
}
| ^^^^^^^^^^^
error[E0015]: calls in constants are limited to constant functions, tuple structs and tuple variants
- --> $DIR/issue-39559-2.rs:27:15
+ --> $DIR/issue-39559-2.rs:26:15
|
LL | = [0; Dim3::dim()];
| ^^^^^^^^^^^
-error[E0080]: could not evaluate repeat length
- --> $DIR/issue-39559-2.rs:27:15
- |
-LL | = [0; Dim3::dim()];
- | ^^^^^^^^^^^ calling non-const fn `<Dim3 as Dim>::dim`
-
-error[E0080]: could not evaluate constant expression
- --> $DIR/issue-39559-2.rs:24:16
- |
-LL | let array: [usize; Dim3::dim()]
- | ^^^^^^^^-----------^
- | |
- | calling non-const fn `<Dim3 as Dim>::dim`
-
-error: aborting due to 4 previous errors
+error: aborting due to 2 previous errors
-Some errors occurred: E0015, E0080.
-For more information about an error, try `rustc --explain E0015`.
+For more information about this error, try `rustc --explain E0015`.
LL | collection.swap(1, 2); //~ ERROR also borrowed as immutable
| ^^^^^^^^^^ mutable borrow occurs here
LL | _a.use_ref();
- | -- borrow later used here
+ | -- immutable borrow later used here
error: aborting due to previous error
fn main() {
match 1 {
NUM => unimplemented!(),
- //~^ ERROR could not evaluate constant pattern
_ => unimplemented!(),
}
}
LL | const NUM: u8 = xyz();
| ^^^^^
-error[E0080]: could not evaluate constant pattern
- --> $DIR/issue-43105.rs:18:9
- |
-LL | const NUM: u8 = xyz();
- | ----- calling non-const fn `xyz`
-...
-LL | NUM => unimplemented!(),
- | ^^^
-
-error: aborting due to 2 previous errors
+error: aborting due to previous error
-Some errors occurred: E0015, E0080.
-For more information about an error, try `rustc --explain E0015`.
+For more information about this error, try `rustc --explain E0015`.
| ^^^^^^ immutable borrow occurs here
LL | //~^ ERROR cannot borrow `u.z.c` as immutable because it is also borrowed as mutable [E0502]
LL | println!("{} {}", mref, nref)
- | ---- borrow later used here
+ | ---- mutable borrow later used here
error: aborting due to previous error
--- /dev/null
+// Some non-controversial subset of ambiguities "modern macro name" vs "macro_rules"
+// is disambiguated to mitigate regressions from macro modularization.
+// Scoping for `macro_rules` behaves like scoping for `let` at module level, in general.
+
+#![feature(decl_macro)]
+
+fn same_unnamed_mod() {
+ macro m() { 0 }
+
+ macro_rules! m { () => (()) }
+
+ m!() // OK
+}
+
+fn nested_unnamed_mod() {
+ macro m() { 0 }
+
+ {
+ macro_rules! m { () => (()) }
+
+ m!() // OK
+ }
+}
+
+fn nested_unnamed_mod_fail() {
+ macro_rules! m { () => (()) }
+
+ {
+ macro m() { 0 }
+
+ m!() //~ ERROR `m` is ambiguous
+ }
+}
+
+fn nexted_named_mod_fail() {
+ macro m() { 0 }
+
+ #[macro_use]
+ mod inner {
+ macro_rules! m { () => (()) }
+ }
+
+ m!() //~ ERROR `m` is ambiguous
+}
+
+fn main() {}
--- /dev/null
+error[E0659]: `m` is ambiguous
+ --> $DIR/ambiguity-legacy-vs-modern.rs:31:9
+ |
+LL | m!() //~ ERROR `m` is ambiguous
+ | ^ ambiguous name
+ |
+note: `m` could refer to the name defined here
+ --> $DIR/ambiguity-legacy-vs-modern.rs:26:5
+ |
+LL | macro_rules! m { () => (()) }
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+note: `m` could also refer to the name defined here
+ --> $DIR/ambiguity-legacy-vs-modern.rs:29:9
+ |
+LL | macro m() { 0 }
+ | ^^^^^^^^^^^^^^^
+
+error[E0659]: `m` is ambiguous
+ --> $DIR/ambiguity-legacy-vs-modern.rs:43:5
+ |
+LL | m!() //~ ERROR `m` is ambiguous
+ | ^ ambiguous name
+ |
+note: `m` could refer to the name defined here
+ --> $DIR/ambiguity-legacy-vs-modern.rs:40:9
+ |
+LL | macro_rules! m { () => (()) }
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+note: `m` could also refer to the name defined here
+ --> $DIR/ambiguity-legacy-vs-modern.rs:36:5
+ |
+LL | macro m() { 0 }
+ | ^^^^^^^^^^^^^^^
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0659`.
LL | Foo::bar(&x); //~ERROR cannot borrow `x`
| ^^ immutable borrow occurs here
LL | y.use_mut();
- | - borrow later used here
+ | - mutable borrow later used here
error[E0499]: cannot borrow `x` as mutable more than once at a time
--> $DIR/method-self-arg-2.rs:30:14
LL | Foo::baz(&mut x); //~ERROR cannot borrow `x`
| ^^^^^^ second mutable borrow occurs here
LL | y.use_mut();
- | - borrow later used here
+ | - first borrow later used here
error: aborting due to 2 previous errors
--> $DIR/moves-based-on-type-no-recursive-stack-closure.rs:30:27
|
LL | (f.c)(f, true);
- | ------^-------
- | | |
- | | second mutable borrow occurs here
+ | ----- ^ second mutable borrow occurs here
+ | |
| first mutable borrow occurs here
- | borrow later used here
+ | first borrow later used by call
error[E0382]: borrow of moved value: `f`
--> $DIR/moves-based-on-type-no-recursive-stack-closure.rs:42:5
LL | let b2 = &mut *b; //~ ERROR cannot borrow
| ^ second mutable borrow occurs here
LL | b1.use_mut();
- | -- borrow later used here
+ | -- first borrow later used here
error: aborting due to previous error
error[E0597]: `v` does not live long enough
--> $DIR/borrowed-local-error.rs:20:9
|
-LL | let x = gimme({
- | _____________-
-LL | | let v = (22,);
-LL | | &v
- | | ^^ borrowed value does not live long enough
-LL | | //~^ ERROR `v` does not live long enough [E0597]
-LL | | });
- | |_____-- borrow later used here
- | |
- | `v` dropped here while still borrowed
+LL | let x = gimme({
+ | ----- borrow later used by call
+LL | let v = (22,);
+LL | &v
+ | ^^ borrowed value does not live long enough
+LL | //~^ ERROR `v` does not live long enough [E0597]
+LL | });
+ | - `v` dropped here while still borrowed
error: aborting due to previous error
| ^^^^^^^^^^^^^^^ immutable borrow occurs here
LL | //~^ ERROR cannot borrow `*block.current` as immutable because it is also borrowed as mutable
LL | drop(x);
- | - borrow later used here
+ | - mutable borrow later used here
error: aborting due to previous error
| |
| immutable borrow occurs here
LL | r.use_mut();
- | - borrow later used here
+ | - mutable borrow later used here
error[E0499]: cannot borrow `x` as mutable more than once at a time
--> $DIR/closure-access-spans.rs:23:5
| |
| second mutable borrow occurs here
LL | r.use_mut();
- | - borrow later used here
+ | - first borrow later used here
error[E0500]: closure requires unique access to `x` but it is already borrowed
--> $DIR/closure-access-spans.rs:29:5
| |
| closure construction occurs here
LL | r.use_mut();
- | - borrow later used here
+ | - first borrow later used here
error[E0503]: cannot use `x` because it was mutably borrowed
--> $DIR/closure-access-spans.rs:35:13
LL | let y = &mut x; //~ ERROR
| ^^^^^^ mutable borrow occurs here
LL | f.use_ref();
- | - borrow later used here
+ | - immutable borrow later used here
error[E0597]: `x` does not live long enough
--> $DIR/closure-borrow-spans.rs:31:16
LL | let y = &x; //~ ERROR
| ^^ immutable borrow occurs here
LL | f.use_ref();
- | - borrow later used here
+ | - mutable borrow later used here
error[E0499]: cannot borrow `x` as mutable more than once at a time
--> $DIR/closure-borrow-spans.rs:56:13
LL | let y = &mut x; //~ ERROR
| ^^^^^^ second mutable borrow occurs here
LL | f.use_ref();
- | - borrow later used here
+ | - first borrow later used here
error[E0597]: `x` does not live long enough
--> $DIR/closure-borrow-spans.rs:64:16
LL | let y = &x; //~ ERROR
| ^^ borrow occurs here
LL | f.use_ref();
- | - borrow later used here
+ | - first borrow later used here
error[E0501]: cannot borrow `x` as mutable because previous closure requires unique access
--> $DIR/closure-borrow-spans.rs:89:13
LL | let y = &mut x; //~ ERROR
| ^^^^^^ borrow occurs here
LL | f.use_ref();
- | - borrow later used here
+ | - first borrow later used here
error[E0597]: `x` does not live long enough
--> $DIR/closure-borrow-spans.rs:98:17
LL | map.set(String::new()); // Ideally, this would not error.
| ^^^^^^^^^^^^^^^^^^^^^^ mutable borrow occurs here
|
-note: borrowed value must be valid for the anonymous lifetime #1 defined on the function body at 26:1...
+note: immutable borrowed value must be valid for the anonymous lifetime #1 defined on the function body at 26:1...
--> $DIR/get_default.rs:26:1
|
LL | / fn ok(map: &mut Map) -> &String {
LL | map.set(String::new()); // Both AST and MIR error here
| ^^^^^^^^^^^^^^^^^^^^^^ mutable borrow occurs here
|
-note: borrowed value must be valid for the anonymous lifetime #1 defined on the function body at 41:1...
+note: immutable borrowed value must be valid for the anonymous lifetime #1 defined on the function body at 41:1...
--> $DIR/get_default.rs:41:1
|
LL | / fn err(map: &mut Map) -> &String {
LL | map.set(String::new()); // Ideally, just AST would error here
| ^^^^^^^^^^^^^^^^^^^^^^ mutable borrow occurs here
|
-note: borrowed value must be valid for the anonymous lifetime #1 defined on the function body at 41:1...
+note: immutable borrowed value must be valid for the anonymous lifetime #1 defined on the function body at 41:1...
--> $DIR/get_default.rs:41:1
|
LL | / fn err(map: &mut Map) -> &String {
LL | map.set(String::new()); // Ideally, this would not error.
| ^^^ mutable borrow occurs here
|
-note: borrowed value must be valid for the anonymous lifetime #1 defined on the function body at 26:1...
+note: immutable borrowed value must be valid for the anonymous lifetime #1 defined on the function body at 26:1...
--> $DIR/get_default.rs:26:1
|
LL | / fn ok(map: &mut Map) -> &String {
LL | map.set(String::new()); // Both AST and MIR error here
| ^^^ mutable borrow occurs here
|
-note: borrowed value must be valid for the anonymous lifetime #1 defined on the function body at 41:1...
+note: immutable borrowed value must be valid for the anonymous lifetime #1 defined on the function body at 41:1...
--> $DIR/get_default.rs:41:1
|
LL | / fn err(map: &mut Map) -> &String {
LL | map.set(String::new()); // Ideally, just AST would error here
| ^^^ mutable borrow occurs here
|
-note: borrowed value must be valid for the anonymous lifetime #1 defined on the function body at 41:1...
+note: immutable borrowed value must be valid for the anonymous lifetime #1 defined on the function body at 41:1...
--> $DIR/get_default.rs:41:1
|
LL | / fn err(map: &mut Map) -> &String {
--- /dev/null
+// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![feature(nll)]
+
+struct Struct;
+
+impl Struct {
+ fn bar(self: &mut Self) {
+ (&mut self).bar();
+ //~^ ERROR cannot borrow `self` as mutable, as it is not declared as mutable [E0596]
+ }
+
+ fn imm(self) {
+ (&mut self).bar();
+ //~^ ERROR cannot borrow `self` as mutable, as it is not declared as mutable [E0596]
+ }
+
+ fn mtbl(mut self) {
+ (&mut self).bar();
+ }
+
+ fn immref(&self) {
+ (&mut self).bar();
+ //~^ ERROR cannot borrow `self` as mutable, as it is not declared as mutable [E0596]
+ //~^^ ERROR cannot borrow data in a `&` reference as mutable [E0596]
+ }
+
+ fn mtblref(&mut self) {
+ (&mut self).bar();
+ //~^ ERROR cannot borrow `self` as mutable, as it is not declared as mutable [E0596]
+ }
+}
+
+fn main () {}
--- /dev/null
+error[E0596]: cannot borrow `self` as mutable, as it is not declared as mutable
+ --> $DIR/issue-51191.rs:17:9
+ |
+LL | (&mut self).bar();
+ | ^^^^^^^^^^^
+ | |
+ | cannot borrow as mutable
+ | try removing `&mut` here
+
+error[E0596]: cannot borrow `self` as mutable, as it is not declared as mutable
+ --> $DIR/issue-51191.rs:22:9
+ |
+LL | fn imm(self) {
+ | ---- help: consider changing this to be mutable: `mut self`
+LL | (&mut self).bar();
+ | ^^^^^^^^^^^ cannot borrow as mutable
+
+error[E0596]: cannot borrow `self` as mutable, as it is not declared as mutable
+ --> $DIR/issue-51191.rs:31:9
+ |
+LL | (&mut self).bar();
+ | ^^^^^^^^^^^ cannot borrow as mutable
+
+error[E0596]: cannot borrow data in a `&` reference as mutable
+ --> $DIR/issue-51191.rs:31:9
+ |
+LL | (&mut self).bar();
+ | ^^^^^^^^^^^ cannot borrow as mutable
+
+error[E0596]: cannot borrow `self` as mutable, as it is not declared as mutable
+ --> $DIR/issue-51191.rs:37:9
+ |
+LL | (&mut self).bar();
+ | ^^^^^^^^^^^
+ | |
+ | cannot borrow as mutable
+ | try removing `&mut` here
+
+error: aborting due to 5 previous errors
+
+For more information about this error, try `rustc --explain E0596`.
error[E0502]: cannot borrow `self.thing` as mutable because it is also borrowed as immutable
--> $DIR/issue-51268.rs:28:9
|
-LL | self.thing.bar(|| {
- | ^ -- immutable borrow occurs here
- | _________|
- | |_________|
- | ||
-LL | || //~^ ERROR cannot borrow `self.thing` as mutable because it is also borrowed as immutable [E0502]
-LL | || &self.number;
- | || ---- first borrow occurs due to use of `self` in closure
-LL | || });
- | || ^
- | ||__________|
- | |___________mutable borrow occurs here
- | borrow later used here
+LL | self.thing.bar(|| {
+ | ^ --- -- immutable borrow occurs here
+ | | |
+ | _________| immutable borrow later used by call
+ | |
+LL | | //~^ ERROR cannot borrow `self.thing` as mutable because it is also borrowed as immutable [E0502]
+LL | | &self.number;
+ | | ---- first borrow occurs due to use of `self` in closure
+LL | | });
+ | |__________^ mutable borrow occurs here
error: aborting due to previous error
--- /dev/null
+// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![feature(nll)]
+
+use std::rc::Rc;
+use std::sync::Arc;
+
+struct Bar { field: Vec<i32> }
+
+fn main() {
+ let x = Rc::new(Bar { field: vec![] });
+ drop(x.field);
+
+ let y = Arc::new(Bar { field: vec![] });
+ drop(y.field);
+}
--- /dev/null
+error[E0507]: cannot move out of an `Rc`
+ --> $DIR/issue-52086.rs:20:10
+ |
+LL | drop(x.field);
+ | ^^^^^^^ cannot move out of an `Rc`
+
+error[E0507]: cannot move out of an `Arc`
+ --> $DIR/issue-52086.rs:23:10
+ |
+LL | drop(y.field);
+ | ^^^^^^^ cannot move out of an `Arc`
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0507`.
| ^^^^ second mutable borrow occurs here
...
LL | capitalize(slice);
- | ----- borrow later used here
+ | ----- first borrow later used here
error[E0499]: cannot borrow `data` as mutable more than once at a time (Mir)
--> $DIR/loan_ends_mid_block_vec.rs:27:5
| ^^^^ second mutable borrow occurs here
...
LL | capitalize(slice);
- | ----- borrow later used here
+ | ----- first borrow later used here
error[E0499]: cannot borrow `data` as mutable more than once at a time (Mir)
--> $DIR/loan_ends_mid_block_vec.rs:30:5
| ^^^^ second mutable borrow occurs here
...
LL | capitalize(slice);
- | ----- borrow later used here
+ | ----- first borrow later used here
error: aborting due to 9 previous errors
| cannot move out of borrowed content
| help: consider removing the `*`: `*r`
-error[E0507]: cannot move out of borrowed content
+error[E0507]: cannot move out of an `Rc`
--> $DIR/move-errors.rs:40:13
|
LL | let s = *r;
| ^^
| |
- | cannot move out of borrowed content
+ | cannot move out of an `Rc`
| help: consider removing the `*`: `r`
error[E0508]: cannot move out of type `[A; 1]`, a non-copy array
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ mutable borrow occurs here
...
LL | drop(value);
- | ----- borrow later used here
+ | ----- immutable borrow later used here
error: aborting due to 3 previous errors
| ^^^^^^^^^^^^^^^ mutable borrow occurs here
...
LL | drop(value);
- | ----- borrow later used here
+ | ----- immutable borrow later used here
error: aborting due to 3 previous errors
| ^^^^^^^^^^^^^^^ second mutable borrow occurs here
...
LL | value.len();
- | ----- borrow later used here
+ | ----- first borrow later used here
error: aborting due to 3 previous errors
--- /dev/null
+// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+
+#![allow(warnings)]
+#![feature(nll)]
+#![feature(type_ascription)]
+
+fn main() {
+ let x = 22_u32;
+ let y: &u32 = &x: &'static u32; //~ ERROR E0597
+}
--- /dev/null
+error[E0597]: `x` does not live long enough
+ --> $DIR/type_ascription_static_lifetime.rs:18:19
+ |
+LL | let y: &u32 = &x: &'static u32; //~ ERROR E0597
+ | ^^ borrowed value does not live long enough
+LL | }
+ | - `x` dropped here while still borrowed
+ |
+ = note: borrowed value must be valid for the static lifetime...
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0597`.
trait Tr2<T> {}
impl<T> Tr2<T> for u8 {}
fn g() -> impl Tr2<m::Alias> { 0 } //~ ERROR type `m::Priv` is private
-//~^ ERROR type `m::Priv` is private
fn g_ext() -> impl Tr2<ext::Alias> { 0 } //~ ERROR type `ext::Priv` is private
-//~^ ERROR type `ext::Priv` is private
fn main() {}
LL | fn g() -> impl Tr2<m::Alias> { 0 } //~ ERROR type `m::Priv` is private
| ^^^^^^^^^^^^^^^^^^
-error: type `m::Priv` is private
- --> $DIR/private-type-in-interface.rs:37:16
- |
-LL | fn g() -> impl Tr2<m::Alias> { 0 } //~ ERROR type `m::Priv` is private
- | ^^^^^^^^^^^^^
-
error: type `ext::Priv` is private
- --> $DIR/private-type-in-interface.rs:39:15
+ --> $DIR/private-type-in-interface.rs:38:15
|
LL | fn g_ext() -> impl Tr2<ext::Alias> { 0 } //~ ERROR type `ext::Priv` is private
| ^^^^^^^^^^^^^^^^^^^^
-error: type `ext::Priv` is private
- --> $DIR/private-type-in-interface.rs:39:20
- |
-LL | fn g_ext() -> impl Tr2<ext::Alias> { 0 } //~ ERROR type `ext::Priv` is private
- | ^^^^^^^^^^^^^^^
-
-error: aborting due to 11 previous errors
+error: aborting due to 9 previous errors
--> $DIR/region-bound-on-closure-outlives-call.rs:12:25
|
LL | (|x| f(x))(call_rec(f)) //~ ERROR cannot move out of `f`
- | --------------------^--
- | || | |
- | || | move out of `f` occurs here
+ | ---------- ^ move out of `f` occurs here
+ | || |
| || borrow occurs due to use in closure
| |borrow of `f` occurs here
- | borrow later used here
+ | borrow later used by call
error: aborting due to previous error
--> $DIR/regions-adjusted-lvalue-op.rs:24:16
|
LL | v[0].oh_no(&v); //~ ERROR cannot borrow `v` as immutable because
- | -----------^^-
- | | |
- | | immutable borrow occurs here
+ | - ----- ^^ immutable borrow occurs here
+ | | |
+ | | mutable borrow later used by call
| mutable borrow occurs here
- | borrow later used here
error[E0502]: cannot borrow `v` as immutable because it is also borrowed as mutable
--> $DIR/regions-adjusted-lvalue-op.rs:25:16
|
LL | (*v).oh_no(&v); //~ ERROR cannot borrow `v` as immutable because
- | -----------^^-
- | | | |
- | | | immutable borrow occurs here
- | | mutable borrow occurs here
- | borrow later used here
+ | - ----- ^^ immutable borrow occurs here
+ | | |
+ | | mutable borrow later used by call
+ | mutable borrow occurs here
error: aborting due to 2 previous errors
mod b {
use alloc::HashMap;
//~^ ERROR unresolved import `alloc` [E0432]
- //~| Did you mean `a::alloc`?
+ //~| Did you mean `super::alloc`?
mod c {
use alloc::HashMap;
//~^ ERROR unresolved import `alloc` [E0432]
- //~| Did you mean `a::alloc`?
+ //~| Did you mean `std::alloc`?
mod d {
use alloc::HashMap;
//~^ ERROR unresolved import `alloc` [E0432]
- //~| Did you mean `a::alloc`?
+ //~| Did you mean `std::alloc`?
}
}
}
--> $DIR/resolve_self_super_hint.rs:20:13
|
LL | use alloc::HashMap;
- | ^^^^^ Did you mean `a::alloc`?
+ | ^^^^^ Did you mean `super::alloc`?
error[E0432]: unresolved import `alloc`
--> $DIR/resolve_self_super_hint.rs:24:17
|
LL | use alloc::HashMap;
- | ^^^^^ Did you mean `a::alloc`?
+ | ^^^^^ Did you mean `std::alloc`?
error[E0432]: unresolved import `alloc`
--> $DIR/resolve_self_super_hint.rs:28:21
|
LL | use alloc::HashMap;
- | ^^^^^ Did you mean `a::alloc`?
+ | ^^^^^ Did you mean `std::alloc`?
error: aborting due to 4 previous errors
| ^^^^^^^^^^^^ mutable borrow occurs here
LL | //~^ ERROR cannot borrow `foo` as mutable
LL | println!("foo={:?}", *string);
- | ------- borrow used here, in later iteration of loop
+ | ------- immutable borrow used here, in later iteration of loop
error: aborting due to previous error
--- /dev/null
+// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// run-pass
+
+trait Foo<'a> {
+ fn xyz(self);
+}
+impl<'a, T> Foo<'a> for T where 'static: 'a {
+ fn xyz(self) {}
+}
+
+trait Bar {
+ fn uvw(self);
+}
+impl<T> Bar for T where for<'a> T: Foo<'a> {
+ fn uvw(self) { self.xyz(); }
+}
+
+fn foo<T>(t: T) where T: Bar {
+ t.uvw();
+}
+
+fn main() {
+ foo(0);
+}
--- /dev/null
+// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// This file is used as part of the local-path-suggestions.rs test.
+
+pub mod foobar {
+ pub struct Baz;
+}
--> $DIR/issue-54006.rs:16:5
|
LL | use alloc::vec;
- | ^^^^^ Could not find `alloc` in `{{root}}`
+ | ^^^^^ Did you mean `std::alloc`?
error: cannot determine resolution for the macro `vec`
--> $DIR/issue-54006.rs:20:18
--- /dev/null
+// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// aux-build:baz.rs
+// compile-flags:--extern baz
+// edition:2015
+
+// This test exists to demonstrate the behaviour of the import suggestions
+// from the `local-path-suggestions-2018.rs` test when not using the 2018 edition.
+
+extern crate baz as aux_baz;
+
+mod foo {
+ pub type Bar = u32;
+}
+
+mod baz {
+ use foo::Bar;
+
+ fn baz() {
+ let x: Bar = 22;
+ }
+}
+
+use foo::Bar;
+
+use foobar::Baz;
+
+fn main() { }
--- /dev/null
+error[E0432]: unresolved import `foobar`
+ --> $DIR/local-path-suggestions-2015.rs:34:5
+ |
+LL | use foobar::Baz;
+ | ^^^^^^ Did you mean `aux_baz::foobar`?
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0432`.
--- /dev/null
+// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// aux-build:baz.rs
+// compile-flags:--extern baz
+// edition:2018
+
+mod foo {
+ pub type Bar = u32;
+}
+
+mod baz {
+ use foo::Bar;
+
+ fn baz() {
+ let x: Bar = 22;
+ }
+}
+
+use foo::Bar;
+
+use foobar::Baz;
+
+fn main() { }
--- /dev/null
+error[E0432]: unresolved import `foo`
+ --> $DIR/local-path-suggestions-2018.rs:20:9
+ |
+LL | use foo::Bar;
+ | ^^^ Did you mean `crate::foo`?
+
+error[E0432]: unresolved import `foo`
+ --> $DIR/local-path-suggestions-2018.rs:27:5
+ |
+LL | use foo::Bar;
+ | ^^^ Did you mean `self::foo`?
+
+error[E0432]: unresolved import `foobar`
+ --> $DIR/local-path-suggestions-2018.rs:29:5
+ |
+LL | use foobar::Baz;
+ | ^^^^^^ Did you mean `baz::foobar`?
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0432`.
fn main() {
foo(2);
foo(2 + 3);
- foo(baz());
+ const BAZ: i32 = baz();
+ foo(BAZ);
let a = 4;
foo(A);
foo(a); //~ ERROR: argument 1 is required to be a constant
error: argument 1 is required to be a constant
- --> $DIR/rustc-args-required-const.rs:33:5
+ --> $DIR/rustc-args-required-const.rs:34:5
|
LL | foo(a); //~ ERROR: argument 1 is required to be a constant
| ^^^^^^
error: argument 2 is required to be a constant
- --> $DIR/rustc-args-required-const.rs:35:5
+ --> $DIR/rustc-args-required-const.rs:36:5
|
LL | bar(a, a); //~ ERROR: argument 2 is required to be a constant
| ^^^^^^^^^
error[E0499]: cannot borrow `f` as mutable more than once at a time
--> $DIR/borrowck-call-is-borrow-issue-12224.rs:22:16
|
-LL | f(Box::new(|| {
- | - ^^ second mutable borrow occurs here
- | |
- | _____first mutable borrow occurs here
- | |
-LL | | //~^ ERROR: cannot borrow `f` as mutable more than once
-LL | | f((Box::new(|| {})))
- | | - second borrow occurs due to use of `f` in closure
-LL | | }));
- | |_______- borrow later used here
+LL | f(Box::new(|| {
+ | - ^^ second mutable borrow occurs here
+ | |
+ | first mutable borrow occurs here
+ | first borrow later used by call
+LL | //~^ ERROR: cannot borrow `f` as mutable more than once
+LL | f((Box::new(|| {})))
+ | - second borrow occurs due to use of `f` in closure
error[E0596]: cannot borrow `*f` as mutable, as it is behind a `&` reference
--> $DIR/borrowck-call-is-borrow-issue-12224.rs:35:5
error[E0505]: cannot move out of `f` because it is borrowed
--> $DIR/borrowck-call-is-borrow-issue-12224.rs:65:16
|
-LL | f(Box::new(|a| {
- | - ^^^ move out of `f` occurs here
- | |
- | _____borrow of `f` occurs here
- | |
-LL | | foo(f);
- | | - move occurs due to use in closure
-LL | | //~^ ERROR cannot move `f` into closure because it is borrowed
-LL | | //~| ERROR cannot move out of captured outer variable in an `FnMut` closure
-LL | | }), 3);
- | |__________- borrow later used here
+LL | f(Box::new(|a| {
+ | - ^^^ move out of `f` occurs here
+ | |
+ | borrow of `f` occurs here
+ | borrow later used by call
+LL | foo(f);
+ | - move occurs due to use in closure
error: aborting due to 5 previous errors
--> $DIR/unboxed-closures-recursive-fn-using-fn-mut.rs:32:21
|
LL | (self.func)(self, arg)
- | ------------^^^^------
- | | |
- | | second mutable borrow occurs here
+ | ----------- ^^^^ second mutable borrow occurs here
+ | |
| first mutable borrow occurs here
- | borrow later used here
+ | first borrow later used by call
error: aborting due to previous error
| -------
| |
| first mutable borrow occurs here
- | borrow used here, in later iteration of loop
+ | first borrow used here, in later iteration of loop
LL | xs.push(1) //~ ERROR cannot borrow `xs`
| ^^ second mutable borrow occurs here
-Subproject commit e69fe2fb19b7b2f3b07fe1178c536810dabf896f
+Subproject commit c47b9489ab4f2124e2e93a3b1ec8a2eeafe54cf4
"wincon",
"wincrypt",
]
+
+[dependencies.serde_json]
+version = "1.0.31"
+features = ["raw_value"]
+
+[dependencies.rand]
+version = "0.5.5"
+features = ["i128_support"]