Auto merge of #106025 - matthiaskrgr:rollup-vz5rqah, r=matthiaskrgr
Rollup of 6 pull requests Successful merges: - #105837 (Don't ICE in `check_must_not_suspend_ty` for mismatched tuple arity) - #105932 (Correct branch-protection ModFlagBehavior for Aarch64 on LLVM-15) - #105960 (Various cleanups) - #105985 (Method chain nitpicks) - #105996 (Test that async blocks are `UnwindSafe`) - #106012 (Clarify that raw retags are not permitted in Mir) Failed merges: r? `@ghost` `@rustbot` modify labels: rollup
This commit is contained in:
commit
75f4ee8b44
24 changed files with 181 additions and 99 deletions
|
@ -280,29 +280,35 @@ pub unsafe fn create_module<'ll>(
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(BranchProtection { bti, pac_ret }) = sess.opts.unstable_opts.branch_protection {
|
if let Some(BranchProtection { bti, pac_ret }) = sess.opts.unstable_opts.branch_protection {
|
||||||
|
let behavior = if llvm_version >= (15, 0, 0) {
|
||||||
|
llvm::LLVMModFlagBehavior::Min
|
||||||
|
} else {
|
||||||
|
llvm::LLVMModFlagBehavior::Error
|
||||||
|
};
|
||||||
|
|
||||||
if sess.target.arch == "aarch64" {
|
if sess.target.arch == "aarch64" {
|
||||||
llvm::LLVMRustAddModuleFlag(
|
llvm::LLVMRustAddModuleFlag(
|
||||||
llmod,
|
llmod,
|
||||||
llvm::LLVMModFlagBehavior::Error,
|
behavior,
|
||||||
"branch-target-enforcement\0".as_ptr().cast(),
|
"branch-target-enforcement\0".as_ptr().cast(),
|
||||||
bti.into(),
|
bti.into(),
|
||||||
);
|
);
|
||||||
llvm::LLVMRustAddModuleFlag(
|
llvm::LLVMRustAddModuleFlag(
|
||||||
llmod,
|
llmod,
|
||||||
llvm::LLVMModFlagBehavior::Error,
|
behavior,
|
||||||
"sign-return-address\0".as_ptr().cast(),
|
"sign-return-address\0".as_ptr().cast(),
|
||||||
pac_ret.is_some().into(),
|
pac_ret.is_some().into(),
|
||||||
);
|
);
|
||||||
let pac_opts = pac_ret.unwrap_or(PacRet { leaf: false, key: PAuthKey::A });
|
let pac_opts = pac_ret.unwrap_or(PacRet { leaf: false, key: PAuthKey::A });
|
||||||
llvm::LLVMRustAddModuleFlag(
|
llvm::LLVMRustAddModuleFlag(
|
||||||
llmod,
|
llmod,
|
||||||
llvm::LLVMModFlagBehavior::Error,
|
behavior,
|
||||||
"sign-return-address-all\0".as_ptr().cast(),
|
"sign-return-address-all\0".as_ptr().cast(),
|
||||||
pac_opts.leaf.into(),
|
pac_opts.leaf.into(),
|
||||||
);
|
);
|
||||||
llvm::LLVMRustAddModuleFlag(
|
llvm::LLVMRustAddModuleFlag(
|
||||||
llmod,
|
llmod,
|
||||||
llvm::LLVMModFlagBehavior::Error,
|
behavior,
|
||||||
"sign-return-address-with-bkey\0".as_ptr().cast(),
|
"sign-return-address-with-bkey\0".as_ptr().cast(),
|
||||||
u32::from(pac_opts.key == PAuthKey::B),
|
u32::from(pac_opts.key == PAuthKey::B),
|
||||||
);
|
);
|
||||||
|
|
|
@ -79,6 +79,7 @@ pub enum LLVMModFlagBehavior {
|
||||||
Append = 5,
|
Append = 5,
|
||||||
AppendUnique = 6,
|
AppendUnique = 6,
|
||||||
Max = 7,
|
Max = 7,
|
||||||
|
Min = 8,
|
||||||
}
|
}
|
||||||
|
|
||||||
// Consts for the LLVM CallConv type, pre-cast to usize.
|
// Consts for the LLVM CallConv type, pre-cast to usize.
|
||||||
|
|
|
@ -9,8 +9,8 @@ use rustc_middle::mir::visit::{PlaceContext, Visitor};
|
||||||
use rustc_middle::mir::{
|
use rustc_middle::mir::{
|
||||||
traversal, AggregateKind, BasicBlock, BinOp, Body, BorrowKind, CastKind, CopyNonOverlapping,
|
traversal, AggregateKind, BasicBlock, BinOp, Body, BorrowKind, CastKind, CopyNonOverlapping,
|
||||||
Local, Location, MirPass, MirPhase, NonDivergingIntrinsic, Operand, Place, PlaceElem, PlaceRef,
|
Local, Location, MirPass, MirPhase, NonDivergingIntrinsic, Operand, Place, PlaceElem, PlaceRef,
|
||||||
ProjectionElem, RuntimePhase, Rvalue, SourceScope, Statement, StatementKind, Terminator,
|
ProjectionElem, RetagKind, RuntimePhase, Rvalue, SourceScope, Statement, StatementKind,
|
||||||
TerminatorKind, UnOp, START_BLOCK,
|
Terminator, TerminatorKind, UnOp, START_BLOCK,
|
||||||
};
|
};
|
||||||
use rustc_middle::ty::{self, InstanceDef, ParamEnv, Ty, TyCtxt, TypeVisitable};
|
use rustc_middle::ty::{self, InstanceDef, ParamEnv, Ty, TyCtxt, TypeVisitable};
|
||||||
use rustc_mir_dataflow::impls::MaybeStorageLive;
|
use rustc_mir_dataflow::impls::MaybeStorageLive;
|
||||||
|
@ -667,10 +667,13 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
|
||||||
self.fail(location, "`Deinit`is not allowed until deaggregation");
|
self.fail(location, "`Deinit`is not allowed until deaggregation");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
StatementKind::Retag(_, _) => {
|
StatementKind::Retag(kind, _) => {
|
||||||
// FIXME(JakobDegen) The validator should check that `self.mir_phase <
|
// FIXME(JakobDegen) The validator should check that `self.mir_phase <
|
||||||
// DropsLowered`. However, this causes ICEs with generation of drop shims, which
|
// DropsLowered`. However, this causes ICEs with generation of drop shims, which
|
||||||
// seem to fail to set their `MirPhase` correctly.
|
// seem to fail to set their `MirPhase` correctly.
|
||||||
|
if *kind == RetagKind::Raw || *kind == RetagKind::TwoPhase {
|
||||||
|
self.fail(location, format!("explicit `{:?}` is forbidden", kind));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
StatementKind::StorageLive(..)
|
StatementKind::StorageLive(..)
|
||||||
| StatementKind::StorageDead(..)
|
| StatementKind::StorageDead(..)
|
||||||
|
|
|
@ -607,10 +607,7 @@ fn check_must_not_suspend_ty<'tcx>(
|
||||||
ty::Tuple(fields) => {
|
ty::Tuple(fields) => {
|
||||||
let mut has_emitted = false;
|
let mut has_emitted = false;
|
||||||
let comps = match data.expr.map(|e| &e.kind) {
|
let comps = match data.expr.map(|e| &e.kind) {
|
||||||
Some(hir::ExprKind::Tup(comps)) => {
|
Some(hir::ExprKind::Tup(comps)) if comps.len() == fields.len() => Some(comps),
|
||||||
debug_assert_eq!(comps.len(), fields.len());
|
|
||||||
Some(comps)
|
|
||||||
}
|
|
||||||
_ => None,
|
_ => None,
|
||||||
};
|
};
|
||||||
for (i, ty) in fields.iter().enumerate() {
|
for (i, ty) in fields.iter().enumerate() {
|
||||||
|
|
|
@ -170,6 +170,7 @@ impl<'hir> Map<'hir> {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
|
#[track_caller]
|
||||||
pub fn local_def_id(self, hir_id: HirId) -> LocalDefId {
|
pub fn local_def_id(self, hir_id: HirId) -> LocalDefId {
|
||||||
self.opt_local_def_id(hir_id).unwrap_or_else(|| {
|
self.opt_local_def_id(hir_id).unwrap_or_else(|| {
|
||||||
bug!(
|
bug!(
|
||||||
|
@ -310,6 +311,7 @@ impl<'hir> Map<'hir> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[track_caller]
|
||||||
pub fn get_parent_node(self, hir_id: HirId) -> HirId {
|
pub fn get_parent_node(self, hir_id: HirId) -> HirId {
|
||||||
self.find_parent_node(hir_id)
|
self.find_parent_node(hir_id)
|
||||||
.unwrap_or_else(|| bug!("No parent for node {:?}", self.node_to_string(hir_id)))
|
.unwrap_or_else(|| bug!("No parent for node {:?}", self.node_to_string(hir_id)))
|
||||||
|
@ -334,12 +336,14 @@ impl<'hir> Map<'hir> {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Retrieves the `Node` corresponding to `id`, panicking if it cannot be found.
|
/// Retrieves the `Node` corresponding to `id`, panicking if it cannot be found.
|
||||||
|
#[track_caller]
|
||||||
pub fn get(self, id: HirId) -> Node<'hir> {
|
pub fn get(self, id: HirId) -> Node<'hir> {
|
||||||
self.find(id).unwrap_or_else(|| bug!("couldn't find hir id {} in the HIR map", id))
|
self.find(id).unwrap_or_else(|| bug!("couldn't find hir id {} in the HIR map", id))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Retrieves the `Node` corresponding to `id`, panicking if it cannot be found.
|
/// Retrieves the `Node` corresponding to `id`, panicking if it cannot be found.
|
||||||
#[inline]
|
#[inline]
|
||||||
|
#[track_caller]
|
||||||
pub fn get_by_def_id(self, id: LocalDefId) -> Node<'hir> {
|
pub fn get_by_def_id(self, id: LocalDefId) -> Node<'hir> {
|
||||||
self.find_by_def_id(id).unwrap_or_else(|| bug!("couldn't find {:?} in the HIR map", id))
|
self.find_by_def_id(id).unwrap_or_else(|| bug!("couldn't find {:?} in the HIR map", id))
|
||||||
}
|
}
|
||||||
|
@ -377,6 +381,7 @@ impl<'hir> Map<'hir> {
|
||||||
self.tcx.hir_owner_nodes(id.hir_id.owner).unwrap().bodies[&id.hir_id.local_id]
|
self.tcx.hir_owner_nodes(id.hir_id.owner).unwrap().bodies[&id.hir_id.local_id]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[track_caller]
|
||||||
pub fn fn_decl_by_hir_id(self, hir_id: HirId) -> Option<&'hir FnDecl<'hir>> {
|
pub fn fn_decl_by_hir_id(self, hir_id: HirId) -> Option<&'hir FnDecl<'hir>> {
|
||||||
if let Some(node) = self.find(hir_id) {
|
if let Some(node) = self.find(hir_id) {
|
||||||
node.fn_decl()
|
node.fn_decl()
|
||||||
|
@ -385,6 +390,7 @@ impl<'hir> Map<'hir> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[track_caller]
|
||||||
pub fn fn_sig_by_hir_id(self, hir_id: HirId) -> Option<&'hir FnSig<'hir>> {
|
pub fn fn_sig_by_hir_id(self, hir_id: HirId) -> Option<&'hir FnSig<'hir>> {
|
||||||
if let Some(node) = self.find(hir_id) {
|
if let Some(node) = self.find(hir_id) {
|
||||||
node.fn_sig()
|
node.fn_sig()
|
||||||
|
@ -393,6 +399,7 @@ impl<'hir> Map<'hir> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[track_caller]
|
||||||
pub fn enclosing_body_owner(self, hir_id: HirId) -> LocalDefId {
|
pub fn enclosing_body_owner(self, hir_id: HirId) -> LocalDefId {
|
||||||
for (_, node) in self.parent_iter(hir_id) {
|
for (_, node) in self.parent_iter(hir_id) {
|
||||||
if let Some(body) = associated_body(node) {
|
if let Some(body) = associated_body(node) {
|
||||||
|
@ -408,7 +415,7 @@ impl<'hir> Map<'hir> {
|
||||||
/// item (possibly associated), a closure, or a `hir::AnonConst`.
|
/// item (possibly associated), a closure, or a `hir::AnonConst`.
|
||||||
pub fn body_owner(self, BodyId { hir_id }: BodyId) -> HirId {
|
pub fn body_owner(self, BodyId { hir_id }: BodyId) -> HirId {
|
||||||
let parent = self.get_parent_node(hir_id);
|
let parent = self.get_parent_node(hir_id);
|
||||||
assert!(self.find(parent).map_or(false, |n| is_body_owner(n, hir_id)));
|
assert!(self.find(parent).map_or(false, |n| is_body_owner(n, hir_id)), "{hir_id:?}");
|
||||||
parent
|
parent
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -419,10 +426,11 @@ impl<'hir> Map<'hir> {
|
||||||
/// Given a `LocalDefId`, returns the `BodyId` associated with it,
|
/// Given a `LocalDefId`, returns the `BodyId` associated with it,
|
||||||
/// if the node is a body owner, otherwise returns `None`.
|
/// if the node is a body owner, otherwise returns `None`.
|
||||||
pub fn maybe_body_owned_by(self, id: LocalDefId) -> Option<BodyId> {
|
pub fn maybe_body_owned_by(self, id: LocalDefId) -> Option<BodyId> {
|
||||||
self.get_if_local(id.to_def_id()).map(associated_body).flatten()
|
self.find_by_def_id(id).and_then(associated_body)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Given a body owner's id, returns the `BodyId` associated with it.
|
/// Given a body owner's id, returns the `BodyId` associated with it.
|
||||||
|
#[track_caller]
|
||||||
pub fn body_owned_by(self, id: LocalDefId) -> BodyId {
|
pub fn body_owned_by(self, id: LocalDefId) -> BodyId {
|
||||||
self.maybe_body_owned_by(id).unwrap_or_else(|| {
|
self.maybe_body_owned_by(id).unwrap_or_else(|| {
|
||||||
let hir_id = self.local_def_id_to_hir_id(id);
|
let hir_id = self.local_def_id_to_hir_id(id);
|
||||||
|
|
|
@ -320,8 +320,10 @@ pub enum StatementKind<'tcx> {
|
||||||
/// <https://internals.rust-lang.org/t/stacked-borrows-an-aliasing-model-for-rust/8153/> for
|
/// <https://internals.rust-lang.org/t/stacked-borrows-an-aliasing-model-for-rust/8153/> for
|
||||||
/// more details.
|
/// more details.
|
||||||
///
|
///
|
||||||
/// For code that is not specific to stacked borrows, you should consider retags to read
|
/// For code that is not specific to stacked borrows, you should consider retags to read and
|
||||||
/// and modify the place in an opaque way.
|
/// modify the place in an opaque way.
|
||||||
|
///
|
||||||
|
/// Only `RetagKind::Default` and `RetagKind::FnEntry` are permitted.
|
||||||
Retag(RetagKind, Box<Place<'tcx>>),
|
Retag(RetagKind, Box<Place<'tcx>>),
|
||||||
|
|
||||||
/// Encodes a user's type ascription. These need to be preserved
|
/// Encodes a user's type ascription. These need to be preserved
|
||||||
|
|
|
@ -70,14 +70,6 @@ impl GenericParamDef {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn has_default(&self) -> bool {
|
|
||||||
match self.kind {
|
|
||||||
GenericParamDefKind::Type { has_default, .. }
|
|
||||||
| GenericParamDefKind::Const { has_default } => has_default,
|
|
||||||
GenericParamDefKind::Lifetime => false,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn is_anonymous_lifetime(&self) -> bool {
|
pub fn is_anonymous_lifetime(&self) -> bool {
|
||||||
match self.kind {
|
match self.kind {
|
||||||
GenericParamDefKind::Lifetime => {
|
GenericParamDefKind::Lifetime => {
|
||||||
|
|
|
@ -348,7 +348,7 @@ impl<'tcx> InternalSubsts<'tcx> {
|
||||||
substs.reserve(defs.params.len());
|
substs.reserve(defs.params.len());
|
||||||
for param in &defs.params {
|
for param in &defs.params {
|
||||||
let kind = mk_kind(param, substs);
|
let kind = mk_kind(param, substs);
|
||||||
assert_eq!(param.index as usize, substs.len());
|
assert_eq!(param.index as usize, substs.len(), "{substs:#?}, {defs:#?}");
|
||||||
substs.push(kind);
|
substs.push(kind);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -88,9 +88,11 @@ pub trait TypeVisitable<'tcx>: fmt::Debug + Clone {
|
||||||
self.has_vars_bound_at_or_above(ty::INNERMOST)
|
self.has_vars_bound_at_or_above(ty::INNERMOST)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[instrument(level = "trace", ret)]
|
|
||||||
fn has_type_flags(&self, flags: TypeFlags) -> bool {
|
fn has_type_flags(&self, flags: TypeFlags) -> bool {
|
||||||
self.visit_with(&mut HasTypeFlagsVisitor { flags }).break_value() == Some(FoundFlags)
|
let res =
|
||||||
|
self.visit_with(&mut HasTypeFlagsVisitor { flags }).break_value() == Some(FoundFlags);
|
||||||
|
trace!(?self, ?flags, ?res, "has_type_flags");
|
||||||
|
res
|
||||||
}
|
}
|
||||||
fn has_projections(&self) -> bool {
|
fn has_projections(&self) -> bool {
|
||||||
self.has_type_flags(TypeFlags::HAS_PROJECTION)
|
self.has_type_flags(TypeFlags::HAS_PROJECTION)
|
||||||
|
@ -560,10 +562,8 @@ impl<'tcx> TypeVisitor<'tcx> for HasTypeFlagsVisitor {
|
||||||
type BreakTy = FoundFlags;
|
type BreakTy = FoundFlags;
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
#[instrument(skip(self), level = "trace", ret)]
|
|
||||||
fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
|
fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
|
||||||
let flags = t.flags();
|
let flags = t.flags();
|
||||||
trace!(t.flags=?t.flags());
|
|
||||||
if flags.intersects(self.flags) {
|
if flags.intersects(self.flags) {
|
||||||
ControlFlow::Break(FoundFlags)
|
ControlFlow::Break(FoundFlags)
|
||||||
} else {
|
} else {
|
||||||
|
@ -572,10 +572,8 @@ impl<'tcx> TypeVisitor<'tcx> for HasTypeFlagsVisitor {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
#[instrument(skip(self), level = "trace", ret)]
|
|
||||||
fn visit_region(&mut self, r: ty::Region<'tcx>) -> ControlFlow<Self::BreakTy> {
|
fn visit_region(&mut self, r: ty::Region<'tcx>) -> ControlFlow<Self::BreakTy> {
|
||||||
let flags = r.type_flags();
|
let flags = r.type_flags();
|
||||||
trace!(r.flags=?flags);
|
|
||||||
if flags.intersects(self.flags) {
|
if flags.intersects(self.flags) {
|
||||||
ControlFlow::Break(FoundFlags)
|
ControlFlow::Break(FoundFlags)
|
||||||
} else {
|
} else {
|
||||||
|
@ -584,7 +582,6 @@ impl<'tcx> TypeVisitor<'tcx> for HasTypeFlagsVisitor {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
#[instrument(level = "trace", ret)]
|
|
||||||
fn visit_const(&mut self, c: ty::Const<'tcx>) -> ControlFlow<Self::BreakTy> {
|
fn visit_const(&mut self, c: ty::Const<'tcx>) -> ControlFlow<Self::BreakTy> {
|
||||||
let flags = FlagComputation::for_const(c);
|
let flags = FlagComputation::for_const(c);
|
||||||
trace!(r.flags=?flags);
|
trace!(r.flags=?flags);
|
||||||
|
@ -596,14 +593,7 @@ impl<'tcx> TypeVisitor<'tcx> for HasTypeFlagsVisitor {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
#[instrument(level = "trace", ret)]
|
|
||||||
fn visit_predicate(&mut self, predicate: ty::Predicate<'tcx>) -> ControlFlow<Self::BreakTy> {
|
fn visit_predicate(&mut self, predicate: ty::Predicate<'tcx>) -> ControlFlow<Self::BreakTy> {
|
||||||
debug!(
|
|
||||||
"HasTypeFlagsVisitor: predicate={:?} predicate.flags={:?} self.flags={:?}",
|
|
||||||
predicate,
|
|
||||||
predicate.flags(),
|
|
||||||
self.flags
|
|
||||||
);
|
|
||||||
if predicate.flags().intersects(self.flags) {
|
if predicate.flags().intersects(self.flags) {
|
||||||
ControlFlow::Break(FoundFlags)
|
ControlFlow::Break(FoundFlags)
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -15,9 +15,6 @@ impl<'tcx, 'body> ParseCtxt<'tcx, 'body> {
|
||||||
@call("mir_retag", args) => {
|
@call("mir_retag", args) => {
|
||||||
Ok(StatementKind::Retag(RetagKind::Default, Box::new(self.parse_place(args[0])?)))
|
Ok(StatementKind::Retag(RetagKind::Default, Box::new(self.parse_place(args[0])?)))
|
||||||
},
|
},
|
||||||
@call("mir_retag_raw", args) => {
|
|
||||||
Ok(StatementKind::Retag(RetagKind::Raw, Box::new(self.parse_place(args[0])?)))
|
|
||||||
},
|
|
||||||
@call("mir_set_discriminant", args) => {
|
@call("mir_set_discriminant", args) => {
|
||||||
let place = self.parse_place(args[0])?;
|
let place = self.parse_place(args[0])?;
|
||||||
let var = self.parse_integer_literal(args[1])? as u32;
|
let var = self.parse_integer_literal(args[1])? as u32;
|
||||||
|
|
|
@ -14,21 +14,27 @@ impl<'a, 'tcx> TypeRelation<'tcx> for CollectAllMismatches<'a, 'tcx> {
|
||||||
fn tag(&self) -> &'static str {
|
fn tag(&self) -> &'static str {
|
||||||
"CollectAllMismatches"
|
"CollectAllMismatches"
|
||||||
}
|
}
|
||||||
|
|
||||||
fn tcx(&self) -> TyCtxt<'tcx> {
|
fn tcx(&self) -> TyCtxt<'tcx> {
|
||||||
self.infcx.tcx
|
self.infcx.tcx
|
||||||
}
|
}
|
||||||
|
|
||||||
fn intercrate(&self) -> bool {
|
fn intercrate(&self) -> bool {
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
|
|
||||||
fn param_env(&self) -> ty::ParamEnv<'tcx> {
|
fn param_env(&self) -> ty::ParamEnv<'tcx> {
|
||||||
self.param_env
|
self.param_env
|
||||||
}
|
}
|
||||||
|
|
||||||
fn a_is_expected(&self) -> bool {
|
fn a_is_expected(&self) -> bool {
|
||||||
true
|
true
|
||||||
} // irrelevant
|
}
|
||||||
|
|
||||||
fn mark_ambiguous(&mut self) {
|
fn mark_ambiguous(&mut self) {
|
||||||
bug!()
|
bug!()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn relate_with_variance<T: Relate<'tcx>>(
|
fn relate_with_variance<T: Relate<'tcx>>(
|
||||||
&mut self,
|
&mut self,
|
||||||
_: ty::Variance,
|
_: ty::Variance,
|
||||||
|
@ -38,6 +44,7 @@ impl<'a, 'tcx> TypeRelation<'tcx> for CollectAllMismatches<'a, 'tcx> {
|
||||||
) -> RelateResult<'tcx, T> {
|
) -> RelateResult<'tcx, T> {
|
||||||
self.relate(a, b)
|
self.relate(a, b)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn regions(
|
fn regions(
|
||||||
&mut self,
|
&mut self,
|
||||||
a: ty::Region<'tcx>,
|
a: ty::Region<'tcx>,
|
||||||
|
@ -45,15 +52,20 @@ impl<'a, 'tcx> TypeRelation<'tcx> for CollectAllMismatches<'a, 'tcx> {
|
||||||
) -> RelateResult<'tcx, ty::Region<'tcx>> {
|
) -> RelateResult<'tcx, ty::Region<'tcx>> {
|
||||||
Ok(a)
|
Ok(a)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn tys(&mut self, a: Ty<'tcx>, b: Ty<'tcx>) -> RelateResult<'tcx, Ty<'tcx>> {
|
fn tys(&mut self, a: Ty<'tcx>, b: Ty<'tcx>) -> RelateResult<'tcx, Ty<'tcx>> {
|
||||||
if a == b || matches!(a.kind(), ty::Infer(_)) || matches!(b.kind(), ty::Infer(_)) {
|
self.infcx.probe(|_| {
|
||||||
return Ok(a);
|
if a.is_ty_infer() || b.is_ty_infer() {
|
||||||
}
|
Ok(a)
|
||||||
relate::super_relate_tys(self, a, b).or_else(|e| {
|
} else {
|
||||||
|
self.infcx.super_combine_tys(self, a, b).or_else(|e| {
|
||||||
self.errors.push(e);
|
self.errors.push(e);
|
||||||
Ok(a)
|
Ok(a)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
fn consts(
|
fn consts(
|
||||||
&mut self,
|
&mut self,
|
||||||
a: ty::Const<'tcx>,
|
a: ty::Const<'tcx>,
|
||||||
|
@ -64,6 +76,7 @@ impl<'a, 'tcx> TypeRelation<'tcx> for CollectAllMismatches<'a, 'tcx> {
|
||||||
}
|
}
|
||||||
relate::super_relate_consts(self, a, b) // could do something similar here for constants!
|
relate::super_relate_consts(self, a, b) // could do something similar here for constants!
|
||||||
}
|
}
|
||||||
|
|
||||||
fn binders<T: Relate<'tcx>>(
|
fn binders<T: Relate<'tcx>>(
|
||||||
&mut self,
|
&mut self,
|
||||||
a: ty::Binder<'tcx, T>,
|
a: ty::Binder<'tcx, T>,
|
||||||
|
|
|
@ -335,7 +335,7 @@ pub trait TypeErrCtxtExt<'tcx> {
|
||||||
err: &mut Diagnostic,
|
err: &mut Diagnostic,
|
||||||
trait_pred: ty::PolyTraitPredicate<'tcx>,
|
trait_pred: ty::PolyTraitPredicate<'tcx>,
|
||||||
);
|
);
|
||||||
fn function_argument_obligation(
|
fn note_function_argument_obligation(
|
||||||
&self,
|
&self,
|
||||||
arg_hir_id: HirId,
|
arg_hir_id: HirId,
|
||||||
err: &mut Diagnostic,
|
err: &mut Diagnostic,
|
||||||
|
@ -2909,7 +2909,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
|
||||||
ref parent_code,
|
ref parent_code,
|
||||||
..
|
..
|
||||||
} => {
|
} => {
|
||||||
self.function_argument_obligation(
|
self.note_function_argument_obligation(
|
||||||
arg_hir_id,
|
arg_hir_id,
|
||||||
err,
|
err,
|
||||||
parent_code,
|
parent_code,
|
||||||
|
@ -3141,23 +3141,20 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fn function_argument_obligation(
|
fn note_function_argument_obligation(
|
||||||
&self,
|
&self,
|
||||||
arg_hir_id: HirId,
|
arg_hir_id: HirId,
|
||||||
err: &mut Diagnostic,
|
err: &mut Diagnostic,
|
||||||
parent_code: &ObligationCauseCode<'tcx>,
|
parent_code: &ObligationCauseCode<'tcx>,
|
||||||
param_env: ty::ParamEnv<'tcx>,
|
param_env: ty::ParamEnv<'tcx>,
|
||||||
predicate: ty::Predicate<'tcx>,
|
failed_pred: ty::Predicate<'tcx>,
|
||||||
call_hir_id: HirId,
|
call_hir_id: HirId,
|
||||||
) {
|
) {
|
||||||
let tcx = self.tcx;
|
let tcx = self.tcx;
|
||||||
let hir = tcx.hir();
|
let hir = tcx.hir();
|
||||||
if let Some(Node::Expr(expr)) = hir.find(arg_hir_id) {
|
if let Some(Node::Expr(expr)) = hir.find(arg_hir_id)
|
||||||
let parent_id = hir.get_parent_item(arg_hir_id);
|
&& let Some(typeck_results) = &self.typeck_results
|
||||||
let typeck_results: &TypeckResults<'tcx> = match &self.typeck_results {
|
{
|
||||||
Some(t) if t.hir_owner == parent_id => t,
|
|
||||||
_ => self.tcx.typeck(parent_id.def_id),
|
|
||||||
};
|
|
||||||
if let hir::Expr { kind: hir::ExprKind::Block(..), .. } = expr {
|
if let hir::Expr { kind: hir::ExprKind::Block(..), .. } = expr {
|
||||||
let expr = expr.peel_blocks();
|
let expr = expr.peel_blocks();
|
||||||
let ty = typeck_results.expr_ty_adjusted_opt(expr).unwrap_or(tcx.ty_error());
|
let ty = typeck_results.expr_ty_adjusted_opt(expr).unwrap_or(tcx.ty_error());
|
||||||
|
@ -3182,37 +3179,29 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
|
||||||
let mut type_diffs = vec![];
|
let mut type_diffs = vec![];
|
||||||
|
|
||||||
if let ObligationCauseCode::ExprBindingObligation(def_id, _, _, idx) = parent_code.deref()
|
if let ObligationCauseCode::ExprBindingObligation(def_id, _, _, idx) = parent_code.deref()
|
||||||
&& let predicates = self.tcx.predicates_of(def_id).instantiate_identity(self.tcx)
|
&& let Some(node_substs) = typeck_results.node_substs_opt(call_hir_id)
|
||||||
&& let Some(pred) = predicates.predicates.get(*idx)
|
&& let where_clauses = self.tcx.predicates_of(def_id).instantiate(self.tcx, node_substs)
|
||||||
|
&& let Some(where_pred) = where_clauses.predicates.get(*idx)
|
||||||
{
|
{
|
||||||
if let Ok(trait_pred) = pred.kind().try_map_bound(|pred| match pred {
|
if let Some(where_pred) = where_pred.to_opt_poly_trait_pred()
|
||||||
ty::PredicateKind::Clause(ty::Clause::Trait(trait_pred)) => Ok(trait_pred),
|
&& let Some(failed_pred) = failed_pred.to_opt_poly_trait_pred()
|
||||||
_ => Err(()),
|
|
||||||
})
|
|
||||||
&& let Ok(trait_predicate) = predicate.kind().try_map_bound(|pred| match pred {
|
|
||||||
ty::PredicateKind::Clause(ty::Clause::Trait(trait_pred)) => Ok(trait_pred),
|
|
||||||
_ => Err(()),
|
|
||||||
})
|
|
||||||
{
|
{
|
||||||
let mut c = CollectAllMismatches {
|
let mut c = CollectAllMismatches {
|
||||||
infcx: self.infcx,
|
infcx: self.infcx,
|
||||||
param_env,
|
param_env,
|
||||||
errors: vec![],
|
errors: vec![],
|
||||||
};
|
};
|
||||||
if let Ok(_) = c.relate(trait_pred, trait_predicate) {
|
if let Ok(_) = c.relate(where_pred, failed_pred) {
|
||||||
type_diffs = c.errors;
|
type_diffs = c.errors;
|
||||||
}
|
}
|
||||||
} else if let ty::PredicateKind::Clause(
|
} else if let Some(where_pred) = where_pred.to_opt_poly_projection_pred()
|
||||||
ty::Clause::Projection(proj)
|
&& let Some(failed_pred) = failed_pred.to_opt_poly_projection_pred()
|
||||||
) = pred.kind().skip_binder()
|
&& let Some(found) = failed_pred.skip_binder().term.ty()
|
||||||
&& let ty::PredicateKind::Clause(
|
|
||||||
ty::Clause::Projection(projection)
|
|
||||||
) = predicate.kind().skip_binder()
|
|
||||||
{
|
{
|
||||||
type_diffs = vec![
|
type_diffs = vec![
|
||||||
Sorts(ty::error::ExpectedFound {
|
Sorts(ty::error::ExpectedFound {
|
||||||
expected: self.tcx.mk_ty(ty::Alias(ty::Projection, proj.projection_ty)),
|
expected: self.tcx.mk_ty(ty::Alias(ty::Projection, where_pred.skip_binder().projection_ty)),
|
||||||
found: projection.term.ty().unwrap(),
|
found,
|
||||||
}),
|
}),
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
@ -3227,9 +3216,9 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
|
||||||
// If the expression we're calling on is a binding, we want to point at the
|
// If the expression we're calling on is a binding, we want to point at the
|
||||||
// `let` when talking about the type. Otherwise we'll point at every part
|
// `let` when talking about the type. Otherwise we'll point at every part
|
||||||
// of the method chain with the type.
|
// of the method chain with the type.
|
||||||
self.point_at_chain(binding_expr, typeck_results, type_diffs, param_env, err);
|
self.point_at_chain(binding_expr, &typeck_results, type_diffs, param_env, err);
|
||||||
} else {
|
} else {
|
||||||
self.point_at_chain(expr, typeck_results, type_diffs, param_env, err);
|
self.point_at_chain(expr, &typeck_results, type_diffs, param_env, err);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
let call_node = hir.find(call_hir_id);
|
let call_node = hir.find(call_hir_id);
|
||||||
|
|
|
@ -51,7 +51,7 @@ macro_rules! impl_fn_mut_tuple {
|
||||||
impl<'a, $($var,)* ClosureArguments, Function, ClosureReturnValue> const
|
impl<'a, $($var,)* ClosureArguments, Function, ClosureReturnValue> const
|
||||||
FnOnce<ClosureArguments> for ConstFnMutClosure<($(&'a mut $var),*), Function>
|
FnOnce<ClosureArguments> for ConstFnMutClosure<($(&'a mut $var),*), Function>
|
||||||
where
|
where
|
||||||
Function: ~const Fn(($(&mut $var),*), ClosureArguments) -> ClosureReturnValue+ ~const Destruct,
|
Function: ~const Fn(($(&mut $var),*), ClosureArguments) -> ClosureReturnValue + ~const Destruct,
|
||||||
{
|
{
|
||||||
type Output = ClosureReturnValue;
|
type Output = ClosureReturnValue;
|
||||||
|
|
||||||
|
@ -64,7 +64,7 @@ macro_rules! impl_fn_mut_tuple {
|
||||||
impl<'a, $($var,)* ClosureArguments, Function, ClosureReturnValue> const
|
impl<'a, $($var,)* ClosureArguments, Function, ClosureReturnValue> const
|
||||||
FnMut<ClosureArguments> for ConstFnMutClosure<($(&'a mut $var),*), Function>
|
FnMut<ClosureArguments> for ConstFnMutClosure<($(&'a mut $var),*), Function>
|
||||||
where
|
where
|
||||||
Function: ~const Fn(($(&mut $var),*), ClosureArguments)-> ClosureReturnValue,
|
Function: ~const Fn(($(&mut $var),*), ClosureArguments)-> ClosureReturnValue + ~const Destruct,
|
||||||
{
|
{
|
||||||
extern "rust-call" fn call_mut(&mut self, args: ClosureArguments) -> Self::Output {
|
extern "rust-call" fn call_mut(&mut self, args: ClosureArguments) -> Self::Output {
|
||||||
#[allow(non_snake_case)]
|
#[allow(non_snake_case)]
|
||||||
|
|
|
@ -199,7 +199,7 @@ pub trait Hash {
|
||||||
/// println!("Hash is {:x}!", hasher.finish());
|
/// println!("Hash is {:x}!", hasher.finish());
|
||||||
/// ```
|
/// ```
|
||||||
#[stable(feature = "rust1", since = "1.0.0")]
|
#[stable(feature = "rust1", since = "1.0.0")]
|
||||||
fn hash<H: Hasher>(&self, state: &mut H);
|
fn hash<H: ~const Hasher>(&self, state: &mut H);
|
||||||
|
|
||||||
/// Feeds a slice of this type into the given [`Hasher`].
|
/// Feeds a slice of this type into the given [`Hasher`].
|
||||||
///
|
///
|
||||||
|
@ -980,7 +980,7 @@ mod impls {
|
||||||
#[rustc_const_unstable(feature = "const_hash", issue = "104061")]
|
#[rustc_const_unstable(feature = "const_hash", issue = "104061")]
|
||||||
impl<T: ?Sized + ~const Hash> const Hash for &mut T {
|
impl<T: ?Sized + ~const Hash> const Hash for &mut T {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn hash<H: Hasher>(&self, state: &mut H) {
|
fn hash<H: ~const Hasher>(&self, state: &mut H) {
|
||||||
(**self).hash(state);
|
(**self).hash(state);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -259,7 +259,6 @@ define!("mir_drop", fn Drop<T>(place: T, goto: BasicBlock));
|
||||||
define!("mir_drop_and_replace", fn DropAndReplace<T>(place: T, value: T, goto: BasicBlock));
|
define!("mir_drop_and_replace", fn DropAndReplace<T>(place: T, value: T, goto: BasicBlock));
|
||||||
define!("mir_call", fn Call<T>(place: T, goto: BasicBlock, call: T));
|
define!("mir_call", fn Call<T>(place: T, goto: BasicBlock, call: T));
|
||||||
define!("mir_retag", fn Retag<T>(place: T));
|
define!("mir_retag", fn Retag<T>(place: T));
|
||||||
define!("mir_retag_raw", fn RetagRaw<T>(place: T));
|
|
||||||
define!("mir_move", fn Move<T>(place: T) -> T);
|
define!("mir_move", fn Move<T>(place: T) -> T);
|
||||||
define!("mir_static", fn Static<T>(s: T) -> &'static T);
|
define!("mir_static", fn Static<T>(s: T) -> &'static T);
|
||||||
define!("mir_static_mut", fn StaticMut<T>(s: T) -> *mut T);
|
define!("mir_static_mut", fn StaticMut<T>(s: T) -> *mut T);
|
||||||
|
|
|
@ -165,7 +165,7 @@ see chapter in The Book <https://doc.rust-lang.org/book/ch08-02-strings.html#ind
|
||||||
#[doc(alias = "]")]
|
#[doc(alias = "]")]
|
||||||
#[doc(alias = "[]")]
|
#[doc(alias = "[]")]
|
||||||
#[const_trait]
|
#[const_trait]
|
||||||
pub trait IndexMut<Idx: ?Sized>: Index<Idx> {
|
pub trait IndexMut<Idx: ?Sized>: ~const Index<Idx> {
|
||||||
/// Performs the mutable indexing (`container[index]`) operation.
|
/// Performs the mutable indexing (`container[index]`) operation.
|
||||||
///
|
///
|
||||||
/// # Panics
|
/// # Panics
|
||||||
|
|
|
@ -6,9 +6,8 @@ fn immut_ref(_1: &i32) -> &i32 {
|
||||||
|
|
||||||
bb0: {
|
bb0: {
|
||||||
_2 = &raw const (*_1); // scope 0 at $DIR/references.rs:+5:13: +5:29
|
_2 = &raw const (*_1); // scope 0 at $DIR/references.rs:+5:13: +5:29
|
||||||
Retag([raw] _2); // scope 0 at $DIR/references.rs:+6:13: +6:24
|
_0 = &(*_2); // scope 0 at $DIR/references.rs:+6:13: +6:23
|
||||||
_0 = &(*_2); // scope 0 at $DIR/references.rs:+7:13: +7:23
|
Retag(_0); // scope 0 at $DIR/references.rs:+7:13: +7:23
|
||||||
Retag(_0); // scope 0 at $DIR/references.rs:+8:13: +8:23
|
return; // scope 0 at $DIR/references.rs:+8:13: +8:21
|
||||||
return; // scope 0 at $DIR/references.rs:+9:13: +9:21
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,9 +6,8 @@ fn mut_ref(_1: &mut i32) -> &mut i32 {
|
||||||
|
|
||||||
bb0: {
|
bb0: {
|
||||||
_2 = &raw mut (*_1); // scope 0 at $DIR/references.rs:+5:13: +5:33
|
_2 = &raw mut (*_1); // scope 0 at $DIR/references.rs:+5:13: +5:33
|
||||||
Retag([raw] _2); // scope 0 at $DIR/references.rs:+6:13: +6:24
|
_0 = &mut (*_2); // scope 0 at $DIR/references.rs:+6:13: +6:26
|
||||||
_0 = &mut (*_2); // scope 0 at $DIR/references.rs:+7:13: +7:26
|
Retag(_0); // scope 0 at $DIR/references.rs:+7:13: +7:23
|
||||||
Retag(_0); // scope 0 at $DIR/references.rs:+8:13: +8:23
|
return; // scope 0 at $DIR/references.rs:+8:13: +8:21
|
||||||
return; // scope 0 at $DIR/references.rs:+9:13: +9:21
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,7 +12,6 @@ pub fn mut_ref(x: &mut i32) -> &mut i32 {
|
||||||
|
|
||||||
{
|
{
|
||||||
t = addr_of_mut!(*x);
|
t = addr_of_mut!(*x);
|
||||||
RetagRaw(t);
|
|
||||||
RET = &mut *t;
|
RET = &mut *t;
|
||||||
Retag(RET);
|
Retag(RET);
|
||||||
Return()
|
Return()
|
||||||
|
@ -28,7 +27,6 @@ pub fn immut_ref(x: &i32) -> &i32 {
|
||||||
|
|
||||||
{
|
{
|
||||||
t = addr_of!(*x);
|
t = addr_of!(*x);
|
||||||
RetagRaw(t);
|
|
||||||
RET = & *t;
|
RET = & *t;
|
||||||
Retag(RET);
|
Retag(RET);
|
||||||
Return()
|
Return()
|
||||||
|
|
30
src/test/ui/async-await/async-is-unwindsafe.rs
Normal file
30
src/test/ui/async-await/async-is-unwindsafe.rs
Normal file
|
@ -0,0 +1,30 @@
|
||||||
|
// edition:2018
|
||||||
|
|
||||||
|
fn is_unwindsafe(_: impl std::panic::UnwindSafe) {}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
// A normal future created by an async block takes a `&mut Context<'_>` argument.
|
||||||
|
// That should not leak through to the whole async block.
|
||||||
|
is_unwindsafe(async {
|
||||||
|
async {}.await; // this needs an inner await point
|
||||||
|
});
|
||||||
|
|
||||||
|
is_unwindsafe(async {
|
||||||
|
//~^ ERROR the type `&mut Context<'_>` may not be safely transferred across an unwind boundary
|
||||||
|
use std::ptr::null;
|
||||||
|
use std::task::{Context, RawWaker, RawWakerVTable, Waker};
|
||||||
|
let waker = unsafe {
|
||||||
|
Waker::from_raw(RawWaker::new(
|
||||||
|
null(),
|
||||||
|
&RawWakerVTable::new(|_| todo!(), |_| todo!(), |_| todo!(), |_| todo!()),
|
||||||
|
))
|
||||||
|
};
|
||||||
|
let mut cx = Context::from_waker(&waker);
|
||||||
|
let cx_ref = &mut cx;
|
||||||
|
|
||||||
|
async {}.await; // this needs an inner await point
|
||||||
|
|
||||||
|
// in this case, `&mut Context<'_>` is *truly* alive across an await point
|
||||||
|
drop(cx_ref);
|
||||||
|
});
|
||||||
|
}
|
38
src/test/ui/async-await/async-is-unwindsafe.stderr
Normal file
38
src/test/ui/async-await/async-is-unwindsafe.stderr
Normal file
|
@ -0,0 +1,38 @@
|
||||||
|
error[E0277]: the type `&mut Context<'_>` may not be safely transferred across an unwind boundary
|
||||||
|
--> $DIR/async-is-unwindsafe.rs:12:19
|
||||||
|
|
|
||||||
|
LL | is_unwindsafe(async {
|
||||||
|
| ___________________^
|
||||||
|
LL | |
|
||||||
|
LL | | use std::ptr::null;
|
||||||
|
LL | | use std::task::{Context, RawWaker, RawWakerVTable, Waker};
|
||||||
|
... |
|
||||||
|
LL | | drop(cx_ref);
|
||||||
|
LL | | });
|
||||||
|
| | ^
|
||||||
|
| | |
|
||||||
|
| |_____`&mut Context<'_>` may not be safely transferred across an unwind boundary
|
||||||
|
| within this `[async block@$DIR/async-is-unwindsafe.rs:12:19: 29:6]`
|
||||||
|
|
|
||||||
|
= help: within `[async block@$DIR/async-is-unwindsafe.rs:12:19: 29:6]`, the trait `UnwindSafe` is not implemented for `&mut Context<'_>`
|
||||||
|
= note: `UnwindSafe` is implemented for `&std::task::Context<'_>`, but not for `&mut std::task::Context<'_>`
|
||||||
|
note: future does not implement `UnwindSafe` as this value is used across an await
|
||||||
|
--> $DIR/async-is-unwindsafe.rs:25:17
|
||||||
|
|
|
||||||
|
LL | let cx_ref = &mut cx;
|
||||||
|
| ------ has type `&mut Context<'_>` which does not implement `UnwindSafe`
|
||||||
|
LL |
|
||||||
|
LL | async {}.await; // this needs an inner await point
|
||||||
|
| ^^^^^^ await occurs here, with `cx_ref` maybe used later
|
||||||
|
...
|
||||||
|
LL | });
|
||||||
|
| - `cx_ref` is later dropped here
|
||||||
|
note: required by a bound in `is_unwindsafe`
|
||||||
|
--> $DIR/async-is-unwindsafe.rs:3:26
|
||||||
|
|
|
||||||
|
LL | fn is_unwindsafe(_: impl std::panic::UnwindSafe) {}
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_unwindsafe`
|
||||||
|
|
||||||
|
error: aborting due to previous error
|
||||||
|
|
||||||
|
For more information about this error, try `rustc --explain E0277`.
|
|
@ -52,14 +52,14 @@ LL | .sum::<i32>(),
|
||||||
<i32 as Sum<&'a i32>>
|
<i32 as Sum<&'a i32>>
|
||||||
<i32 as Sum>
|
<i32 as Sum>
|
||||||
note: the method call chain might not have had the expected associated types
|
note: the method call chain might not have had the expected associated types
|
||||||
--> $DIR/invalid-iterator-chain.rs:20:14
|
--> $DIR/invalid-iterator-chain.rs:25:14
|
||||||
|
|
|
|
||||||
LL | vec![0, 1]
|
LL | vec![0, 1]
|
||||||
| ---------- this expression has type `Vec<{integer}>`
|
| ---------- this expression has type `Vec<{integer}>`
|
||||||
LL | .iter()
|
LL | .iter()
|
||||||
| ------ `Iterator::Item` is `&{integer}` here
|
| ------ `Iterator::Item` is `&{integer}` here
|
||||||
LL | .map(|x| x * 2)
|
LL | .map(|x| x * 2)
|
||||||
| ^^^^^^^^^^^^^^ `Iterator::Item` changed to `{integer}` here
|
| -------------- `Iterator::Item` changed to `{integer}` here
|
||||||
LL | .map(|x| x as f64)
|
LL | .map(|x| x as f64)
|
||||||
| ----------------- `Iterator::Item` changed to `f64` here
|
| ----------------- `Iterator::Item` changed to `f64` here
|
||||||
LL | .map(|x| x as i64)
|
LL | .map(|x| x as i64)
|
||||||
|
@ -84,14 +84,14 @@ LL | .sum::<i32>(),
|
||||||
<i32 as Sum<&'a i32>>
|
<i32 as Sum<&'a i32>>
|
||||||
<i32 as Sum>
|
<i32 as Sum>
|
||||||
note: the method call chain might not have had the expected associated types
|
note: the method call chain might not have had the expected associated types
|
||||||
--> $DIR/invalid-iterator-chain.rs:32:14
|
--> $DIR/invalid-iterator-chain.rs:33:14
|
||||||
|
|
|
|
||||||
LL | vec![0, 1]
|
LL | vec![0, 1]
|
||||||
| ---------- this expression has type `Vec<{integer}>`
|
| ---------- this expression has type `Vec<{integer}>`
|
||||||
LL | .iter()
|
LL | .iter()
|
||||||
| ------ `Iterator::Item` is `&{integer}` here
|
| ------ `Iterator::Item` is `&{integer}` here
|
||||||
LL | .map(|x| x * 2)
|
LL | .map(|x| x * 2)
|
||||||
| ^^^^^^^^^^^^^^ `Iterator::Item` changed to `{integer}` here
|
| -------------- `Iterator::Item` changed to `{integer}` here
|
||||||
LL | .map(|x| x as f64)
|
LL | .map(|x| x as f64)
|
||||||
| ^^^^^^^^^^^^^^^^^ `Iterator::Item` changed to `f64` here
|
| ^^^^^^^^^^^^^^^^^ `Iterator::Item` changed to `f64` here
|
||||||
LL | .filter(|x| *x > 0.0)
|
LL | .filter(|x| *x > 0.0)
|
||||||
|
|
9
src/test/ui/lint/must_not_suspend/tuple-mismatch.rs
Normal file
9
src/test/ui/lint/must_not_suspend/tuple-mismatch.rs
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
#![feature(generators)]
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let _generator = || {
|
||||||
|
yield ((), ((), ()));
|
||||||
|
yield ((), ());
|
||||||
|
//~^ ERROR mismatched types
|
||||||
|
};
|
||||||
|
}
|
12
src/test/ui/lint/must_not_suspend/tuple-mismatch.stderr
Normal file
12
src/test/ui/lint/must_not_suspend/tuple-mismatch.stderr
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
error[E0308]: mismatched types
|
||||||
|
--> $DIR/tuple-mismatch.rs:6:20
|
||||||
|
|
|
||||||
|
LL | yield ((), ());
|
||||||
|
| ^^ expected tuple, found `()`
|
||||||
|
|
|
||||||
|
= note: expected tuple `((), ())`
|
||||||
|
found unit type `()`
|
||||||
|
|
||||||
|
error: aborting due to previous error
|
||||||
|
|
||||||
|
For more information about this error, try `rustc --explain E0308`.
|
Loading…
Add table
Add a link
Reference in a new issue