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:
commit
1557fb031b
@ -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)
|
||||
|
@ -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:
|
||||
|
||||
|
@ -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)
|
||||
|
@ -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
|
||||
|
@ -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)]
|
||||
|
@ -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>()`.
|
||||
///
|
||||
|
@ -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>()`.
|
||||
///
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
@ -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!
|
||||
```
|
||||
|
@ -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),
|
||||
|
||||
|
@ -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
|
||||
// -------------------------------------------------------------------------
|
||||
|
@ -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() {
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -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,
|
||||
);
|
||||
}
|
||||
_ => {}
|
||||
},
|
||||
_ => {}
|
||||
}
|
||||
|
@ -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,
|
||||
)
|
||||
}
|
||||
|
@ -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(())
|
||||
})
|
||||
}
|
||||
|
@ -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) {
|
||||
|
@ -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))
|
||||
}
|
||||
}
|
||||
|
@ -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)]
|
||||
|
@ -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)> {
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -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),
|
||||
|
@ -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()?;
|
||||
|
@ -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.
|
||||
//!
|
||||
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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,
|
||||
|
@ -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);
|
||||
|
@ -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)
|
||||
})
|
||||
}
|
||||
|
@ -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));
|
||||
}
|
||||
});
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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
|
||||
{
|
||||
|
@ -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;
|
||||
|
@ -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();
|
||||
|
@ -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)
|
||||
}
|
||||
|
@ -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()
|
||||
{
|
||||
|
@ -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
|
||||
|
@ -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`.
|
@ -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() {}
|
||||
|
@ -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`.
|
||||
|
@ -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`
|
||||
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
||||
|
@ -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`
|
||||
|
||||
|
@ -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
|
||||
|
||||
|
@ -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]
|
||||
|
@ -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`
|
||||
|
||||
|
@ -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<'_>`
|
||||
|
||||
|
@ -0,0 +1,8 @@
|
||||
error: higher-ranked subtype error
|
||||
--> $DIR/higher-ranked-projection.rs:25:5
|
||||
|
|
||||
LL | foo(());
|
||||
| ^^^^^^^
|
||||
|
||||
error: aborting due to previous error
|
||||
|
@ -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`.
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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`.
|
||||
|
@ -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() {}
|
||||
|
@ -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`.
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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`.
|
||||
|
@ -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() {}
|
@ -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`.
|
26
src/test/ui/coherence/coherence-fn-implied-bounds.rs
Normal file
26
src/test/ui/coherence/coherence-fn-implied-bounds.rs
Normal 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() {}
|
20
src/test/ui/coherence/coherence-fn-implied-bounds.stderr
Normal file
20
src/test/ui/coherence/coherence-fn-implied-bounds.stderr
Normal 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
|
||||
|
25
src/test/ui/coherence/coherence-fn-inputs.rs
Normal file
25
src/test/ui/coherence/coherence-fn-inputs.rs
Normal 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() {}
|
13
src/test/ui/coherence/coherence-fn-inputs.stderr
Normal file
13
src/test/ui/coherence/coherence-fn-inputs.stderr
Normal 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`.
|
21
src/test/ui/coherence/coherence-free-vs-bound-region.rs
Normal file
21
src/test/ui/coherence/coherence-free-vs-bound-region.rs
Normal 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() {}
|
20
src/test/ui/coherence/coherence-free-vs-bound-region.stderr
Normal file
20
src/test/ui/coherence/coherence-free-vs-bound-region.stderr
Normal 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
|
||||
|
37
src/test/ui/coherence/coherence-wasm-bindgen.rs
Normal file
37
src/test/ui/coherence/coherence-wasm-bindgen.rs
Normal 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() {}
|
32
src/test/ui/coherence/coherence-wasm-bindgen.stderr
Normal file
32
src/test/ui/coherence/coherence-wasm-bindgen.stderr
Normal 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
|
||||
|
@ -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
|
||||
|
||||
|
@ -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()
|
||||
}
|
||||
|
@ -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
|
||||
|
||||
|
@ -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>}>;
|
||||
}
|
||||
|
@ -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`.
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
||||
|
@ -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 _ }>;
|
||||
}
|
||||
|
@ -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`.
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
||||
|
13
src/test/ui/consts/const-eval/const_raw_ptr_ops2.rs
Normal file
13
src/test/ui/consts/const-eval/const_raw_ptr_ops2.rs
Normal 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
|
28
src/test/ui/consts/const-eval/const_raw_ptr_ops2.stderr
Normal file
28
src/test/ui/consts/const-eval/const_raw_ptr_ops2.stderr
Normal 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
|
||||
|
@ -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
|
||||
|
||||
|
20
src/test/ui/consts/const-eval/livedrop.rs
Normal file
20
src/test/ui/consts/const-eval/livedrop.rs
Normal 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() {}
|
12
src/test/ui/consts/const-eval/livedrop.stderr
Normal file
12
src/test/ui/consts/const-eval/livedrop.stderr
Normal 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`.
|
@ -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);
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
||||
|
@ -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;
|
||||
|
17
src/test/ui/consts/miri_unleashed/slice_eq.rs
Normal file
17
src/test/ui/consts/miri_unleashed/slice_eq.rs
Normal 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);
|
||||
}
|
@ -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
|
||||
|
||||
|
@ -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() {
|
||||
}
|
||||
|
@ -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`.
|
||||
|
@ -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() {}
|
||||
|
@ -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
|
||||
|
||||
|
8
src/test/ui/generator/resume-arg-late-bound.nll.stderr
Normal file
8
src/test/ui/generator/resume-arg-late-bound.nll.stderr
Normal 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
|
||||
|
@ -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
Loading…
x
Reference in New Issue
Block a user