Auto merge of #123108 - matthiaskrgr:rollup-zossklv, r=matthiaskrgr
Rollup of 9 pull requests Successful merges: - #108675 (Document `adt_const_params` feature in Unstable Book) - #122120 (Suggest associated type bounds on problematic associated equality bounds) - #122589 (Fix diagnostics for async block cloning) - #122835 (Require `DerefMut` and `DerefPure` on `deref!()` patterns when appropriate) - #123049 (In `ConstructCoroutineInClosureShim`, pass receiver by mut ref, not mut pointer) - #123055 (enable cargo miri test doctests) - #123057 (unix fs: Make hurd using explicit new rather than From) - #123087 (Change `f16` and `f128` clippy stubs to be nonpanicking) - #123103 (Rename `Inherited` -> `TypeckRootCtxt`) r? `@ghost` `@rustbot` modify labels: rollup
This commit is contained in:
commit
a1b499134a
compiler
rustc_borrowck/src/diagnostics
rustc_hir/src
rustc_hir_analysis/src/hir_ty_lowering
rustc_hir_typeck/src
rustc_middle/src/ty
rustc_mir_transform/src
rustc_parse
rustc_span/src
rustc_ty_utils/src
library
alloc/src
core/src/ops
std/src/sys/pal/unix
src
bootstrap/src/core/build_steps
doc/unstable-book/src/language-features
tools
clippy/clippy_lints/src
miri
tests
mir-opt
async_closure_shims.main-{closure#0}-{closure#1}.coroutine_closure_by_ref.0.panic-abort.mirasync_closure_shims.main-{closure#0}-{closure#1}.coroutine_closure_by_ref.0.panic-unwind.mir
ui
associated-type-bounds
borrowck
parser/recover
pattern/deref-patterns
@ -4,6 +4,7 @@
|
||||
#![allow(rustc::untranslatable_diagnostic)]
|
||||
|
||||
use either::Either;
|
||||
use hir::ClosureKind;
|
||||
use rustc_data_structures::captures::Captures;
|
||||
use rustc_data_structures::fx::FxIndexSet;
|
||||
use rustc_errors::{codes::*, struct_span_code_err, Applicability, Diag, MultiSpan};
|
||||
@ -463,6 +464,15 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
||||
} else if let UseSpans::FnSelfUse { kind: CallKind::Normal { .. }, .. } = move_spans
|
||||
{
|
||||
// We already suggest cloning for these cases in `explain_captures`.
|
||||
} else if let UseSpans::ClosureUse {
|
||||
closure_kind:
|
||||
ClosureKind::Coroutine(CoroutineKind::Desugared(_, CoroutineSource::Block)),
|
||||
args_span: _,
|
||||
capture_kind_span: _,
|
||||
path_span,
|
||||
} = move_spans
|
||||
{
|
||||
self.suggest_cloning(err, ty, expr, path_span);
|
||||
} else if self.suggest_hoisting_call_outside_loop(err, expr) {
|
||||
// The place where the the type moves would be misleading to suggest clone.
|
||||
// #121466
|
||||
@ -621,7 +631,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
||||
}
|
||||
|
||||
// FIXME: We make sure that this is a normal top-level binding,
|
||||
// but we could suggest `todo!()` for all uninitalized bindings in the pattern pattern
|
||||
// but we could suggest `todo!()` for all uninitialized bindings in the pattern pattern
|
||||
if let hir::StmtKind::Let(hir::LetStmt { span, ty, init: None, pat, .. }) =
|
||||
&ex.kind
|
||||
&& let hir::PatKind::Binding(..) = pat.kind
|
||||
@ -749,7 +759,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
||||
true
|
||||
}
|
||||
|
||||
/// In a move error that occurs on a call wihtin a loop, we try to identify cases where cloning
|
||||
/// In a move error that occurs on a call within a loop, we try to identify cases where cloning
|
||||
/// the value would lead to a logic error. We infer these cases by seeing if the moved value is
|
||||
/// part of the logic to break the loop, either through an explicit `break` or if the expression
|
||||
/// is part of a `while let`.
|
||||
@ -950,7 +960,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
||||
{
|
||||
// FIXME: We could check that the call's *parent* takes `&mut val` to make the
|
||||
// suggestion more targeted to the `mk_iter(val).next()` case. Maybe do that only to
|
||||
// check for wheter to suggest `let value` or `let mut value`.
|
||||
// check for whether to suggest `let value` or `let mut value`.
|
||||
|
||||
let span = in_loop.span;
|
||||
if !finder.found_breaks.is_empty()
|
||||
|
@ -2289,21 +2289,15 @@ pub enum ImplItemKind<'hir> {
|
||||
Type(&'hir Ty<'hir>),
|
||||
}
|
||||
|
||||
/// Bind a type to an associated type (i.e., `A = Foo`).
|
||||
/// An associated item binding.
|
||||
///
|
||||
/// Bindings like `A: Debug` are represented as a special type `A =
|
||||
/// $::Debug` that is understood by the HIR ty lowering code.
|
||||
/// ### Examples
|
||||
///
|
||||
/// FIXME(alexreg): why have a separate type for the binding case,
|
||||
/// wouldn't it be better to make the `ty` field an enum like the
|
||||
/// following?
|
||||
///
|
||||
/// ```ignore (pseudo-rust)
|
||||
/// enum TypeBindingKind {
|
||||
/// Equals(...),
|
||||
/// Binding(...),
|
||||
/// }
|
||||
/// ```
|
||||
/// * `Trait<A = Ty, B = Ty>`
|
||||
/// * `Trait<G<Ty> = Ty>`
|
||||
/// * `Trait<A: Bound>`
|
||||
/// * `Trait<C = { Ct }>` (under feature `associated_const_equality`)
|
||||
/// * `Trait<f(): Bound>` (under feature `return_type_notation`)
|
||||
#[derive(Debug, Clone, Copy, HashStable_Generic)]
|
||||
pub struct TypeBinding<'hir> {
|
||||
pub hir_id: HirId,
|
||||
@ -2336,7 +2330,7 @@ impl<'hir> From<AnonConst> for Term<'hir> {
|
||||
pub enum TypeBindingKind<'hir> {
|
||||
/// E.g., `Foo<Bar: Send>`.
|
||||
Constraint { bounds: &'hir [GenericBound<'hir>] },
|
||||
/// E.g., `Foo<Bar = ()>`, `Foo<Bar = ()>`
|
||||
/// E.g., `Foo<Bar = ()>`.
|
||||
Equality { term: Term<'hir> },
|
||||
}
|
||||
|
||||
|
@ -199,6 +199,7 @@ language_item_table! {
|
||||
|
||||
Deref, sym::deref, deref_trait, Target::Trait, GenericRequirement::Exact(0);
|
||||
DerefMut, sym::deref_mut, deref_mut_trait, Target::Trait, GenericRequirement::Exact(0);
|
||||
DerefPure, sym::deref_pure, deref_pure_trait, Target::Trait, GenericRequirement::Exact(0);
|
||||
DerefTarget, sym::deref_target, deref_target, Target::AssocTy, GenericRequirement::None;
|
||||
Receiver, sym::receiver, receiver_trait, Target::Trait, GenericRequirement::None;
|
||||
|
||||
|
@ -9,8 +9,85 @@ use rustc_trait_selection::traits::error_reporting::suggestions::NextTypeParamNa
|
||||
use super::HirTyLowerer;
|
||||
|
||||
impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
||||
/// Prohibit or lint against *bare* trait object types depending on the edition.
|
||||
///
|
||||
/// *Bare* trait object types are ones that aren't preceeded by the keyword `dyn`.
|
||||
/// In edition 2021 and onward we emit a hard error for them.
|
||||
pub(super) fn prohibit_or_lint_bare_trait_object_ty(
|
||||
&self,
|
||||
self_ty: &hir::Ty<'_>,
|
||||
in_path: bool,
|
||||
) {
|
||||
let tcx = self.tcx();
|
||||
|
||||
let hir::TyKind::TraitObject([poly_trait_ref, ..], _, TraitObjectSyntax::None) =
|
||||
self_ty.kind
|
||||
else {
|
||||
return;
|
||||
};
|
||||
|
||||
let needs_bracket = in_path
|
||||
&& !tcx
|
||||
.sess
|
||||
.source_map()
|
||||
.span_to_prev_source(self_ty.span)
|
||||
.ok()
|
||||
.is_some_and(|s| s.trim_end().ends_with('<'));
|
||||
|
||||
let is_global = poly_trait_ref.trait_ref.path.is_global();
|
||||
|
||||
let mut sugg = vec![(
|
||||
self_ty.span.shrink_to_lo(),
|
||||
format!(
|
||||
"{}dyn {}",
|
||||
if needs_bracket { "<" } else { "" },
|
||||
if is_global { "(" } else { "" },
|
||||
),
|
||||
)];
|
||||
|
||||
if is_global || needs_bracket {
|
||||
sugg.push((
|
||||
self_ty.span.shrink_to_hi(),
|
||||
format!(
|
||||
"{}{}",
|
||||
if is_global { ")" } else { "" },
|
||||
if needs_bracket { ">" } else { "" },
|
||||
),
|
||||
));
|
||||
}
|
||||
|
||||
if self_ty.span.edition().at_least_rust_2021() {
|
||||
let msg = "trait objects must include the `dyn` keyword";
|
||||
let label = "add `dyn` keyword before this trait";
|
||||
let mut diag =
|
||||
rustc_errors::struct_span_code_err!(tcx.dcx(), self_ty.span, E0782, "{}", msg);
|
||||
if self_ty.span.can_be_used_for_suggestions()
|
||||
&& !self.maybe_suggest_impl_trait(self_ty, &mut diag)
|
||||
{
|
||||
// FIXME: Only emit this suggestion if the trait is object safe.
|
||||
diag.multipart_suggestion_verbose(label, sugg, Applicability::MachineApplicable);
|
||||
}
|
||||
// Check if the impl trait that we are considering is an impl of a local trait.
|
||||
self.maybe_suggest_blanket_trait_impl(self_ty, &mut diag);
|
||||
self.maybe_suggest_assoc_ty_bound(self_ty, &mut diag);
|
||||
diag.stash(self_ty.span, StashKey::TraitMissingMethod);
|
||||
} else {
|
||||
let msg = "trait objects without an explicit `dyn` are deprecated";
|
||||
tcx.node_span_lint(BARE_TRAIT_OBJECTS, self_ty.hir_id, self_ty.span, msg, |lint| {
|
||||
if self_ty.span.can_be_used_for_suggestions() {
|
||||
lint.multipart_suggestion_verbose(
|
||||
"if this is an object-safe trait, use `dyn`",
|
||||
sugg,
|
||||
Applicability::MachineApplicable,
|
||||
);
|
||||
}
|
||||
self.maybe_suggest_blanket_trait_impl(self_ty, lint);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/// Make sure that we are in the condition to suggest the blanket implementation.
|
||||
pub(super) fn maybe_lint_blanket_trait_impl<G: EmissionGuarantee>(
|
||||
fn maybe_suggest_blanket_trait_impl<G: EmissionGuarantee>(
|
||||
&self,
|
||||
self_ty: &hir::Ty<'_>,
|
||||
diag: &mut Diag<'_, G>,
|
||||
@ -75,9 +152,11 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
||||
}
|
||||
|
||||
/// Make sure that we are in the condition to suggest `impl Trait`.
|
||||
fn maybe_lint_impl_trait(&self, self_ty: &hir::Ty<'_>, diag: &mut Diag<'_>) -> bool {
|
||||
fn maybe_suggest_impl_trait(&self, self_ty: &hir::Ty<'_>, diag: &mut Diag<'_>) -> bool {
|
||||
let tcx = self.tcx();
|
||||
let parent_id = tcx.hir().get_parent_item(self_ty.hir_id).def_id;
|
||||
// FIXME: If `type_alias_impl_trait` is enabled, also look for `Trait0<Ty = Trait1>`
|
||||
// and suggest `Trait0<Ty = impl Trait1>`.
|
||||
let (sig, generics, owner) = match tcx.hir_node_by_def_id(parent_id) {
|
||||
hir::Node::Item(hir::Item { kind: hir::ItemKind::Fn(sig, generics, _), .. }) => {
|
||||
(sig, generics, None)
|
||||
@ -186,71 +265,37 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
||||
false
|
||||
}
|
||||
|
||||
pub(super) fn maybe_lint_bare_trait(&self, self_ty: &hir::Ty<'_>, in_path: bool) {
|
||||
let tcx = self.tcx();
|
||||
if let hir::TyKind::TraitObject([poly_trait_ref, ..], _, TraitObjectSyntax::None) =
|
||||
self_ty.kind
|
||||
fn maybe_suggest_assoc_ty_bound(&self, self_ty: &hir::Ty<'_>, diag: &mut Diag<'_>) {
|
||||
let mut parents = self.tcx().hir().parent_iter(self_ty.hir_id);
|
||||
|
||||
if let Some((_, hir::Node::TypeBinding(binding))) = parents.next()
|
||||
&& let hir::TypeBindingKind::Equality { term: hir::Term::Ty(obj_ty) } = binding.kind
|
||||
{
|
||||
let needs_bracket = in_path
|
||||
&& !tcx
|
||||
.sess
|
||||
.source_map()
|
||||
.span_to_prev_source(self_ty.span)
|
||||
.ok()
|
||||
.is_some_and(|s| s.trim_end().ends_with('<'));
|
||||
|
||||
let is_global = poly_trait_ref.trait_ref.path.is_global();
|
||||
|
||||
let mut sugg = Vec::from_iter([(
|
||||
self_ty.span.shrink_to_lo(),
|
||||
format!(
|
||||
"{}dyn {}",
|
||||
if needs_bracket { "<" } else { "" },
|
||||
if is_global { "(" } else { "" },
|
||||
),
|
||||
)]);
|
||||
|
||||
if is_global || needs_bracket {
|
||||
sugg.push((
|
||||
self_ty.span.shrink_to_hi(),
|
||||
format!(
|
||||
"{}{}",
|
||||
if is_global { ")" } else { "" },
|
||||
if needs_bracket { ">" } else { "" },
|
||||
),
|
||||
));
|
||||
if let Some((_, hir::Node::TraitRef(..))) = parents.next()
|
||||
&& let Some((_, hir::Node::Ty(ty))) = parents.next()
|
||||
&& let hir::TyKind::TraitObject(..) = ty.kind
|
||||
{
|
||||
// Assoc ty bounds aren't permitted inside trait object types.
|
||||
return;
|
||||
}
|
||||
|
||||
if self_ty.span.edition().at_least_rust_2021() {
|
||||
let msg = "trait objects must include the `dyn` keyword";
|
||||
let label = "add `dyn` keyword before this trait";
|
||||
let mut diag =
|
||||
rustc_errors::struct_span_code_err!(tcx.dcx(), self_ty.span, E0782, "{}", msg);
|
||||
if self_ty.span.can_be_used_for_suggestions()
|
||||
&& !self.maybe_lint_impl_trait(self_ty, &mut diag)
|
||||
{
|
||||
diag.multipart_suggestion_verbose(
|
||||
label,
|
||||
sugg,
|
||||
Applicability::MachineApplicable,
|
||||
);
|
||||
}
|
||||
// check if the impl trait that we are considering is a impl of a local trait
|
||||
self.maybe_lint_blanket_trait_impl(self_ty, &mut diag);
|
||||
diag.stash(self_ty.span, StashKey::TraitMissingMethod);
|
||||
let lo = if binding.gen_args.span_ext.is_dummy() {
|
||||
binding.ident.span
|
||||
} else {
|
||||
let msg = "trait objects without an explicit `dyn` are deprecated";
|
||||
tcx.node_span_lint(BARE_TRAIT_OBJECTS, self_ty.hir_id, self_ty.span, msg, |lint| {
|
||||
if self_ty.span.can_be_used_for_suggestions() {
|
||||
lint.multipart_suggestion_verbose(
|
||||
"if this is an object-safe trait, use `dyn`",
|
||||
sugg,
|
||||
Applicability::MachineApplicable,
|
||||
);
|
||||
}
|
||||
self.maybe_lint_blanket_trait_impl(self_ty, lint);
|
||||
});
|
||||
binding.gen_args.span_ext
|
||||
};
|
||||
let hi = obj_ty.span;
|
||||
|
||||
if !lo.eq_ctxt(hi) {
|
||||
return;
|
||||
}
|
||||
|
||||
diag.span_suggestion_verbose(
|
||||
lo.between(hi),
|
||||
"you might have meant to write a bound here",
|
||||
": ",
|
||||
Applicability::MaybeIncorrect,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -2339,12 +2339,12 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
||||
)
|
||||
}
|
||||
hir::TyKind::TraitObject(bounds, lifetime, repr) => {
|
||||
self.maybe_lint_bare_trait(hir_ty, in_path);
|
||||
self.prohibit_or_lint_bare_trait_object_ty(hir_ty, in_path);
|
||||
|
||||
let repr = match repr {
|
||||
TraitObjectSyntax::Dyn | TraitObjectSyntax::None => ty::Dyn,
|
||||
TraitObjectSyntax::DynStar => ty::DynStar,
|
||||
};
|
||||
|
||||
self.lower_trait_object_ty(
|
||||
hir_ty.span,
|
||||
hir_ty.hir_id,
|
||||
|
@ -243,7 +243,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
let can_coerce_to_return_ty = match self.ret_coercion.as_ref() {
|
||||
Some(ret_coercion) => {
|
||||
let ret_ty = ret_coercion.borrow().expected_ty();
|
||||
let ret_ty = self.inh.infcx.shallow_resolve(ret_ty);
|
||||
let ret_ty = self.infcx.shallow_resolve(ret_ty);
|
||||
self.can_coerce(arm_ty, ret_ty)
|
||||
&& prior_arm.map_or(true, |(_, ty, _)| self.can_coerce(ty, ret_ty))
|
||||
// The match arms need to unify for the case of `impl Trait`.
|
||||
|
@ -848,7 +848,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
bound_vars,
|
||||
);
|
||||
|
||||
let c_result = self.inh.infcx.canonicalize_response(result);
|
||||
let c_result = self.infcx.canonicalize_response(result);
|
||||
self.typeck_results.borrow_mut().user_provided_sigs.insert(expr_def_id, c_result);
|
||||
|
||||
// Normalize only after registering in `user_provided_sigs`.
|
||||
|
@ -347,7 +347,6 @@ impl<'tcx> FnCtxt<'_, 'tcx> {
|
||||
.any(|n| roots_reachable_from_non_diverging.visited(n));
|
||||
|
||||
let infer_var_infos: UnordBag<_> = self
|
||||
.inh
|
||||
.infer_var_info
|
||||
.borrow()
|
||||
.items()
|
||||
|
@ -526,7 +526,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
pub(in super::super) fn resolve_rvalue_scopes(&self, def_id: DefId) {
|
||||
let scope_tree = self.tcx.region_scope_tree(def_id);
|
||||
let rvalue_scopes = { rvalue_scopes::resolve_rvalue_scopes(self, scope_tree, def_id) };
|
||||
let mut typeck_results = self.inh.typeck_results.borrow_mut();
|
||||
let mut typeck_results = self.typeck_results.borrow_mut();
|
||||
typeck_results.rvalue_scopes = rvalue_scopes;
|
||||
}
|
||||
|
||||
|
@ -7,7 +7,7 @@ mod suggestions;
|
||||
use crate::coercion::DynamicCoerceMany;
|
||||
use crate::fallback::DivergingFallbackBehavior;
|
||||
use crate::fn_ctxt::checks::DivergingBlockBehavior;
|
||||
use crate::{CoroutineTypes, Diverges, EnclosingBreakables, Inherited};
|
||||
use crate::{CoroutineTypes, Diverges, EnclosingBreakables, TypeckRootCtxt};
|
||||
use hir::def_id::CRATE_DEF_ID;
|
||||
use rustc_errors::{DiagCtxt, ErrorGuaranteed};
|
||||
use rustc_hir as hir;
|
||||
@ -108,7 +108,7 @@ pub struct FnCtxt<'a, 'tcx> {
|
||||
|
||||
pub(super) enclosing_breakables: RefCell<EnclosingBreakables<'tcx>>,
|
||||
|
||||
pub(super) inh: &'a Inherited<'tcx>,
|
||||
pub(super) root_ctxt: &'a TypeckRootCtxt<'tcx>,
|
||||
|
||||
pub(super) fallback_has_occurred: Cell<bool>,
|
||||
|
||||
@ -118,12 +118,12 @@ pub struct FnCtxt<'a, 'tcx> {
|
||||
|
||||
impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
pub fn new(
|
||||
inh: &'a Inherited<'tcx>,
|
||||
root_ctxt: &'a TypeckRootCtxt<'tcx>,
|
||||
param_env: ty::ParamEnv<'tcx>,
|
||||
body_id: LocalDefId,
|
||||
) -> FnCtxt<'a, 'tcx> {
|
||||
let (diverging_fallback_behavior, diverging_block_behavior) =
|
||||
parse_never_type_options_attr(inh.tcx);
|
||||
parse_never_type_options_attr(root_ctxt.tcx);
|
||||
FnCtxt {
|
||||
body_id,
|
||||
param_env,
|
||||
@ -137,7 +137,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
stack: Vec::new(),
|
||||
by_id: Default::default(),
|
||||
}),
|
||||
inh,
|
||||
root_ctxt,
|
||||
fallback_has_occurred: Cell::new(false),
|
||||
diverging_fallback_behavior,
|
||||
diverging_block_behavior,
|
||||
@ -206,9 +206,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
}
|
||||
|
||||
impl<'a, 'tcx> Deref for FnCtxt<'a, 'tcx> {
|
||||
type Target = Inherited<'tcx>;
|
||||
type Target = TypeckRootCtxt<'tcx>;
|
||||
fn deref(&self) -> &Self::Target {
|
||||
self.inh
|
||||
self.root_ctxt
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -95,8 +95,7 @@ impl<'a, 'tcx> GatherLocalsVisitor<'a, 'tcx> {
|
||||
Some(ref ty) => {
|
||||
let o_ty = self.fcx.lower_ty(ty);
|
||||
|
||||
let c_ty =
|
||||
self.fcx.inh.infcx.canonicalize_user_type_annotation(UserType::Ty(o_ty.raw));
|
||||
let c_ty = self.fcx.infcx.canonicalize_user_type_annotation(UserType::Ty(o_ty.raw));
|
||||
debug!("visit_local: ty.hir_id={:?} o_ty={:?} c_ty={:?}", ty.hir_id, o_ty, c_ty);
|
||||
self.fcx
|
||||
.typeck_results
|
||||
|
@ -31,7 +31,6 @@ pub mod expr_use_visitor;
|
||||
mod fallback;
|
||||
mod fn_ctxt;
|
||||
mod gather_locals;
|
||||
mod inherited;
|
||||
mod intrinsicck;
|
||||
mod mem_categorization;
|
||||
mod method;
|
||||
@ -39,11 +38,12 @@ mod op;
|
||||
mod pat;
|
||||
mod place_op;
|
||||
mod rvalue_scopes;
|
||||
mod typeck_root_ctxt;
|
||||
mod upvar;
|
||||
mod writeback;
|
||||
|
||||
pub use fn_ctxt::FnCtxt;
|
||||
pub use inherited::Inherited;
|
||||
pub use typeck_root_ctxt::TypeckRootCtxt;
|
||||
|
||||
use crate::check::check_fn;
|
||||
use crate::coercion::DynamicCoerceMany;
|
||||
@ -170,11 +170,11 @@ fn typeck_with_fallback<'tcx>(
|
||||
|
||||
let param_env = tcx.param_env(def_id);
|
||||
|
||||
let inh = Inherited::new(tcx, def_id);
|
||||
let root_ctxt = TypeckRootCtxt::new(tcx, def_id);
|
||||
if let Some(inspector) = inspector {
|
||||
inh.infcx.attach_obligation_inspector(inspector);
|
||||
root_ctxt.infcx.attach_obligation_inspector(inspector);
|
||||
}
|
||||
let mut fcx = FnCtxt::new(&inh, param_env, def_id);
|
||||
let mut fcx = FnCtxt::new(&root_ctxt, param_env, def_id);
|
||||
|
||||
if let Some(hir::FnSig { header, decl, .. }) = fn_sig {
|
||||
let fn_sig = if decl.output.get_infer_ret_ty().is_some() {
|
||||
|
@ -388,8 +388,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
|
||||
if !pat_adjustments.is_empty() {
|
||||
debug!("default binding mode is now {:?}", def_bm);
|
||||
self.inh
|
||||
.typeck_results
|
||||
self.typeck_results
|
||||
.borrow_mut()
|
||||
.pat_adjustments_mut()
|
||||
.insert(pat.hir_id, pat_adjustments);
|
||||
@ -614,7 +613,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
_ => BindingMode::convert(ba),
|
||||
};
|
||||
// ...and store it in a side table:
|
||||
self.inh.typeck_results.borrow_mut().pat_binding_modes_mut().insert(pat.hir_id, bm);
|
||||
self.typeck_results.borrow_mut().pat_binding_modes_mut().insert(pat.hir_id, bm);
|
||||
|
||||
debug!("check_pat_ident: pat.hir_id={:?} bm={:?}", pat.hir_id, bm);
|
||||
|
||||
@ -2002,8 +2001,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
pat_info: PatInfo<'tcx, '_>,
|
||||
) -> Ty<'tcx> {
|
||||
let tcx = self.tcx;
|
||||
// FIXME(deref_patterns): use `DerefPure` for soundness
|
||||
// FIXME(deref_patterns): use `DerefMut` when required
|
||||
// Register a `DerefPure` bound, which is required by all `deref!()` pats.
|
||||
self.register_bound(
|
||||
expected,
|
||||
tcx.require_lang_item(hir::LangItem::DerefPure, Some(span)),
|
||||
self.misc(span),
|
||||
);
|
||||
// <expected as Deref>::Target
|
||||
let ty = Ty::new_projection(
|
||||
tcx,
|
||||
@ -2013,6 +2016,19 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
let ty = self.normalize(span, ty);
|
||||
let ty = self.try_structurally_resolve_type(span, ty);
|
||||
self.check_pat(inner, ty, pat_info);
|
||||
|
||||
// Check if the pattern has any `ref mut` bindings, which would require
|
||||
// `DerefMut` to be emitted in MIR building instead of just `Deref`.
|
||||
// We do this *after* checking the inner pattern, since we want to make
|
||||
// sure to apply any match-ergonomics adjustments.
|
||||
if self.typeck_results.borrow().pat_has_ref_mut_binding(inner) {
|
||||
self.register_bound(
|
||||
expected,
|
||||
tcx.require_lang_item(hir::LangItem::DerefMut, Some(span)),
|
||||
self.misc(span),
|
||||
);
|
||||
}
|
||||
|
||||
expected
|
||||
}
|
||||
|
||||
|
@ -16,7 +16,8 @@ use rustc_trait_selection::traits::{self, PredicateObligation, TraitEngine, Trai
|
||||
use std::cell::RefCell;
|
||||
use std::ops::Deref;
|
||||
|
||||
/// Closures defined within the function. For example:
|
||||
// Data shared between a "typeck root" and its nested bodies,
|
||||
/// e.g. closures defined within the function. For example:
|
||||
/// ```ignore (illustrative)
|
||||
/// fn foo() {
|
||||
/// bar(move|| { ... })
|
||||
@ -24,8 +25,9 @@ use std::ops::Deref;
|
||||
/// ```
|
||||
/// Here, the function `foo()` and the closure passed to
|
||||
/// `bar()` will each have their own `FnCtxt`, but they will
|
||||
/// share the inherited fields.
|
||||
pub struct Inherited<'tcx> {
|
||||
/// share the inference context, will process obligations together,
|
||||
/// can access each other's local types (scoping permitted), etc.
|
||||
pub struct TypeckRootCtxt<'tcx> {
|
||||
pub(super) infcx: InferCtxt<'tcx>,
|
||||
|
||||
pub(super) typeck_results: RefCell<ty::TypeckResults<'tcx>>,
|
||||
@ -65,14 +67,14 @@ pub struct Inherited<'tcx> {
|
||||
pub(super) infer_var_info: RefCell<UnordMap<ty::TyVid, ty::InferVarInfo>>,
|
||||
}
|
||||
|
||||
impl<'tcx> Deref for Inherited<'tcx> {
|
||||
impl<'tcx> Deref for TypeckRootCtxt<'tcx> {
|
||||
type Target = InferCtxt<'tcx>;
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&self.infcx
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> Inherited<'tcx> {
|
||||
impl<'tcx> TypeckRootCtxt<'tcx> {
|
||||
pub fn new(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> Self {
|
||||
let hir_owner = tcx.local_def_id_to_hir_id(def_id).owner;
|
||||
|
||||
@ -83,7 +85,7 @@ impl<'tcx> Inherited<'tcx> {
|
||||
.build();
|
||||
let typeck_results = RefCell::new(ty::TypeckResults::new(hir_owner));
|
||||
|
||||
Inherited {
|
||||
TypeckRootCtxt {
|
||||
typeck_results,
|
||||
fulfillment_cx: RefCell::new(<dyn TraitEngine<'_>>::new(&infcx)),
|
||||
infcx,
|
@ -430,6 +430,31 @@ impl<'tcx> TypeckResults<'tcx> {
|
||||
LocalTableInContextMut { hir_owner: self.hir_owner, data: &mut self.pat_adjustments }
|
||||
}
|
||||
|
||||
/// Does the pattern recursively contain a `ref mut` binding in it?
|
||||
///
|
||||
/// This is used to determined whether a `deref` pattern should emit a `Deref`
|
||||
/// or `DerefMut` call for its pattern scrutinee.
|
||||
///
|
||||
/// This is computed from the typeck results since we want to make
|
||||
/// sure to apply any match-ergonomics adjustments, which we cannot
|
||||
/// determine from the HIR alone.
|
||||
pub fn pat_has_ref_mut_binding(&self, pat: &'tcx hir::Pat<'tcx>) -> bool {
|
||||
let mut has_ref_mut = false;
|
||||
pat.walk(|pat| {
|
||||
if let hir::PatKind::Binding(_, id, _, _) = pat.kind
|
||||
&& let Some(ty::BindByReference(ty::Mutability::Mut)) =
|
||||
self.pat_binding_modes().get(id)
|
||||
{
|
||||
has_ref_mut = true;
|
||||
// No need to continue recursing
|
||||
false
|
||||
} else {
|
||||
true
|
||||
}
|
||||
});
|
||||
has_ref_mut
|
||||
}
|
||||
|
||||
/// For a given closure, returns the iterator of `ty::CapturedPlace`s that are captured
|
||||
/// by the closure.
|
||||
pub fn closure_min_captures_flattened(
|
||||
|
@ -1015,8 +1015,8 @@ fn build_construct_coroutine_by_move_shim<'tcx>(
|
||||
bug!();
|
||||
};
|
||||
|
||||
// We use `*mut Self` here because we only need to emit an ABI-compatible shim body,
|
||||
// rather than match the signature exactly.
|
||||
// We use `&mut Self` here because we only need to emit an ABI-compatible shim body,
|
||||
// rather than match the signature exactly (which might take `&self` instead).
|
||||
//
|
||||
// The self type here is a coroutine-closure, not a coroutine, and we never read from
|
||||
// it because it never has any captures, because this is only true in the Fn/FnMut
|
||||
@ -1025,7 +1025,7 @@ fn build_construct_coroutine_by_move_shim<'tcx>(
|
||||
if receiver_by_ref {
|
||||
// Triple-check that there's no captures here.
|
||||
assert_eq!(args.as_coroutine_closure().tupled_upvars_ty(), tcx.types.unit);
|
||||
self_ty = Ty::new_mut_ptr(tcx, self_ty);
|
||||
self_ty = Ty::new_mut_ref(tcx, tcx.lifetimes.re_erased, self_ty);
|
||||
}
|
||||
|
||||
let poly_sig = args.as_coroutine_closure().coroutine_closure_sig().map_bound(|sig| {
|
||||
|
@ -14,10 +14,6 @@ parse_array_index_offset_of = array indexing not supported in offset_of
|
||||
|
||||
parse_assignment_else_not_allowed = <assignment> ... else {"{"} ... {"}"} is not allowed
|
||||
|
||||
parse_assoc_lifetime = associated lifetimes are not supported
|
||||
.label = the lifetime is given here
|
||||
.help = if you meant to specify a trait object, write `dyn Trait + 'lifetime`
|
||||
|
||||
parse_associated_static_item_not_allowed = associated `static` items are not allowed
|
||||
|
||||
parse_async_block_in_2015 = `async` blocks are only allowed in Rust 2018 or later
|
||||
@ -445,6 +441,12 @@ parse_lifetime_in_borrow_expression = borrow expressions cannot be annotated wit
|
||||
.suggestion = remove the lifetime annotation
|
||||
.label = annotated with lifetime here
|
||||
|
||||
parse_lifetime_in_eq_constraint = lifetimes are not permitted in this context
|
||||
.label = lifetime is not allowed here
|
||||
.context_label = this introduces an associated item binding
|
||||
.help = if you meant to specify a trait object, write `dyn /* Trait */ + {$lifetime}`
|
||||
.colon_sugg = you might have meant to write a bound here
|
||||
|
||||
parse_lone_slash = invalid trailing slash in literal
|
||||
.label = {parse_lone_slash}
|
||||
|
||||
|
@ -2631,13 +2631,22 @@ pub(crate) struct GenericsInPath {
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(parse_assoc_lifetime)]
|
||||
#[diag(parse_lifetime_in_eq_constraint)]
|
||||
#[help]
|
||||
pub(crate) struct AssocLifetime {
|
||||
pub(crate) struct LifetimeInEqConstraint {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
#[label]
|
||||
pub lifetime: Span,
|
||||
pub span: Span,
|
||||
pub lifetime: Ident,
|
||||
#[label(parse_context_label)]
|
||||
pub binding_label: Span,
|
||||
#[suggestion(
|
||||
parse_colon_sugg,
|
||||
style = "verbose",
|
||||
applicability = "maybe-incorrect",
|
||||
code = ": "
|
||||
)]
|
||||
pub colon_sugg: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
|
@ -718,7 +718,11 @@ impl<'a> Parser<'a> {
|
||||
let bounds = self.parse_generic_bounds()?;
|
||||
AssocConstraintKind::Bound { bounds }
|
||||
} else if self.eat(&token::Eq) {
|
||||
self.parse_assoc_equality_term(ident, self.prev_token.span)?
|
||||
self.parse_assoc_equality_term(
|
||||
ident,
|
||||
gen_args.as_ref(),
|
||||
self.prev_token.span,
|
||||
)?
|
||||
} else {
|
||||
unreachable!();
|
||||
};
|
||||
@ -753,11 +757,13 @@ impl<'a> Parser<'a> {
|
||||
}
|
||||
|
||||
/// Parse the term to the right of an associated item equality constraint.
|
||||
/// That is, parse `<term>` in `Item = <term>`.
|
||||
/// Right now, this only admits types in `<term>`.
|
||||
///
|
||||
/// That is, parse `$term` in `Item = $term` where `$term` is a type or
|
||||
/// a const expression (wrapped in curly braces if complex).
|
||||
fn parse_assoc_equality_term(
|
||||
&mut self,
|
||||
ident: Ident,
|
||||
gen_args: Option<&GenericArgs>,
|
||||
eq: Span,
|
||||
) -> PResult<'a, AssocConstraintKind> {
|
||||
let arg = self.parse_generic_arg(None)?;
|
||||
@ -769,9 +775,15 @@ impl<'a> Parser<'a> {
|
||||
c.into()
|
||||
}
|
||||
Some(GenericArg::Lifetime(lt)) => {
|
||||
let guar =
|
||||
self.dcx().emit_err(errors::AssocLifetime { span, lifetime: lt.ident.span });
|
||||
self.mk_ty(span, ast::TyKind::Err(guar)).into()
|
||||
let guar = self.dcx().emit_err(errors::LifetimeInEqConstraint {
|
||||
span: lt.ident.span,
|
||||
lifetime: lt.ident,
|
||||
binding_label: span,
|
||||
colon_sugg: gen_args
|
||||
.map_or(ident.span, |args| args.span())
|
||||
.between(lt.ident.span),
|
||||
});
|
||||
self.mk_ty(lt.ident.span, ast::TyKind::Err(guar)).into()
|
||||
}
|
||||
None => {
|
||||
let after_eq = eq.shrink_to_hi();
|
||||
|
@ -674,6 +674,7 @@ symbols! {
|
||||
deref_mut,
|
||||
deref_mut_method,
|
||||
deref_patterns,
|
||||
deref_pure,
|
||||
deref_target,
|
||||
derive,
|
||||
derive_const,
|
||||
|
@ -125,8 +125,12 @@ fn fn_sig_for_fn_abi<'tcx>(
|
||||
coroutine_kind = ty::ClosureKind::FnOnce;
|
||||
|
||||
// Implementations of `FnMut` and `Fn` for coroutine-closures
|
||||
// still take their receiver by ref.
|
||||
if receiver_by_ref { Ty::new_mut_ptr(tcx, coroutine_ty) } else { coroutine_ty }
|
||||
// still take their receiver by (mut) ref.
|
||||
if receiver_by_ref {
|
||||
Ty::new_mut_ref(tcx, tcx.lifetimes.re_erased, coroutine_ty)
|
||||
} else {
|
||||
coroutine_ty
|
||||
}
|
||||
} else {
|
||||
tcx.closure_env_ty(coroutine_ty, coroutine_kind, env_region)
|
||||
};
|
||||
|
@ -161,7 +161,7 @@ use core::marker::Unsize;
|
||||
use core::mem::{self, SizedTypeProperties};
|
||||
use core::ops::{AsyncFn, AsyncFnMut, AsyncFnOnce};
|
||||
use core::ops::{
|
||||
CoerceUnsized, Coroutine, CoroutineState, Deref, DerefMut, DispatchFromDyn, Receiver,
|
||||
CoerceUnsized, Coroutine, CoroutineState, Deref, DerefMut, DerefPure, DispatchFromDyn, Receiver,
|
||||
};
|
||||
use core::pin::Pin;
|
||||
use core::ptr::{self, addr_of_mut, NonNull, Unique};
|
||||
@ -1939,6 +1939,9 @@ impl<T: ?Sized, A: Allocator> DerefMut for Box<T, A> {
|
||||
}
|
||||
}
|
||||
|
||||
#[unstable(feature = "deref_pure_trait", issue = "87121")]
|
||||
unsafe impl<T: ?Sized, A: Allocator> DerefPure for Box<T, A> {}
|
||||
|
||||
#[unstable(feature = "receiver_trait", issue = "none")]
|
||||
impl<T: ?Sized, A: Allocator> Receiver for Box<T, A> {}
|
||||
|
||||
|
@ -122,6 +122,7 @@
|
||||
#![feature(const_waker)]
|
||||
#![feature(core_intrinsics)]
|
||||
#![feature(deprecated_suggestion)]
|
||||
#![feature(deref_pure_trait)]
|
||||
#![feature(dispatch_from_dyn)]
|
||||
#![feature(error_generic_member_access)]
|
||||
#![feature(error_in_core)]
|
||||
|
@ -260,7 +260,7 @@ use core::marker::{PhantomData, Unsize};
|
||||
#[cfg(not(no_global_oom_handling))]
|
||||
use core::mem::size_of_val;
|
||||
use core::mem::{self, align_of_val_raw, forget, ManuallyDrop};
|
||||
use core::ops::{CoerceUnsized, Deref, DerefMut, DispatchFromDyn, Receiver};
|
||||
use core::ops::{CoerceUnsized, Deref, DerefMut, DerefPure, DispatchFromDyn, Receiver};
|
||||
use core::panic::{RefUnwindSafe, UnwindSafe};
|
||||
#[cfg(not(no_global_oom_handling))]
|
||||
use core::pin::Pin;
|
||||
@ -2126,6 +2126,9 @@ impl<T: ?Sized, A: Allocator> Deref for Rc<T, A> {
|
||||
}
|
||||
}
|
||||
|
||||
#[unstable(feature = "deref_pure_trait", issue = "87121")]
|
||||
unsafe impl<T: ?Sized, A: Allocator> DerefPure for Rc<T, A> {}
|
||||
|
||||
#[unstable(feature = "receiver_trait", issue = "none")]
|
||||
impl<T: ?Sized> Receiver for Rc<T> {}
|
||||
|
||||
|
@ -2479,6 +2479,9 @@ impl ops::Deref for String {
|
||||
}
|
||||
}
|
||||
|
||||
#[unstable(feature = "deref_pure_trait", issue = "87121")]
|
||||
unsafe impl ops::DerefPure for String {}
|
||||
|
||||
#[stable(feature = "derefmut_for_string", since = "1.3.0")]
|
||||
impl ops::DerefMut for String {
|
||||
#[inline]
|
||||
|
@ -21,7 +21,7 @@ use core::marker::{PhantomData, Unsize};
|
||||
#[cfg(not(no_global_oom_handling))]
|
||||
use core::mem::size_of_val;
|
||||
use core::mem::{self, align_of_val_raw};
|
||||
use core::ops::{CoerceUnsized, Deref, DispatchFromDyn, Receiver};
|
||||
use core::ops::{CoerceUnsized, Deref, DerefPure, DispatchFromDyn, Receiver};
|
||||
use core::panic::{RefUnwindSafe, UnwindSafe};
|
||||
use core::pin::Pin;
|
||||
use core::ptr::{self, NonNull};
|
||||
@ -2107,6 +2107,9 @@ impl<T: ?Sized, A: Allocator> Deref for Arc<T, A> {
|
||||
}
|
||||
}
|
||||
|
||||
#[unstable(feature = "deref_pure_trait", issue = "87121")]
|
||||
unsafe impl<T: ?Sized, A: Allocator> DerefPure for Arc<T, A> {}
|
||||
|
||||
#[unstable(feature = "receiver_trait", issue = "none")]
|
||||
impl<T: ?Sized> Receiver for Arc<T> {}
|
||||
|
||||
|
@ -2772,6 +2772,9 @@ impl<T, A: Allocator> ops::DerefMut for Vec<T, A> {
|
||||
}
|
||||
}
|
||||
|
||||
#[unstable(feature = "deref_pure_trait", issue = "87121")]
|
||||
unsafe impl<T, A: Allocator> ops::DerefPure for Vec<T, A> {}
|
||||
|
||||
#[cfg(not(no_global_oom_handling))]
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl<T: Clone, A: Allocator + Clone> Clone for Vec<T, A> {
|
||||
|
@ -275,6 +275,25 @@ impl<T: ?Sized> DerefMut for &mut T {
|
||||
}
|
||||
}
|
||||
|
||||
/// Perma-unstable marker trait. Indicates that the type has a well-behaved [`Deref`]
|
||||
/// (and, if applicable, [`DerefMut`]) implementation. This is relied on for soundness
|
||||
/// of deref patterns.
|
||||
///
|
||||
/// FIXME(deref_patterns): The precise semantics are undecided; the rough idea is that
|
||||
/// successive calls to `deref`/`deref_mut` without intermediate mutation should be
|
||||
/// idempotent, in the sense that they return the same value as far as pattern-matching
|
||||
/// is concerned. Calls to `deref`/`deref_mut`` must leave the pointer itself likewise
|
||||
/// unchanged.
|
||||
#[unstable(feature = "deref_pure_trait", issue = "87121")]
|
||||
#[cfg_attr(not(bootstrap), lang = "deref_pure")]
|
||||
pub unsafe trait DerefPure {}
|
||||
|
||||
#[unstable(feature = "deref_pure_trait", issue = "87121")]
|
||||
unsafe impl<T: ?Sized> DerefPure for &T {}
|
||||
|
||||
#[unstable(feature = "deref_pure_trait", issue = "87121")]
|
||||
unsafe impl<T: ?Sized> DerefPure for &mut T {}
|
||||
|
||||
/// Indicates that a struct can be used as a method receiver, without the
|
||||
/// `arbitrary_self_types` feature. This is implemented by stdlib pointer types like `Box<T>`,
|
||||
/// `Rc<T>`, `&T`, and `Pin<P>`.
|
||||
|
@ -165,6 +165,9 @@ pub use self::bit::{BitAndAssign, BitOrAssign, BitXorAssign, ShlAssign, ShrAssig
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
pub use self::deref::{Deref, DerefMut};
|
||||
|
||||
#[unstable(feature = "deref_pure_trait", issue = "87121")]
|
||||
pub use self::deref::DerefPure;
|
||||
|
||||
#[unstable(feature = "receiver_trait", issue = "none")]
|
||||
pub use self::deref::Receiver;
|
||||
|
||||
|
@ -517,7 +517,7 @@ impl FileAttr {
|
||||
|
||||
#[cfg(any(target_os = "horizon", target_os = "hurd"))]
|
||||
pub fn modified(&self) -> io::Result<SystemTime> {
|
||||
Ok(SystemTime::from(self.stat.st_mtim))
|
||||
SystemTime::new(self.stat.st_mtim.tv_sec as i64, self.stat.st_mtim.tv_nsec as i64)
|
||||
}
|
||||
|
||||
#[cfg(not(any(
|
||||
@ -545,7 +545,7 @@ impl FileAttr {
|
||||
|
||||
#[cfg(any(target_os = "horizon", target_os = "hurd"))]
|
||||
pub fn accessed(&self) -> io::Result<SystemTime> {
|
||||
Ok(SystemTime::from(self.stat.st_atim))
|
||||
SystemTime::new(self.stat.st_atim.tv_sec as i64, self.stat.st_atim.tv_nsec as i64)
|
||||
}
|
||||
|
||||
#[cfg(any(
|
||||
|
@ -680,9 +680,13 @@ impl Step for Miri {
|
||||
.arg("--manifest-path")
|
||||
.arg(builder.src.join("src/tools/miri/test-cargo-miri/Cargo.toml"));
|
||||
cargo.arg("--target").arg(target.rustc_target_arg());
|
||||
cargo.arg("--tests"); // don't run doctests, they are too confused by the staging
|
||||
cargo.arg("--").args(builder.config.test_args());
|
||||
|
||||
// `prepare_tool_cargo` sets RUSTDOC to the bootstrap wrapper and RUSTDOC_REAL to a dummy path as this is a "run", not a "test".
|
||||
// Also, we want the rustdoc from the "next" stage for the same reason that we build a std from the next stage.
|
||||
// So let's just set that here, and bypass bootstrap's RUSTDOC (just like cargo-miri already ignores bootstrap's RUSTC_WRAPPER).
|
||||
cargo.env("RUSTDOC", builder.rustdoc(compiler_std));
|
||||
|
||||
// Tell `cargo miri` where to find things.
|
||||
cargo.env("MIRI_SYSROOT", &miri_sysroot);
|
||||
cargo.env("MIRI_HOST_SYSROOT", sysroot);
|
||||
|
@ -0,0 +1,35 @@
|
||||
# `adt_const_params`
|
||||
|
||||
The tracking issue for this feature is: [#95174]
|
||||
|
||||
[#95174]: https://github.com/rust-lang/rust/issues/95174
|
||||
|
||||
------------------------
|
||||
|
||||
Allows for using more complex types for const parameters, such as structs or enums.
|
||||
|
||||
```rust
|
||||
#![feature(adt_const_params)]
|
||||
#![allow(incomplete_features)]
|
||||
|
||||
use std::marker::ConstParamTy;
|
||||
|
||||
#[derive(ConstParamTy, PartialEq, Eq)]
|
||||
enum Foo {
|
||||
A,
|
||||
B,
|
||||
C,
|
||||
}
|
||||
|
||||
#[derive(ConstParamTy, PartialEq, Eq)]
|
||||
struct Bar {
|
||||
flag: bool,
|
||||
}
|
||||
|
||||
fn is_foo_a_and_bar_true<const F: Foo, const B: Bar>() -> bool {
|
||||
match (F, B.flag) {
|
||||
(Foo::A, true) => true,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
```
|
@ -83,7 +83,10 @@ impl<'tcx> LateLintPass<'tcx> for FloatLiteral {
|
||||
LitFloatType::Unsuffixed => None,
|
||||
};
|
||||
let (is_whole, is_inf, mut float_str) = match fty {
|
||||
FloatTy::F16 => unimplemented!("f16_f128"),
|
||||
FloatTy::F16 => {
|
||||
// FIXME(f16_f128): do a check like the others when parsing is available
|
||||
return;
|
||||
},
|
||||
FloatTy::F32 => {
|
||||
let value = sym_str.parse::<f32>().unwrap();
|
||||
|
||||
@ -94,7 +97,10 @@ impl<'tcx> LateLintPass<'tcx> for FloatLiteral {
|
||||
|
||||
(value.fract() == 0.0, value.is_infinite(), formatter.format(value))
|
||||
},
|
||||
FloatTy::F128 => unimplemented!("f16_f128"),
|
||||
FloatTy::F128 => {
|
||||
// FIXME(f16_f128): do a check like the others when parsing is available
|
||||
return;
|
||||
},
|
||||
};
|
||||
|
||||
if is_inf {
|
||||
@ -139,10 +145,11 @@ impl<'tcx> LateLintPass<'tcx> for FloatLiteral {
|
||||
#[must_use]
|
||||
fn max_digits(fty: FloatTy) -> u32 {
|
||||
match fty {
|
||||
FloatTy::F16 => unimplemented!("f16_f128"),
|
||||
// FIXME(f16_f128): replace the magic numbers once `{f16,f128}::DIGITS` are available
|
||||
FloatTy::F16 => 3,
|
||||
FloatTy::F32 => f32::DIGITS,
|
||||
FloatTy::F64 => f64::DIGITS,
|
||||
FloatTy::F128 => unimplemented!("f16_f128"),
|
||||
FloatTy::F128 => 33,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -12,7 +12,7 @@ use rustc_errors::Applicability;
|
||||
use rustc_hir::def::{DefKind, Res};
|
||||
use rustc_hir::def_id::DefId;
|
||||
use rustc_hir::{BorrowKind, Expr, ExprKind, ItemKind, LangItem, Node};
|
||||
use rustc_hir_typeck::{FnCtxt, Inherited};
|
||||
use rustc_hir_typeck::{FnCtxt, TypeckRootCtxt};
|
||||
use rustc_infer::infer::TyCtxtInferExt;
|
||||
use rustc_lint::LateContext;
|
||||
use rustc_middle::mir::Mutability;
|
||||
@ -438,8 +438,8 @@ fn can_change_type<'a>(cx: &LateContext<'a>, mut expr: &'a Expr<'a>, mut ty: Ty<
|
||||
Node::Item(item) => {
|
||||
if let ItemKind::Fn(_, _, body_id) = &item.kind
|
||||
&& let output_ty = return_ty(cx, item.owner_id)
|
||||
&& let inherited = Inherited::new(cx.tcx, item.owner_id.def_id)
|
||||
&& let fn_ctxt = FnCtxt::new(&inherited, cx.param_env, item.owner_id.def_id)
|
||||
&& let root_ctxt = TypeckRootCtxt::new(cx.tcx, item.owner_id.def_id)
|
||||
&& let fn_ctxt = FnCtxt::new(&root_ctxt, cx.param_env, item.owner_id.def_id)
|
||||
&& fn_ctxt.can_coerce(ty, output_ty)
|
||||
{
|
||||
if has_lifetime(output_ty) && has_lifetime(ty) {
|
||||
|
@ -1,6 +1,6 @@
|
||||
use rustc_hir as hir;
|
||||
use rustc_hir::Expr;
|
||||
use rustc_hir_typeck::{cast, FnCtxt, Inherited};
|
||||
use rustc_hir_typeck::{cast, FnCtxt, TypeckRootCtxt};
|
||||
use rustc_lint::LateContext;
|
||||
use rustc_middle::ty::cast::CastKind;
|
||||
use rustc_middle::ty::Ty;
|
||||
@ -34,8 +34,8 @@ pub(super) fn check_cast<'tcx>(
|
||||
let hir_id = e.hir_id;
|
||||
let local_def_id = hir_id.owner.def_id;
|
||||
|
||||
let inherited = Inherited::new(cx.tcx, local_def_id);
|
||||
let fn_ctxt = FnCtxt::new(&inherited, cx.param_env, local_def_id);
|
||||
let root_ctxt = TypeckRootCtxt::new(cx.tcx, local_def_id);
|
||||
let fn_ctxt = FnCtxt::new(&root_ctxt, cx.param_env, local_def_id);
|
||||
|
||||
if let Ok(check) = cast::CastCheck::new(
|
||||
&fn_ctxt,
|
||||
|
@ -505,6 +505,8 @@ binaries, and as such worth documenting:
|
||||
* `MIRI_LOCAL_CRATES` is set by `cargo-miri` to tell the Miri driver which
|
||||
crates should be given special treatment in diagnostics, in addition to the
|
||||
crate currently being compiled.
|
||||
* `MIRI_ORIG_RUSTDOC` is set and read by different phases of `cargo-miri` to remember the
|
||||
value of `RUSTDOC` from before it was overwritten.
|
||||
* `MIRI_VERBOSE` when set to any value tells the various `cargo-miri` phases to
|
||||
perform verbose logging.
|
||||
* `MIRI_HOST_SYSROOT` is set by bootstrap to tell `cargo-miri` which sysroot to use for *host*
|
||||
|
@ -202,6 +202,9 @@ pub fn phase_cargo_miri(mut args: impl Iterator<Item = String>) {
|
||||
cmd.env("MIRI_BE_RUSTC", "target"); // we better remember to *unset* this in the other phases!
|
||||
|
||||
// Set rustdoc to us as well, so we can run doctests.
|
||||
if let Some(orig_rustdoc) = env::var_os("RUSTDOC") {
|
||||
cmd.env("MIRI_ORIG_RUSTDOC", orig_rustdoc);
|
||||
}
|
||||
cmd.env("RUSTDOC", &cargo_miri_path);
|
||||
|
||||
cmd.env("MIRI_LOCAL_CRATES", local_crates(&metadata));
|
||||
@ -581,9 +584,10 @@ pub fn phase_rustdoc(mut args: impl Iterator<Item = String>) {
|
||||
let verbose = std::env::var("MIRI_VERBOSE")
|
||||
.map_or(0, |verbose| verbose.parse().expect("verbosity flag must be an integer"));
|
||||
|
||||
// phase_cargo_miri sets the RUSTDOC env var to ourselves, so we can't use that here;
|
||||
// just default to a straight-forward invocation for now:
|
||||
let mut cmd = Command::new("rustdoc");
|
||||
// phase_cargo_miri sets the RUSTDOC env var to ourselves, and puts a backup
|
||||
// of the old value into MIRI_ORIG_RUSTDOC. So that's what we have to invoke now.
|
||||
let rustdoc = env::var("MIRI_ORIG_RUSTDOC").unwrap_or("rustdoc".to_string());
|
||||
let mut cmd = Command::new(rustdoc);
|
||||
|
||||
let extern_flag = "--extern";
|
||||
let runtool_flag = "--runtool";
|
||||
|
40
src/tools/miri/tests/pass/async-closure-drop.rs
Normal file
40
src/tools/miri/tests/pass/async-closure-drop.rs
Normal file
@ -0,0 +1,40 @@
|
||||
#![feature(async_closure, noop_waker, async_fn_traits)]
|
||||
|
||||
use std::future::Future;
|
||||
use std::pin::pin;
|
||||
use std::task::*;
|
||||
|
||||
pub fn block_on<T>(fut: impl Future<Output = T>) -> T {
|
||||
let mut fut = pin!(fut);
|
||||
let ctx = &mut Context::from_waker(Waker::noop());
|
||||
|
||||
loop {
|
||||
match fut.as_mut().poll(ctx) {
|
||||
Poll::Pending => {}
|
||||
Poll::Ready(t) => break t,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async fn call_once(f: impl async FnOnce(DropMe)) {
|
||||
f(DropMe("world")).await;
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
struct DropMe(&'static str);
|
||||
|
||||
impl Drop for DropMe {
|
||||
fn drop(&mut self) {
|
||||
println!("{}", self.0);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn main() {
|
||||
block_on(async {
|
||||
let b = DropMe("hello");
|
||||
let async_closure = async move |a: DropMe| {
|
||||
println!("{a:?} {b:?}");
|
||||
};
|
||||
call_once(async_closure).await;
|
||||
});
|
||||
}
|
3
src/tools/miri/tests/pass/async-closure-drop.stdout
Normal file
3
src/tools/miri/tests/pass/async-closure-drop.stdout
Normal file
@ -0,0 +1,3 @@
|
||||
DropMe("world") DropMe("hello")
|
||||
world
|
||||
hello
|
@ -1,6 +1,7 @@
|
||||
#![feature(async_closure, noop_waker, async_fn_traits)]
|
||||
|
||||
use std::future::Future;
|
||||
use std::ops::{AsyncFnMut, AsyncFnOnce};
|
||||
use std::pin::pin;
|
||||
use std::task::*;
|
||||
|
||||
@ -16,25 +17,36 @@ pub fn block_on<T>(fut: impl Future<Output = T>) -> T {
|
||||
}
|
||||
}
|
||||
|
||||
async fn call_once(f: impl async FnOnce(DropMe)) {
|
||||
f(DropMe("world")).await;
|
||||
async fn call_mut(f: &mut impl AsyncFnMut(i32)) {
|
||||
f(0).await;
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
struct DropMe(&'static str);
|
||||
async fn call_once(f: impl AsyncFnOnce(i32)) {
|
||||
f(1).await;
|
||||
}
|
||||
|
||||
impl Drop for DropMe {
|
||||
fn drop(&mut self) {
|
||||
println!("{}", self.0);
|
||||
}
|
||||
async fn call_normal<F: Future<Output = ()>>(f: &impl Fn(i32) -> F) {
|
||||
f(0).await;
|
||||
}
|
||||
|
||||
async fn call_normal_once<F: Future<Output = ()>>(f: impl FnOnce(i32) -> F) {
|
||||
f(1).await;
|
||||
}
|
||||
|
||||
pub fn main() {
|
||||
block_on(async {
|
||||
let b = DropMe("hello");
|
||||
let async_closure = async move |a: DropMe| {
|
||||
println!("{a:?} {b:?}");
|
||||
let b = 2i32;
|
||||
let mut async_closure = async move |a: i32| {
|
||||
println!("{a} {b}");
|
||||
};
|
||||
call_mut(&mut async_closure).await;
|
||||
call_once(async_closure).await;
|
||||
|
||||
// No-capture closures implement `Fn`.
|
||||
let async_closure = async move |a: i32| {
|
||||
println!("{a}");
|
||||
};
|
||||
call_normal(&async_closure).await;
|
||||
call_normal_once(async_closure).await;
|
||||
});
|
||||
}
|
||||
|
@ -1,3 +1,4 @@
|
||||
DropMe("world") DropMe("hello")
|
||||
world
|
||||
hello
|
||||
0 2
|
||||
1 2
|
||||
0
|
||||
1
|
||||
|
@ -1,6 +1,6 @@
|
||||
// MIR for `main::{closure#0}::{closure#1}` 0 coroutine_closure_by_ref
|
||||
|
||||
fn main::{closure#0}::{closure#1}(_1: *mut {async closure@$DIR/async_closure_shims.rs:49:29: 49:48}, _2: i32) -> {async closure body@$DIR/async_closure_shims.rs:49:49: 51:10} {
|
||||
fn main::{closure#0}::{closure#1}(_1: &mut {async closure@$DIR/async_closure_shims.rs:49:29: 49:48}, _2: i32) -> {async closure body@$DIR/async_closure_shims.rs:49:49: 51:10} {
|
||||
let mut _0: {async closure body@$DIR/async_closure_shims.rs:49:49: 51:10};
|
||||
|
||||
bb0: {
|
||||
|
@ -1,6 +1,6 @@
|
||||
// MIR for `main::{closure#0}::{closure#1}` 0 coroutine_closure_by_ref
|
||||
|
||||
fn main::{closure#0}::{closure#1}(_1: *mut {async closure@$DIR/async_closure_shims.rs:49:29: 49:48}, _2: i32) -> {async closure body@$DIR/async_closure_shims.rs:49:49: 51:10} {
|
||||
fn main::{closure#0}::{closure#1}(_1: &mut {async closure@$DIR/async_closure_shims.rs:49:29: 49:48}, _2: i32) -> {async closure body@$DIR/async_closure_shims.rs:49:49: 51:10} {
|
||||
let mut _0: {async closure body@$DIR/async_closure_shims.rs:49:49: 51:10};
|
||||
|
||||
bb0: {
|
||||
|
@ -0,0 +1,30 @@
|
||||
// Regression test for issue #105056.
|
||||
//@ edition: 2021
|
||||
|
||||
fn f(_: impl Trait<T = Copy>) {}
|
||||
//~^ ERROR trait objects must include the `dyn` keyword
|
||||
//~| HELP add `dyn` keyword before this trait
|
||||
//~| HELP you might have meant to write a bound here
|
||||
//~| ERROR the trait `Copy` cannot be made into an object
|
||||
|
||||
fn g(_: impl Trait<T = std::fmt::Debug + Eq>) {}
|
||||
//~^ ERROR trait objects must include the `dyn` keyword
|
||||
//~| HELP add `dyn` keyword before this trait
|
||||
//~| HELP you might have meant to write a bound here
|
||||
//~| ERROR only auto traits can be used as additional traits in a trait object
|
||||
//~| HELP consider creating a new trait
|
||||
//~| ERROR the trait `Eq` cannot be made into an object
|
||||
|
||||
fn h(_: impl Trait<T<> = 'static + for<'a> Fn(&'a ())>) {}
|
||||
//~^ ERROR trait objects must include the `dyn` keyword
|
||||
//~| HELP add `dyn` keyword before this trait
|
||||
//~| HELP you might have meant to write a bound here
|
||||
|
||||
// Don't suggest assoc ty bound in trait object types, that's not valid:
|
||||
type Obj = dyn Trait<T = Clone>;
|
||||
//~^ ERROR trait objects must include the `dyn` keyword
|
||||
//~| HELP add `dyn` keyword before this trait
|
||||
|
||||
trait Trait { type T; }
|
||||
|
||||
fn main() {}
|
@ -0,0 +1,91 @@
|
||||
error[E0038]: the trait `Copy` cannot be made into an object
|
||||
--> $DIR/suggest-assoc-ty-bound-on-eq-bound.rs:4:20
|
||||
|
|
||||
LL | fn f(_: impl Trait<T = Copy>) {}
|
||||
| ^^^^^^^^ `Copy` cannot be made into an object
|
||||
|
|
||||
= note: the trait cannot be made into an object because it requires `Self: Sized`
|
||||
= note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
|
||||
|
||||
error[E0225]: only auto traits can be used as additional traits in a trait object
|
||||
--> $DIR/suggest-assoc-ty-bound-on-eq-bound.rs:10:42
|
||||
|
|
||||
LL | fn g(_: impl Trait<T = std::fmt::Debug + Eq>) {}
|
||||
| --------------- ^^ additional non-auto trait
|
||||
| |
|
||||
| first non-auto trait
|
||||
|
|
||||
= help: consider creating a new trait with all of these as supertraits and using that trait here instead: `trait NewTrait: Debug + Eq {}`
|
||||
= note: auto-traits like `Send` and `Sync` are traits that have special properties; for more information on them, visit <https://doc.rust-lang.org/reference/special-types-and-traits.html#auto-traits>
|
||||
|
||||
error[E0038]: the trait `Eq` cannot be made into an object
|
||||
--> $DIR/suggest-assoc-ty-bound-on-eq-bound.rs:10:24
|
||||
|
|
||||
LL | fn g(_: impl Trait<T = std::fmt::Debug + Eq>) {}
|
||||
| ^^^^^^^^^^^^^^^^^^^^ `Eq` cannot be made into an object
|
||||
|
|
||||
note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
|
||||
--> $SRC_DIR/core/src/cmp.rs:LL:COL
|
||||
|
|
||||
= note: the trait cannot be made into an object because it uses `Self` as a type parameter
|
||||
|
||||
error[E0782]: trait objects must include the `dyn` keyword
|
||||
--> $DIR/suggest-assoc-ty-bound-on-eq-bound.rs:4:24
|
||||
|
|
||||
LL | fn f(_: impl Trait<T = Copy>) {}
|
||||
| ^^^^
|
||||
|
|
||||
help: add `dyn` keyword before this trait
|
||||
|
|
||||
LL | fn f(_: impl Trait<T = dyn Copy>) {}
|
||||
| +++
|
||||
help: you might have meant to write a bound here
|
||||
|
|
||||
LL | fn f(_: impl Trait<T: Copy>) {}
|
||||
| ~
|
||||
|
||||
error[E0782]: trait objects must include the `dyn` keyword
|
||||
--> $DIR/suggest-assoc-ty-bound-on-eq-bound.rs:10:24
|
||||
|
|
||||
LL | fn g(_: impl Trait<T = std::fmt::Debug + Eq>) {}
|
||||
| ^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
help: add `dyn` keyword before this trait
|
||||
|
|
||||
LL | fn g(_: impl Trait<T = dyn std::fmt::Debug + Eq>) {}
|
||||
| +++
|
||||
help: you might have meant to write a bound here
|
||||
|
|
||||
LL | fn g(_: impl Trait<T: std::fmt::Debug + Eq>) {}
|
||||
| ~
|
||||
|
||||
error[E0782]: trait objects must include the `dyn` keyword
|
||||
--> $DIR/suggest-assoc-ty-bound-on-eq-bound.rs:18:26
|
||||
|
|
||||
LL | fn h(_: impl Trait<T<> = 'static + for<'a> Fn(&'a ())>) {}
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
help: add `dyn` keyword before this trait
|
||||
|
|
||||
LL | fn h(_: impl Trait<T<> = dyn 'static + for<'a> Fn(&'a ())>) {}
|
||||
| +++
|
||||
help: you might have meant to write a bound here
|
||||
|
|
||||
LL | fn h(_: impl Trait<T<>: 'static + for<'a> Fn(&'a ())>) {}
|
||||
| ~
|
||||
|
||||
error[E0782]: trait objects must include the `dyn` keyword
|
||||
--> $DIR/suggest-assoc-ty-bound-on-eq-bound.rs:24:26
|
||||
|
|
||||
LL | type Obj = dyn Trait<T = Clone>;
|
||||
| ^^^^^
|
||||
|
|
||||
help: add `dyn` keyword before this trait
|
||||
|
|
||||
LL | type Obj = dyn Trait<T = dyn Clone>;
|
||||
| +++
|
||||
|
||||
error: aborting due to 7 previous errors
|
||||
|
||||
Some errors have detailed explanations: E0038, E0225, E0782.
|
||||
For more information about an error, try `rustc --explain E0038`.
|
11
tests/ui/borrowck/cloning-in-async-block-121547.rs
Normal file
11
tests/ui/borrowck/cloning-in-async-block-121547.rs
Normal file
@ -0,0 +1,11 @@
|
||||
//@ edition:2021
|
||||
|
||||
async fn clone_async_block(value: String) {
|
||||
for _ in 0..10 {
|
||||
async { //~ ERROR: use of moved value: `value` [E0382]
|
||||
drop(value);
|
||||
//~^ HELP: consider cloning the value if the performance cost is acceptable
|
||||
}.await
|
||||
}
|
||||
}
|
||||
fn main() {}
|
22
tests/ui/borrowck/cloning-in-async-block-121547.stderr
Normal file
22
tests/ui/borrowck/cloning-in-async-block-121547.stderr
Normal file
@ -0,0 +1,22 @@
|
||||
error[E0382]: use of moved value: `value`
|
||||
--> $DIR/cloning-in-async-block-121547.rs:5:9
|
||||
|
|
||||
LL | async fn clone_async_block(value: String) {
|
||||
| ----- move occurs because `value` has type `String`, which does not implement the `Copy` trait
|
||||
LL | for _ in 0..10 {
|
||||
| -------------- inside of this loop
|
||||
LL | / async {
|
||||
LL | | drop(value);
|
||||
| | ----- use occurs due to use in coroutine
|
||||
LL | |
|
||||
LL | | }.await
|
||||
| |_________^ value moved here, in previous iteration of loop
|
||||
|
|
||||
help: consider cloning the value if the performance cost is acceptable
|
||||
|
|
||||
LL | drop(value.clone());
|
||||
| ++++++++
|
||||
|
||||
error: aborting due to 1 previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0382`.
|
@ -1,6 +1,6 @@
|
||||
#[cfg(FALSE)]
|
||||
fn syntax() {
|
||||
bar::<Item = 'a>(); //~ ERROR associated lifetimes are not supported
|
||||
bar::<Item = 'a>(); //~ ERROR lifetimes are not permitted in this context
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
|
@ -1,12 +1,17 @@
|
||||
error: associated lifetimes are not supported
|
||||
--> $DIR/recover-assoc-lifetime-constraint.rs:3:11
|
||||
error: lifetimes are not permitted in this context
|
||||
--> $DIR/recover-assoc-lifetime-constraint.rs:3:18
|
||||
|
|
||||
LL | bar::<Item = 'a>();
|
||||
| ^^^^^^^--
|
||||
| |
|
||||
| the lifetime is given here
|
||||
| -------^^
|
||||
| | |
|
||||
| | lifetime is not allowed here
|
||||
| this introduces an associated item binding
|
||||
|
|
||||
= help: if you meant to specify a trait object, write `dyn Trait + 'lifetime`
|
||||
= help: if you meant to specify a trait object, write `dyn /* Trait */ + 'a`
|
||||
help: you might have meant to write a bound here
|
||||
|
|
||||
LL | bar::<Item: 'a>();
|
||||
| ~
|
||||
|
||||
error: aborting due to 1 previous error
|
||||
|
||||
|
17
tests/ui/pattern/deref-patterns/ref-mut.rs
Normal file
17
tests/ui/pattern/deref-patterns/ref-mut.rs
Normal file
@ -0,0 +1,17 @@
|
||||
#![feature(deref_patterns)]
|
||||
//~^ WARN the feature `deref_patterns` is incomplete
|
||||
|
||||
use std::rc::Rc;
|
||||
|
||||
fn main() {
|
||||
match &mut vec![1] {
|
||||
deref!(x) => {}
|
||||
_ => {}
|
||||
}
|
||||
|
||||
match &mut Rc::new(1) {
|
||||
deref!(x) => {}
|
||||
//~^ ERROR the trait bound `Rc<{integer}>: DerefMut` is not satisfied
|
||||
_ => {}
|
||||
}
|
||||
}
|
20
tests/ui/pattern/deref-patterns/ref-mut.stderr
Normal file
20
tests/ui/pattern/deref-patterns/ref-mut.stderr
Normal file
@ -0,0 +1,20 @@
|
||||
warning: the feature `deref_patterns` is incomplete and may not be safe to use and/or cause compiler crashes
|
||||
--> $DIR/ref-mut.rs:1:12
|
||||
|
|
||||
LL | #![feature(deref_patterns)]
|
||||
| ^^^^^^^^^^^^^^
|
||||
|
|
||||
= note: see issue #87121 <https://github.com/rust-lang/rust/issues/87121> for more information
|
||||
= note: `#[warn(incomplete_features)]` on by default
|
||||
|
||||
error[E0277]: the trait bound `Rc<{integer}>: DerefMut` is not satisfied
|
||||
--> $DIR/ref-mut.rs:13:9
|
||||
|
|
||||
LL | deref!(x) => {}
|
||||
| ^^^^^^^^^ the trait `DerefMut` is not implemented for `Rc<{integer}>`
|
||||
|
|
||||
= note: this error originates in the macro `deref` (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||
|
||||
error: aborting due to 1 previous error; 1 warning emitted
|
||||
|
||||
For more information about this error, try `rustc --explain E0277`.
|
Loading…
x
Reference in New Issue
Block a user