Auto merge of #73643 - Manishearth:rollup-68dr8fz, r=Manishearth

Rollup of 9 pull requests

Successful merges:

 - #72271 (Improve compiler error message for wrong generic parameter order)
 - #72493 ( move leak-check to during coherence, candidate eval)
 - #73398 (A way forward for pointer equality in const eval)
 - #73472 (Clean up E0689 explanation)
 - #73496 (Account for multiple impl/dyn Trait in return type when suggesting `'_`)
 - #73515 (Add second message for LiveDrop errors)
 - #73567 (Clarify --extern documentation.)
 - #73572 (Fix typos in doc comments)
 - #73590 (bootstrap: no `config.toml` exists regression)

Failed merges:

r? @ghost
This commit is contained in:
bors 2020-06-23 07:50:51 +00:00
commit 1557fb031b
206 changed files with 3093 additions and 1580 deletions

View File

@ -893,15 +893,18 @@ def bootstrap(help_triggered):
build.verbose = args.verbose
build.clean = args.clean
try:
toml_path = os.getenv('RUST_BOOTSTRAP_CONFIG') or args.config or 'config.toml'
# Read from `RUST_BOOTSTRAP_CONFIG`, then `--config`, then fallback to `config.toml` (if it
# exists).
toml_path = os.getenv('RUST_BOOTSTRAP_CONFIG') or args.config
if not toml_path and os.path.exists('config.toml'):
toml_path = 'config.toml'
if toml_path:
if not os.path.exists(toml_path):
toml_path = os.path.join(build.rust_root, toml_path)
with open(toml_path) as config:
build.config_toml = config.read()
except (OSError, IOError):
pass
config_verbose = build.get_toml('verbose', 'build')
if config_verbose is not None:
@ -947,11 +950,12 @@ def bootstrap(help_triggered):
env["SRC"] = build.rust_root
env["BOOTSTRAP_PARENT_ID"] = str(os.getpid())
env["BOOTSTRAP_PYTHON"] = sys.executable
env["BOOTSTRAP_CONFIG"] = toml_path
env["BUILD_DIR"] = build.build_dir
env["RUSTC_BOOTSTRAP"] = '1'
env["CARGO"] = build.cargo()
env["RUSTC"] = build.rustc()
if toml_path:
env["BOOTSTRAP_CONFIG"] = toml_path
if build.rustfmt():
env["RUSTFMT"] = build.rustfmt()
run(args, env=env, verbose=build.verbose)

View File

@ -273,10 +273,18 @@ This flag, when combined with other flags, makes them produce extra output.
This flag allows you to pass the name and location for an external crate of a
direct dependency. Indirect dependencies (dependencies of dependencies) are
located using the [`-L` flag](#option-l-search-path). The given crate name is
added to the [extern prelude], which is the same as specifying `extern crate`
within the root module. The given crate name does not need to match the name
added to the [extern prelude], similar to specifying `extern crate` within the
root module. The given crate name does not need to match the name
the library was built with.
Specifying `--extern` has one behavior difference from `extern crate`:
`--extern` merely makes the crate a _candidate_ for being linked; it does not
actually link it unless it's actively used. In rare occasions you may wish
to ensure a crate is linked even if you don't actively use it from your
code: for example, if it changes the global allocator or if it contains
`#[no_mangle]` symbols for use by other programming languages. In such
cases you'll need to use `extern crate`.
This flag may be specified multiple times. This flag takes an argument with
either of the following formats:

View File

@ -60,7 +60,7 @@ impl<T> RawVec<T, Global> {
/// `#[rustc_force_min_const_fn]` attribute which requires conformance
/// with `min_const_fn` but does not necessarily allow calling it in
/// `stable(...) const fn` / user code not enabling `foo` when
/// `#[rustc_const_unstable(feature = "foo", ..)]` is present.
/// `#[rustc_const_unstable(feature = "foo", issue = "01234")]` is present.
pub const NEW: Self = Self::new();
/// Creates the biggest possible `RawVec` (on the system heap)

View File

@ -1012,7 +1012,7 @@ extern "rust-intrinsic" {
///
/// The stabilized version of this intrinsic is
/// [`std::any::type_name`](../../std/any/fn.type_name.html)
#[rustc_const_unstable(feature = "const_type_name", issue = "none")]
#[rustc_const_unstable(feature = "const_type_name", issue = "63084")]
pub fn type_name<T: ?Sized>() -> &'static str;
/// Gets an identifier which is globally unique to the specified type. This
@ -1021,7 +1021,7 @@ extern "rust-intrinsic" {
///
/// The stabilized version of this intrinsic is
/// [`std::any::TypeId::of`](../../std/any/struct.TypeId.html#method.of)
#[rustc_const_unstable(feature = "const_type_id", issue = "none")]
#[rustc_const_unstable(feature = "const_type_id", issue = "41875")]
pub fn type_id<T: ?Sized + 'static>() -> u64;
/// A guard for unsafe functions that cannot ever be executed if `T` is uninhabited:
@ -1931,7 +1931,7 @@ extern "rust-intrinsic" {
pub fn nontemporal_store<T>(ptr: *mut T, val: T);
/// See documentation of `<*const T>::offset_from` for details.
#[rustc_const_unstable(feature = "const_ptr_offset_from", issue = "none")]
#[rustc_const_unstable(feature = "const_ptr_offset_from", issue = "41079")]
pub fn ptr_offset_from<T>(ptr: *const T, base: *const T) -> isize;
/// Internal hook used by Miri to implement unwinding.
@ -1948,6 +1948,16 @@ extern "rust-intrinsic" {
#[cfg(not(bootstrap))]
#[lang = "count_code_region"]
pub fn count_code_region(index: u32);
/// See documentation of `<*const T>::guaranteed_eq` for details.
#[rustc_const_unstable(feature = "const_raw_ptr_comparison", issue = "53020")]
#[cfg(not(bootstrap))]
pub fn ptr_guaranteed_eq<T>(ptr: *const T, other: *const T) -> bool;
/// See documentation of `<*const T>::guaranteed_ne` for details.
#[rustc_const_unstable(feature = "const_raw_ptr_comparison", issue = "53020")]
#[cfg(not(bootstrap))]
pub fn ptr_guaranteed_ne<T>(ptr: *const T, other: *const T) -> bool;
}
// Some functions are defined here because they accidentally got made

View File

@ -87,6 +87,7 @@
#![feature(const_generics)]
#![feature(const_ptr_offset)]
#![feature(const_ptr_offset_from)]
#![cfg_attr(not(bootstrap), feature(const_raw_ptr_comparison))]
#![feature(const_result)]
#![feature(const_slice_from_raw_parts)]
#![feature(const_slice_ptr_len)]

View File

@ -295,6 +295,72 @@ impl<T: ?Sized> *const T {
intrinsics::ptr_offset_from(self, origin)
}
/// Returns whether two pointers are guaranteed to be equal.
///
/// At runtime this function behaves like `self == other`.
/// However, in some contexts (e.g., compile-time evaluation),
/// it is not always possible to determine equality of two pointers, so this function may
/// spuriously return `false` for pointers that later actually turn out to be equal.
/// But when it returns `true`, the pointers are guaranteed to be equal.
///
/// This function is the mirror of [`guaranteed_ne`], but not its inverse. There are pointer
/// comparisons for which both functions return `false`.
///
/// [`guaranteed_ne`]: #method.guaranteed_ne
///
/// The return value may change depending on the compiler version and unsafe code may not
/// rely on the result of this function for soundness. It is suggested to only use this function
/// for performance optimizations where spurious `false` return values by this function do not
/// affect the outcome, but just the performance.
/// The consequences of using this method to make runtime and compile-time code behave
/// differently have not been explored. This method should not be used to introduce such
/// differences, and it should also not be stabilized before we have a better understanding
/// of this issue.
/// ```
#[unstable(feature = "const_raw_ptr_comparison", issue = "53020")]
#[rustc_const_unstable(feature = "const_raw_ptr_comparison", issue = "53020")]
#[inline]
#[cfg(not(bootstrap))]
pub const fn guaranteed_eq(self, other: *const T) -> bool
where
T: Sized,
{
intrinsics::ptr_guaranteed_eq(self, other)
}
/// Returns whether two pointers are guaranteed to be inequal.
///
/// At runtime this function behaves like `self != other`.
/// However, in some contexts (e.g., compile-time evaluation),
/// it is not always possible to determine the inequality of two pointers, so this function may
/// spuriously return `false` for pointers that later actually turn out to be inequal.
/// But when it returns `true`, the pointers are guaranteed to be inequal.
///
/// This function is the mirror of [`guaranteed_eq`], but not its inverse. There are pointer
/// comparisons for which both functions return `false`.
///
/// [`guaranteed_eq`]: #method.guaranteed_eq
///
/// The return value may change depending on the compiler version and unsafe code may not
/// rely on the result of this function for soundness. It is suggested to only use this function
/// for performance optimizations where spurious `false` return values by this function do not
/// affect the outcome, but just the performance.
/// The consequences of using this method to make runtime and compile-time code behave
/// differently have not been explored. This method should not be used to introduce such
/// differences, and it should also not be stabilized before we have a better understanding
/// of this issue.
/// ```
#[unstable(feature = "const_raw_ptr_comparison", issue = "53020")]
#[rustc_const_unstable(feature = "const_raw_ptr_comparison", issue = "53020")]
#[inline]
#[cfg(not(bootstrap))]
pub const fn guaranteed_ne(self, other: *const T) -> bool
where
T: Sized,
{
intrinsics::ptr_guaranteed_ne(self, other)
}
/// Calculates the distance between two pointers. The returned value is in
/// units of T: the distance in bytes is divided by `mem::size_of::<T>()`.
///

View File

@ -273,6 +273,72 @@ impl<T: ?Sized> *mut T {
if self.is_null() { None } else { Some(&mut *self) }
}
/// Returns whether two pointers are guaranteed to be equal.
///
/// At runtime this function behaves like `self == other`.
/// However, in some contexts (e.g., compile-time evaluation),
/// it is not always possible to determine equality of two pointers, so this function may
/// spuriously return `false` for pointers that later actually turn out to be equal.
/// But when it returns `true`, the pointers are guaranteed to be equal.
///
/// This function is the mirror of [`guaranteed_ne`], but not its inverse. There are pointer
/// comparisons for which both functions return `false`.
///
/// [`guaranteed_ne`]: #method.guaranteed_ne
///
/// The return value may change depending on the compiler version and unsafe code may not
/// rely on the result of this function for soundness. It is suggested to only use this function
/// for performance optimizations where spurious `false` return values by this function do not
/// affect the outcome, but just the performance.
/// The consequences of using this method to make runtime and compile-time code behave
/// differently have not been explored. This method should not be used to introduce such
/// differences, and it should also not be stabilized before we have a better understanding
/// of this issue.
/// ```
#[unstable(feature = "const_raw_ptr_comparison", issue = "53020")]
#[rustc_const_unstable(feature = "const_raw_ptr_comparison", issue = "53020")]
#[inline]
#[cfg(not(bootstrap))]
pub const fn guaranteed_eq(self, other: *mut T) -> bool
where
T: Sized,
{
intrinsics::ptr_guaranteed_eq(self as *const _, other as *const _)
}
/// Returns whether two pointers are guaranteed to be inequal.
///
/// At runtime this function behaves like `self != other`.
/// However, in some contexts (e.g., compile-time evaluation),
/// it is not always possible to determine the inequality of two pointers, so this function may
/// spuriously return `false` for pointers that later actually turn out to be inequal.
/// But when it returns `true`, the pointers are guaranteed to be inequal.
///
/// This function is the mirror of [`guaranteed_eq`], but not its inverse. There are pointer
/// comparisons for which both functions return `false`.
///
/// [`guaranteed_eq`]: #method.guaranteed_eq
///
/// The return value may change depending on the compiler version and unsafe code may not
/// rely on the result of this function for soundness. It is suggested to only use this function
/// for performance optimizations where spurious `false` return values by this function do not
/// affect the outcome, but just the performance.
/// The consequences of using this method to make runtime and compile-time code behave
/// differently have not been explored. This method should not be used to introduce such
/// differences, and it should also not be stabilized before we have a better understanding
/// of this issue.
/// ```
#[unstable(feature = "const_raw_ptr_comparison", issue = "53020")]
#[rustc_const_unstable(feature = "const_raw_ptr_comparison", issue = "53020")]
#[inline]
#[cfg(not(bootstrap))]
pub const unsafe fn guaranteed_ne(self, other: *mut T) -> bool
where
T: Sized,
{
intrinsics::ptr_guaranteed_ne(self as *const _, other as *const _)
}
/// Calculates the distance between two pointers. The returned value is in
/// units of T: the distance in bytes is divided by `mem::size_of::<T>()`.
///

View File

@ -5956,10 +5956,18 @@ where
return false;
}
#[cfg(bootstrap)]
if self.as_ptr() == other.as_ptr() {
return true;
}
// While performance would suffer if `guaranteed_eq` just returned `false`
// for all arguments, correctness and return value of this function are not affected.
#[cfg(not(bootstrap))]
if self.as_ptr().guaranteed_eq(other.as_ptr()) {
return true;
}
self.iter().zip(other.iter()).all(|(x, y)| x == y)
}
}
@ -5973,9 +5981,18 @@ where
if self.len() != other.len() {
return false;
}
#[cfg(bootstrap)]
if self.as_ptr() == other.as_ptr() {
return true;
}
// While performance would suffer if `guaranteed_eq` just returned `false`
// for all arguments, correctness and return value of this function are not affected.
#[cfg(not(bootstrap))]
if self.as_ptr().guaranteed_eq(other.as_ptr()) {
return true;
}
unsafe {
let size = mem::size_of_val(self);
memcmp(self.as_ptr() as *const u8, other.as_ptr() as *const u8, size) == 0

View File

@ -12,7 +12,7 @@ use log::debug;
use rustc_ast::ast;
use rustc_codegen_ssa::base::{compare_simd_types, to_immediate, wants_msvc_seh};
use rustc_codegen_ssa::common::span_invalid_monomorphization_error;
use rustc_codegen_ssa::common::TypeKind;
use rustc_codegen_ssa::common::{IntPredicate, TypeKind};
use rustc_codegen_ssa::glue;
use rustc_codegen_ssa::mir::operand::{OperandRef, OperandValue};
use rustc_codegen_ssa::mir::place::PlaceRef;
@ -731,6 +731,16 @@ impl IntrinsicCallMethods<'tcx> for Builder<'a, 'll, 'tcx> {
return;
}
"ptr_guaranteed_eq" | "ptr_guaranteed_ne" => {
let a = args[0].immediate();
let b = args[1].immediate();
if name == "ptr_guaranteed_eq" {
self.icmp(IntPredicate::IntEQ, a, b)
} else {
self.icmp(IntPredicate::IntNE, a, b)
}
}
"ptr_offset_from" => {
let ty = substs.type_at(0);
let pointee_size = self.size_of(ty);

View File

@ -1,13 +1,16 @@
A method was called on an ambiguous numeric type.
Erroneous code example:
```compile_fail,E0689
2.0.neg(); // error!
```
This error indicates that the numeric value for the method being passed exists
but the type of the numeric value or binding could not be identified.
The error happens on numeric literals:
```compile_fail,E0689
2.0.neg();
```
and on numeric bindings without an identified concrete type:
The error happens on numeric literals and on numeric bindings without an
identified concrete type:
```compile_fail,E0689
let x = 2.0;
@ -19,8 +22,8 @@ Because of this, you must give the numeric literal or binding a type:
```
use std::ops::Neg;
let _ = 2.0_f32.neg();
let _ = 2.0_f32.neg(); // ok!
let x: f32 = 2.0;
let _ = x.neg();
let _ = (2.0 as f32).neg();
let _ = x.neg(); // ok!
let _ = (2.0 as f32).neg(); // ok!
```

View File

@ -401,9 +401,6 @@ declare_features! (
/// Allows dereferencing raw pointers during const eval.
(active, const_raw_ptr_deref, "1.27.0", Some(51911), None),
/// Allows comparing raw pointers during const eval.
(active, const_compare_raw_pointers, "1.27.0", Some(53020), None),
/// Allows `#[doc(alias = "...")]`.
(active, doc_alias, "1.27.0", Some(50146), None),

View File

@ -113,6 +113,11 @@ declare_features! (
Some("removed in favor of `#![feature(marker_trait_attr)]`")),
/// Allows `#[no_debug]`.
(removed, no_debug, "1.43.0", Some(29721), None, Some("removed due to lack of demand")),
/// Allows comparing raw pointers during const eval.
(removed, const_compare_raw_pointers, "1.46.0", Some(53020), None,
Some("cannot be allowed in const eval in any meaningful way")),
// -------------------------------------------------------------------------
// feature-group-end: removed features
// -------------------------------------------------------------------------

View File

@ -26,7 +26,7 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
&self,
region: Region<'tcx>,
br: &ty::BoundRegion,
) -> Option<(&hir::Ty<'_>, &hir::FnDecl<'_>)> {
) -> Option<(&hir::Ty<'tcx>, &hir::FnDecl<'tcx>)> {
if let Some(anon_reg) = self.tcx().is_suitable_region(region) {
let def_id = anon_reg.def_id;
if let Some(def_id) = def_id.as_local() {

View File

@ -2,7 +2,8 @@
//! where one region is named and the other is anonymous.
use crate::infer::error_reporting::nice_region_error::NiceRegionError;
use rustc_errors::{struct_span_err, Applicability, DiagnosticBuilder};
use rustc_hir::{FnRetTy, TyKind};
use rustc_hir::intravisit::Visitor;
use rustc_hir::FnRetTy;
use rustc_middle::ty;
impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
@ -80,16 +81,21 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
}
if let FnRetTy::Return(ty) = &fndecl.output {
let mut v = ty::TraitObjectVisitor(vec![]);
rustc_hir::intravisit::walk_ty(&mut v, ty);
let mut v = ty::TraitObjectVisitor(vec![], self.tcx().hir());
v.visit_ty(ty);
debug!("try_report_named_anon_conflict: ret ty {:?}", ty);
if sub == &ty::ReStatic
&& (matches!(ty.kind, TyKind::OpaqueDef(_, _)) || v.0.len() == 1)
&& v.0
.into_iter()
.filter(|t| t.span.desugaring_kind().is_none())
.next()
.is_some()
{
// If the failure is due to a `'static` requirement coming from a `dyn` or
// `impl` Trait that *isn't* caused by `async fn` desugaring, handle this case
// better in `static_impl_trait`.
debug!("try_report_named_anon_conflict: impl Trait + 'static");
// This is an `impl Trait` or `dyn Trait` return that evaluates de need of
// `'static`. We handle this case better in `static_impl_trait`.
return None;
}
}

View File

@ -26,8 +26,11 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
);
let anon_reg_sup = self.tcx().is_suitable_region(sup_r)?;
debug!("try_report_static_impl_trait: anon_reg_sup={:?}", anon_reg_sup);
let fn_return = self.tcx().return_type_impl_or_dyn_trait(anon_reg_sup.def_id)?;
debug!("try_report_static_impl_trait: fn_return={:?}", fn_return);
let fn_returns = self.tcx().return_type_impl_or_dyn_traits(anon_reg_sup.def_id);
if fn_returns.is_empty() {
return None;
}
debug!("try_report_static_impl_trait: fn_return={:?}", fn_returns);
if **sub_r == RegionKind::ReStatic {
let sp = var_origin.span();
let return_sp = sub_origin.span();
@ -98,25 +101,26 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
);
}
// only apply this suggestion onto functions with
// explicit non-desugar'able return.
if fn_return.span.desugaring_kind().is_none() {
// FIXME: account for the need of parens in `&(dyn Trait + '_)`
let consider = "consider changing the";
let declare = "to declare that the";
let arg = match param_info.param.pat.simple_ident() {
Some(simple_ident) => format!("argument `{}`", simple_ident),
None => "the argument".to_string(),
};
let explicit =
format!("you can add an explicit `{}` lifetime bound", lifetime_name);
let explicit_static =
format!("explicit `'static` bound to the lifetime of {}", arg);
let captures = format!("captures data from {}", arg);
let add_static_bound =
"alternatively, add an explicit `'static` bound to this reference";
let plus_lt = format!(" + {}", lifetime_name);
// FIXME: account for the need of parens in `&(dyn Trait + '_)`
let consider = "consider changing the";
let declare = "to declare that the";
let arg = match param_info.param.pat.simple_ident() {
Some(simple_ident) => format!("argument `{}`", simple_ident),
None => "the argument".to_string(),
};
let explicit =
format!("you can add an explicit `{}` lifetime bound", lifetime_name);
let explicit_static =
format!("explicit `'static` bound to the lifetime of {}", arg);
let captures = format!("captures data from {}", arg);
let add_static_bound =
"alternatively, add an explicit `'static` bound to this reference";
let plus_lt = format!(" + {}", lifetime_name);
for fn_return in fn_returns {
if fn_return.span.desugaring_kind().is_some() {
// Skip `async` desugaring `impl Future`.
continue;
}
match fn_return.kind {
TyKind::OpaqueDef(item_id, _) => {
let item = self.tcx().hir().item(item_id.id);
@ -143,7 +147,7 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
err.span_suggestion_verbose(
span,
&format!("{} `impl Trait`'s {}", consider, explicit_static),
lifetime_name,
lifetime_name.clone(),
Applicability::MaybeIncorrect,
);
err.span_suggestion_verbose(
@ -152,6 +156,19 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
param_info.param_ty.to_string(),
Applicability::MaybeIncorrect,
);
} else if let Some(_) = opaque
.bounds
.iter()
.filter_map(|arg| match arg {
GenericBound::Outlives(Lifetime { name, span, .. })
if name.ident().to_string() == lifetime_name =>
{
Some(*span)
}
_ => None,
})
.next()
{
} else {
err.span_suggestion_verbose(
fn_return.span.shrink_to_hi(),
@ -161,10 +178,10 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
captures = captures,
explicit = explicit,
),
plus_lt,
plus_lt.clone(),
Applicability::MaybeIncorrect,
);
};
}
}
TyKind::TraitObject(_, lt) => match lt.name {
LifetimeName::ImplicitObjectLifetimeDefault => {
@ -176,15 +193,19 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
captures = captures,
explicit = explicit,
),
plus_lt,
plus_lt.clone(),
Applicability::MaybeIncorrect,
);
}
_ => {
name if name.ident().to_string() != lifetime_name => {
// With this check we avoid suggesting redundant bounds. This
// would happen if there are nested impl/dyn traits and only
// one of them has the bound we'd suggest already there, like
// in `impl Foo<X = dyn Bar> + '_`.
err.span_suggestion_verbose(
lt.span,
&format!("{} trait object's {}", consider, explicit_static),
lifetime_name,
lifetime_name.clone(),
Applicability::MaybeIncorrect,
);
err.span_suggestion_verbose(
@ -194,6 +215,7 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
Applicability::MaybeIncorrect,
);
}
_ => {}
},
_ => {}
}

View File

@ -30,10 +30,10 @@ impl<'a, 'tcx> CombineFields<'a, 'tcx> {
let span = self.trace.cause.span;
self.infcx.commit_if_ok(|snapshot| {
self.infcx.commit_if_ok(|_| {
// First, we instantiate each bound region in the supertype with a
// fresh placeholder region.
let (b_prime, placeholder_map) = self.infcx.replace_bound_vars_with_placeholders(b);
let (b_prime, _) = self.infcx.replace_bound_vars_with_placeholders(b);
// Next, we instantiate each bound region in the subtype
// with a fresh region variable. These region variables --
@ -48,8 +48,6 @@ impl<'a, 'tcx> CombineFields<'a, 'tcx> {
// Compare types now that bound regions have been replaced.
let result = self.sub(a_is_expected).relate(&a_prime, &b_prime)?;
self.infcx.leak_check(!a_is_expected, &placeholder_map, snapshot)?;
debug!("higher_ranked_sub: OK result={:?}", result);
Ok(ty::Binder::bind(result))
@ -75,7 +73,12 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
where
T: TypeFoldable<'tcx>,
{
let next_universe = self.create_next_universe();
// Figure out what the next universe will be, but don't actually create
// it until after we've done the substitution (in particular there may
// be no bound variables). This is a performance optimization, since the
// leak check for example can be skipped if no new universes are created
// (i.e., if there are no placeholders).
let next_universe = self.universe().next_universe();
let fld_r = |br| {
self.tcx.mk_region(ty::RePlaceholder(ty::PlaceholderRegion {
@ -103,6 +106,13 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
let (result, map) = self.tcx.replace_bound_vars(binder, fld_r, fld_t, fld_c);
// If there were higher-ranked regions to replace, then actually create
// the next universe (this avoids needlessly creating universes).
if !map.is_empty() {
let n_u = self.create_next_universe();
assert_eq!(n_u, next_universe);
}
debug!(
"replace_bound_vars_with_placeholders(\
next_universe={:?}, \
@ -119,7 +129,6 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
pub fn leak_check(
&self,
overly_polymorphic: bool,
placeholder_map: &PlaceholderMap<'tcx>,
snapshot: &CombinedSnapshot<'_, 'tcx>,
) -> RelateResult<'tcx, ()> {
// If the user gave `-Zno-leak-check`, or we have been
@ -135,7 +144,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
self.inner.borrow_mut().unwrap_region_constraints().leak_check(
self.tcx,
overly_polymorphic,
placeholder_map,
self.universe(),
snapshot,
)
}

View File

@ -991,14 +991,12 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
return None;
}
Some(self.commit_if_ok(|snapshot| {
let (ty::SubtypePredicate { a_is_expected, a, b }, placeholder_map) =
Some(self.commit_if_ok(|_snapshot| {
let (ty::SubtypePredicate { a_is_expected, a, b }, _) =
self.replace_bound_vars_with_placeholders(&predicate);
let ok = self.at(cause, param_env).sub_exp(a_is_expected, a, b)?;
self.leak_check(false, &placeholder_map, snapshot)?;
Ok(ok.unit())
}))
}
@ -1008,14 +1006,13 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
cause: &traits::ObligationCause<'tcx>,
predicate: ty::PolyRegionOutlivesPredicate<'tcx>,
) -> UnitResult<'tcx> {
self.commit_if_ok(|snapshot| {
let (ty::OutlivesPredicate(r_a, r_b), placeholder_map) =
self.commit_if_ok(|_snapshot| {
let (ty::OutlivesPredicate(r_a, r_b), _) =
self.replace_bound_vars_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, &placeholder_map, snapshot)?;
Ok(())
})
}

View File

@ -522,7 +522,13 @@ where
}
if a == b {
return Ok(a);
// Subtle: if a or b has a bound variable that we are lazilly
// substituting, then even if a == b, it could be that the values we
// will substitute for those bound variables are *not* the same, and
// hence returning `Ok(a)` is incorrect.
if !a.has_escaping_bound_vars() && !b.has_escaping_bound_vars() {
return Ok(a);
}
}
match (&a.kind, &b.kind) {

View File

@ -1,158 +1,446 @@
use super::*;
use crate::infer::{CombinedSnapshot, PlaceholderMap};
use rustc_data_structures::undo_log::UndoLogs;
use crate::infer::CombinedSnapshot;
use rustc_data_structures::{
graph::{scc::Sccs, vec_graph::VecGraph},
undo_log::UndoLogs,
};
use rustc_index::vec::Idx;
use rustc_middle::ty::error::TypeError;
use rustc_middle::ty::relate::RelateResult;
impl<'tcx> RegionConstraintCollector<'_, 'tcx> {
/// Searches region constraints created since `snapshot` that
/// affect one of the placeholders in `placeholder_map`, returning
/// an error if any of the placeholders are related to another
/// placeholder or would have to escape into some parent universe
/// that cannot name them.
/// Searches new universes created during `snapshot`, looking for
/// placeholders that may "leak" out from the universes they are contained
/// in. If any leaking placeholders are found, then an `Err` is returned
/// (typically leading to the snapshot being reversed).
///
/// This is a temporary backwards compatibility measure to try and
/// retain the older (arguably incorrect) behavior of the
/// compiler.
/// The leak check *used* to be the only way we had to handle higher-ranked
/// obligations. Now that we have integrated universes into the region
/// solvers, this is no longer the case, but we retain the leak check for
/// backwards compatibility purposes. In particular, it lets us make "early"
/// decisions about whether a region error will be reported that are used in
/// coherence and elsewhere -- see #56105 and #59490 for more details. The
/// eventual fate of the leak checker is not yet settled.
///
/// NB. Although `_snapshot` isn't used, it's passed in to prove
/// that we are in a snapshot, which guarantees that we can just
/// search the "undo log" for edges. This is mostly an efficiency
/// thing -- we could search *all* region constraints, but that'd be
/// a bigger set and the data structures are not setup for that. If
/// we wind up keeping some form of this check long term, it would
/// probably be better to remove the snapshot parameter and to
/// refactor the constraint set.
/// The leak checker works by searching for the following error patterns:
///
/// * P1: P2, where P1 != P2
/// * P1: R, where R is in some universe that cannot name P1
///
/// The idea here is that each of these patterns represents something that
/// the region solver would eventually report as an error, so we can detect
/// the error early. There is a fly in the ointment, though, in that this is
/// not entirely true. In particular, in the future, we may extend the
/// environment with implied bounds or other info about how placeholders
/// relate to regions in outer universes. In that case, `P1: R` for example
/// might become solveable.
///
/// # Summary of the implementation
///
/// The leak checks as follows. First, we construct a graph where `R2: R1`
/// implies `R2 -> R1`, and we compute the SCCs.
///
/// For each SCC S, we compute:
///
/// * what placeholder P it must be equal to, if any
/// * if there are multiple placeholders that must be equal, report an error because `P1: P2`
/// * the minimum universe of its constituents
///
/// Then we walk the SCCs in dependency order and compute
///
/// * what placeholder they must outlive transitively
/// * if they must also be equal to a placeholder, report an error because `P1: P2`
/// * minimum universe U of all SCCs they must outlive
/// * if they must also be equal to a placeholder P, and U cannot name P, report an error, as that
/// indicates `P: R` and `R` is in an incompatible universe
///
/// # Historical note
///
/// Older variants of the leak check used to report errors for these
/// patterns, but we no longer do:
///
/// * R: P1, even if R cannot name P1, because R = 'static is a valid sol'n
/// * R: P1, R: P2, as above
pub fn leak_check(
&mut self,
tcx: TyCtxt<'tcx>,
overly_polymorphic: bool,
placeholder_map: &PlaceholderMap<'tcx>,
_snapshot: &CombinedSnapshot<'_, 'tcx>,
max_universe: ty::UniverseIndex,
snapshot: &CombinedSnapshot<'_, 'tcx>,
) -> RelateResult<'tcx, ()> {
debug!("leak_check(placeholders={:?})", placeholder_map);
debug!(
"leak_check(max_universe={:?}, snapshot.universe={:?}, overly_polymorphic={:?})",
max_universe, snapshot.universe, overly_polymorphic
);
assert!(UndoLogs::<super::UndoLog<'_>>::in_snapshot(&self.undo_log));
// Go through each placeholder that we created.
for &placeholder_region in placeholder_map.values() {
// Find the universe this placeholder inhabits.
let placeholder = match placeholder_region {
ty::RePlaceholder(p) => p,
_ => bug!("leak_check: expected placeholder found {:?}", placeholder_region,),
};
let universe_at_start_of_snapshot = snapshot.universe;
if universe_at_start_of_snapshot == max_universe {
return Ok(());
}
// Find all regions that are related to this placeholder
// in some way. This means any region that either outlives
// or is outlived by a placeholder.
let mut taint_set = TaintSet::new(TaintDirections::both(), placeholder_region);
taint_set.fixed_point(
tcx,
self.undo_log.region_constraints(),
&self.storage.data.verifys,
let mini_graph =
&MiniGraph::new(tcx, self.undo_log.region_constraints(), &self.storage.data.verifys);
let mut leak_check = LeakCheck::new(
tcx,
universe_at_start_of_snapshot,
max_universe,
overly_polymorphic,
mini_graph,
self,
);
leak_check.assign_placeholder_values()?;
leak_check.propagate_scc_value()?;
Ok(())
}
}
struct LeakCheck<'me, 'tcx> {
tcx: TyCtxt<'tcx>,
universe_at_start_of_snapshot: ty::UniverseIndex,
overly_polymorphic: bool,
mini_graph: &'me MiniGraph<'tcx>,
rcc: &'me RegionConstraintCollector<'me, 'tcx>,
// Initially, for each SCC S, stores a placeholder `P` such that `S = P`
// must hold.
//
// Later, during the [`LeakCheck::propagate_scc_value`] function, this array
// is repurposed to store some placeholder `P` such that the weaker
// condition `S: P` must hold. (This is true if `S: S1` transitively and `S1
// = P`.)
scc_placeholders: IndexVec<LeakCheckScc, Option<ty::PlaceholderRegion>>,
// For each SCC S, track the minimum universe that flows into it. Note that
// this is both the minimum of the universes for every region that is a
// member of the SCC, but also if you have `R1: R2`, then the universe of
// `R2` must be less than the universe of `R1` (i.e., `R1` flows `R2`). To
// see that, imagine that you have `P1: R` -- in that case, `R` must be
// either the placeholder `P1` or the empty region in that same universe.
//
// To detect errors, we look for an SCC S where the values in
// `scc_values[S]` (if any) cannot be stored into `scc_universes[S]`.
scc_universes: IndexVec<LeakCheckScc, SccUniverse<'tcx>>,
}
impl<'me, 'tcx> LeakCheck<'me, 'tcx> {
fn new(
tcx: TyCtxt<'tcx>,
universe_at_start_of_snapshot: ty::UniverseIndex,
max_universe: ty::UniverseIndex,
overly_polymorphic: bool,
mini_graph: &'me MiniGraph<'tcx>,
rcc: &'me RegionConstraintCollector<'me, 'tcx>,
) -> Self {
let dummy_scc_universe = SccUniverse { universe: max_universe, region: None };
Self {
tcx,
universe_at_start_of_snapshot,
overly_polymorphic,
mini_graph,
rcc,
scc_placeholders: IndexVec::from_elem_n(None, mini_graph.sccs.num_sccs()),
scc_universes: IndexVec::from_elem_n(dummy_scc_universe, mini_graph.sccs.num_sccs()),
}
}
/// Compute what placeholders (if any) each SCC must be equal to.
/// Also compute the minimum universe of all the regions in each SCC.
fn assign_placeholder_values(&mut self) -> RelateResult<'tcx, ()> {
// First walk: find each placeholder that is from a newly created universe.
for (region, leak_check_node) in &self.mini_graph.nodes {
let scc = self.mini_graph.sccs.scc(*leak_check_node);
// Set the universe of each SCC to be the minimum of its constituent universes
let universe = self.rcc.universe(region);
debug!(
"assign_placeholder_values: scc={:?} universe={:?} region={:?}",
scc, universe, region
);
let tainted_regions = taint_set.into_set();
self.scc_universes[scc].take_min(universe, region);
// Report an error if two placeholders in the same universe
// are related to one another, or if a placeholder is related
// to something from a parent universe.
for &tainted_region in &tainted_regions {
if let ty::RePlaceholder(_) = tainted_region {
// Two placeholders cannot be related:
if tainted_region == placeholder_region {
continue;
}
} else if self.universe(tainted_region).can_name(placeholder.universe) {
continue;
// Detect those SCCs that directly contain a placeholder
if let ty::RePlaceholder(placeholder) = region {
if self.universe_at_start_of_snapshot.cannot_name(placeholder.universe) {
self.assign_scc_value(scc, *placeholder)?;
}
return Err(if overly_polymorphic {
debug!("overly polymorphic!");
TypeError::RegionsOverlyPolymorphic(placeholder.name, tainted_region)
} else {
debug!("not as polymorphic!");
TypeError::RegionsInsufficientlyPolymorphic(placeholder.name, tainted_region)
});
}
}
Ok(())
}
}
#[derive(Debug)]
struct TaintSet<'tcx> {
directions: TaintDirections,
regions: FxHashSet<ty::Region<'tcx>>,
}
// assign_scc_value(S, P): Update `scc_values` to account for the fact that `P: S` must hold.
// This may create an error.
fn assign_scc_value(
&mut self,
scc: LeakCheckScc,
placeholder: ty::PlaceholderRegion,
) -> RelateResult<'tcx, ()> {
match self.scc_placeholders[scc] {
Some(p) => {
assert_ne!(p, placeholder);
return Err(self.placeholder_error(p, placeholder));
}
None => {
self.scc_placeholders[scc] = Some(placeholder);
}
};
impl<'tcx> TaintSet<'tcx> {
fn new(directions: TaintDirections, initial_region: ty::Region<'tcx>) -> Self {
let mut regions = FxHashSet::default();
regions.insert(initial_region);
TaintSet { directions, regions }
Ok(())
}
fn fixed_point<'a>(
&mut self,
/// For each SCC S, iterate over each successor S1 where `S: S1`:
///
/// * Compute
/// Iterate over each SCC `S` and ensure that, for each `S1` where `S1: S`,
/// `universe(S) <= universe(S1)`. This executes after
/// `assign_placeholder_values`, so `universe(S)` is already the minimum
/// universe of any of its direct constituents.
fn propagate_scc_value(&mut self) -> RelateResult<'tcx, ()> {
// Loop invariants:
//
// On start of the loop iteration for `scc1`:
//
// * `scc_universes[scc1]` contains the minimum universe of the
// constituents of `scc1`
// * `scc_placeholder[scc1]` stores the placeholder that `scc1` must
// be equal to (if any)
//
// For each succssor `scc2` where `scc1: scc2`:
//
// * `scc_placeholder[scc2]` stores some placeholder `P` where
// `scc2: P` (if any)
// * `scc_universes[scc2]` contains the minimum universe of the
// constituents of `scc2` and any of its successors
for scc1 in self.mini_graph.sccs.all_sccs() {
debug!(
"propagate_scc_value: scc={:?} with universe {:?}",
scc1, self.scc_universes[scc1]
);
// Walk over each `scc2` such that `scc1: scc2` and compute:
//
// * `scc1_universe`: the minimum universe of `scc2` and the constituents of `scc1`
// * `succ_bound`: placeholder `P` that the successors must outlive, if any (if there are multiple,
// we pick one arbitrarily)
let mut scc1_universe = self.scc_universes[scc1];
let mut succ_bound = None;
for &scc2 in self.mini_graph.sccs.successors(scc1) {
let SccUniverse { universe: scc2_universe, region: scc2_region } =
self.scc_universes[scc2];
scc1_universe.take_min(scc2_universe, scc2_region.unwrap());
if let Some(b) = self.scc_placeholders[scc2] {
succ_bound = Some(b);
}
}
// Update minimum universe of scc1.
self.scc_universes[scc1] = scc1_universe;
// At this point, `scc_placholder[scc1]` stores the placeholder that
// `scc1` must be equal to, if any.
if let Some(scc1_placeholder) = self.scc_placeholders[scc1] {
debug!(
"propagate_scc_value: scc1={:?} placeholder={:?} scc1_universe={:?}",
scc1, scc1_placeholder, scc1_universe
);
// Check if `P1: R` for some `R` in a universe that cannot name
// P1. That's an error.
if scc1_universe.universe.cannot_name(scc1_placeholder.universe) {
return Err(self.error(scc1_placeholder, scc1_universe.region.unwrap()));
}
// Check if we have some placeholder where `S: P2`
// (transitively). In that case, since `S = P1`, that implies
// `P1: P2`, which is an error condition.
if let Some(scc2_placeholder) = succ_bound {
assert_ne!(scc1_placeholder, scc2_placeholder);
return Err(self.placeholder_error(scc1_placeholder, scc2_placeholder));
}
} else {
// Otherwise, we can reach a placeholder if some successor can.
self.scc_placeholders[scc1] = succ_bound;
}
// At this point, `scc_placeholder[scc1]` stores some placeholder that `scc1` must outlive (if any).
}
Ok(())
}
fn placeholder_error(
&self,
placeholder1: ty::PlaceholderRegion,
placeholder2: ty::PlaceholderRegion,
) -> TypeError<'tcx> {
self.error(placeholder1, self.tcx.mk_region(ty::RePlaceholder(placeholder2)))
}
fn error(
&self,
placeholder: ty::PlaceholderRegion,
other_region: ty::Region<'tcx>,
) -> TypeError<'tcx> {
debug!("error: placeholder={:?}, other_region={:?}", placeholder, other_region);
if self.overly_polymorphic {
return TypeError::RegionsOverlyPolymorphic(placeholder.name, other_region);
} else {
return TypeError::RegionsInsufficientlyPolymorphic(placeholder.name, other_region);
}
}
}
// States we need to distinguish:
//
// * must be equal to a placeholder (i.e., a placeholder is in the SCC)
// * it could conflict with some other regions in the SCC in different universes
// * or a different placeholder
// * `P1: S` and `S` must be equal to a placeholder
// * `P1: S` and `S` is in an incompatible universe
//
// So if we
//
// (a) compute which placeholder (if any) each SCC must be equal to
// (b) compute its minimum universe
// (c) compute *some* placeholder where `S: P1` (any one will do)
//
// then we get an error if:
//
// - it must be equal to a placeholder `P1` and minimum universe cannot name `P1`
// - `S: P1` and minimum universe cannot name `P1`
// - `S: P1` and we must be equal to `P2`
//
// So we want to track:
//
// * Equal placeholder (if any)
// * Some bounding placeholder (if any)
// * Minimum universe
//
// * We compute equal placeholder + minimum universe of constituents in first pass
// * Then we walk in order and compute from our dependencies `S1` where `S: S1` (`S -> S1`)
// * bounding placeholder (if any)
// * minimum universe
// * And if we must be equal to a placeholder then we check it against
// * minimum universe
// * no bounding placeholder
/// Tracks the "minimum universe" for each SCC, along with some region that
/// caused it to change.
#[derive(Copy, Clone, Debug)]
struct SccUniverse<'tcx> {
/// For some SCC S, the minimum universe of:
///
/// * each region R in S
/// * each SCC S1 such that S: S1
universe: ty::UniverseIndex,
/// Some region that caused `universe` to be what it is.
region: Option<ty::Region<'tcx>>,
}
impl<'tcx> SccUniverse<'tcx> {
/// If `universe` is less than our current universe, then update
/// `self.universe` and `self.region`.
fn take_min(&mut self, universe: ty::UniverseIndex, region: ty::Region<'tcx>) {
if universe < self.universe || self.region.is_none() {
self.universe = universe;
self.region = Some(region);
}
}
}
rustc_index::newtype_index! {
struct LeakCheckNode {
DEBUG_FORMAT = "LeakCheckNode({})"
}
}
rustc_index::newtype_index! {
struct LeakCheckScc {
DEBUG_FORMAT = "LeakCheckScc({})"
}
}
/// Represents the graph of constraints. For each `R1: R2` constraint we create
/// an edge `R1 -> R2` in the graph.
struct MiniGraph<'tcx> {
/// Map from a region to the index of the node in the graph.
nodes: FxHashMap<ty::Region<'tcx>, LeakCheckNode>,
/// Map from node index to SCC, and stores the successors of each SCC. All
/// the regions in the same SCC are equal to one another, and if `S1 -> S2`,
/// then `S1: S2`.
sccs: Sccs<LeakCheckNode, LeakCheckScc>,
}
impl<'tcx> MiniGraph<'tcx> {
fn new<'a>(
tcx: TyCtxt<'tcx>,
undo_log: impl IntoIterator<Item = &'a UndoLog<'tcx>> + Clone,
undo_log: impl Iterator<Item = &'a UndoLog<'tcx>>,
verifys: &[Verify<'tcx>],
) -> Self
where
'tcx: 'a,
{
let mut nodes = FxHashMap::default();
let mut edges = Vec::new();
// Note that if `R2: R1`, we get a callback `r1, r2`, so `target` is first parameter.
Self::iterate_undo_log(tcx, undo_log, verifys, |target, source| {
let source_node = Self::add_node(&mut nodes, source);
let target_node = Self::add_node(&mut nodes, target);
edges.push((source_node, target_node));
});
let graph = VecGraph::new(nodes.len(), edges);
let sccs = Sccs::new(&graph);
Self { nodes, sccs }
}
/// Invokes `each_edge(R1, R2)` for each edge where `R2: R1`
fn iterate_undo_log<'a>(
tcx: TyCtxt<'tcx>,
undo_log: impl Iterator<Item = &'a UndoLog<'tcx>>,
verifys: &[Verify<'tcx>],
mut each_edge: impl FnMut(ty::Region<'tcx>, ty::Region<'tcx>),
) where
'tcx: 'a,
{
let mut prev_len = 0;
while prev_len < self.len() {
debug!("tainted: prev_len = {:?} new_len = {:?}", prev_len, self.len());
prev_len = self.len();
for undo_entry in undo_log.clone() {
match undo_entry {
&AddConstraint(Constraint::VarSubVar(a, b)) => {
self.add_edge(tcx.mk_region(ReVar(a)), tcx.mk_region(ReVar(b)));
}
&AddConstraint(Constraint::RegSubVar(a, b)) => {
self.add_edge(a, tcx.mk_region(ReVar(b)));
}
&AddConstraint(Constraint::VarSubReg(a, b)) => {
self.add_edge(tcx.mk_region(ReVar(a)), b);
}
&AddConstraint(Constraint::RegSubReg(a, b)) => {
self.add_edge(a, b);
}
&AddGiven(a, b) => {
self.add_edge(a, tcx.mk_region(ReVar(b)));
}
&AddVerify(i) => span_bug!(
verifys[i].origin.span(),
"we never add verifications while doing higher-ranked things",
),
&AddCombination(..) | &AddVar(..) => {}
for undo_entry in undo_log {
match undo_entry {
&AddConstraint(Constraint::VarSubVar(a, b)) => {
each_edge(tcx.mk_region(ReVar(a)), tcx.mk_region(ReVar(b)));
}
&AddConstraint(Constraint::RegSubVar(a, b)) => {
each_edge(a, tcx.mk_region(ReVar(b)));
}
&AddConstraint(Constraint::VarSubReg(a, b)) => {
each_edge(tcx.mk_region(ReVar(a)), b);
}
&AddConstraint(Constraint::RegSubReg(a, b)) => {
each_edge(a, b);
}
&AddGiven(a, b) => {
each_edge(a, tcx.mk_region(ReVar(b)));
}
&AddVerify(i) => span_bug!(
verifys[i].origin.span(),
"we never add verifications while doing higher-ranked things",
),
&AddCombination(..) | &AddVar(..) => {}
}
}
}
fn into_set(self) -> FxHashSet<ty::Region<'tcx>> {
self.regions
}
fn len(&self) -> usize {
self.regions.len()
}
fn add_edge(&mut self, source: ty::Region<'tcx>, target: ty::Region<'tcx>) {
if self.directions.incoming {
if self.regions.contains(&target) {
self.regions.insert(source);
}
}
if self.directions.outgoing {
if self.regions.contains(&source) {
self.regions.insert(target);
}
}
fn add_node(
nodes: &mut FxHashMap<ty::Region<'tcx>, LeakCheckNode>,
r: ty::Region<'tcx>,
) -> LeakCheckNode {
let l = nodes.len();
*nodes.entry(r).or_insert(LeakCheckNode::new(l))
}
}

View File

@ -16,6 +16,9 @@
#![feature(bool_to_option)]
#![feature(box_patterns)]
#![feature(box_syntax)]
#![feature(const_fn)]
#![feature(const_if_match)]
#![feature(const_panic)]
#![feature(extend_one)]
#![feature(never_type)]
#![feature(or_patterns)]

View File

@ -38,6 +38,7 @@ use rustc_hir as hir;
use rustc_hir::def::{DefKind, Res};
use rustc_hir::def_id::{CrateNum, DefId, DefIdMap, LocalDefId, LOCAL_CRATE};
use rustc_hir::definitions::{DefPathHash, Definitions};
use rustc_hir::intravisit::Visitor;
use rustc_hir::lang_items::{self, PanicLocationLangItem};
use rustc_hir::{HirId, ItemKind, ItemLocalId, ItemLocalMap, ItemLocalSet, Node, TraitCandidate};
use rustc_index::vec::{Idx, IndexVec};
@ -1427,10 +1428,8 @@ impl<'tcx> TyCtxt<'tcx> {
})
}
pub fn return_type_impl_or_dyn_trait(
&self,
scope_def_id: DefId,
) -> Option<&'tcx hir::Ty<'tcx>> {
/// Given a `DefId` for an `fn`, return all the `dyn` and `impl` traits in its return type.
pub fn return_type_impl_or_dyn_traits(&self, scope_def_id: DefId) -> Vec<&'tcx hir::Ty<'tcx>> {
let hir_id = self.hir().as_local_hir_id(scope_def_id.expect_local());
let hir_output = match self.hir().get(hir_id) {
Node::Item(hir::Item {
@ -1466,30 +1465,12 @@ impl<'tcx> TyCtxt<'tcx> {
),
..
}) => ty,
_ => return None,
_ => return vec![],
};
let ret_ty = self.type_of(scope_def_id);
match ret_ty.kind {
ty::FnDef(_, _) => {
let sig = ret_ty.fn_sig(*self);
let output = self.erase_late_bound_regions(&sig.output());
if output.is_impl_trait() {
let fn_decl = self.hir().fn_decl_by_hir_id(hir_id).unwrap();
if let hir::FnRetTy::Return(ty) = fn_decl.output {
return Some(ty);
}
} else {
let mut v = TraitObjectVisitor(vec![]);
rustc_hir::intravisit::walk_ty(&mut v, hir_output);
if v.0.len() == 1 {
return Some(v.0[0]);
}
}
None
}
_ => None,
}
let mut v = TraitObjectVisitor(vec![], self.hir());
v.visit_ty(hir_output);
v.0
}
pub fn return_type_impl_trait(&self, scope_def_id: DefId) -> Option<(Ty<'tcx>, Span)> {

View File

@ -236,7 +236,9 @@ pub fn suggest_constraining_type_param(
}
}
pub struct TraitObjectVisitor<'tcx>(pub Vec<&'tcx hir::Ty<'tcx>>);
/// Collect al types that have an implicit `'static` obligation that we could suggest `'_` for.
pub struct TraitObjectVisitor<'tcx>(pub Vec<&'tcx hir::Ty<'tcx>>, pub crate::hir::map::Map<'tcx>);
impl<'v> hir::intravisit::Visitor<'v> for TraitObjectVisitor<'v> {
type Map = rustc_hir::intravisit::ErasedMap<'v>;
@ -245,15 +247,24 @@ impl<'v> hir::intravisit::Visitor<'v> for TraitObjectVisitor<'v> {
}
fn visit_ty(&mut self, ty: &'v hir::Ty<'v>) {
if let hir::TyKind::TraitObject(
_,
hir::Lifetime {
name: hir::LifetimeName::ImplicitObjectLifetimeDefault | hir::LifetimeName::Static,
..
},
) = ty.kind
{
self.0.push(ty);
match ty.kind {
hir::TyKind::TraitObject(
_,
hir::Lifetime {
name:
hir::LifetimeName::ImplicitObjectLifetimeDefault | hir::LifetimeName::Static,
..
},
) => {
self.0.push(ty);
}
hir::TyKind::OpaqueDef(item_id, _) => {
self.0.push(ty);
let item = self.1.expect_item(item_id.id);
hir::intravisit::walk_item(self, item);
}
_ => {}
}
hir::intravisit::walk_ty(self, ty);
}
}

View File

@ -25,7 +25,7 @@ pub(super) fn relate_types<'tcx>(
category: ConstraintCategory,
borrowck_context: Option<&mut BorrowCheckContext<'_, 'tcx>>,
) -> Fallible<()> {
debug!("eq_types(a={:?}, b={:?}, locations={:?})", a, b, locations);
debug!("relate_types(a={:?}, v={:?}, b={:?}, locations={:?})", a, v, b, locations);
TypeRelating::new(
infcx,
NllTypeRelatingDelegate::new(infcx, borrowck_context, locations, category),

View File

@ -296,6 +296,11 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
let offset_ptr = ptr.ptr_wrapping_signed_offset(offset_bytes, self);
self.write_scalar(offset_ptr, dest)?;
}
sym::ptr_guaranteed_eq | sym::ptr_guaranteed_ne => {
// FIXME: return `true` for at least some comparisons where we can reliably
// determine the result of runtime (in)equality tests at compile-time.
self.write_scalar(Scalar::from_bool(false), dest)?;
}
sym::ptr_offset_from => {
let a = self.read_immediate(args[0])?.to_scalar()?;
let b = self.read_immediate(args[1])?.to_scalar()?;

View File

@ -1,7 +1,7 @@
//! Mono Item Collection
//! ====================
//!
//! This module is responsible for discovering all items that will contribute to
//! This module is responsible for discovering all items that will contribute
//! to code generation of the crate. The important part here is that it not only
//! needs to find syntax-level items (functions, structs, etc) but also all
//! their monomorphized instantiations. Every non-generic, non-const function
@ -79,7 +79,7 @@
//! function or method call (represented by a CALL terminator in MIR). But
//! calls are not the only thing that might introduce a reference between two
//! function mono items, and as we will see below, they are just a
//! specialized of the form described next, and consequently will don't get any
//! specialization of the form described next, and consequently will not get any
//! special treatment in the algorithm.
//!
//! #### Taking a reference to a function or method
@ -158,7 +158,7 @@
//! - Eager mode is meant to be used in conjunction with incremental compilation
//! where a stable set of mono items is more important than a minimal
//! one. Thus, eager mode will instantiate drop-glue for every drop-able type
//! in the crate, even of no drop call for that type exists (yet). It will
//! in the crate, even if no drop call for that type exists (yet). It will
//! also instantiate default implementations of trait methods, something that
//! otherwise is only done on demand.
//!

View File

@ -160,17 +160,20 @@ pub struct InlineAsm;
impl NonConstOp for InlineAsm {}
#[derive(Debug)]
pub struct LiveDrop;
pub struct LiveDrop(pub Option<Span>);
impl NonConstOp for LiveDrop {
fn emit_error(&self, ccx: &ConstCx<'_, '_>, span: Span) {
struct_span_err!(
let mut diagnostic = struct_span_err!(
ccx.tcx.sess,
span,
E0493,
"destructors cannot be evaluated at compile-time"
)
.span_label(span, format!("{}s cannot evaluate destructors", ccx.const_kind()))
.emit();
);
diagnostic.span_label(span, format!("{}s cannot evaluate destructors", ccx.const_kind()));
if let Some(span) = self.0 {
diagnostic.span_label(span, "value is dropped here");
}
diagnostic.emit();
}
}
@ -296,18 +299,16 @@ impl NonConstOp for Panic {
#[derive(Debug)]
pub struct RawPtrComparison;
impl NonConstOp for RawPtrComparison {
fn feature_gate() -> Option<Symbol> {
Some(sym::const_compare_raw_pointers)
}
fn emit_error(&self, ccx: &ConstCx<'_, '_>, span: Span) {
feature_err(
&ccx.tcx.sess.parse_sess,
sym::const_compare_raw_pointers,
span,
&format!("comparing raw pointers inside {}", ccx.const_kind()),
)
.emit();
let mut err = ccx
.tcx
.sess
.struct_span_err(span, "pointers cannot be reliably compared during const eval.");
err.note(
"see issue #53020 <https://github.com/rust-lang/rust/issues/53020> \
for more information",
);
err.emit();
}
}

View File

@ -58,7 +58,7 @@ impl std::ops::Deref for CheckLiveDrops<'mir, 'tcx> {
impl CheckLiveDrops<'mir, 'tcx> {
fn check_live_drop(&self, span: Span) {
ops::non_const(self.ccx, ops::LiveDrop, span);
ops::non_const(self.ccx, ops::LiveDrop(None), span);
}
}

View File

@ -588,7 +588,10 @@ impl Visitor<'tcx> for Validator<'mir, 'tcx> {
};
if needs_drop {
self.check_op_spanned(ops::LiveDrop, err_span);
self.check_op_spanned(
ops::LiveDrop(Some(terminator.source_info.span)),
err_span,
);
}
}

View File

@ -171,21 +171,6 @@ impl<'a, 'tcx> Visitor<'tcx> for UnsafetyChecker<'a, 'tcx> {
_ => {}
}
}
// raw pointer and fn pointer operations are unsafe as it is not clear whether one
// pointer would be "less" or "equal" to another, because we cannot know where llvm
// or the linker will place various statics in memory. Without this information the
// result of a comparison of addresses would differ between runtime and compile-time.
Rvalue::BinaryOp(_, ref lhs, _)
if self.const_context && self.tcx.features().const_compare_raw_pointers =>
{
if let ty::RawPtr(_) | ty::FnPtr(..) = lhs.ty(self.body, self.tcx).kind {
self.require_unsafe(
"pointer operation",
"operations on pointers in constants",
UnsafetyViolationKind::General,
);
}
}
_ => {}
}
self.super_rvalue(rvalue, location);

View File

@ -588,6 +588,8 @@ symbols! {
proc_macro_non_items,
proc_macro_path_invoc,
profiler_runtime,
ptr_guaranteed_eq,
ptr_guaranteed_ne,
ptr_offset_from,
pub_restricted,
pure,

View File

@ -120,12 +120,13 @@ fn overlap<'cx, 'tcx>(
debug!("overlap(a_def_id={:?}, b_def_id={:?})", a_def_id, b_def_id);
selcx.infcx().probe_maybe_skip_leak_check(skip_leak_check.is_yes(), |snapshot| {
overlap_within_probe(selcx, a_def_id, b_def_id, snapshot)
overlap_within_probe(selcx, skip_leak_check, a_def_id, b_def_id, snapshot)
})
}
fn overlap_within_probe(
selcx: &mut SelectionContext<'cx, 'tcx>,
skip_leak_check: SkipLeakCheck,
a_def_id: DefId,
b_def_id: DefId,
snapshot: &CombinedSnapshot<'_, 'tcx>,
@ -180,6 +181,13 @@ fn overlap_within_probe(
return None;
}
if !skip_leak_check.is_yes() {
if let Err(_) = infcx.leak_check(true, snapshot) {
debug!("overlap: leak check failed");
return None;
}
}
let impl_header = selcx.infcx().resolve_vars_if_possible(&a_impl_header);
let intercrate_ambiguity_causes = selcx.take_intercrate_ambiguity_causes();
debug!("overlap: intercrate_ambiguity_causes={:#?}", intercrate_ambiguity_causes);

View File

@ -149,15 +149,12 @@ pub fn poly_project_and_unify_type<'cx, 'tcx>(
debug!("poly_project_and_unify_type(obligation={:?})", obligation);
let infcx = selcx.infcx();
infcx.commit_if_ok(|snapshot| {
let (placeholder_predicate, placeholder_map) =
infcx.commit_if_ok(|_snapshot| {
let (placeholder_predicate, _) =
infcx.replace_bound_vars_with_placeholders(&obligation.predicate);
let placeholder_obligation = obligation.with(placeholder_predicate);
let result = project_and_unify_type(selcx, &placeholder_obligation)?;
infcx
.leak_check(false, &placeholder_map, snapshot)
.map_err(|err| MismatchedProjectionTypes { err })?;
Ok(result)
})
}

View File

@ -163,9 +163,9 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
_ => return,
}
let result = self.infcx.probe(|snapshot| {
self.match_projection_obligation_against_definition_bounds(obligation, snapshot)
});
let result = self
.infcx
.probe(|_| self.match_projection_obligation_against_definition_bounds(obligation));
if result {
candidates.vec.push(ProjectionCandidate);
@ -345,8 +345,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
obligation.predicate.def_id(),
obligation.predicate.skip_binder().trait_ref.self_ty(),
|impl_def_id| {
self.infcx.probe(|snapshot| {
if let Ok(_substs) = self.match_impl(impl_def_id, obligation, snapshot) {
self.infcx.probe(|_| {
if let Ok(_substs) = self.match_impl(impl_def_id, obligation) {
candidates.vec.push(ImplCandidate(impl_def_id));
}
});

View File

@ -121,9 +121,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
}
fn confirm_projection_candidate(&mut self, obligation: &TraitObligation<'tcx>) {
self.infcx.commit_unconditionally(|snapshot| {
let result =
self.match_projection_obligation_against_definition_bounds(obligation, snapshot);
self.infcx.commit_unconditionally(|_| {
let result = self.match_projection_obligation_against_definition_bounds(obligation);
assert!(result);
})
}
@ -265,8 +264,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
// First, create the substitutions by matching the impl again,
// this time not in a probe.
self.infcx.commit_unconditionally(|snapshot| {
let substs = self.rematch_impl(impl_def_id, obligation, snapshot);
self.infcx.commit_unconditionally(|_| {
let substs = self.rematch_impl(impl_def_id, obligation);
debug!("confirm_impl_candidate: substs={:?}", substs);
let cause = obligation.derived_cause(ImplDerivedObligation);
ensure_sufficient_stack(|| {
@ -612,24 +611,10 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
// Require that the traits involved in this upcast are **equal**;
// only the **lifetime bound** is changed.
//
// FIXME: This condition is arguably too strong -- it would
// suffice for the source trait to be a *subtype* of the target
// trait. In particular, changing from something like
// `for<'a, 'b> Foo<'a, 'b>` to `for<'a> Foo<'a, 'a>` should be
// permitted. And, indeed, in the in commit
// 904a0bde93f0348f69914ee90b1f8b6e4e0d7cbc, this
// condition was loosened. However, when the leak check was
// added back, using subtype here actually guides the coercion
// code in such a way that it accepts `old-lub-glb-object.rs`.
// This is probably a good thing, but I've modified this to `.eq`
// because I want to continue rejecting that test (as we have
// done for quite some time) before we are firmly comfortable
// with what our behavior should be there. -nikomatsakis
let InferOk { obligations, .. } = self
.infcx
.at(&obligation.cause, obligation.param_env)
.eq(target, source_trait) // FIXME -- see below
.sup(target, source_trait)
.map_err(|_| Unimplemented)?;
nested.extend(obligations);

View File

@ -21,7 +21,7 @@ use super::{Normalized, ProjectionCacheKey};
use super::{ObligationCause, PredicateObligation, TraitObligation};
use super::{Overflow, SelectionError, Unimplemented};
use crate::infer::{CombinedSnapshot, InferCtxt, InferOk, PlaceholderMap, TypeFreshener};
use crate::infer::{InferCtxt, InferOk, TypeFreshener};
use crate::traits::error_reporting::InferCtxtExt;
use crate::traits::project::ProjectionCacheKeyExt;
use rustc_ast::attr;
@ -347,6 +347,12 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
) -> Result<EvaluationResult, OverflowError> {
self.infcx.probe(|snapshot| -> Result<EvaluationResult, OverflowError> {
let result = op(self)?;
match self.infcx.leak_check(true, snapshot) {
Ok(()) => {}
Err(_) => return Ok(EvaluatedToErr),
}
match self.infcx.region_constraints_added_in_snapshot(snapshot) {
None => Ok(result),
Some(_) => Ok(result.max(EvaluatedToOkModuloRegions)),
@ -1262,10 +1268,9 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
fn match_projection_obligation_against_definition_bounds(
&mut self,
obligation: &TraitObligation<'tcx>,
snapshot: &CombinedSnapshot<'_, 'tcx>,
) -> bool {
let poly_trait_predicate = self.infcx().resolve_vars_if_possible(&obligation.predicate);
let (placeholder_trait_predicate, placeholder_map) =
let (placeholder_trait_predicate, _) =
self.infcx().replace_bound_vars_with_placeholders(&poly_trait_predicate);
debug!(
"match_projection_obligation_against_definition_bounds: \
@ -1293,13 +1298,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
if let ty::PredicateKind::Trait(bound, _) = bound.kind() {
let bound = bound.to_poly_trait_ref();
if self.infcx.probe(|_| {
self.match_projection(
obligation,
bound,
placeholder_trait_predicate.trait_ref,
&placeholder_map,
snapshot,
)
self.match_projection(obligation, bound, placeholder_trait_predicate.trait_ref)
}) {
return Some(bound);
}
@ -1316,13 +1315,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
None => false,
Some(bound) => {
// Repeat the successful match, if any, this time outside of a probe.
let result = self.match_projection(
obligation,
bound,
placeholder_trait_predicate.trait_ref,
&placeholder_map,
snapshot,
);
let result =
self.match_projection(obligation, bound, placeholder_trait_predicate.trait_ref);
assert!(result);
true
@ -1335,15 +1329,12 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
obligation: &TraitObligation<'tcx>,
trait_bound: ty::PolyTraitRef<'tcx>,
placeholder_trait_ref: ty::TraitRef<'tcx>,
placeholder_map: &PlaceholderMap<'tcx>,
snapshot: &CombinedSnapshot<'_, 'tcx>,
) -> bool {
debug_assert!(!placeholder_trait_ref.has_escaping_bound_vars());
self.infcx
.at(&obligation.cause, obligation.param_env)
.sup(ty::Binder::dummy(placeholder_trait_ref), trait_bound)
.is_ok()
&& self.infcx.leak_check(false, placeholder_map, snapshot).is_ok()
}
fn evaluate_where_clause<'o>(
@ -1808,9 +1799,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
&mut self,
impl_def_id: DefId,
obligation: &TraitObligation<'tcx>,
snapshot: &CombinedSnapshot<'_, 'tcx>,
) -> Normalized<'tcx, SubstsRef<'tcx>> {
match self.match_impl(impl_def_id, obligation, snapshot) {
match self.match_impl(impl_def_id, obligation) {
Ok(substs) => substs,
Err(()) => {
bug!(
@ -1826,7 +1816,6 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
&mut self,
impl_def_id: DefId,
obligation: &TraitObligation<'tcx>,
snapshot: &CombinedSnapshot<'_, 'tcx>,
) -> Result<Normalized<'tcx, SubstsRef<'tcx>>, ()> {
let impl_trait_ref = self.tcx().impl_trait_ref(impl_def_id).unwrap();
@ -1837,7 +1826,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
return Err(());
}
let (placeholder_obligation, placeholder_map) =
let (placeholder_obligation, _) =
self.infcx().replace_bound_vars_with_placeholders(&obligation.predicate);
let placeholder_obligation_trait_ref = placeholder_obligation.trait_ref;
@ -1869,11 +1858,6 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
.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, &placeholder_map, snapshot) {
debug!("match_impl: failed leak check due to `{}`", e);
return Err(());
}
if !self.intercrate
&& self.tcx().impl_polarity(impl_def_id) == ty::ImplPolarity::Reservation
{

View File

@ -8,8 +8,7 @@
use crate::collect::PlaceholderHirTyCollector;
use crate::middle::resolve_lifetime as rl;
use crate::require_c_abi_if_c_variadic;
use rustc_ast::ast::ParamKindOrd;
use rustc_ast::util::lev_distance::find_best_match_for_name;
use rustc_ast::{ast::ParamKindOrd, util::lev_distance::find_best_match_for_name};
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
use rustc_errors::ErrorReported;
use rustc_errors::{pluralize, struct_span_err, Applicability, DiagnosticId, FatalError};
@ -27,7 +26,7 @@ use rustc_middle::ty::{GenericParamDef, GenericParamDefKind};
use rustc_session::lint::builtin::{AMBIGUOUS_ASSOCIATED_ITEMS, LATE_BOUND_LIFETIME_ARGUMENTS};
use rustc_session::parse::feature_err;
use rustc_session::Session;
use rustc_span::symbol::{sym, Ident, Symbol};
use rustc_span::symbol::{kw, sym, Ident, Symbol};
use rustc_span::{MultiSpan, Span, DUMMY_SP};
use rustc_target::spec::abi;
use rustc_trait_selection::traits;
@ -475,7 +474,12 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
/// Report an error that a generic argument did not match the generic parameter that was
/// expected.
fn generic_arg_mismatch_err(sess: &Session, arg: &GenericArg<'_>, kind: &'static str) {
fn generic_arg_mismatch_err(
sess: &Session,
arg: &GenericArg<'_>,
kind: &'static str,
help: Option<&str>,
) {
let mut err = struct_span_err!(
sess,
arg.span(),
@ -503,6 +507,10 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
let (first, last) =
if kind_ord < arg_ord { (kind, arg.descr()) } else { (arg.descr(), kind) };
err.note(&format!("{} arguments must be provided before {} arguments", first, last));
if let Some(help) = help {
err.help(help);
}
err.emit();
}
@ -648,7 +656,60 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
if arg_count.correct.is_ok()
&& arg_count.explicit_late_bound == ExplicitLateBound::No
{
Self::generic_arg_mismatch_err(tcx.sess, arg, kind.descr());
// We're going to iterate over the parameters to sort them out, and
// show that order to the user as a possible order for the parameters
let mut param_types_present = defs
.params
.clone()
.into_iter()
.map(|param| {
(
match param.kind {
GenericParamDefKind::Lifetime => {
ParamKindOrd::Lifetime
}
GenericParamDefKind::Type { .. } => {
ParamKindOrd::Type
}
GenericParamDefKind::Const => {
ParamKindOrd::Const
}
},
param,
)
})
.collect::<Vec<(ParamKindOrd, GenericParamDef)>>();
param_types_present.sort_by_key(|(ord, _)| *ord);
let (mut param_types_present, ordered_params): (
Vec<ParamKindOrd>,
Vec<GenericParamDef>,
) = param_types_present.into_iter().unzip();
param_types_present.dedup();
Self::generic_arg_mismatch_err(
tcx.sess,
arg,
kind.descr(),
Some(&format!(
"reorder the arguments: {}: `<{}>`",
param_types_present
.into_iter()
.map(|ord| format!("{}s", ord.to_string()))
.collect::<Vec<String>>()
.join(", then "),
ordered_params
.into_iter()
.filter_map(|param| {
if param.name == kw::SelfUpper {
None
} else {
Some(param.name.to_string())
}
})
.collect::<Vec<String>>()
.join(", ")
)),
);
}
// We've reported the error, but we want to make sure that this
@ -680,7 +741,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
assert_eq!(kind, "lifetime");
let provided =
force_infer_lt.expect("lifetimes ought to have been inferred");
Self::generic_arg_mismatch_err(tcx.sess, provided, kind);
Self::generic_arg_mismatch_err(tcx.sess, provided, kind, None);
}
break;

View File

@ -895,7 +895,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
{
let prev_ty = self.resolve_vars_with_obligations(prev_ty);
let new_ty = self.resolve_vars_with_obligations(new_ty);
debug!("coercion::try_find_coercion_lub({:?}, {:?})", prev_ty, new_ty);
debug!(
"coercion::try_find_coercion_lub({:?}, {:?}, exprs={:?} exprs)",
prev_ty,
new_ty,
exprs.len()
);
// Special-case that coercion alone cannot handle:
// Function items or non-capturing closures of differing IDs or InternalSubsts.
@ -1001,6 +1006,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
Ok(ok) => {
let (adjustments, target) = self.register_infer_ok_obligations(ok);
self.apply_adjustments(new, adjustments);
debug!(
"coercion::try_find_coercion_lub: was able to coerce from previous type {:?} to new type {:?}",
prev_ty, new_ty,
);
return Ok(target);
}
Err(e) => first_error = Some(e),
@ -1031,6 +1040,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
};
if !noop {
debug!(
"coercion::try_find_coercion_lub: older expression {:?} had adjustments, requiring LUB",
expr,
);
return self
.commit_if_ok(|_| self.at(cause, self.param_env).lub(prev_ty, new_ty))
.map(|ok| self.register_infer_ok_obligations(ok));
@ -1048,6 +1062,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
}
}
Ok(ok) => {
debug!(
"coercion::try_find_coercion_lub: was able to coerce previous type {:?} to new type {:?}",
prev_ty, new_ty,
);
let (adjustments, target) = self.register_infer_ok_obligations(ok);
for expr in exprs {
let expr = expr.as_coercion_site();

View File

@ -74,9 +74,8 @@ pub fn intrinsic_operation_unsafety(intrinsic: &str) -> hir::Unsafety {
| "wrapping_add" | "wrapping_sub" | "wrapping_mul" | "saturating_add"
| "saturating_sub" | "rotate_left" | "rotate_right" | "ctpop" | "ctlz" | "cttz"
| "bswap" | "bitreverse" | "discriminant_value" | "type_id" | "likely" | "unlikely"
| "minnumf32" | "minnumf64" | "maxnumf32" | "maxnumf64" | "type_name" => {
hir::Unsafety::Normal
}
| "ptr_guaranteed_eq" | "ptr_guaranteed_ne" | "minnumf32" | "minnumf64" | "maxnumf32"
| "maxnumf64" | "type_name" => hir::Unsafety::Normal,
_ => hir::Unsafety::Unsafe,
}
}
@ -258,6 +257,10 @@ pub fn check_intrinsic_type(tcx: TyCtxt<'_>, it: &hir::ForeignItem<'_>) {
(1, vec![param(0), param(0)], tcx.intern_tup(&[param(0), tcx.types.bool]))
}
"ptr_guaranteed_eq" | "ptr_guaranteed_ne" => {
(1, vec![tcx.mk_imm_ptr(param(0)), tcx.mk_imm_ptr(param(0))], tcx.types.bool)
}
"ptr_offset_from" => {
(1, vec![tcx.mk_imm_ptr(param(0)), tcx.mk_imm_ptr(param(0))], tcx.types.isize)
}

View File

@ -10,8 +10,7 @@ use rustc_middle::hir::map::Map;
use rustc_middle::ty::subst::{GenericArgKind, InternalSubsts};
use rustc_middle::ty::util::IntTypeExt;
use rustc_middle::ty::{self, DefIdTree, Ty, TyCtxt, TypeFoldable};
use rustc_session::parse::feature_err;
use rustc_span::symbol::{sym, Ident};
use rustc_span::symbol::Ident;
use rustc_span::{Span, DUMMY_SP};
use rustc_trait_selection::traits;
@ -303,25 +302,22 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: DefId) -> Ty<'_> {
GenericParamKind::Type { default: Some(ref ty), .. } => icx.to_ty(ty),
GenericParamKind::Const { ty: ref hir_ty, .. } => {
let ty = icx.to_ty(hir_ty);
if !tcx.features().const_compare_raw_pointers {
let err = match ty.peel_refs().kind {
ty::FnPtr(_) => Some("function pointers"),
ty::RawPtr(_) => Some("raw pointers"),
_ => None,
};
if let Some(unsupported_type) = err {
feature_err(
&tcx.sess.parse_sess,
sym::const_compare_raw_pointers,
let err = match ty.peel_refs().kind {
ty::FnPtr(_) => Some("function pointers"),
ty::RawPtr(_) => Some("raw pointers"),
_ => None,
};
if let Some(unsupported_type) = err {
tcx.sess
.struct_span_err(
hir_ty.span,
&format!(
"using {} as const generic parameters is unstable",
"using {} as const generic parameters is forbidden",
unsupported_type
),
)
.emit();
};
}
};
if traits::search_for_structural_match_violation(param.hir_id, param.span, tcx, ty)
.is_some()
{

View File

@ -12,7 +12,7 @@
| 8: Canonical { max_universe: U0, variables: [], value: Ty(*const [i32]) } at $DIR/address-of.rs:16:12: 16:24
| 9: Canonical { max_universe: U0, variables: [], value: Ty(*const [i32]) } at $DIR/address-of.rs:16:12: 16:24
| 10: Canonical { max_universe: U0, variables: [CanonicalVarInfo { kind: Ty(General(U0)) }], value: Ty(*const ^0) } at $DIR/address-of.rs:18:5: 18:18
| 11: Canonical { max_universe: U3, variables: [CanonicalVarInfo { kind: Region(U3) }], value: Ty(*const dyn std::marker::Send) } at $DIR/address-of.rs:20:5: 20:25
| 11: Canonical { max_universe: U0, variables: [CanonicalVarInfo { kind: Region(U0) }], value: Ty(*const dyn std::marker::Send) } at $DIR/address-of.rs:20:5: 20:25
| 12: Canonical { max_universe: U0, variables: [CanonicalVarInfo { kind: Ty(General(U0)) }], value: Ty(*const ^0) } at $DIR/address-of.rs:23:12: 23:20
| 13: Canonical { max_universe: U0, variables: [CanonicalVarInfo { kind: Ty(General(U0)) }], value: Ty(*const ^0) } at $DIR/address-of.rs:23:12: 23:20
| 14: Canonical { max_universe: U0, variables: [], value: Ty(*const [i32; 10]) } at $DIR/address-of.rs:24:12: 24:28
@ -22,7 +22,7 @@
| 18: Canonical { max_universe: U0, variables: [], value: Ty(*const [i32]) } at $DIR/address-of.rs:26:12: 26:24
| 19: Canonical { max_universe: U0, variables: [], value: Ty(*const [i32]) } at $DIR/address-of.rs:26:12: 26:24
| 20: Canonical { max_universe: U0, variables: [CanonicalVarInfo { kind: Ty(General(U0)) }], value: Ty(*mut ^0) } at $DIR/address-of.rs:28:5: 28:16
| 21: Canonical { max_universe: U6, variables: [CanonicalVarInfo { kind: Region(U6) }], value: Ty(*mut dyn std::marker::Send) } at $DIR/address-of.rs:30:5: 30:23
| 21: Canonical { max_universe: U0, variables: [CanonicalVarInfo { kind: Region(U0) }], value: Ty(*mut dyn std::marker::Send) } at $DIR/address-of.rs:30:5: 30:23
| 22: Canonical { max_universe: U0, variables: [CanonicalVarInfo { kind: Ty(General(U0)) }], value: Ty(*mut ^0) } at $DIR/address-of.rs:33:12: 33:18
| 23: Canonical { max_universe: U0, variables: [CanonicalVarInfo { kind: Ty(General(U0)) }], value: Ty(*mut ^0) } at $DIR/address-of.rs:33:12: 33:18
| 24: Canonical { max_universe: U0, variables: [], value: Ty(*mut [i32; 10]) } at $DIR/address-of.rs:34:12: 34:26

View File

@ -0,0 +1,33 @@
error[E0271]: type mismatch resolving `for<'x> <UintStruct as TheTrait<&'x isize>>::A == &'x isize`
--> $DIR/associated-types-eq-hr.rs:87:5
|
LL | fn foo<T>()
| --- required by a bound in this
LL | where
LL | T: for<'x> TheTrait<&'x isize, A = &'x isize>,
| ------------- required by this bound in `foo`
...
LL | foo::<UintStruct>();
| ^^^^^^^^^^^^^^^^^ expected `isize`, found `usize`
|
= note: expected reference `&isize`
found reference `&usize`
error[E0271]: type mismatch resolving `for<'x> <IntStruct as TheTrait<&'x isize>>::A == &'x usize`
--> $DIR/associated-types-eq-hr.rs:91:5
|
LL | fn bar<T>()
| --- required by a bound in this
LL | where
LL | T: for<'x> TheTrait<&'x isize, A = &'x usize>,
| ------------- required by this bound in `bar`
...
LL | bar::<IntStruct>();
| ^^^^^^^^^^^^^^^^ expected `usize`, found `isize`
|
= note: expected reference `&usize`
found reference `&isize`
error: aborting due to 2 previous errors
For more information about this error, try `rustc --explain E0271`.

View File

@ -7,7 +7,7 @@ pub trait TheTrait<T> {
}
struct IntStruct {
x: isize
x: isize,
}
impl<'a> TheTrait<&'a isize> for IntStruct {
@ -19,7 +19,7 @@ impl<'a> TheTrait<&'a isize> for IntStruct {
}
struct UintStruct {
x: isize
x: isize,
}
impl<'a> TheTrait<&'a isize> for UintStruct {
@ -30,8 +30,7 @@ impl<'a> TheTrait<&'a isize> for UintStruct {
}
}
struct Tuple {
}
struct Tuple {}
impl<'a> TheTrait<(&'a isize, &'a isize)> for Tuple {
type A = &'a isize;
@ -42,37 +41,43 @@ impl<'a> TheTrait<(&'a isize, &'a isize)> for Tuple {
}
fn foo<T>()
where T : for<'x> TheTrait<&'x isize, A = &'x isize>
where
T: for<'x> TheTrait<&'x isize, A = &'x isize>,
{
// ok for IntStruct, but not UintStruct
}
fn bar<T>()
where T : for<'x> TheTrait<&'x isize, A = &'x usize>
where
T: for<'x> TheTrait<&'x isize, A = &'x usize>,
{
// ok for UintStruct, but not IntStruct
}
fn tuple_one<T>()
where T : for<'x,'y> TheTrait<(&'x isize, &'y isize), A = &'x isize>
where
T: for<'x, 'y> TheTrait<(&'x isize, &'y isize), A = &'x isize>,
{
// not ok for tuple, two lifetimes and we pick first
}
fn tuple_two<T>()
where T : for<'x,'y> TheTrait<(&'x isize, &'y isize), A = &'y isize>
where
T: for<'x, 'y> TheTrait<(&'x isize, &'y isize), A = &'y isize>,
{
// not ok for tuple, two lifetimes and we pick second
}
fn tuple_three<T>()
where T : for<'x> TheTrait<(&'x isize, &'x isize), A = &'x isize>
where
T: for<'x> TheTrait<(&'x isize, &'x isize), A = &'x isize>,
{
// ok for tuple
}
fn tuple_four<T>()
where T : for<'x,'y> TheTrait<(&'x isize, &'y isize)>
where
T: for<'x, 'y> TheTrait<(&'x isize, &'y isize)>,
{
// not ok for tuple, two lifetimes, and lifetime matching is invariant
}
@ -89,14 +94,14 @@ pub fn call_bar() {
pub fn call_tuple_one() {
tuple_one::<Tuple>();
//~^ ERROR not satisfied
//~| ERROR type mismatch
//~^ ERROR implementation of `TheTrait` is not general enough
//~| ERROR implementation of `TheTrait` is not general enough
}
pub fn call_tuple_two() {
tuple_two::<Tuple>();
//~^ ERROR not satisfied
//~| ERROR type mismatch
//~^ ERROR implementation of `TheTrait` is not general enough
//~| ERROR implementation of `TheTrait` is not general enough
}
pub fn call_tuple_three() {
@ -105,7 +110,7 @@ pub fn call_tuple_three() {
pub fn call_tuple_four() {
tuple_four::<Tuple>();
//~^ ERROR not satisfied
//~^ ERROR implementation of `TheTrait` is not general enough
}
fn main() { }
fn main() {}

View File

@ -1,10 +1,11 @@
error[E0271]: type mismatch resolving `for<'x> <UintStruct as TheTrait<&'x isize>>::A == &'x isize`
--> $DIR/associated-types-eq-hr.rs:82:5
--> $DIR/associated-types-eq-hr.rs:87:5
|
LL | fn foo<T>()
| --- required by a bound in this
LL | where T : for<'x> TheTrait<&'x isize, A = &'x isize>
| ------------- required by this bound in `foo`
LL | where
LL | T: for<'x> TheTrait<&'x isize, A = &'x isize>,
| ------------- required by this bound in `foo`
...
LL | foo::<UintStruct>();
| ^^^^^^^^^^^^^^^^^ expected `isize`, found `usize`
@ -13,12 +14,13 @@ LL | foo::<UintStruct>();
found reference `&usize`
error[E0271]: type mismatch resolving `for<'x> <IntStruct as TheTrait<&'x isize>>::A == &'x usize`
--> $DIR/associated-types-eq-hr.rs:86:5
--> $DIR/associated-types-eq-hr.rs:91:5
|
LL | fn bar<T>()
| --- required by a bound in this
LL | where T : for<'x> TheTrait<&'x isize, A = &'x usize>
| ------------- required by this bound in `bar`
LL | where
LL | T: for<'x> TheTrait<&'x isize, A = &'x usize>,
| ------------- required by this bound in `bar`
...
LL | bar::<IntStruct>();
| ^^^^^^^^^^^^^^^^ expected `usize`, found `isize`
@ -26,71 +28,86 @@ LL | bar::<IntStruct>();
= note: expected reference `&usize`
found reference `&isize`
error[E0277]: the trait bound `for<'x, 'y> Tuple: TheTrait<(&'x isize, &'y isize)>` is not satisfied
--> $DIR/associated-types-eq-hr.rs:91:17
error: implementation of `TheTrait` is not general enough
--> $DIR/associated-types-eq-hr.rs:96:5
|
LL | fn tuple_one<T>()
| --------- required by a bound in this
LL | where T : for<'x,'y> TheTrait<(&'x isize, &'y isize), A = &'x isize>
| ---------------------------------------------------------- required by this bound in `tuple_one`
LL | / pub trait TheTrait<T> {
LL | | type A;
LL | |
LL | | fn get(&self, t: T) -> Self::A;
LL | | }
| |_- trait `TheTrait` defined here
...
LL | tuple_one::<Tuple>();
| ^^^^^ the trait `for<'x, 'y> TheTrait<(&'x isize, &'y isize)>` is not implemented for `Tuple`
LL | tuple_one::<Tuple>();
| ^^^^^^^^^^^^^^^^^^ implementation of `TheTrait` is not general enough
|
= help: the following implementations were found:
<Tuple as TheTrait<(&'a isize, &'a isize)>>
= note: `Tuple` must implement `TheTrait<(&'0 isize, &'1 isize)>`, for any two lifetimes `'0` and `'1`...
= note: ...but `Tuple` actually implements `TheTrait<(&'2 isize, &'2 isize)>`, for some specific lifetime `'2`
error[E0271]: type mismatch resolving `for<'x, 'y> <Tuple as TheTrait<(&'x isize, &'y isize)>>::A == &'x isize`
--> $DIR/associated-types-eq-hr.rs:91:5
error: implementation of `TheTrait` is not general enough
--> $DIR/associated-types-eq-hr.rs:96:5
|
LL | fn tuple_one<T>()
| --------- required by a bound in this
LL | where T : for<'x,'y> TheTrait<(&'x isize, &'y isize), A = &'x isize>
| ------------- required by this bound in `tuple_one`
LL | / pub trait TheTrait<T> {
LL | | type A;
LL | |
LL | | fn get(&self, t: T) -> Self::A;
LL | | }
| |_- trait `TheTrait` defined here
...
LL | tuple_one::<Tuple>();
| ^^^^^^^^^^^^^^^^^^ expected bound lifetime parameter 'x, found concrete lifetime
LL | tuple_one::<Tuple>();
| ^^^^^^^^^^^^^^^^^^ implementation of `TheTrait` is not general enough
|
= note: `Tuple` must implement `TheTrait<(&'0 isize, &'1 isize)>`, for any two lifetimes `'0` and `'1`...
= note: ...but `Tuple` actually implements `TheTrait<(&'2 isize, &'2 isize)>`, for some specific lifetime `'2`
error[E0277]: the trait bound `for<'x, 'y> Tuple: TheTrait<(&'x isize, &'y isize)>` is not satisfied
--> $DIR/associated-types-eq-hr.rs:97:17
error: implementation of `TheTrait` is not general enough
--> $DIR/associated-types-eq-hr.rs:102:5
|
LL | fn tuple_two<T>()
| --------- required by a bound in this
LL | where T : for<'x,'y> TheTrait<(&'x isize, &'y isize), A = &'y isize>
| ---------------------------------------------------------- required by this bound in `tuple_two`
LL | / pub trait TheTrait<T> {
LL | | type A;
LL | |
LL | | fn get(&self, t: T) -> Self::A;
LL | | }
| |_- trait `TheTrait` defined here
...
LL | tuple_two::<Tuple>();
| ^^^^^ the trait `for<'x, 'y> TheTrait<(&'x isize, &'y isize)>` is not implemented for `Tuple`
LL | tuple_two::<Tuple>();
| ^^^^^^^^^^^^^^^^^^ implementation of `TheTrait` is not general enough
|
= help: the following implementations were found:
<Tuple as TheTrait<(&'a isize, &'a isize)>>
= note: `Tuple` must implement `TheTrait<(&'0 isize, &'1 isize)>`, for any two lifetimes `'0` and `'1`...
= note: ...but `Tuple` actually implements `TheTrait<(&'2 isize, &'2 isize)>`, for some specific lifetime `'2`
error[E0271]: type mismatch resolving `for<'x, 'y> <Tuple as TheTrait<(&'x isize, &'y isize)>>::A == &'y isize`
--> $DIR/associated-types-eq-hr.rs:97:5
error: implementation of `TheTrait` is not general enough
--> $DIR/associated-types-eq-hr.rs:102:5
|
LL | fn tuple_two<T>()
| --------- required by a bound in this
LL | where T : for<'x,'y> TheTrait<(&'x isize, &'y isize), A = &'y isize>
| ------------- required by this bound in `tuple_two`
LL | / pub trait TheTrait<T> {
LL | | type A;
LL | |
LL | | fn get(&self, t: T) -> Self::A;
LL | | }
| |_- trait `TheTrait` defined here
...
LL | tuple_two::<Tuple>();
| ^^^^^^^^^^^^^^^^^^ expected bound lifetime parameter 'x, found concrete lifetime
LL | tuple_two::<Tuple>();
| ^^^^^^^^^^^^^^^^^^ implementation of `TheTrait` is not general enough
|
= note: `Tuple` must implement `TheTrait<(&'0 isize, &'1 isize)>`, for any two lifetimes `'0` and `'1`...
= note: ...but `Tuple` actually implements `TheTrait<(&'2 isize, &'2 isize)>`, for some specific lifetime `'2`
error[E0277]: the trait bound `for<'x, 'y> Tuple: TheTrait<(&'x isize, &'y isize)>` is not satisfied
--> $DIR/associated-types-eq-hr.rs:107:18
error: implementation of `TheTrait` is not general enough
--> $DIR/associated-types-eq-hr.rs:112:5
|
LL | fn tuple_four<T>()
| ---------- required by a bound in this
LL | where T : for<'x,'y> TheTrait<(&'x isize, &'y isize)>
| ------------------------------------------- required by this bound in `tuple_four`
LL | / pub trait TheTrait<T> {
LL | | type A;
LL | |
LL | | fn get(&self, t: T) -> Self::A;
LL | | }
| |_- trait `TheTrait` defined here
...
LL | tuple_four::<Tuple>();
| ^^^^^ the trait `for<'x, 'y> TheTrait<(&'x isize, &'y isize)>` is not implemented for `Tuple`
LL | tuple_four::<Tuple>();
| ^^^^^^^^^^^^^^^^^^^ implementation of `TheTrait` is not general enough
|
= help: the following implementations were found:
<Tuple as TheTrait<(&'a isize, &'a isize)>>
= note: `Tuple` must implement `TheTrait<(&'0 isize, &'1 isize)>`, for any two lifetimes `'0` and `'1`...
= note: ...but `Tuple` actually implements `TheTrait<(&'2 isize, &'2 isize)>`, for some specific lifetime `'2`
error: aborting due to 7 previous errors
Some errors have detailed explanations: E0271, E0277.
For more information about an error, try `rustc --explain E0271`.
For more information about this error, try `rustc --explain E0271`.

View File

@ -1,26 +1,26 @@
error: lifetime may not live long enough
--> $DIR/project-fn-ret-invariant.rs:55:4
--> $DIR/project-fn-ret-invariant.rs:56:5
|
LL | fn transmute<'a,'b>(x: Type<'a>, y: Type<'b>) -> (Type<'a>, Type<'b>) {
| -- -- lifetime `'b` defined here
LL | fn transmute<'a, 'b>(x: Type<'a>, y: Type<'b>) -> (Type<'a>, Type<'b>) {
| -- -- lifetime `'b` defined here
| |
| lifetime `'a` defined here
...
LL | (a, b)
| ^^^^^^ function was supposed to return data with lifetime `'b` but it is returning data with lifetime `'a`
LL | (a, b)
| ^^^^^^ function was supposed to return data with lifetime `'b` but it is returning data with lifetime `'a`
|
= help: consider adding the following bound: `'a: 'b`
error: lifetime may not live long enough
--> $DIR/project-fn-ret-invariant.rs:55:4
--> $DIR/project-fn-ret-invariant.rs:56:5
|
LL | fn transmute<'a,'b>(x: Type<'a>, y: Type<'b>) -> (Type<'a>, Type<'b>) {
| -- -- lifetime `'b` defined here
LL | fn transmute<'a, 'b>(x: Type<'a>, y: Type<'b>) -> (Type<'a>, Type<'b>) {
| -- -- lifetime `'b` defined here
| |
| lifetime `'a` defined here
...
LL | (a, b)
| ^^^^^^ function was supposed to return data with lifetime `'a` but it is returning data with lifetime `'b`
LL | (a, b)
| ^^^^^^ function was supposed to return data with lifetime `'a` but it is returning data with lifetime `'b`
|
= help: consider adding the following bound: `'b: 'a`

View File

@ -1,23 +1,23 @@
error[E0623]: lifetime mismatch
--> $DIR/project-fn-ret-invariant.rs:53:21
--> $DIR/project-fn-ret-invariant.rs:54:22
|
LL | fn transmute<'a,'b>(x: Type<'a>, y: Type<'b>) -> (Type<'a>, Type<'b>) {
| -------- --------------------
| |
| this parameter and the return type are declared with different lifetimes...
LL | let a = bar(foo, y);
| ^ ...but data from `x` is returned here
LL | fn transmute<'a, 'b>(x: Type<'a>, y: Type<'b>) -> (Type<'a>, Type<'b>) {
| -------- --------------------
| |
| this parameter and the return type are declared with different lifetimes...
LL | let a = bar(foo, y);
| ^ ...but data from `x` is returned here
error[E0623]: lifetime mismatch
--> $DIR/project-fn-ret-invariant.rs:54:21
--> $DIR/project-fn-ret-invariant.rs:56:9
|
LL | fn transmute<'a,'b>(x: Type<'a>, y: Type<'b>) -> (Type<'a>, Type<'b>) {
| -------- --------------------
| |
| this parameter and the return type are declared with different lifetimes...
LL | let a = bar(foo, y);
LL | let b = bar(foo, x);
| ^ ...but data from `y` is returned here
LL | fn transmute<'a, 'b>(x: Type<'a>, y: Type<'b>) -> (Type<'a>, Type<'b>) {
| -------- --------------------
| |
| this parameter and the return type are declared with different lifetimes...
...
LL | (a, b)
| ^ ...but data from `x` is returned here
error: aborting due to 2 previous errors

View File

@ -1,8 +1,8 @@
error: fatal error triggered by #[rustc_error]
--> $DIR/project-fn-ret-invariant.rs:59:1
--> $DIR/project-fn-ret-invariant.rs:60:1
|
LL | fn main() { }
| ^^^^^^^^^^^^^
LL | fn main() {}
| ^^^^^^^^^^^^
error: aborting due to previous error

View File

@ -1,26 +1,26 @@
error: lifetime may not live long enough
--> $DIR/project-fn-ret-invariant.rs:38:12
--> $DIR/project-fn-ret-invariant.rs:39:13
|
LL | fn baz<'a,'b>(x: Type<'a>, y: Type<'b>) -> (Type<'a>, Type<'b>) {
| -- -- lifetime `'b` defined here
LL | fn baz<'a, 'b>(x: Type<'a>, y: Type<'b>) -> (Type<'a>, Type<'b>) {
| -- -- lifetime `'b` defined here
| |
| lifetime `'a` defined here
LL | let f = foo; // <-- No consistent type can be inferred for `f` here.
LL | let a = bar(f, x);
| ^^^^^^^^^ argument requires that `'a` must outlive `'b`
LL | let f = foo; // <-- No consistent type can be inferred for `f` here.
LL | let a = bar(f, x);
| ^^^^^^^^^ argument requires that `'a` must outlive `'b`
|
= help: consider adding the following bound: `'a: 'b`
error: lifetime may not live long enough
--> $DIR/project-fn-ret-invariant.rs:39:12
--> $DIR/project-fn-ret-invariant.rs:40:13
|
LL | fn baz<'a,'b>(x: Type<'a>, y: Type<'b>) -> (Type<'a>, Type<'b>) {
| -- -- lifetime `'b` defined here
LL | fn baz<'a, 'b>(x: Type<'a>, y: Type<'b>) -> (Type<'a>, Type<'b>) {
| -- -- lifetime `'b` defined here
| |
| lifetime `'a` defined here
...
LL | let b = bar(f, y);
| ^^^^^^^^^ argument requires that `'b` must outlive `'a`
LL | let b = bar(f, y);
| ^^^^^^^^^ argument requires that `'b` must outlive `'a`
|
= help: consider adding the following bound: `'b: 'a`

View File

@ -1,13 +1,13 @@
error[E0623]: lifetime mismatch
--> $DIR/project-fn-ret-invariant.rs:39:19
--> $DIR/project-fn-ret-invariant.rs:40:20
|
LL | fn baz<'a,'b>(x: Type<'a>, y: Type<'b>) -> (Type<'a>, Type<'b>) {
| -------- --------------------
| |
| this parameter and the return type are declared with different lifetimes...
LL | fn baz<'a, 'b>(x: Type<'a>, y: Type<'b>) -> (Type<'a>, Type<'b>) {
| -------- --------------------
| |
| this parameter and the return type are declared with different lifetimes...
...
LL | let b = bar(f, y);
| ^ ...but data from `x` is returned here
LL | let b = bar(f, y);
| ^ ...but data from `x` is returned here
error: aborting due to previous error

View File

@ -1,60 +1,61 @@
#![feature(unboxed_closures)]
#![feature(rustc_attrs)]
// Test for projection cache. We should be able to project distinct
// lifetimes from `foo` as we reinstantiate it multiple times, but not
// if we do it just once. In this variant, the region `'a` is used in
// an invariant position, which affects the results.
// revisions: ok oneuse transmute krisskross
#![allow(dead_code, unused_variables)]
use std::marker::PhantomData;
struct Type<'a> {
// Invariant
data: PhantomData<fn(&'a u32) -> &'a u32>
data: PhantomData<fn(&'a u32) -> &'a u32>,
}
fn foo<'a>() -> Type<'a> { loop { } }
fn foo<'a>() -> Type<'a> {
loop {}
}
fn bar<T>(t: T, x: T::Output) -> T::Output
where T: FnOnce<()>
where
T: FnOnce<()>,
{
t()
}
#[cfg(ok)] // two instantiations: OK
fn baz<'a,'b>(x: Type<'a>, y: Type<'b>) -> (Type<'a>, Type<'b>) {
fn baz<'a, 'b>(x: Type<'a>, y: Type<'b>) -> (Type<'a>, Type<'b>) {
let a = bar(foo, x);
let b = bar(foo, y);
(a, b)
}
#[cfg(oneuse)] // one instantiation: BAD
fn baz<'a,'b>(x: Type<'a>, y: Type<'b>) -> (Type<'a>, Type<'b>) {
let f = foo; // <-- No consistent type can be inferred for `f` here.
let a = bar(f, x);
let b = bar(f, y); //[oneuse]~ ERROR lifetime mismatch [E0623]
(a, b)
fn baz<'a, 'b>(x: Type<'a>, y: Type<'b>) -> (Type<'a>, Type<'b>) {
let f = foo; // <-- No consistent type can be inferred for `f` here.
let a = bar(f, x);
let b = bar(f, y); //[oneuse]~ ERROR lifetime mismatch [E0623]
(a, b)
}
#[cfg(transmute)] // one instantiations: BAD
fn baz<'a,'b>(x: Type<'a>) -> Type<'static> {
// Cannot instantiate `foo` with any lifetime other than `'a`,
// since it is provided as input.
fn baz<'a, 'b>(x: Type<'a>) -> Type<'static> {
// Cannot instantiate `foo` with any lifetime other than `'a`,
// since it is provided as input.
bar(foo, x) //[transmute]~ ERROR E0495
bar(foo, x) //[transmute]~ ERROR E0495
}
#[cfg(krisskross)] // two instantiations, mixing and matching: BAD
fn transmute<'a,'b>(x: Type<'a>, y: Type<'b>) -> (Type<'a>, Type<'b>) {
let a = bar(foo, y); //[krisskross]~ ERROR E0623
let b = bar(foo, x); //[krisskross]~ ERROR E0623
(a, b)
fn transmute<'a, 'b>(x: Type<'a>, y: Type<'b>) -> (Type<'a>, Type<'b>) {
let a = bar(foo, y); //[krisskross]~ ERROR E0623
let b = bar(foo, x);
(a, b) //[krisskross]~ ERROR E0623
}
#[rustc_error]
fn main() { }
fn main() {}
//[ok]~^ ERROR fatal error triggered by #[rustc_error]

View File

@ -1,11 +1,11 @@
error: lifetime may not live long enough
--> $DIR/project-fn-ret-invariant.rs:48:4
--> $DIR/project-fn-ret-invariant.rs:49:5
|
LL | fn baz<'a,'b>(x: Type<'a>) -> Type<'static> {
LL | fn baz<'a, 'b>(x: Type<'a>) -> Type<'static> {
| -- lifetime `'a` defined here
...
LL | bar(foo, x)
| ^^^^^^^^^^^ returning this value requires that `'a` must outlive `'static`
LL | bar(foo, x)
| ^^^^^^^^^^^ returning this value requires that `'a` must outlive `'static`
|
= help: consider replacing `'a` with `'static`

View File

@ -1,27 +1,27 @@
error[E0495]: cannot infer an appropriate lifetime due to conflicting requirements
--> $DIR/project-fn-ret-invariant.rs:48:4
error[E0495]: cannot infer an appropriate lifetime for lifetime parameter `'a` due to conflicting requirements
--> $DIR/project-fn-ret-invariant.rs:49:9
|
LL | bar(foo, x)
| ^^^^^^^^^^^
LL | bar(foo, x)
| ^^^
|
note: first, the lifetime cannot outlive the lifetime `'a` as defined on the function body at 44:8...
--> $DIR/project-fn-ret-invariant.rs:44:8
note: first, the lifetime cannot outlive the lifetime `'a` as defined on the function body at 45:8...
--> $DIR/project-fn-ret-invariant.rs:45:8
|
LL | fn baz<'a,'b>(x: Type<'a>) -> Type<'static> {
LL | fn baz<'a, 'b>(x: Type<'a>) -> Type<'static> {
| ^^
note: ...so that the expression is assignable
--> $DIR/project-fn-ret-invariant.rs:48:13
--> $DIR/project-fn-ret-invariant.rs:49:14
|
LL | bar(foo, x)
| ^
LL | bar(foo, x)
| ^
= note: expected `Type<'_>`
found `Type<'a>`
= note: but, the lifetime must be valid for the static lifetime...
note: ...so that the expression is assignable
--> $DIR/project-fn-ret-invariant.rs:48:4
--> $DIR/project-fn-ret-invariant.rs:49:5
|
LL | bar(foo, x)
| ^^^^^^^^^^^
LL | bar(foo, x)
| ^^^^^^^^^^^
= note: expected `Type<'static>`
found `Type<'_>`

View File

@ -0,0 +1,8 @@
error: higher-ranked subtype error
--> $DIR/higher-ranked-projection.rs:25:5
|
LL | foo(());
| ^^^^^^^
error: aborting due to previous error

View File

@ -1,14 +1,12 @@
error[E0271]: type mismatch resolving `for<'a> <&'a _ as Mirror>::Image == _`
error[E0308]: mismatched types
--> $DIR/higher-ranked-projection.rs:25:5
|
LL | fn foo<U, T>(_t: T)
| --- required by a bound in this
LL | where for<'a> &'a T: Mirror<Image=U>
| ------- required by this bound in `foo`
...
LL | foo(());
| ^^^ expected bound lifetime parameter 'a, found concrete lifetime
| ^^^ one type is more general than the other
|
= note: expected type `&'a ()`
found type `&()`
error: aborting due to previous error
For more information about this error, try `rustc --explain E0271`.
For more information about this error, try `rustc --explain E0308`.

View File

@ -23,5 +23,5 @@ fn foo<U, T>(_t: T)
#[rustc_error]
fn main() { //[good]~ ERROR fatal error triggered by #[rustc_error]
foo(());
//[bad]~^ ERROR type mismatch
//[bad]~^ ERROR mismatched types
}

View File

@ -5,7 +5,9 @@ LL | ..SafeStruct{field1: SafeEnum::Va
| ___________________________________________^
LL | |
LL | | field2: SafeEnum::Variant1}};
| |________________________________________________________________________________^ statics cannot evaluate destructors
| | ^- value is dropped here
| |________________________________________________________________________________|
| statics cannot evaluate destructors
error[E0010]: allocations are not allowed in statics
--> $DIR/check-static-values-constraints.rs:79:33

View File

@ -1,42 +1,43 @@
error[E0631]: type mismatch in closure arguments
--> $DIR/expect-fn-supply-fn.rs:30:5
error: lifetime may not live long enough
--> $DIR/expect-fn-supply-fn.rs:16:49
|
LL | fn with_closure_expecting_fn_with_free_region<F>(_: F)
| ------------------------------------------ required by a bound in this
LL | where F: for<'a> FnOnce(fn(&'a u32), &i32)
| ------------------------- required by this bound in `with_closure_expecting_fn_with_free_region`
LL | fn expect_free_supply_free_from_fn<'x>(x: &'x u32) {
| -- lifetime `'x` defined here
...
LL | with_closure_expecting_fn_with_free_region(|x: fn(&'x u32), y| {});
| ^
| |
| has type `fn(&'1 u32)`
| requires that `'1` must outlive `'x`
error: lifetime may not live long enough
--> $DIR/expect-fn-supply-fn.rs:16:49
|
LL | fn expect_free_supply_free_from_fn<'x>(x: &'x u32) {
| -- lifetime `'x` defined here
...
LL | with_closure_expecting_fn_with_free_region(|x: fn(&'x u32), y| {});
| ^ requires that `'x` must outlive `'static`
|
= help: consider replacing `'x` with `'static`
error: higher-ranked subtype error
--> $DIR/expect-fn-supply-fn.rs:32:49
|
LL | with_closure_expecting_fn_with_free_region(|x: fn(&u32), y| {});
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ---------------- found signature of `fn(for<'r> fn(&'r u32), _) -> _`
| |
| expected signature of `fn(fn(&'a u32), &i32) -> _`
| ^
error[E0631]: type mismatch in closure arguments
--> $DIR/expect-fn-supply-fn.rs:37:5
error: higher-ranked subtype error
--> $DIR/expect-fn-supply-fn.rs:39:50
|
LL | fn with_closure_expecting_fn_with_bound_region<F>(_: F)
| ------------------------------------------- required by a bound in this
LL | where F: FnOnce(fn(&u32), &i32)
| ---------------------- required by this bound in `with_closure_expecting_fn_with_bound_region`
...
LL | with_closure_expecting_fn_with_bound_region(|x: fn(&'x u32), y| {});
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ------------------- found signature of `fn(fn(&'x u32), _) -> _`
| |
| expected signature of `fn(for<'r> fn(&'r u32), &i32) -> _`
| ^
error[E0631]: type mismatch in closure arguments
--> $DIR/expect-fn-supply-fn.rs:46:5
error: higher-ranked subtype error
--> $DIR/expect-fn-supply-fn.rs:48:50
|
LL | fn with_closure_expecting_fn_with_bound_region<F>(_: F)
| ------------------------------------------- required by a bound in this
LL | where F: FnOnce(fn(&u32), &i32)
| ---------------------- required by this bound in `with_closure_expecting_fn_with_bound_region`
...
LL | with_closure_expecting_fn_with_bound_region(|x: Foo<'_>, y| {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ --------------- found signature of `for<'r> fn(fn(&'r u32), _) -> _`
| |
| expected signature of `fn(for<'r> fn(&'r u32), &i32) -> _`
| ^
error: aborting due to 3 previous errors
error: aborting due to 5 previous errors
For more information about this error, try `rustc --explain E0631`.

View File

@ -1,10 +1,12 @@
fn with_closure_expecting_fn_with_free_region<F>(_: F)
where F: for<'a> FnOnce(fn(&'a u32), &i32)
where
F: for<'a> FnOnce(fn(&'a u32), &i32),
{
}
fn with_closure_expecting_fn_with_bound_region<F>(_: F)
where F: FnOnce(fn(&u32), &i32)
where
F: FnOnce(fn(&u32), &i32),
{
}
@ -28,14 +30,14 @@ fn expect_free_supply_bound() {
// Here, we are given a function whose region is bound at closure level,
// but we expect one bound in the argument. Error results.
with_closure_expecting_fn_with_free_region(|x: fn(&u32), y| {});
//~^ ERROR type mismatch
//~^ ERROR mismatched types
}
fn expect_bound_supply_free_from_fn<'x>(x: &'x u32) {
// Here, we are given a `fn(&u32)` but we expect a `fn(&'x
// u32)`. In principle, this could be ok, but we demand equality.
with_closure_expecting_fn_with_bound_region(|x: fn(&'x u32), y| {});
//~^ ERROR type mismatch
//~^ ERROR mismatched types
}
fn expect_bound_supply_free_from_closure() {
@ -44,7 +46,7 @@ fn expect_bound_supply_free_from_closure() {
// the argument level.
type Foo<'a> = fn(&'a u32);
with_closure_expecting_fn_with_bound_region(|x: Foo<'_>, y| {
//~^ ERROR type mismatch
//~^ ERROR mismatched types
});
}
@ -52,8 +54,7 @@ fn expect_bound_supply_bound<'x>(x: &'x u32) {
// No error in this case. The supplied type supplies the bound
// regions, and hence we are able to figure out the type of `y`
// from the expected type
with_closure_expecting_fn_with_bound_region(|x: for<'z> fn(&'z u32), y| {
});
with_closure_expecting_fn_with_bound_region(|x: for<'z> fn(&'z u32), y| {});
}
fn main() { }
fn main() {}

View File

@ -1,81 +1,68 @@
error[E0308]: mismatched types
--> $DIR/expect-fn-supply-fn.rs:14:52
--> $DIR/expect-fn-supply-fn.rs:16:52
|
LL | with_closure_expecting_fn_with_free_region(|x: fn(&'x u32), y| {});
| ^^^^^^^^^^^ lifetime mismatch
|
= note: expected fn pointer `fn(&u32)`
found fn pointer `fn(&'x u32)`
note: the anonymous lifetime #2 defined on the body at 14:48...
--> $DIR/expect-fn-supply-fn.rs:14:48
note: the anonymous lifetime #2 defined on the body at 16:48...
--> $DIR/expect-fn-supply-fn.rs:16:48
|
LL | with_closure_expecting_fn_with_free_region(|x: fn(&'x u32), y| {});
| ^^^^^^^^^^^^^^^^^^^^^^
note: ...does not necessarily outlive the lifetime `'x` as defined on the function body at 11:36
--> $DIR/expect-fn-supply-fn.rs:11:36
note: ...does not necessarily outlive the lifetime `'x` as defined on the function body at 13:36
--> $DIR/expect-fn-supply-fn.rs:13:36
|
LL | fn expect_free_supply_free_from_fn<'x>(x: &'x u32) {
| ^^
error[E0308]: mismatched types
--> $DIR/expect-fn-supply-fn.rs:14:52
--> $DIR/expect-fn-supply-fn.rs:16:52
|
LL | with_closure_expecting_fn_with_free_region(|x: fn(&'x u32), y| {});
| ^^^^^^^^^^^ lifetime mismatch
|
= note: expected fn pointer `fn(&u32)`
found fn pointer `fn(&'x u32)`
note: the lifetime `'x` as defined on the function body at 11:36...
--> $DIR/expect-fn-supply-fn.rs:11:36
note: the lifetime `'x` as defined on the function body at 13:36...
--> $DIR/expect-fn-supply-fn.rs:13:36
|
LL | fn expect_free_supply_free_from_fn<'x>(x: &'x u32) {
| ^^
note: ...does not necessarily outlive the anonymous lifetime #2 defined on the body at 14:48
--> $DIR/expect-fn-supply-fn.rs:14:48
note: ...does not necessarily outlive the anonymous lifetime #2 defined on the body at 16:48
--> $DIR/expect-fn-supply-fn.rs:16:48
|
LL | with_closure_expecting_fn_with_free_region(|x: fn(&'x u32), y| {});
| ^^^^^^^^^^^^^^^^^^^^^^
error[E0631]: type mismatch in closure arguments
--> $DIR/expect-fn-supply-fn.rs:30:5
error[E0308]: mismatched types
--> $DIR/expect-fn-supply-fn.rs:32:52
|
LL | fn with_closure_expecting_fn_with_free_region<F>(_: F)
| ------------------------------------------ required by a bound in this
LL | where F: for<'a> FnOnce(fn(&'a u32), &i32)
| ------------------------- required by this bound in `with_closure_expecting_fn_with_free_region`
...
LL | with_closure_expecting_fn_with_free_region(|x: fn(&u32), y| {});
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ---------------- found signature of `fn(for<'r> fn(&'r u32), _) -> _`
| |
| expected signature of `fn(fn(&'a u32), &i32) -> _`
error[E0631]: type mismatch in closure arguments
--> $DIR/expect-fn-supply-fn.rs:37:5
| ^^^^^^^^ one type is more general than the other
|
= note: expected fn pointer `fn(&u32)`
found fn pointer `for<'r> fn(&'r u32)`
error[E0308]: mismatched types
--> $DIR/expect-fn-supply-fn.rs:39:53
|
LL | fn with_closure_expecting_fn_with_bound_region<F>(_: F)
| ------------------------------------------- required by a bound in this
LL | where F: FnOnce(fn(&u32), &i32)
| ---------------------- required by this bound in `with_closure_expecting_fn_with_bound_region`
...
LL | with_closure_expecting_fn_with_bound_region(|x: fn(&'x u32), y| {});
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ------------------- found signature of `fn(fn(&'x u32), _) -> _`
| |
| expected signature of `fn(for<'r> fn(&'r u32), &i32) -> _`
error[E0631]: type mismatch in closure arguments
--> $DIR/expect-fn-supply-fn.rs:46:5
| ^^^^^^^^^^^ one type is more general than the other
|
= note: expected fn pointer `for<'r> fn(&'r u32)`
found fn pointer `fn(&'x u32)`
error[E0308]: mismatched types
--> $DIR/expect-fn-supply-fn.rs:48:53
|
LL | fn with_closure_expecting_fn_with_bound_region<F>(_: F)
| ------------------------------------------- required by a bound in this
LL | where F: FnOnce(fn(&u32), &i32)
| ---------------------- required by this bound in `with_closure_expecting_fn_with_bound_region`
...
LL | with_closure_expecting_fn_with_bound_region(|x: Foo<'_>, y| {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ --------------- found signature of `for<'r> fn(fn(&'r u32), _) -> _`
| |
| expected signature of `fn(for<'r> fn(&'r u32), &i32) -> _`
| ^^^^^^^ one type is more general than the other
|
= note: expected fn pointer `for<'r> fn(&'r u32)`
found fn pointer `fn(&u32)`
error: aborting due to 5 previous errors
Some errors have detailed explanations: E0308, E0631.
For more information about an error, try `rustc --explain E0308`.
For more information about this error, try `rustc --explain E0308`.

View File

@ -7,7 +7,6 @@ impl<'g> T<'g> for u32 {
}
fn main() {
(&|_|()) as &dyn for<'x> Fn(<u32 as T<'x>>::V);
(&|_| ()) as &dyn for<'x> Fn(<u32 as T<'x>>::V);
//~^ ERROR: type mismatch in closure arguments
//~| ERROR: type mismatch resolving
}

View File

@ -1,23 +1,14 @@
error[E0631]: type mismatch in closure arguments
--> $DIR/issue-41366.rs:10:5
|
LL | (&|_|()) as &dyn for<'x> Fn(<u32 as T<'x>>::V);
| ^^-----^
LL | (&|_| ()) as &dyn for<'x> Fn(<u32 as T<'x>>::V);
| ^^------^
| | |
| | found signature of `fn(_) -> _`
| expected signature of `for<'x> fn(<u32 as T<'x>>::V) -> _`
| | found signature of `fn(u16) -> _`
| expected signature of `fn(<u32 as T<'x>>::V) -> _`
|
= note: required for the cast to the object type `dyn for<'x> std::ops::Fn(<u32 as T<'x>>::V)`
error[E0271]: type mismatch resolving `for<'x> <[closure@$DIR/issue-41366.rs:10:7: 10:12] as std::ops::FnOnce<(<u32 as T<'x>>::V,)>>::Output == ()`
--> $DIR/issue-41366.rs:10:5
|
LL | (&|_|()) as &dyn for<'x> Fn(<u32 as T<'x>>::V);
| ^^^^^^^^ expected bound lifetime parameter 'x, found concrete lifetime
|
= note: required for the cast to the object type `dyn for<'x> std::ops::Fn(<u32 as T<'x>>::V)`
error: aborting due to previous error
error: aborting due to 2 previous errors
Some errors have detailed explanations: E0271, E0631.
For more information about an error, try `rustc --explain E0271`.
For more information about this error, try `rustc --explain E0631`.

View File

@ -0,0 +1,26 @@
// Test that impls for these two types are considered ovelapping:
//
// * `for<'r> fn(fn(&'r u32))`
// * `fn(fn(&'a u32)` where `'a` is free
//
// This is because, for `'a = 'static`, the two types overlap.
// Effectively for them to be equal to you get:
//
// * `for<'r> fn(fn(&'r u32)) <: fn(fn(&'static u32))`
// * true if `exists<'r> { 'r: 'static }` (obviously true)
// * `fn(fn(&'static u32)) <: for<'r> fn(fn(&'r u32))`
// * true if `forall<'r> { 'static: 'r }` (also true)
trait Trait {}
impl Trait for for<'r> fn(fn(&'r ())) {}
impl<'a> Trait for fn(fn(&'a ())) {}
//~^ ERROR conflicting implementations
//
// Note in particular that we do NOT get a future-compatibility warning
// here. This is because the new leak-check proposed in [MCP 295] does not
// "error" when these two types are equated.
//
// [MCP 295]: https://github.com/rust-lang/compiler-team/issues/295
fn main() {}

View File

@ -0,0 +1,13 @@
error[E0119]: conflicting implementations of trait `Trait` for type `for<'r> fn(fn(&'r ()))`:
--> $DIR/coherence-fn-covariant-bound-vs-static.rs:17:1
|
LL | impl Trait for for<'r> fn(fn(&'r ())) {}
| ------------------------------------- first implementation here
LL | impl<'a> Trait for fn(fn(&'a ())) {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `for<'r> fn(fn(&'r ()))`
|
= note: this behavior recently changed as a result of a bug fix; see rust-lang/rust#56105 for details
error: aborting due to previous error
For more information about this error, try `rustc --explain E0119`.

View File

@ -0,0 +1,26 @@
// Test that our leak-check is not smart enough to take implied bounds
// into account (yet). Here we have two types that look like they
// should not be equivalent, but because of the rules on implied
// bounds we ought to know that, in fact, `'a = 'b` must always hold,
// and hence they are.
//
// Rustc can't figure this out and hence it accepts the impls but
// gives a future-compatibility warning (because we'd like to make
// this an error someday).
//
// Note that while we would like to make this a hard error, we also
// give the same warning for `coherence-wasm-bindgen.rs`, which ought
// to be accepted.
#![deny(coherence_leak_check)]
trait Trait {}
impl Trait for for<'a, 'b> fn(&'a &'b u32, &'b &'a u32) -> &'b u32 {}
impl Trait for for<'c> fn(&'c &'c u32, &'c &'c u32) -> &'c u32 {
//~^ ERROR conflicting implementations
//~| WARNING this was previously accepted by the compiler
}
fn main() {}

View File

@ -0,0 +1,20 @@
error: conflicting implementations of trait `Trait` for type `for<'a, 'b> fn(&'a &'b u32, &'b &'a u32) -> &'b u32`:
--> $DIR/coherence-fn-implied-bounds.rs:21:1
|
LL | impl Trait for for<'a, 'b> fn(&'a &'b u32, &'b &'a u32) -> &'b u32 {}
| ------------------------------------------------------------------ first implementation here
LL |
LL | impl Trait for for<'c> fn(&'c &'c u32, &'c &'c u32) -> &'c u32 {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `for<'a, 'b> fn(&'a &'b u32, &'b &'a u32) -> &'b u32`
|
note: the lint level is defined here
--> $DIR/coherence-fn-implied-bounds.rs:15:9
|
LL | #![deny(coherence_leak_check)]
| ^^^^^^^^^^^^^^^^^^^^
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
= note: for more information, see issue #56105 <https://github.com/rust-lang/rust/issues/56105>
= note: this behavior recently changed as a result of a bug fix; see rust-lang/rust#56105 for details
error: aborting due to previous error

View File

@ -0,0 +1,25 @@
// Test that we consider these two types completely equal:
//
// * `for<'a, 'b> fn(&'a u32, &'b u32)`
// * `for<'c> fn(&'c u32, &'c u32)`
//
// For a long time we considered these to be distinct types. But in fact they
// are equivalent, if you work through the implications of subtyping -- this is
// because:
//
// * `'c` can be the intersection of `'a` and `'b` (and there is always an intersection)
// * `'a` and `'b` can both be equal to `'c`
trait Trait {}
impl Trait for for<'a, 'b> fn(&'a u32, &'b u32) {}
impl Trait for for<'c> fn(&'c u32, &'c u32) {
//~^ ERROR conflicting implementations
//
// Note in particular that we do NOT get a future-compatibility warning
// here. This is because the new leak-check proposed in [MCP 295] does not
// "error" when these two types are equated.
//
// [MCP 295]: https://github.com/rust-lang/compiler-team/issues/295
}
fn main() {}

View File

@ -0,0 +1,13 @@
error[E0119]: conflicting implementations of trait `Trait` for type `for<'a, 'b> fn(&'a u32, &'b u32)`:
--> $DIR/coherence-fn-inputs.rs:15:1
|
LL | impl Trait for for<'a, 'b> fn(&'a u32, &'b u32) {}
| ----------------------------------------------- first implementation here
LL | impl Trait for for<'c> fn(&'c u32, &'c u32) {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `for<'a, 'b> fn(&'a u32, &'b u32)`
|
= note: this behavior recently changed as a result of a bug fix; see rust-lang/rust#56105 for details
error: aborting due to previous error
For more information about this error, try `rustc --explain E0119`.

View File

@ -0,0 +1,21 @@
// Capture a coherence pattern from wasm-bindgen that we discovered as part of
// future-compatibility warning #56105. This pattern currently receives a lint
// warning but we probably want to support it long term.
//
// Key distinction: we are implementing once for `A` (take ownership) and one
// for `&A` (borrow).
//
// c.f. #56105
#![deny(coherence_leak_check)]
trait TheTrait {}
impl<'a> TheTrait for fn(&'a u8) {}
impl TheTrait for fn(&u8) {
//~^ ERROR conflicting implementations of trait
//~| WARNING this was previously accepted by the compiler
}
fn main() {}

View File

@ -0,0 +1,20 @@
error: conflicting implementations of trait `TheTrait` for type `fn(&u8)`:
--> $DIR/coherence-free-vs-bound-region.rs:16:1
|
LL | impl<'a> TheTrait for fn(&'a u8) {}
| -------------------------------- first implementation here
LL |
LL | impl TheTrait for fn(&u8) {
| ^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `fn(&u8)`
|
note: the lint level is defined here
--> $DIR/coherence-free-vs-bound-region.rs:10:9
|
LL | #![deny(coherence_leak_check)]
| ^^^^^^^^^^^^^^^^^^^^
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
= note: for more information, see issue #56105 <https://github.com/rust-lang/rust/issues/56105>
= note: this behavior recently changed as a result of a bug fix; see rust-lang/rust#56105 for details
error: aborting due to previous error

View File

@ -0,0 +1,37 @@
// Capture a coherence pattern from wasm-bindgen that we discovered as part of
// future-compatibility warning #56105. This pattern currently receives a lint
// warning but we probably want to support it long term.
//
// Key distinction: we are implementing once for `A` (take ownership) and one
// for `&A` (borrow).
//
// c.f. #56105
#![deny(coherence_leak_check)]
trait IntoWasmAbi {
fn some_method(&self) {}
}
trait FromWasmAbi {}
trait RefFromWasmAbi {}
trait ReturnWasmAbi {}
impl<'a, 'b, A, R> IntoWasmAbi for &'a (dyn Fn(A) -> R + 'b)
where
A: FromWasmAbi,
R: ReturnWasmAbi,
{
}
// Explicitly writing the bound lifetime.
impl<'a, 'b, A, R> IntoWasmAbi for &'a (dyn for<'x> Fn(&'x A) -> R + 'b)
where
A: RefFromWasmAbi,
R: ReturnWasmAbi,
{
//~^^^^^ ERROR conflicting implementation
//~| WARNING this was previously accepted
}
fn main() {}

View File

@ -0,0 +1,32 @@
error: conflicting implementations of trait `IntoWasmAbi` for type `&dyn std::ops::Fn(&_) -> _`:
--> $DIR/coherence-wasm-bindgen.rs:28:1
|
LL | / impl<'a, 'b, A, R> IntoWasmAbi for &'a (dyn Fn(A) -> R + 'b)
LL | | where
LL | | A: FromWasmAbi,
LL | | R: ReturnWasmAbi,
LL | | {
LL | | }
| |_- first implementation here
...
LL | / impl<'a, 'b, A, R> IntoWasmAbi for &'a (dyn for<'x> Fn(&'x A) -> R + 'b)
LL | | where
LL | | A: RefFromWasmAbi,
LL | | R: ReturnWasmAbi,
... |
LL | |
LL | | }
| |_^ conflicting implementation for `&dyn std::ops::Fn(&_) -> _`
|
note: the lint level is defined here
--> $DIR/coherence-wasm-bindgen.rs:10:9
|
LL | #![deny(coherence_leak_check)]
| ^^^^^^^^^^^^^^^^^^^^
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
= note: for more information, see issue #56105 <https://github.com/rust-lang/rust/issues/56105>
= note: downstream crates may implement trait `FromWasmAbi` for type `&_`
= note: this behavior recently changed as a result of a bug fix; see rust-lang/rust#56105 for details
error: aborting due to previous error

View File

@ -14,6 +14,7 @@ LL | fn foo<const N: usize>() -> Array<N, ()> {
| ^
|
= note: type arguments must be provided before constant arguments
= help: reorder the arguments: types, then consts: `<T, N>`
error: aborting due to previous error; 1 warning emitted

View File

@ -1,15 +1,14 @@
// run-pass
#![feature(const_generics, const_compare_raw_pointers)]
#![feature(const_generics)]
//~^ WARN the feature `const_generics` is incomplete
fn function() -> u32 {
17
}
struct Wrapper<const F: fn() -> u32>;
struct Wrapper<const F: fn() -> u32>; //~ ERROR: using function pointers as const generic parameters
impl<const F: fn() -> u32> Wrapper<F> {
//~^ ERROR: using function pointers as const generic parameters
fn call() -> u32 {
F()
}

View File

@ -1,11 +1,23 @@
warning: the feature `const_generics` is incomplete and may not be safe to use and/or cause compiler crashes
--> $DIR/fn-const-param-call.rs:3:12
--> $DIR/fn-const-param-call.rs:1:12
|
LL | #![feature(const_generics, const_compare_raw_pointers)]
LL | #![feature(const_generics)]
| ^^^^^^^^^^^^^^
|
= note: `#[warn(incomplete_features)]` on by default
= note: see issue #44580 <https://github.com/rust-lang/rust/issues/44580> for more information
warning: 1 warning emitted
error: using function pointers as const generic parameters is forbidden
--> $DIR/fn-const-param-call.rs:8:25
|
LL | struct Wrapper<const F: fn() -> u32>;
| ^^^^^^^^^^^
error: using function pointers as const generic parameters is forbidden
--> $DIR/fn-const-param-call.rs:10:15
|
LL | impl<const F: fn() -> u32> Wrapper<F> {
| ^^^^^^^^^^^
error: aborting due to 2 previous errors; 1 warning emitted

View File

@ -1,7 +1,8 @@
#![feature(const_generics, const_compare_raw_pointers)]
#![feature(const_generics)]
//~^ WARN the feature `const_generics` is incomplete
struct Checked<const F: fn(usize) -> bool>;
//~^ ERROR: using function pointers as const generic parameters
fn not_one(val: usize) -> bool { val != 1 }
fn not_two(val: usize) -> bool { val != 2 }
@ -13,14 +14,14 @@ fn generic<T>(val: usize) -> bool { val != 1 }
fn main() {
let _: Option<Checked<not_one>> = None;
let _: Checked<not_one> = Checked::<not_one>;
let _: Checked<not_one> = Checked::<not_two>; //~ mismatched types
let _: Checked<not_one> = Checked::<not_two>;
let _ = Checked::<generic_arg>;
let _ = Checked::<{generic_arg::<usize>}>;
let _ = Checked::<{generic_arg::<u32>}>; //~ mismatched types
let _ = Checked::<{generic_arg::<u32>}>;
let _ = Checked::<generic>; //~ type annotations needed
let _ = Checked::<generic>;
let _ = Checked::<{generic::<u16>}>;
let _: Checked<{generic::<u16>}> = Checked::<{generic::<u16>}>;
let _: Checked<{generic::<u32>}> = Checked::<{generic::<u16>}>; //~ mismatched types
let _: Checked<{generic::<u32>}> = Checked::<{generic::<u16>}>;
}

View File

@ -1,46 +1,17 @@
warning: the feature `const_generics` is incomplete and may not be safe to use and/or cause compiler crashes
--> $DIR/fn-const-param-infer.rs:1:12
|
LL | #![feature(const_generics, const_compare_raw_pointers)]
LL | #![feature(const_generics)]
| ^^^^^^^^^^^^^^
|
= note: `#[warn(incomplete_features)]` on by default
= note: see issue #44580 <https://github.com/rust-lang/rust/issues/44580> for more information
error[E0308]: mismatched types
--> $DIR/fn-const-param-infer.rs:16:31
error: using function pointers as const generic parameters is forbidden
--> $DIR/fn-const-param-infer.rs:4:25
|
LL | let _: Checked<not_one> = Checked::<not_two>;
| ^^^^^^^^^^^^^^^^^^ expected `{not_one as fn(usize) -> bool}`, found `{not_two as fn(usize) -> bool}`
|
= note: expected type `{not_one as fn(usize) -> bool}`
found type `{not_two as fn(usize) -> bool}`
LL | struct Checked<const F: fn(usize) -> bool>;
| ^^^^^^^^^^^^^^^^^
error[E0308]: mismatched types
--> $DIR/fn-const-param-infer.rs:20:24
|
LL | let _ = Checked::<{generic_arg::<u32>}>;
| ^^^^^^^^^^^^^^^^^^ expected `usize`, found `u32`
|
= note: expected fn pointer `fn(usize) -> _`
found fn item `fn(u32) -> _ {generic_arg::<u32>}`
error: aborting due to previous error; 1 warning emitted
error[E0282]: type annotations needed
--> $DIR/fn-const-param-infer.rs:22:23
|
LL | let _ = Checked::<generic>;
| ^^^^^^^ cannot infer type for type parameter `T` declared on the function `generic`
error[E0308]: mismatched types
--> $DIR/fn-const-param-infer.rs:25:40
|
LL | let _: Checked<{generic::<u32>}> = Checked::<{generic::<u16>}>;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `{generic::<u32> as fn(usize) -> bool}`, found `{generic::<u16> as fn(usize) -> bool}`
|
= note: expected type `{generic::<u32> as fn(usize) -> bool}`
found type `{generic::<u16> as fn(usize) -> bool}`
error: aborting due to 4 previous errors; 1 warning emitted
Some errors have detailed explanations: E0282, E0308.
For more information about an error, try `rustc --explain E0282`.

View File

@ -1,12 +1,11 @@
// run-pass
#![feature(const_generics, const_compare_raw_pointers)]
#![feature(const_generics)]
//~^ WARN the feature `const_generics` is incomplete
const A: u32 = 3;
struct Const<const P: *const u32>;
struct Const<const P: *const u32>; //~ ERROR: using raw pointers as const generic parameters
impl<const P: *const u32> Const<P> {
impl<const P: *const u32> Const<P> { //~ ERROR: using raw pointers as const generic parameters
fn get() -> u32 {
unsafe {
*P

View File

@ -1,11 +1,23 @@
warning: the feature `const_generics` is incomplete and may not be safe to use and/or cause compiler crashes
--> $DIR/raw-ptr-const-param-deref.rs:2:12
--> $DIR/raw-ptr-const-param-deref.rs:1:12
|
LL | #![feature(const_generics, const_compare_raw_pointers)]
LL | #![feature(const_generics)]
| ^^^^^^^^^^^^^^
|
= note: `#[warn(incomplete_features)]` on by default
= note: see issue #44580 <https://github.com/rust-lang/rust/issues/44580> for more information
warning: 1 warning emitted
error: using raw pointers as const generic parameters is forbidden
--> $DIR/raw-ptr-const-param-deref.rs:6:23
|
LL | struct Const<const P: *const u32>;
| ^^^^^^^^^^
error: using raw pointers as const generic parameters is forbidden
--> $DIR/raw-ptr-const-param-deref.rs:8:15
|
LL | impl<const P: *const u32> Const<P> {
| ^^^^^^^^^^
error: aborting due to 2 previous errors; 1 warning emitted

View File

@ -1,9 +1,9 @@
#![feature(const_generics, const_compare_raw_pointers)]
#![feature(const_generics)]
//~^ WARN the feature `const_generics` is incomplete
struct Const<const P: *const u32>;
struct Const<const P: *const u32>; //~ ERROR: using raw pointers as const generic parameters
fn main() {
let _: Const<{ 15 as *const _ }> = Const::<{ 10 as *const _ }>; //~ mismatched types
let _: Const<{ 15 as *const _ }> = Const::<{ 10 as *const _ }>;
let _: Const<{ 10 as *const _ }> = Const::<{ 10 as *const _ }>;
}

View File

@ -1,21 +1,17 @@
warning: the feature `const_generics` is incomplete and may not be safe to use and/or cause compiler crashes
--> $DIR/raw-ptr-const-param.rs:1:12
|
LL | #![feature(const_generics, const_compare_raw_pointers)]
LL | #![feature(const_generics)]
| ^^^^^^^^^^^^^^
|
= note: `#[warn(incomplete_features)]` on by default
= note: see issue #44580 <https://github.com/rust-lang/rust/issues/44580> for more information
error[E0308]: mismatched types
--> $DIR/raw-ptr-const-param.rs:7:40
error: using raw pointers as const generic parameters is forbidden
--> $DIR/raw-ptr-const-param.rs:4:23
|
LL | let _: Const<{ 15 as *const _ }> = Const::<{ 10 as *const _ }>;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `{0xf as *const u32}`, found `{0xa as *const u32}`
|
= note: expected type `{0xf as *const u32}`
found type `{0xa as *const u32}`
LL | struct Const<const P: *const u32>;
| ^^^^^^^^^^
error: aborting due to previous error; 1 warning emitted
For more information about this error, try `rustc --explain E0308`.

View File

@ -2,25 +2,33 @@ error[E0493]: destructors cannot be evaluated at compile-time
--> $DIR/const_let.rs:16:32
|
LL | const Y: FakeNeedsDrop = { let mut x = FakeNeedsDrop; x = FakeNeedsDrop; x };
| ^^^^^ constants cannot evaluate destructors
| ^^^^^ - value is dropped here
| |
| constants cannot evaluate destructors
error[E0493]: destructors cannot be evaluated at compile-time
--> $DIR/const_let.rs:20:33
|
LL | const Y2: FakeNeedsDrop = { let mut x; x = FakeNeedsDrop; x = FakeNeedsDrop; x };
| ^^^^^ constants cannot evaluate destructors
| ^^^^^ - value is dropped here
| |
| constants cannot evaluate destructors
error[E0493]: destructors cannot be evaluated at compile-time
--> $DIR/const_let.rs:24:21
|
LL | const Z: () = { let mut x = None; x = Some(FakeNeedsDrop); };
| ^^^^^ constants cannot evaluate destructors
| ^^^^^ - value is dropped here
| |
| constants cannot evaluate destructors
error[E0493]: destructors cannot be evaluated at compile-time
--> $DIR/const_let.rs:28:22
|
LL | const Z2: () = { let mut x; x = None; x = Some(FakeNeedsDrop); };
| ^^^^^ constants cannot evaluate destructors
| ^^^^^ - value is dropped here
| |
| constants cannot evaluate destructors
error: aborting due to 4 previous errors

View File

@ -1,17 +1,6 @@
#![feature(const_raw_ptr_to_usize_cast, const_compare_raw_pointers, const_raw_ptr_deref)]
fn main() {}
// unconst and bad, will thus error in miri
const X: bool = unsafe { &1 as *const i32 == &2 as *const i32 }; //~ ERROR any use of this
const X: bool = unsafe { &1 as *const i32 == &2 as *const i32 }; //~ ERROR cannot be reliably
// unconst and bad, will thus error in miri
const X2: bool = unsafe { 42 as *const i32 == 43 as *const i32 }; //~ ERROR any use of this
// unconst and fine
const Y: usize = unsafe { 42usize as *const i32 as usize + 1 };
// unconst and bad, will thus error in miri
const Y2: usize = unsafe { &1 as *const i32 as usize + 1 }; //~ ERROR any use of this
// unconst and fine
const Z: i32 = unsafe { *(&1 as *const i32) };
// unconst and bad, will thus error in miri
const Z2: i32 = unsafe { *(42 as *const i32) }; //~ ERROR any use of this value will cause
const Z3: i32 = unsafe { *(44 as *const i32) }; //~ ERROR any use of this value will cause
const X2: bool = unsafe { 42 as *const i32 == 43 as *const i32 }; //~ ERROR cannot be reliably

View File

@ -1,44 +1,18 @@
error: any use of this value will cause an error
--> $DIR/const_raw_ptr_ops.rs:6:26
error: pointers cannot be reliably compared during const eval.
--> $DIR/const_raw_ptr_ops.rs:4:26
|
LL | const X: bool = unsafe { &1 as *const i32 == &2 as *const i32 };
| -------------------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^---
| |
| "pointer arithmetic or comparison" needs an rfc before being allowed inside constants
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: `#[deny(const_err)]` on by default
= note: see issue #53020 <https://github.com/rust-lang/rust/issues/53020> for more information
error: any use of this value will cause an error
--> $DIR/const_raw_ptr_ops.rs:8:27
error: pointers cannot be reliably compared during const eval.
--> $DIR/const_raw_ptr_ops.rs:6:27
|
LL | const X2: bool = unsafe { 42 as *const i32 == 43 as *const i32 };
| --------------------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^---
| |
| "pointer arithmetic or comparison" needs an rfc before being allowed inside constants
error: any use of this value will cause an error
--> $DIR/const_raw_ptr_ops.rs:12:28
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
LL | const Y2: usize = unsafe { &1 as *const i32 as usize + 1 };
| ---------------------------^^^^^^^^^^^^^^^^^^^^^^^^^-------
| |
| "pointer-to-integer cast" needs an rfc before being allowed inside constants
= note: see issue #53020 <https://github.com/rust-lang/rust/issues/53020> for more information
error: any use of this value will cause an error
--> $DIR/const_raw_ptr_ops.rs:16:26
|
LL | const Z2: i32 = unsafe { *(42 as *const i32) };
| -------------------------^^^^^^^^^^^^^^^^^^^---
| |
| unable to turn bytes into a pointer
error: any use of this value will cause an error
--> $DIR/const_raw_ptr_ops.rs:17:26
|
LL | const Z3: i32 = unsafe { *(44 as *const i32) };
| -------------------------^^^^^^^^^^^^^^^^^^^---
| |
| unable to turn bytes into a pointer
error: aborting due to 5 previous errors
error: aborting due to 2 previous errors

View File

@ -0,0 +1,13 @@
#![feature(const_raw_ptr_to_usize_cast, const_raw_ptr_deref)]
fn main() {}
// unconst and fine
const Y: usize = unsafe { 42usize as *const i32 as usize + 1 };
// unconst and bad, will thus error in miri
const Y2: usize = unsafe { &1 as *const i32 as usize + 1 }; //~ ERROR any use of this
// unconst and fine
const Z: i32 = unsafe { *(&1 as *const i32) };
// unconst and bad, will thus error in miri
const Z2: i32 = unsafe { *(42 as *const i32) }; //~ ERROR any use of this value will cause
const Z3: i32 = unsafe { *(44 as *const i32) }; //~ ERROR any use of this value will cause

View File

@ -0,0 +1,28 @@
error: any use of this value will cause an error
--> $DIR/const_raw_ptr_ops2.rs:8:28
|
LL | const Y2: usize = unsafe { &1 as *const i32 as usize + 1 };
| ---------------------------^^^^^^^^^^^^^^^^^^^^^^^^^-------
| |
| "pointer-to-integer cast" needs an rfc before being allowed inside constants
|
= note: `#[deny(const_err)]` on by default
error: any use of this value will cause an error
--> $DIR/const_raw_ptr_ops2.rs:12:26
|
LL | const Z2: i32 = unsafe { *(42 as *const i32) };
| -------------------------^^^^^^^^^^^^^^^^^^^---
| |
| unable to turn bytes into a pointer
error: any use of this value will cause an error
--> $DIR/const_raw_ptr_ops2.rs:13:26
|
LL | const Z3: i32 = unsafe { *(44 as *const i32) };
| -------------------------^^^^^^^^^^^^^^^^^^^---
| |
| unable to turn bytes into a pointer
error: aborting due to 3 previous errors

View File

@ -9,6 +9,9 @@ error[E0493]: destructors cannot be evaluated at compile-time
|
LL | let mut x = Vec::<i32>::new();
| ^^^^^ constants cannot evaluate destructors
...
LL | };
| - value is dropped here
error: aborting due to 2 previous errors

View File

@ -0,0 +1,20 @@
#![feature(const_if_match)]
#![feature(const_loop)]
const _: Option<Vec<i32>> = {
let mut never_returned = Some(Vec::new());
let mut always_returned = None; //~ ERROR destructors cannot be evaluated at compile-time
let mut i = 0;
loop {
always_returned = never_returned;
never_returned = None;
i += 1;
if i == 10 {
break always_returned;
}
}
};
fn main() {}

View File

@ -0,0 +1,12 @@
error[E0493]: destructors cannot be evaluated at compile-time
--> $DIR/livedrop.rs:6:9
|
LL | let mut always_returned = None;
| ^^^^^^^^^^^^^^^^^^^ constants cannot evaluate destructors
...
LL | always_returned = never_returned;
| --------------- value is dropped here
error: aborting due to previous error
For more information about this error, try `rustc --explain E0493`.

View File

@ -1,4 +1,4 @@
#![feature(const_raw_ptr_to_usize_cast, const_compare_raw_pointers, const_raw_ptr_deref)]
#![feature(const_raw_ptr_to_usize_cast, const_raw_ptr_deref)]
fn main() {
let x: &'static bool = &(42 as *const i32 == 43 as *const i32);

View File

@ -3,24 +3,36 @@ error[E0493]: destructors cannot be evaluated at compile-time
|
LL | let x = Some(Vec::new());
| ^ constants cannot evaluate destructors
...
LL | };
| - value is dropped here
error[E0493]: destructors cannot be evaluated at compile-time
--> $DIR/drop-fail.rs:23:9
|
LL | let vec_tuple = (Vec::new(),);
| ^^^^^^^^^ constants cannot evaluate destructors
...
LL | };
| - value is dropped here
error[E0493]: destructors cannot be evaluated at compile-time
--> $DIR/drop-fail.rs:31:9
|
LL | let x: Result<_, Vec<i32>> = Ok(Vec::new());
| ^ constants cannot evaluate destructors
...
LL | };
| - value is dropped here
error[E0493]: destructors cannot be evaluated at compile-time
--> $DIR/drop-fail.rs:41:9
|
LL | let mut tmp = None;
| ^^^^^^^ constants cannot evaluate destructors
...
LL | };
| - value is dropped here
error: aborting due to 4 previous errors

View File

@ -2,7 +2,9 @@ error[E0493]: destructors cannot be evaluated at compile-time
--> $DIR/min_const_fn.rs:37:25
|
LL | const fn into_inner(self) -> T { self.0 }
| ^^^^ constant functions cannot evaluate destructors
| ^^^^ - value is dropped here
| |
| constant functions cannot evaluate destructors
error[E0723]: mutable references in const fn are unstable
--> $DIR/min_const_fn.rs:39:36
@ -17,7 +19,9 @@ error[E0493]: destructors cannot be evaluated at compile-time
--> $DIR/min_const_fn.rs:44:28
|
LL | const fn into_inner_lt(self) -> T { self.0 }
| ^^^^ constant functions cannot evaluate destructors
| ^^^^ - value is dropped here
| |
| constant functions cannot evaluate destructors
error[E0723]: mutable references in const fn are unstable
--> $DIR/min_const_fn.rs:46:42
@ -32,7 +36,9 @@ error[E0493]: destructors cannot be evaluated at compile-time
--> $DIR/min_const_fn.rs:51:27
|
LL | const fn into_inner_s(self) -> T { self.0 }
| ^^^^ constant functions cannot evaluate destructors
| ^^^^ - value is dropped here
| |
| constant functions cannot evaluate destructors
error[E0723]: mutable references in const fn are unstable
--> $DIR/min_const_fn.rs:53:38

View File

@ -2,7 +2,9 @@ error[E0493]: destructors cannot be evaluated at compile-time
--> $DIR/feature-gate-unleash_the_miri_inside_of_you.rs:11:20
|
LL | const F: u32 = (U::X, 42).1;
| ^^^^^^^^^^ constants cannot evaluate destructors
| ^^^^^^^^^^ - value is dropped here
| |
| constants cannot evaluate destructors
error: aborting due to previous error

View File

@ -12,7 +12,7 @@ LL | let _v = x + 0;
warning: skipping const checks
|
help: skipping check for `const_compare_raw_pointers` feature
help: skipping check that does not even have a feature gate
--> $DIR/ptr_arith.rs:9:14
|
LL | let _v = x == x;

View File

@ -0,0 +1,17 @@
// compile-flags: -Zunleash-the-miri-inside-of-you
// run-pass
#![feature(const_raw_ptr_comparison)]
const EMPTY_SLICE: &[i32] = &[];
const EMPTY_EQ: bool = EMPTY_SLICE.as_ptr().guaranteed_eq(&[] as *const _);
const EMPTY_EQ2: bool = EMPTY_SLICE.as_ptr().guaranteed_ne(&[] as *const _);
const EMPTY_NE: bool = EMPTY_SLICE.as_ptr().guaranteed_ne(&[1] as *const _);
const EMPTY_NE2: bool = EMPTY_SLICE.as_ptr().guaranteed_eq(&[1] as *const _);
fn main() {
assert!(!EMPTY_EQ);
assert!(!EMPTY_EQ2);
assert!(!EMPTY_NE);
assert!(!EMPTY_NE2);
}

View File

@ -9,12 +9,18 @@ error[E0493]: destructors cannot be evaluated at compile-time
|
LL | const fn unwrap_or_else<F: FnOnce() -> T>(self, f: F) -> T {
| ^ constant functions cannot evaluate destructors
...
LL | }
| - value is dropped here
error[E0493]: destructors cannot be evaluated at compile-time
--> $DIR/unstable-const-fn-in-libcore.rs:19:47
|
LL | const fn unwrap_or_else<F: FnOnce() -> T>(self, f: F) -> T {
| ^^^^ constant functions cannot evaluate destructors
...
LL | }
| - value is dropped here
error: aborting due to 3 previous errors

View File

@ -1,10 +1,8 @@
// gate-test-const_compare_raw_pointers
static FOO: i32 = 42;
static BAR: i32 = 42;
static BAZ: bool = unsafe { (&FOO as *const i32) == (&BAR as *const i32) };
//~^ ERROR comparing raw pointers inside static
//~^ ERROR pointers cannot be reliably compared during const eval
fn main() {
}

View File

@ -1,12 +1,10 @@
error[E0658]: comparing raw pointers inside static
--> $DIR/E0395.rs:6:29
error: pointers cannot be reliably compared during const eval.
--> $DIR/E0395.rs:4:29
|
LL | static BAZ: bool = unsafe { (&FOO as *const i32) == (&BAR as *const i32) };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: see issue #53020 <https://github.com/rust-lang/rust/issues/53020> for more information
= help: add `#![feature(const_compare_raw_pointers)]` to the crate attributes to enable
error: aborting due to previous error
For more information about this error, try `rustc --explain E0658`.

View File

@ -1,9 +1,9 @@
struct ConstFn<const F: fn()>;
//~^ ERROR const generics are unstable
//~^^ ERROR using function pointers as const generic parameters is unstable
//~^^ ERROR using function pointers as const generic parameters is forbidden
struct ConstPtr<const P: *const u32>;
//~^ ERROR const generics are unstable
//~^^ ERROR using raw pointers as const generic parameters is unstable
//~^^ ERROR using raw pointers as const generic parameters is forbidden
fn main() {}

View File

@ -16,23 +16,17 @@ LL | struct ConstPtr<const P: *const u32>;
= note: see issue #44580 <https://github.com/rust-lang/rust/issues/44580> for more information
= help: add `#![feature(const_generics)]` to the crate attributes to enable
error[E0658]: using function pointers as const generic parameters is unstable
error: using function pointers as const generic parameters is forbidden
--> $DIR/feature-gate-const_generics-ptr.rs:1:25
|
LL | struct ConstFn<const F: fn()>;
| ^^^^
|
= note: see issue #53020 <https://github.com/rust-lang/rust/issues/53020> for more information
= help: add `#![feature(const_compare_raw_pointers)]` to the crate attributes to enable
error[E0658]: using raw pointers as const generic parameters is unstable
error: using raw pointers as const generic parameters is forbidden
--> $DIR/feature-gate-const_generics-ptr.rs:5:26
|
LL | struct ConstPtr<const P: *const u32>;
| ^^^^^^^^^^
|
= note: see issue #53020 <https://github.com/rust-lang/rust/issues/53020> for more information
= help: add `#![feature(const_compare_raw_pointers)]` to the crate attributes to enable
error: aborting due to 4 previous errors

View File

@ -0,0 +1,8 @@
error: higher-ranked subtype error
--> $DIR/resume-arg-late-bound.rs:15:5
|
LL | test(gen);
| ^^^^^^^^^
error: aborting due to previous error

View File

@ -13,5 +13,6 @@ fn main() {
*arg = true;
};
test(gen);
//~^ ERROR type mismatch in function arguments
//~^ ERROR mismatched types
//~| ERROR mismatched types
}

Some files were not shown because too many files have changed in this diff Show More