commit
8a3688926c
213 changed files with 2113 additions and 1293 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
|
@ -42,6 +42,7 @@ no_llvm_build
|
|||
/llvm/
|
||||
/mingw-build/
|
||||
build/
|
||||
!/compiler/rustc_mir_build/src/build/
|
||||
/build-rust-analyzer/
|
||||
/dist/
|
||||
/unicode-downloads
|
||||
|
|
|
|||
|
|
@ -1365,9 +1365,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "ena"
|
||||
version = "0.14.1"
|
||||
version = "0.14.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b2e5d13ca2353ab7d0230988629def93914a8c4015f621f9b13ed2955614731d"
|
||||
checksum = "c533630cf40e9caa44bd91aadc88a75d75a4c3a12b4cfde353cbed41daa1e1f1"
|
||||
dependencies = [
|
||||
"log",
|
||||
]
|
||||
|
|
|
|||
|
|
@ -1426,13 +1426,9 @@ pub enum ExprKind {
|
|||
Block(P<Block>, Option<Label>),
|
||||
/// An async block (`async move { ... }`).
|
||||
///
|
||||
/// The `NodeId` is the `NodeId` for the closure that results from
|
||||
/// desugaring an async block, just like the NodeId field in the
|
||||
/// `Async::Yes` variant. This is necessary in order to create a def for the
|
||||
/// closure which can be used as a parent of any child defs. Defs
|
||||
/// created during lowering cannot be made the parent of any other
|
||||
/// preexisting defs.
|
||||
Async(CaptureBy, NodeId, P<Block>),
|
||||
/// The async block used to have a `NodeId`, which was removed in favor of
|
||||
/// using the parent `NodeId` of the parent `Expr`.
|
||||
Async(CaptureBy, P<Block>),
|
||||
/// An await expression (`my_future.await`).
|
||||
Await(P<Expr>),
|
||||
|
||||
|
|
|
|||
|
|
@ -1407,8 +1407,7 @@ pub fn noop_visit_expr<T: MutVisitor>(
|
|||
vis.visit_block(blk);
|
||||
visit_opt(label, |label| vis.visit_label(label));
|
||||
}
|
||||
ExprKind::Async(_capture_by, node_id, body) => {
|
||||
vis.visit_id(node_id);
|
||||
ExprKind::Async(_capture_by, body) => {
|
||||
vis.visit_block(body);
|
||||
}
|
||||
ExprKind::Await(expr) => vis.visit_expr(expr),
|
||||
|
|
|
|||
|
|
@ -259,7 +259,6 @@ pub enum ExprPrecedence {
|
|||
Assign,
|
||||
AssignOp,
|
||||
|
||||
Box,
|
||||
AddrOf,
|
||||
Let,
|
||||
Unary,
|
||||
|
|
@ -319,8 +318,7 @@ impl ExprPrecedence {
|
|||
ExprPrecedence::AssignOp => AssocOp::Assign.precedence() as i8,
|
||||
|
||||
// Unary, prefix
|
||||
ExprPrecedence::Box
|
||||
| ExprPrecedence::AddrOf
|
||||
ExprPrecedence::AddrOf
|
||||
// Here `let pats = expr` has `let pats =` as a "unary" prefix of `expr`.
|
||||
// However, this is not exactly right. When `let _ = a` is the LHS of a binop we
|
||||
// need parens sometimes. E.g. we can print `(let _ = a) && b` as `let _ = a && b`
|
||||
|
|
|
|||
|
|
@ -860,7 +860,7 @@ pub fn walk_expr<'a, V: Visitor<'a>>(visitor: &mut V, expression: &'a Expr) {
|
|||
walk_list!(visitor, visit_label, opt_label);
|
||||
visitor.visit_block(block);
|
||||
}
|
||||
ExprKind::Async(_, _, body) => {
|
||||
ExprKind::Async(_, body) => {
|
||||
visitor.visit_block(body);
|
||||
}
|
||||
ExprKind::Await(expr) => visitor.visit_expr(expr),
|
||||
|
|
|
|||
|
|
@ -63,20 +63,6 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
ExprKind::ForLoop(pat, head, body, opt_label) => {
|
||||
return self.lower_expr_for(e, pat, head, body, *opt_label);
|
||||
}
|
||||
// Similarly, async blocks do not use `e.id` but rather `closure_node_id`.
|
||||
ExprKind::Async(capture_clause, closure_node_id, block) => {
|
||||
let hir_id = self.lower_node_id(*closure_node_id);
|
||||
self.lower_attrs(hir_id, &e.attrs);
|
||||
return self.make_async_expr(
|
||||
*capture_clause,
|
||||
hir_id,
|
||||
*closure_node_id,
|
||||
None,
|
||||
e.span,
|
||||
hir::AsyncGeneratorKind::Block,
|
||||
|this| this.with_new_scopes(|this| this.lower_block_expr(block)),
|
||||
);
|
||||
}
|
||||
_ => (),
|
||||
}
|
||||
|
||||
|
|
@ -187,6 +173,14 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
self.arena.alloc_from_iter(arms.iter().map(|x| self.lower_arm(x))),
|
||||
hir::MatchSource::Normal,
|
||||
),
|
||||
ExprKind::Async(capture_clause, block) => self.make_async_expr(
|
||||
*capture_clause,
|
||||
e.id,
|
||||
None,
|
||||
e.span,
|
||||
hir::AsyncGeneratorKind::Block,
|
||||
|this| this.with_new_scopes(|this| this.lower_block_expr(block)),
|
||||
),
|
||||
ExprKind::Await(expr) => {
|
||||
let dot_await_span = if expr.span.hi() < e.span.hi() {
|
||||
let span_with_whitespace = self
|
||||
|
|
@ -320,7 +314,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
),
|
||||
ExprKind::Try(sub_expr) => self.lower_expr_try(e.span, sub_expr),
|
||||
|
||||
ExprKind::Paren(_) | ExprKind::ForLoop(..) | ExprKind::Async(..) => {
|
||||
ExprKind::Paren(_) | ExprKind::ForLoop(..) => {
|
||||
unreachable!("already handled")
|
||||
}
|
||||
|
||||
|
|
@ -591,13 +585,12 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
pub(super) fn make_async_expr(
|
||||
&mut self,
|
||||
capture_clause: CaptureBy,
|
||||
outer_hir_id: hir::HirId,
|
||||
closure_node_id: NodeId,
|
||||
ret_ty: Option<hir::FnRetTy<'hir>>,
|
||||
span: Span,
|
||||
async_gen_kind: hir::AsyncGeneratorKind,
|
||||
body: impl FnOnce(&mut Self) -> hir::Expr<'hir>,
|
||||
) -> hir::Expr<'hir> {
|
||||
) -> hir::ExprKind<'hir> {
|
||||
let output = ret_ty.unwrap_or_else(|| hir::FnRetTy::DefaultReturn(self.lower_span(span)));
|
||||
|
||||
// Resume argument type: `ResumeTy`
|
||||
|
|
@ -644,24 +637,28 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
});
|
||||
|
||||
// `static |_task_context| -> <ret_ty> { body }`:
|
||||
let generator_kind = {
|
||||
let c = self.arena.alloc(hir::Closure {
|
||||
def_id: self.local_def_id(closure_node_id),
|
||||
binder: hir::ClosureBinder::Default,
|
||||
capture_clause,
|
||||
bound_generic_params: &[],
|
||||
fn_decl,
|
||||
body,
|
||||
fn_decl_span: self.lower_span(span),
|
||||
fn_arg_span: None,
|
||||
movability: Some(hir::Movability::Static),
|
||||
constness: hir::Constness::NotConst,
|
||||
});
|
||||
hir::ExprKind::Closure(self.arena.alloc(hir::Closure {
|
||||
def_id: self.local_def_id(closure_node_id),
|
||||
binder: hir::ClosureBinder::Default,
|
||||
capture_clause,
|
||||
bound_generic_params: &[],
|
||||
fn_decl,
|
||||
body,
|
||||
fn_decl_span: self.lower_span(span),
|
||||
fn_arg_span: None,
|
||||
movability: Some(hir::Movability::Static),
|
||||
constness: hir::Constness::NotConst,
|
||||
}))
|
||||
}
|
||||
|
||||
hir::ExprKind::Closure(c)
|
||||
};
|
||||
|
||||
let hir_id = self.lower_node_id(closure_node_id);
|
||||
/// Forwards a possible `#[track_caller]` annotation from `outer_hir_id` to
|
||||
/// `inner_hir_id` in case the `closure_track_caller` feature is enabled.
|
||||
pub(super) fn maybe_forward_track_caller(
|
||||
&mut self,
|
||||
span: Span,
|
||||
outer_hir_id: hir::HirId,
|
||||
inner_hir_id: hir::HirId,
|
||||
) {
|
||||
if self.tcx.features().closure_track_caller
|
||||
&& let Some(attrs) = self.attrs.get(&outer_hir_id.local_id)
|
||||
&& attrs.into_iter().any(|attr| attr.has_name(sym::track_caller))
|
||||
|
|
@ -669,7 +666,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
let unstable_span =
|
||||
self.mark_span_with_reason(DesugaringKind::Async, span, self.allow_gen_future.clone());
|
||||
self.lower_attrs(
|
||||
hir_id,
|
||||
inner_hir_id,
|
||||
&[Attribute {
|
||||
kind: AttrKind::Normal(ptr::P(NormalAttr {
|
||||
item: AttrItem {
|
||||
|
|
@ -685,8 +682,6 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
}],
|
||||
);
|
||||
}
|
||||
|
||||
hir::Expr { hir_id, kind: generator_kind, span: self.lower_span(span) }
|
||||
}
|
||||
|
||||
/// Desugar `<expr>.await` into:
|
||||
|
|
@ -1001,15 +996,17 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
None
|
||||
};
|
||||
|
||||
this.make_async_expr(
|
||||
let async_body = this.make_async_expr(
|
||||
capture_clause,
|
||||
closure_hir_id,
|
||||
inner_closure_id,
|
||||
async_ret_ty,
|
||||
body.span,
|
||||
hir::AsyncGeneratorKind::Closure,
|
||||
|this| this.with_new_scopes(|this| this.lower_expr_mut(body)),
|
||||
)
|
||||
);
|
||||
let hir_id = this.lower_node_id(inner_closure_id);
|
||||
this.maybe_forward_track_caller(body.span, closure_hir_id, hir_id);
|
||||
hir::Expr { hir_id, kind: async_body, span: this.lower_span(body.span) }
|
||||
});
|
||||
body_id
|
||||
});
|
||||
|
|
|
|||
|
|
@ -1146,7 +1146,6 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
|
||||
let async_expr = this.make_async_expr(
|
||||
CaptureBy::Value,
|
||||
fn_id,
|
||||
closure_id,
|
||||
None,
|
||||
body.span,
|
||||
|
|
@ -1180,7 +1179,11 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
},
|
||||
);
|
||||
|
||||
(this.arena.alloc_from_iter(parameters), async_expr)
|
||||
let hir_id = this.lower_node_id(closure_id);
|
||||
this.maybe_forward_track_caller(body.span, fn_id, hir_id);
|
||||
let expr = hir::Expr { hir_id, kind: async_expr, span: this.lower_span(body.span) };
|
||||
|
||||
(this.arena.alloc_from_iter(parameters), expr)
|
||||
})
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -439,7 +439,7 @@ impl<'a> State<'a> {
|
|||
self.ibox(0);
|
||||
self.print_block_with_attrs(blk, attrs);
|
||||
}
|
||||
ast::ExprKind::Async(capture_clause, _, blk) => {
|
||||
ast::ExprKind::Async(capture_clause, blk) => {
|
||||
self.word_nbsp("async");
|
||||
self.print_capture_clause(*capture_clause);
|
||||
// cbox/ibox in analogy to the `ExprKind::Block` arm above
|
||||
|
|
|
|||
|
|
@ -255,7 +255,7 @@ fn sccs_info<'cx, 'tcx>(
|
|||
let var_to_origin = infcx.reg_var_to_origin.borrow();
|
||||
|
||||
let mut var_to_origin_sorted = var_to_origin.clone().into_iter().collect::<Vec<_>>();
|
||||
var_to_origin_sorted.sort_by(|a, b| a.0.cmp(&b.0));
|
||||
var_to_origin_sorted.sort_by_key(|vto| vto.0);
|
||||
let mut debug_str = "region variables to origins:\n".to_string();
|
||||
for (reg_var, origin) in var_to_origin_sorted.into_iter() {
|
||||
debug_str.push_str(&format!("{:?}: {:?}\n", reg_var, origin));
|
||||
|
|
@ -2216,7 +2216,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
|||
// is in the same SCC or something. In that case, find what
|
||||
// appears to be the most interesting point to report to the
|
||||
// user via an even more ad-hoc guess.
|
||||
categorized_path.sort_by(|p0, p1| p0.category.cmp(&p1.category));
|
||||
categorized_path.sort_by_key(|p| p.category);
|
||||
debug!("sorted_path={:#?}", categorized_path);
|
||||
|
||||
(categorized_path.remove(0), extra_info)
|
||||
|
|
|
|||
|
|
@ -287,7 +287,7 @@ impl<'cx, 'a> Context<'cx, 'a> {
|
|||
// sync with the `rfc-2011-nicer-assert-messages/all-expr-kinds.rs` test.
|
||||
ExprKind::Assign(_, _, _)
|
||||
| ExprKind::AssignOp(_, _, _)
|
||||
| ExprKind::Async(_, _, _)
|
||||
| ExprKind::Async(_, _)
|
||||
| ExprKind::Await(_)
|
||||
| ExprKind::Block(_, _)
|
||||
| ExprKind::Break(_, _)
|
||||
|
|
|
|||
|
|
@ -346,17 +346,10 @@ fn codegen_fn_body(fx: &mut FunctionCx<'_, '_, '_>, start_block: Block) {
|
|||
crate::abi::codegen_return(fx);
|
||||
}
|
||||
TerminatorKind::Assert { cond, expected, msg, target, cleanup: _ } => {
|
||||
if !fx.tcx.sess.overflow_checks() {
|
||||
let overflow_not_to_check = match msg {
|
||||
AssertKind::OverflowNeg(..) => true,
|
||||
AssertKind::Overflow(op, ..) => op.is_checkable(),
|
||||
_ => false,
|
||||
};
|
||||
if overflow_not_to_check {
|
||||
let target = fx.get_block(*target);
|
||||
fx.bcx.ins().jump(target, &[]);
|
||||
continue;
|
||||
}
|
||||
if !fx.tcx.sess.overflow_checks() && msg.is_optional_overflow_check() {
|
||||
let target = fx.get_block(*target);
|
||||
fx.bcx.ins().jump(target, &[]);
|
||||
continue;
|
||||
}
|
||||
let cond = codegen_operand(fx, cond).load_scalar(fx);
|
||||
|
||||
|
|
|
|||
|
|
@ -1199,7 +1199,7 @@ pub fn linker_and_flavor(sess: &Session) -> (PathBuf, LinkerFlavor) {
|
|||
.and_then(|(lhs, rhs)| rhs.chars().all(char::is_numeric).then_some(lhs))
|
||||
.unwrap_or(stem);
|
||||
|
||||
// GCC can have an optional target prefix.
|
||||
// GCC/Clang can have an optional target prefix.
|
||||
let flavor = if stem == "emcc" {
|
||||
LinkerFlavor::EmCc
|
||||
} else if stem == "gcc"
|
||||
|
|
@ -1207,7 +1207,9 @@ pub fn linker_and_flavor(sess: &Session) -> (PathBuf, LinkerFlavor) {
|
|||
|| stem == "g++"
|
||||
|| stem.ends_with("-g++")
|
||||
|| stem == "clang"
|
||||
|| stem.ends_with("-clang")
|
||||
|| stem == "clang++"
|
||||
|| stem.ends_with("-clang++")
|
||||
{
|
||||
LinkerFlavor::from_cli(LinkerFlavorCli::Gcc, &sess.target)
|
||||
} else if stem == "wasm-ld" || stem.ends_with("-wasm-ld") {
|
||||
|
|
|
|||
|
|
@ -46,7 +46,7 @@ pub fn size_and_align_of_dst<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
|
|||
// NOTE: ideally, we want the effects of both `unchecked_smul` and `unchecked_umul`
|
||||
// (resulting in `mul nsw nuw` in LLVM IR), since we know that the multiplication
|
||||
// cannot signed wrap, and that both operands are non-negative. But at the time of writing,
|
||||
// `BuilderMethods` can't do this, and it doesn't seem to enable any further optimizations.
|
||||
// the `LLVM-C` binding can't do this, and it doesn't seem to enable any further optimizations.
|
||||
bx.unchecked_smul(info.unwrap(), bx.const_usize(unit.size.bytes())),
|
||||
bx.const_usize(unit.align.abi.bytes()),
|
||||
)
|
||||
|
|
|
|||
|
|
@ -563,15 +563,8 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
|||
// with #[rustc_inherit_overflow_checks] and inlined from
|
||||
// another crate (mostly core::num generic/#[inline] fns),
|
||||
// while the current crate doesn't use overflow checks.
|
||||
if !bx.cx().check_overflow() {
|
||||
let overflow_not_to_check = match msg {
|
||||
AssertKind::OverflowNeg(..) => true,
|
||||
AssertKind::Overflow(op, ..) => op.is_checkable(),
|
||||
_ => false,
|
||||
};
|
||||
if overflow_not_to_check {
|
||||
const_cond = Some(expected);
|
||||
}
|
||||
if !bx.cx().check_overflow() && msg.is_optional_overflow_check() {
|
||||
const_cond = Some(expected);
|
||||
}
|
||||
|
||||
// Don't codegen the panic block if success if known.
|
||||
|
|
|
|||
|
|
@ -155,7 +155,7 @@ pub trait Machine<'mir, 'tcx>: Sized {
|
|||
|
||||
/// Whether Assert(OverflowNeg) and Assert(Overflow) MIR terminators should actually
|
||||
/// check for overflow.
|
||||
fn ignore_checkable_overflow_assertions(_ecx: &InterpCx<'mir, 'tcx, Self>) -> bool;
|
||||
fn ignore_optional_overflow_checks(_ecx: &InterpCx<'mir, 'tcx, Self>) -> bool;
|
||||
|
||||
/// Entry point for obtaining the MIR of anything that should get evaluated.
|
||||
/// So not just functions and shims, but also const/static initializers, anonymous
|
||||
|
|
@ -474,7 +474,7 @@ pub macro compile_time_machine(<$mir: lifetime, $tcx: lifetime>) {
|
|||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn ignore_checkable_overflow_assertions(_ecx: &InterpCx<$mir, $tcx, Self>) -> bool {
|
||||
fn ignore_optional_overflow_checks(_ecx: &InterpCx<$mir, $tcx, Self>) -> bool {
|
||||
false
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -138,12 +138,8 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
|||
}
|
||||
|
||||
Assert { ref cond, expected, ref msg, target, cleanup } => {
|
||||
let ignored = M::ignore_checkable_overflow_assertions(self)
|
||||
&& match msg {
|
||||
mir::AssertKind::OverflowNeg(..) => true,
|
||||
mir::AssertKind::Overflow(op, ..) => op.is_checkable(),
|
||||
_ => false,
|
||||
};
|
||||
let ignored =
|
||||
M::ignore_optional_overflow_checks(self) && msg.is_optional_overflow_check();
|
||||
let cond_val = self.read_scalar(&self.eval_operand(cond, None)?)?.to_bool()?;
|
||||
if ignored || expected == cond_val {
|
||||
self.go_to_block(target);
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ edition = "2021"
|
|||
arrayvec = { version = "0.7", default-features = false }
|
||||
bitflags = "1.2.1"
|
||||
cfg-if = "1.0"
|
||||
ena = "0.14.1"
|
||||
ena = "0.14.2"
|
||||
indexmap = { version = "1.9.1" }
|
||||
jobserver_crate = { version = "0.1.13", package = "jobserver" }
|
||||
libc = "0.2"
|
||||
|
|
|
|||
|
|
@ -97,7 +97,17 @@ pub trait ObligationProcessor {
|
|||
type Error: Debug;
|
||||
type OUT: OutcomeTrait<Obligation = Self::Obligation, Error = Error<Self::Obligation, Self::Error>>;
|
||||
|
||||
fn needs_process_obligation(&self, obligation: &Self::Obligation) -> bool;
|
||||
/// Implementations can provide a fast-path to obligation-processing
|
||||
/// by counting the prefix of the passed iterator for which
|
||||
/// `needs_process_obligation` would return false.
|
||||
fn skippable_obligations<'a>(
|
||||
&'a self,
|
||||
_it: impl Iterator<Item = &'a Self::Obligation>,
|
||||
) -> usize {
|
||||
0
|
||||
}
|
||||
|
||||
fn needs_process_obligation(&self, _obligation: &Self::Obligation) -> bool;
|
||||
|
||||
fn process_obligation(
|
||||
&mut self,
|
||||
|
|
@ -416,6 +426,10 @@ impl<O: ForestObligation> ObligationForest<O> {
|
|||
loop {
|
||||
let mut has_changed = false;
|
||||
|
||||
// This is the super fast path for cheap-to-check conditions.
|
||||
let mut index =
|
||||
processor.skippable_obligations(self.nodes.iter().map(|n| &n.obligation));
|
||||
|
||||
// Note that the loop body can append new nodes, and those new nodes
|
||||
// will then be processed by subsequent iterations of the loop.
|
||||
//
|
||||
|
|
@ -424,9 +438,8 @@ impl<O: ForestObligation> ObligationForest<O> {
|
|||
// `for index in 0..self.nodes.len() { ... }` because the range would
|
||||
// be computed with the initial length, and we would miss the appended
|
||||
// nodes. Therefore we use a `while` loop.
|
||||
let mut index = 0;
|
||||
while let Some(node) = self.nodes.get_mut(index) {
|
||||
// This test is extremely hot.
|
||||
// This is the moderately fast path when the prefix skipping above didn't work out.
|
||||
if node.state.get() != NodeState::Pending
|
||||
|| !processor.needs_process_obligation(&node.obligation)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -513,6 +513,7 @@ E0790: include_str!("./error_codes/E0790.md"),
|
|||
E0791: include_str!("./error_codes/E0791.md"),
|
||||
E0792: include_str!("./error_codes/E0792.md"),
|
||||
E0793: include_str!("./error_codes/E0793.md"),
|
||||
E0794: include_str!("./error_codes/E0794.md"),
|
||||
}
|
||||
|
||||
// Undocumented removed error codes. Note that many removed error codes are documented.
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
The `Copy` trait was implemented on a type which is neither a struct nor an
|
||||
enum.
|
||||
The `Copy` trait was implemented on a type which is neither a struct, an
|
||||
enum, nor a union.
|
||||
|
||||
Erroneous code example:
|
||||
|
||||
|
|
@ -10,6 +10,6 @@ struct Bar;
|
|||
impl Copy for &'static mut Bar { } // error!
|
||||
```
|
||||
|
||||
You can only implement `Copy` for a struct or an enum.
|
||||
You can only implement `Copy` for a struct, an enum, or a union.
|
||||
The previous example will fail because `&'static mut Bar`
|
||||
is not a struct or enum.
|
||||
is not a struct, an enum, or a union.
|
||||
|
|
|
|||
64
compiler/rustc_error_codes/src/error_codes/E0794.md
Normal file
64
compiler/rustc_error_codes/src/error_codes/E0794.md
Normal file
|
|
@ -0,0 +1,64 @@
|
|||
A lifetime parameter of a function definition is called *late-bound* if it both:
|
||||
|
||||
1. appears in an argument type
|
||||
2. does not appear in a generic type constraint
|
||||
|
||||
You cannot specify lifetime arguments for late-bound lifetime parameters.
|
||||
|
||||
Erroneous code example:
|
||||
|
||||
```compile_fail,E0794
|
||||
fn foo<'a>(x: &'a str) -> &'a str { x }
|
||||
let _ = foo::<'static>;
|
||||
```
|
||||
|
||||
The type of a concrete instance of a generic function is universally quantified
|
||||
over late-bound lifetime parameters. This is because we want the function to
|
||||
work for any lifetime substituted for the late-bound lifetime parameter, no
|
||||
matter where the function is called. Consequently, it doesn't make sense to
|
||||
specify arguments for late-bound lifetime parameters, since they are not
|
||||
resolved until the function's call site(s).
|
||||
|
||||
To fix the issue, remove the specified lifetime:
|
||||
|
||||
```
|
||||
fn foo<'a>(x: &'a str) -> &'a str { x }
|
||||
let _ = foo;
|
||||
```
|
||||
|
||||
### Additional information
|
||||
|
||||
Lifetime parameters that are not late-bound are called *early-bound*.
|
||||
Confusion may arise from the fact that late-bound and early-bound
|
||||
lifetime parameters are declared the same way in function definitions.
|
||||
When referring to a function pointer type, universal quantification over
|
||||
late-bound lifetime parameters can be made explicit:
|
||||
|
||||
```
|
||||
trait BarTrait<'a> {}
|
||||
|
||||
struct Bar<'a> {
|
||||
s: &'a str
|
||||
}
|
||||
|
||||
impl<'a> BarTrait<'a> for Bar<'a> {}
|
||||
|
||||
fn bar<'a, 'b, T>(x: &'a str, _t: T) -> &'a str
|
||||
where T: BarTrait<'b>
|
||||
{
|
||||
x
|
||||
}
|
||||
|
||||
let bar_fn: for<'a> fn(&'a str, Bar<'static>) -> &'a str = bar; // OK
|
||||
let bar_fn2 = bar::<'static, Bar>; // Not allowed
|
||||
let bar_fn3 = bar::<Bar>; // OK
|
||||
```
|
||||
|
||||
In the definition of `bar`, the lifetime parameter `'a` is late-bound, while
|
||||
`'b` is early-bound. This is reflected in the type annotation for `bar_fn`,
|
||||
where `'a` is universally quantified and `'b` is substituted by a specific
|
||||
lifetime. It is not allowed to explicitly specify early-bound lifetime
|
||||
arguments when late-bound lifetime parameters are present (as for `bar_fn2`,
|
||||
see issue #42868: https://github.com/rust-lang/rust/issues/42868), although the
|
||||
types that are constrained by early-bound parameters can be specified (as for
|
||||
`bar_fn3`).
|
||||
|
|
@ -245,12 +245,24 @@ pub(super) fn emit_frag_parse_err(
|
|||
e.note(
|
||||
"the macro call doesn't expand to an expression, but it can expand to a statement",
|
||||
);
|
||||
e.span_suggestion_verbose(
|
||||
site_span.shrink_to_hi(),
|
||||
"add `;` to interpret the expansion as a statement",
|
||||
";",
|
||||
Applicability::MaybeIncorrect,
|
||||
);
|
||||
|
||||
if parser.token == token::Semi {
|
||||
if let Ok(snippet) = parser.sess.source_map().span_to_snippet(site_span) {
|
||||
e.span_suggestion_verbose(
|
||||
site_span,
|
||||
"surround the macro invocation with `{}` to interpret the expansion as a statement",
|
||||
format!("{{ {}; }}", snippet),
|
||||
Applicability::MaybeIncorrect,
|
||||
);
|
||||
}
|
||||
} else {
|
||||
e.span_suggestion_verbose(
|
||||
site_span.shrink_to_hi(),
|
||||
"add `;` to interpret the expansion as a statement",
|
||||
";",
|
||||
Applicability::MaybeIncorrect,
|
||||
);
|
||||
}
|
||||
}
|
||||
},
|
||||
_ => annotate_err_with_kind(&mut e, kind, site_span),
|
||||
|
|
|
|||
|
|
@ -91,7 +91,7 @@ declare_features! (
|
|||
/// Allows coercing non capturing closures to function pointers.
|
||||
(accepted, closure_to_fn_coercion, "1.19.0", Some(39817), None),
|
||||
/// Allows using the CMPXCHG16B target feature.
|
||||
(accepted, cmpxchg16b_target_feature, "CURRENT_RUSTC_VERSION", Some(44839), None),
|
||||
(accepted, cmpxchg16b_target_feature, "1.69.0", Some(44839), None),
|
||||
/// Allows usage of the `compile_error!` macro.
|
||||
(accepted, compile_error, "1.20.0", Some(40872), None),
|
||||
/// Allows `impl Trait` in function return types.
|
||||
|
|
|
|||
|
|
@ -161,7 +161,7 @@ declare_features! (
|
|||
/// Allows using `#[lang = ".."]` attribute for linking items to special compiler logic.
|
||||
(active, lang_items, "1.0.0", None, None),
|
||||
/// Allows the `multiple_supertrait_upcastable` lint.
|
||||
(active, multiple_supertrait_upcastable, "CURRENT_RUSTC_VERSION", None, None),
|
||||
(active, multiple_supertrait_upcastable, "1.69.0", None, None),
|
||||
/// Allows using `#[omit_gdb_pretty_printer_section]`.
|
||||
(active, omit_gdb_pretty_printer_section, "1.5.0", None, None),
|
||||
/// Allows using `#[prelude_import]` on glob `use` items.
|
||||
|
|
@ -214,7 +214,7 @@ declare_features! (
|
|||
/// Allows declaring with `#![needs_panic_runtime]` that a panic runtime is needed.
|
||||
(active, needs_panic_runtime, "1.10.0", Some(32837), None),
|
||||
/// Allows using `+bundled,+whole-archive` native libs.
|
||||
(active, packed_bundled_libs, "CURRENT_RUSTC_VERSION", Some(108081), None),
|
||||
(active, packed_bundled_libs, "1.69.0", Some(108081), None),
|
||||
/// Allows using the `#![panic_runtime]` attribute.
|
||||
(active, panic_runtime, "1.10.0", Some(32837), None),
|
||||
/// Allows using `#[rustc_allow_const_fn_unstable]`.
|
||||
|
|
@ -468,7 +468,7 @@ declare_features! (
|
|||
/// Allows using the `non_exhaustive_omitted_patterns` lint.
|
||||
(active, non_exhaustive_omitted_patterns_lint, "1.57.0", Some(89554), None),
|
||||
/// Allows `for<T>` binders in where-clauses
|
||||
(incomplete, non_lifetime_binders, "CURRENT_RUSTC_VERSION", Some(108185), None),
|
||||
(incomplete, non_lifetime_binders, "1.69.0", Some(108185), None),
|
||||
/// Allows making `dyn Trait` well-formed even if `Trait` is not object safe.
|
||||
/// In that case, `dyn Trait: Trait` does not hold. Moreover, coercions and
|
||||
/// casts in safe Rust to `dyn Trait` for such a `Trait` is also forbidden.
|
||||
|
|
|
|||
|
|
@ -1673,7 +1673,6 @@ pub struct Expr<'hir> {
|
|||
impl Expr<'_> {
|
||||
pub fn precedence(&self) -> ExprPrecedence {
|
||||
match self.kind {
|
||||
ExprKind::Box(_) => ExprPrecedence::Box,
|
||||
ExprKind::ConstBlock(_) => ExprPrecedence::ConstBlock,
|
||||
ExprKind::Array(_) => ExprPrecedence::Array,
|
||||
ExprKind::Call(..) => ExprPrecedence::Call,
|
||||
|
|
@ -1763,7 +1762,6 @@ impl Expr<'_> {
|
|||
| ExprKind::Lit(_)
|
||||
| ExprKind::ConstBlock(..)
|
||||
| ExprKind::Unary(..)
|
||||
| ExprKind::Box(..)
|
||||
| ExprKind::AddrOf(..)
|
||||
| ExprKind::Binary(..)
|
||||
| ExprKind::Yield(..)
|
||||
|
|
@ -1851,7 +1849,6 @@ impl Expr<'_> {
|
|||
| ExprKind::InlineAsm(..)
|
||||
| ExprKind::AssignOp(..)
|
||||
| ExprKind::ConstBlock(..)
|
||||
| ExprKind::Box(..)
|
||||
| ExprKind::Binary(..)
|
||||
| ExprKind::Yield(..)
|
||||
| ExprKind::DropTemps(..)
|
||||
|
|
@ -1862,8 +1859,7 @@ impl Expr<'_> {
|
|||
/// To a first-order approximation, is this a pattern?
|
||||
pub fn is_approximately_pattern(&self) -> bool {
|
||||
match &self.kind {
|
||||
ExprKind::Box(_)
|
||||
| ExprKind::Array(_)
|
||||
ExprKind::Array(_)
|
||||
| ExprKind::Call(..)
|
||||
| ExprKind::Tup(_)
|
||||
| ExprKind::Lit(_)
|
||||
|
|
@ -1910,8 +1906,6 @@ pub fn is_range_literal(expr: &Expr<'_>) -> bool {
|
|||
|
||||
#[derive(Debug, HashStable_Generic)]
|
||||
pub enum ExprKind<'hir> {
|
||||
/// A `box x` expression.
|
||||
Box(&'hir Expr<'hir>),
|
||||
/// Allow anonymous constants from an inline `const` block
|
||||
ConstBlock(AnonConst),
|
||||
/// An array (e.g., `[a, b, c, d]`).
|
||||
|
|
|
|||
|
|
@ -682,7 +682,6 @@ pub fn walk_anon_const<'v, V: Visitor<'v>>(visitor: &mut V, constant: &'v AnonCo
|
|||
pub fn walk_expr<'v, V: Visitor<'v>>(visitor: &mut V, expression: &'v Expr<'v>) {
|
||||
visitor.visit_id(expression.hir_id);
|
||||
match expression.kind {
|
||||
ExprKind::Box(ref subexpression) => visitor.visit_expr(subexpression),
|
||||
ExprKind::Array(subexpressions) => {
|
||||
walk_list!(visitor, visit_expr, subexpressions);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -612,7 +612,7 @@ pub(crate) fn prohibit_explicit_late_bound_lifetimes(
|
|||
if position == GenericArgPosition::Value
|
||||
&& args.num_lifetime_params() != param_counts.lifetimes
|
||||
{
|
||||
let mut err = tcx.sess.struct_span_err(span, msg);
|
||||
let mut err = struct_span_err!(tcx.sess, span, E0794, "{}", msg);
|
||||
err.span_note(span_late, note);
|
||||
err.emit();
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -2396,13 +2396,24 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
|
|||
tcx,
|
||||
infcx.fresh_substs_for_item(DUMMY_SP, impl_def_id),
|
||||
);
|
||||
// I guess we don't need to make a universe unless we need it,
|
||||
// but also we're on the error path, so it doesn't matter here.
|
||||
let universe = infcx.create_next_universe();
|
||||
infcx
|
||||
.can_eq(
|
||||
ty::ParamEnv::empty(),
|
||||
impl_.self_ty(),
|
||||
// Must fold past escaping bound vars too,
|
||||
// since we have those at this point in astconv.
|
||||
tcx.fold_regions(qself_ty, |_, _| tcx.lifetimes.re_erased),
|
||||
tcx.replace_escaping_bound_vars_uncached(qself_ty, ty::fold::FnMutDelegate {
|
||||
regions: &mut |_| tcx.lifetimes.re_erased,
|
||||
types: &mut |bv| tcx.mk_placeholder(ty::PlaceholderType {
|
||||
universe,
|
||||
name: bv.kind,
|
||||
}),
|
||||
consts: &mut |bv, ty| tcx.mk_const(ty::PlaceholderConst {
|
||||
universe,
|
||||
name: bv
|
||||
}, ty),
|
||||
})
|
||||
)
|
||||
})
|
||||
&& tcx.impl_polarity(impl_def_id) != ty::ImplPolarity::Negative
|
||||
|
|
@ -3317,10 +3328,13 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
|
|||
tcx,
|
||||
trait_ref.substs.extend_to(tcx, assoc.def_id, |param, _| tcx.mk_param_from_def(param)),
|
||||
);
|
||||
let fn_sig = tcx.liberate_late_bound_regions(fn_hir_id.expect_owner().to_def_id(), fn_sig);
|
||||
|
||||
let ty = if let Some(arg_idx) = arg_idx { fn_sig.input(arg_idx) } else { fn_sig.output() };
|
||||
|
||||
Some(tcx.liberate_late_bound_regions(fn_hir_id.expect_owner().to_def_id(), ty))
|
||||
Some(if let Some(arg_idx) = arg_idx {
|
||||
*fn_sig.inputs().get(arg_idx)?
|
||||
} else {
|
||||
fn_sig.output()
|
||||
})
|
||||
}
|
||||
|
||||
#[instrument(level = "trace", skip(self, generate_err))]
|
||||
|
|
|
|||
|
|
@ -557,7 +557,7 @@ fn check_item_type(tcx: TyCtxt<'_>, id: hir::ItemId) {
|
|||
check_opaque(tcx, id);
|
||||
}
|
||||
DefKind::ImplTraitPlaceholder => {
|
||||
let parent = tcx.impl_trait_in_trait_parent(id.owner_id.to_def_id());
|
||||
let parent = tcx.impl_trait_in_trait_parent_fn(id.owner_id.to_def_id());
|
||||
// Only check the validity of this opaque type if the function has a default body
|
||||
if let hir::Node::TraitItem(hir::TraitItem {
|
||||
kind: hir::TraitItemKind::Fn(_, hir::TraitFn::Provided(_)),
|
||||
|
|
|
|||
|
|
@ -1205,6 +1205,17 @@ fn compare_number_of_generics<'tcx>(
|
|||
return Ok(());
|
||||
}
|
||||
|
||||
// We never need to emit a separate error for RPITITs, since if an RPITIT
|
||||
// has mismatched type or const generic arguments, then the method that it's
|
||||
// inheriting the generics from will also have mismatched arguments, and
|
||||
// we'll report an error for that instead. Delay a bug for safety, though.
|
||||
if tcx.opt_rpitit_info(trait_.def_id).is_some() {
|
||||
return Err(tcx.sess.delay_span_bug(
|
||||
rustc_span::DUMMY_SP,
|
||||
"errors comparing numbers of generics of trait/impl functions were not emitted",
|
||||
));
|
||||
}
|
||||
|
||||
let matchings = [
|
||||
("type", trait_own_counts.types, impl_own_counts.types),
|
||||
("const", trait_own_counts.consts, impl_own_counts.consts),
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
use crate::autoderef::Autoderef;
|
||||
use crate::constrained_generic_params::{identify_constrained_generic_params, Parameter};
|
||||
|
||||
use hir::def::DefKind;
|
||||
use rustc_ast as ast;
|
||||
use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexSet};
|
||||
use rustc_errors::{pluralize, struct_span_err, Applicability, DiagnosticBuilder, ErrorGuaranteed};
|
||||
|
|
@ -1548,16 +1547,27 @@ fn check_return_position_impl_trait_in_trait_bounds<'tcx>(
|
|||
if let Some(assoc_item) = tcx.opt_associated_item(fn_def_id.to_def_id())
|
||||
&& assoc_item.container == ty::AssocItemContainer::TraitContainer
|
||||
{
|
||||
// FIXME(-Zlower-impl-trait-in-trait-to-assoc-ty): Even with the new lowering
|
||||
// strategy, we can't just call `check_associated_item` on the new RPITITs,
|
||||
// because tests like `tests/ui/async-await/in-trait/implied-bounds.rs` will fail.
|
||||
// That's because we need to check that the bounds of the RPITIT hold using
|
||||
// the special substs that we create during opaque type lowering, otherwise we're
|
||||
// getting a bunch of early bound and free regions mixed up... Haven't looked too
|
||||
// deep into this, though.
|
||||
for arg in fn_output.walk() {
|
||||
if let ty::GenericArgKind::Type(ty) = arg.unpack()
|
||||
&& let ty::Alias(ty::Opaque, proj) = ty.kind()
|
||||
&& tcx.def_kind(proj.def_id) == DefKind::ImplTraitPlaceholder
|
||||
&& tcx.impl_trait_in_trait_parent(proj.def_id) == fn_def_id.to_def_id()
|
||||
// RPITITs are always eagerly normalized into opaques, so always look for an
|
||||
// opaque here.
|
||||
&& let ty::Alias(ty::Opaque, opaque_ty) = ty.kind()
|
||||
&& let Some(opaque_def_id) = opaque_ty.def_id.as_local()
|
||||
&& let opaque = tcx.hir().expect_item(opaque_def_id).expect_opaque_ty()
|
||||
&& let hir::OpaqueTyOrigin::FnReturn(source) | hir::OpaqueTyOrigin::AsyncFn(source) = opaque.origin
|
||||
&& source == fn_def_id
|
||||
{
|
||||
let span = tcx.def_span(proj.def_id);
|
||||
let bounds = wfcx.tcx().explicit_item_bounds(proj.def_id);
|
||||
let span = tcx.def_span(opaque_ty.def_id);
|
||||
let bounds = wfcx.tcx().explicit_item_bounds(opaque_ty.def_id);
|
||||
let wf_obligations = bounds.iter().flat_map(|&(bound, bound_span)| {
|
||||
let bound = ty::EarlyBinder(bound).subst(tcx, proj.substs);
|
||||
let bound = ty::EarlyBinder(bound).subst(tcx, opaque_ty.substs);
|
||||
let normalized_bound = wfcx.normalize(span, None, bound);
|
||||
traits::wf::predicate_obligations(
|
||||
wfcx.infcx,
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ use crate::astconv::AstConv;
|
|||
use rustc_hir as hir;
|
||||
use rustc_infer::traits::util;
|
||||
use rustc_middle::ty::subst::InternalSubsts;
|
||||
use rustc_middle::ty::{self, ImplTraitInTraitData, Ty, TyCtxt};
|
||||
use rustc_middle::ty::{self, Ty, TyCtxt};
|
||||
use rustc_span::def_id::DefId;
|
||||
use rustc_span::Span;
|
||||
|
||||
|
|
@ -76,18 +76,26 @@ pub(super) fn explicit_item_bounds(
|
|||
tcx: TyCtxt<'_>,
|
||||
def_id: DefId,
|
||||
) -> &'_ [(ty::Predicate<'_>, Span)] {
|
||||
// If the def_id is about an RPITIT, delegate explicit_item_bounds to the opaque_def_id that
|
||||
// generated the synthesized associate type.
|
||||
let rpitit_info = if let Some(ImplTraitInTraitData::Trait { opaque_def_id, .. }) =
|
||||
tcx.opt_rpitit_info(def_id)
|
||||
{
|
||||
Some(opaque_def_id)
|
||||
} else {
|
||||
None
|
||||
};
|
||||
match tcx.opt_rpitit_info(def_id) {
|
||||
// RPITIT's bounds are the same as opaque type bounds, but with
|
||||
// a projection self type.
|
||||
Some(ty::ImplTraitInTraitData::Trait { opaque_def_id, .. }) => {
|
||||
let item = tcx.hir().get_by_def_id(opaque_def_id.expect_local()).expect_item();
|
||||
let opaque_ty = item.expect_opaque_ty();
|
||||
return opaque_type_bounds(
|
||||
tcx,
|
||||
opaque_def_id,
|
||||
opaque_ty.bounds,
|
||||
tcx.mk_projection(def_id, ty::InternalSubsts::identity_for_item(tcx, def_id)),
|
||||
item.span,
|
||||
);
|
||||
}
|
||||
// These should have been fed!
|
||||
Some(ty::ImplTraitInTraitData::Impl { .. }) => unreachable!(),
|
||||
None => {}
|
||||
}
|
||||
|
||||
let bounds_def_id = rpitit_info.unwrap_or(def_id);
|
||||
let hir_id = tcx.hir().local_def_id_to_hir_id(bounds_def_id.expect_local());
|
||||
let hir_id = tcx.hir().local_def_id_to_hir_id(def_id.expect_local());
|
||||
match tcx.hir().get(hir_id) {
|
||||
hir::Node::TraitItem(hir::TraitItem {
|
||||
kind: hir::TraitItemKind::Type(bounds, _),
|
||||
|
|
@ -100,12 +108,12 @@ pub(super) fn explicit_item_bounds(
|
|||
..
|
||||
}) => {
|
||||
let substs = InternalSubsts::identity_for_item(tcx, def_id);
|
||||
let item_ty = if *in_trait || rpitit_info.is_some() {
|
||||
let item_ty = if *in_trait && !tcx.lower_impl_trait_in_trait_to_assoc_ty() {
|
||||
tcx.mk_projection(def_id, substs)
|
||||
} else {
|
||||
tcx.mk_opaque(def_id, substs)
|
||||
};
|
||||
opaque_type_bounds(tcx, bounds_def_id, bounds, item_ty, *span)
|
||||
opaque_type_bounds(tcx, def_id, bounds, item_ty, *span)
|
||||
}
|
||||
_ => bug!("item_bounds called on {:?}", def_id),
|
||||
}
|
||||
|
|
|
|||
|
|
@ -112,10 +112,14 @@ fn variance_of_opaque(tcx: TyCtxt<'_>, item_def_id: LocalDefId) -> &[ty::Varianc
|
|||
fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
|
||||
match t.kind() {
|
||||
ty::Alias(_, ty::AliasTy { def_id, substs, .. })
|
||||
if matches!(
|
||||
self.tcx.def_kind(*def_id),
|
||||
DefKind::OpaqueTy | DefKind::ImplTraitPlaceholder
|
||||
) =>
|
||||
if matches!(self.tcx.def_kind(*def_id), DefKind::OpaqueTy) =>
|
||||
{
|
||||
self.visit_opaque(*def_id, substs)
|
||||
}
|
||||
// FIXME(-Zlower-impl-trait-in-trait-to-assoc-ty) check whether this is necessary
|
||||
// at all for RPITITs.
|
||||
ty::Alias(_, ty::AliasTy { def_id, substs, .. })
|
||||
if self.tcx.is_impl_trait_in_trait(*def_id) =>
|
||||
{
|
||||
self.visit_opaque(*def_id, substs)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1366,10 +1366,6 @@ impl<'a> State<'a> {
|
|||
self.ibox(INDENT_UNIT);
|
||||
self.ann.pre(self, AnnNode::Expr(expr));
|
||||
match expr.kind {
|
||||
hir::ExprKind::Box(expr) => {
|
||||
self.word_space("Box::new");
|
||||
self.print_call_post(std::slice::from_ref(expr));
|
||||
}
|
||||
hir::ExprKind::Array(exprs) => {
|
||||
self.print_expr_vec(exprs);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -299,7 +299,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
{
|
||||
// check that the `if` expr without `else` is the fn body's expr
|
||||
if expr.span == sp {
|
||||
return self.get_fn_decl(hir_id).and_then(|(fn_decl, _)| {
|
||||
return self.get_fn_decl(hir_id).and_then(|(_, fn_decl, _)| {
|
||||
let span = fn_decl.output.span();
|
||||
let snippet = self.tcx.sess.source_map().span_to_snippet(span).ok()?;
|
||||
Some((span, format!("expected `{snippet}` because of this return type")))
|
||||
|
|
|
|||
|
|
@ -2,7 +2,6 @@
|
|||
|
||||
use super::{check_fn, Expectation, FnCtxt, GeneratorTypes};
|
||||
|
||||
use hir::def::DefKind;
|
||||
use rustc_errors::ErrorGuaranteed;
|
||||
use rustc_hir as hir;
|
||||
use rustc_hir::lang_items::LangItem;
|
||||
|
|
@ -715,14 +714,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
.subst_iter_copied(self.tcx, substs)
|
||||
.find_map(|(p, s)| get_future_output(p, s))?,
|
||||
ty::Error(_) => return None,
|
||||
ty::Alias(ty::Projection, proj)
|
||||
if self.tcx.def_kind(proj.def_id) == DefKind::ImplTraitPlaceholder =>
|
||||
{
|
||||
self.tcx
|
||||
.bound_explicit_item_bounds(proj.def_id)
|
||||
.subst_iter_copied(self.tcx, proj.substs)
|
||||
.find_map(|(p, s)| get_future_output(p, s))?
|
||||
}
|
||||
ty::Alias(ty::Projection, proj) if self.tcx.is_impl_trait_in_trait(proj.def_id) => self
|
||||
.tcx
|
||||
.bound_explicit_item_bounds(proj.def_id)
|
||||
.subst_iter_copied(self.tcx, proj.substs)
|
||||
.find_map(|(p, s)| get_future_output(p, s))?,
|
||||
_ => span_bug!(
|
||||
self.tcx.def_span(expr_def_id),
|
||||
"async fn generator return type not an inference variable: {ret_ty}"
|
||||
|
|
|
|||
|
|
@ -1722,12 +1722,13 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> {
|
|||
fcx.suggest_semicolon_at_end(cond_expr.span, &mut err);
|
||||
}
|
||||
}
|
||||
fcx.get_node_fn_decl(parent).map(|(fn_decl, _, is_main)| (fn_decl, is_main))
|
||||
fcx.get_node_fn_decl(parent)
|
||||
.map(|(fn_id, fn_decl, _, is_main)| (fn_id, fn_decl, is_main))
|
||||
} else {
|
||||
fcx.get_fn_decl(parent_id)
|
||||
};
|
||||
|
||||
if let Some((fn_decl, can_suggest)) = fn_decl {
|
||||
if let Some((fn_id, fn_decl, can_suggest)) = fn_decl {
|
||||
if blk_id.is_none() {
|
||||
pointing_at_return_type |= fcx.suggest_missing_return_type(
|
||||
&mut err,
|
||||
|
|
@ -1735,7 +1736,7 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> {
|
|||
expected,
|
||||
found,
|
||||
can_suggest,
|
||||
fcx.tcx.hir().get_parent_item(id).into(),
|
||||
fn_id,
|
||||
);
|
||||
}
|
||||
if !pointing_at_return_type {
|
||||
|
|
@ -1746,17 +1747,11 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> {
|
|||
let parent_id = fcx.tcx.hir().get_parent_item(id);
|
||||
let parent_item = fcx.tcx.hir().get_by_def_id(parent_id.def_id);
|
||||
|
||||
if let (Some(expr), Some(_), Some((fn_decl, _, _))) =
|
||||
if let (Some(expr), Some(_), Some((fn_id, fn_decl, _, _))) =
|
||||
(expression, blk_id, fcx.get_node_fn_decl(parent_item))
|
||||
{
|
||||
fcx.suggest_missing_break_or_return_expr(
|
||||
&mut err,
|
||||
expr,
|
||||
fn_decl,
|
||||
expected,
|
||||
found,
|
||||
id,
|
||||
parent_id.into(),
|
||||
&mut err, expr, fn_decl, expected, found, id, fn_id,
|
||||
);
|
||||
}
|
||||
|
||||
|
|
@ -1882,7 +1877,7 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> {
|
|||
}
|
||||
|
||||
fn is_return_ty_unsized<'a>(&self, fcx: &FnCtxt<'a, 'tcx>, blk_id: hir::HirId) -> bool {
|
||||
if let Some((fn_decl, _)) = fcx.get_fn_decl(blk_id)
|
||||
if let Some((_, fn_decl, _)) = fcx.get_fn_decl(blk_id)
|
||||
&& let hir::FnRetTy::Return(ty) = fn_decl.output
|
||||
&& let ty = fcx.astconv().ast_ty_to_ty( ty)
|
||||
&& let ty::Dynamic(..) = ty.kind()
|
||||
|
|
|
|||
|
|
@ -284,7 +284,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
|
||||
let tcx = self.tcx;
|
||||
match expr.kind {
|
||||
ExprKind::Box(subexpr) => self.check_expr_box(subexpr, expected),
|
||||
ExprKind::Lit(ref lit) => self.check_lit(&lit, expected),
|
||||
ExprKind::Binary(op, lhs, rhs) => self.check_binop(expr, op, lhs, rhs, expected),
|
||||
ExprKind::Assign(lhs, rhs, span) => {
|
||||
|
|
@ -359,16 +358,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
fn check_expr_box(&self, expr: &'tcx hir::Expr<'tcx>, expected: Expectation<'tcx>) -> Ty<'tcx> {
|
||||
let expected_inner = expected.to_option(self).map_or(NoExpectation, |ty| match ty.kind() {
|
||||
ty::Adt(def, _) if def.is_box() => Expectation::rvalue_hint(self, ty.boxed_ty()),
|
||||
_ => NoExpectation,
|
||||
});
|
||||
let referent_ty = self.check_expr_with_expectation(expr, expected_inner);
|
||||
self.require_type_is_sized(referent_ty, expr.span, traits::SizedBoxType);
|
||||
self.tcx.mk_box(referent_ty)
|
||||
}
|
||||
|
||||
fn check_expr_unary(
|
||||
&self,
|
||||
unop: hir::UnOp,
|
||||
|
|
@ -799,7 +788,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
self.ret_coercion_span.set(Some(expr.span));
|
||||
}
|
||||
let cause = self.cause(expr.span, ObligationCauseCode::ReturnNoExpression);
|
||||
if let Some((fn_decl, _)) = self.get_fn_decl(expr.hir_id) {
|
||||
if let Some((_, fn_decl, _)) = self.get_fn_decl(expr.hir_id) {
|
||||
coercion.coerce_forced_unit(
|
||||
self,
|
||||
&cause,
|
||||
|
|
|
|||
|
|
@ -356,10 +356,6 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> {
|
|||
self.walk_captures(closure);
|
||||
}
|
||||
|
||||
hir::ExprKind::Box(ref base) => {
|
||||
self.consume_expr(base);
|
||||
}
|
||||
|
||||
hir::ExprKind::Yield(value, _) => {
|
||||
self.consume_expr(value);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -898,51 +898,74 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
)
|
||||
}
|
||||
|
||||
/// Given a function `Node`, return its `FnDecl` if it exists, or `None` otherwise.
|
||||
/// Given a function `Node`, return its `HirId` and `FnDecl` if it exists. Given a closure
|
||||
/// that is the child of a function, return that function's `HirId` and `FnDecl` instead.
|
||||
/// This may seem confusing at first, but this is used in diagnostics for `async fn`,
|
||||
/// for example, where most of the type checking actually happens within a nested closure,
|
||||
/// but we often want access to the parent function's signature.
|
||||
///
|
||||
/// Otherwise, return false.
|
||||
pub(in super::super) fn get_node_fn_decl(
|
||||
&self,
|
||||
node: Node<'tcx>,
|
||||
) -> Option<(&'tcx hir::FnDecl<'tcx>, Ident, bool)> {
|
||||
) -> Option<(hir::HirId, &'tcx hir::FnDecl<'tcx>, Ident, bool)> {
|
||||
match node {
|
||||
Node::Item(&hir::Item { ident, kind: hir::ItemKind::Fn(ref sig, ..), .. }) => {
|
||||
Node::Item(&hir::Item {
|
||||
ident,
|
||||
kind: hir::ItemKind::Fn(ref sig, ..),
|
||||
owner_id,
|
||||
..
|
||||
}) => {
|
||||
// This is less than ideal, it will not suggest a return type span on any
|
||||
// method called `main`, regardless of whether it is actually the entry point,
|
||||
// but it will still present it as the reason for the expected type.
|
||||
Some((&sig.decl, ident, ident.name != sym::main))
|
||||
Some((
|
||||
hir::HirId::make_owner(owner_id.def_id),
|
||||
&sig.decl,
|
||||
ident,
|
||||
ident.name != sym::main,
|
||||
))
|
||||
}
|
||||
Node::TraitItem(&hir::TraitItem {
|
||||
ident,
|
||||
kind: hir::TraitItemKind::Fn(ref sig, ..),
|
||||
owner_id,
|
||||
..
|
||||
}) => Some((&sig.decl, ident, true)),
|
||||
}) => Some((hir::HirId::make_owner(owner_id.def_id), &sig.decl, ident, true)),
|
||||
Node::ImplItem(&hir::ImplItem {
|
||||
ident,
|
||||
kind: hir::ImplItemKind::Fn(ref sig, ..),
|
||||
owner_id,
|
||||
..
|
||||
}) => Some((&sig.decl, ident, false)),
|
||||
Node::Expr(&hir::Expr {
|
||||
hir_id,
|
||||
kind: hir::ExprKind::Closure(..),
|
||||
..
|
||||
}) if let Some(Node::Item(&hir::Item {
|
||||
}) => Some((hir::HirId::make_owner(owner_id.def_id), &sig.decl, ident, false)),
|
||||
Node::Expr(&hir::Expr { hir_id, kind: hir::ExprKind::Closure(..), .. })
|
||||
if let Some(Node::Item(&hir::Item {
|
||||
ident,
|
||||
kind: hir::ItemKind::Fn(ref sig, ..),
|
||||
owner_id,
|
||||
..
|
||||
})) = self.tcx.hir().find_parent(hir_id) => Some((
|
||||
hir::HirId::make_owner(owner_id.def_id),
|
||||
&sig.decl,
|
||||
ident,
|
||||
kind: hir::ItemKind::Fn(ref sig, ..),
|
||||
..
|
||||
})) = self.tcx.hir().find_parent(hir_id) => {
|
||||
Some((&sig.decl, ident, ident.name != sym::main))
|
||||
},
|
||||
ident.name != sym::main,
|
||||
)),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
/// Given a `HirId`, return the `FnDecl` of the method it is enclosed by and whether a
|
||||
/// Given a `HirId`, return the `HirId` of the enclosing function, its `FnDecl`, and whether a
|
||||
/// suggestion can be made, `None` otherwise.
|
||||
pub fn get_fn_decl(&self, blk_id: hir::HirId) -> Option<(&'tcx hir::FnDecl<'tcx>, bool)> {
|
||||
pub fn get_fn_decl(
|
||||
&self,
|
||||
blk_id: hir::HirId,
|
||||
) -> Option<(hir::HirId, &'tcx hir::FnDecl<'tcx>, bool)> {
|
||||
// Get enclosing Fn, if it is a function or a trait method, unless there's a `loop` or
|
||||
// `while` before reaching it, as block tail returns are not available in them.
|
||||
self.tcx.hir().get_return_block(blk_id).and_then(|blk_id| {
|
||||
let parent = self.tcx.hir().get(blk_id);
|
||||
self.get_node_fn_decl(parent).map(|(fn_decl, _, is_main)| (fn_decl, is_main))
|
||||
self.get_node_fn_decl(parent)
|
||||
.map(|(fn_id, fn_decl, _, is_main)| (fn_id, fn_decl, is_main))
|
||||
})
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1669,7 +1669,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
/// Given a function block's `HirId`, returns its `FnDecl` if it exists, or `None` otherwise.
|
||||
fn get_parent_fn_decl(&self, blk_id: hir::HirId) -> Option<(&'tcx hir::FnDecl<'tcx>, Ident)> {
|
||||
let parent = self.tcx.hir().get_by_def_id(self.tcx.hir().get_parent_item(blk_id).def_id);
|
||||
self.get_node_fn_decl(parent).map(|(fn_decl, ident, _)| (fn_decl, ident))
|
||||
self.get_node_fn_decl(parent).map(|(_, fn_decl, ident, _)| (fn_decl, ident))
|
||||
}
|
||||
|
||||
/// If `expr` is a `match` expression that has only one non-`!` arm, use that arm's tail
|
||||
|
|
|
|||
|
|
@ -64,8 +64,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
let expr = expr.peel_drop_temps();
|
||||
self.suggest_missing_semicolon(err, expr, expected, false);
|
||||
let mut pointing_at_return_type = false;
|
||||
if let Some((fn_decl, can_suggest)) = self.get_fn_decl(blk_id) {
|
||||
let fn_id = self.tcx.hir().get_return_block(blk_id).unwrap();
|
||||
if let Some((fn_id, fn_decl, can_suggest)) = self.get_fn_decl(blk_id) {
|
||||
pointing_at_return_type = self.suggest_missing_return_type(
|
||||
err,
|
||||
&fn_decl,
|
||||
|
|
|
|||
|
|
@ -190,7 +190,6 @@ impl<'a, 'tcx> DropRangeVisitor<'a, 'tcx> {
|
|||
//
|
||||
// Some of these may be interesting in the future
|
||||
ExprKind::Path(..)
|
||||
| ExprKind::Box(..)
|
||||
| ExprKind::ConstBlock(..)
|
||||
| ExprKind::Array(..)
|
||||
| ExprKind::Call(..)
|
||||
|
|
@ -478,7 +477,6 @@ impl<'a, 'tcx> Visitor<'tcx> for DropRangeVisitor<'a, 'tcx> {
|
|||
| ExprKind::AssignOp(..)
|
||||
| ExprKind::Binary(..)
|
||||
| ExprKind::Block(..)
|
||||
| ExprKind::Box(..)
|
||||
| ExprKind::Cast(..)
|
||||
| ExprKind::Closure { .. }
|
||||
| ExprKind::ConstBlock(..)
|
||||
|
|
|
|||
|
|
@ -382,7 +382,6 @@ impl<'a, 'tcx> MemCategorizationContext<'a, 'tcx> {
|
|||
| hir::ExprKind::Struct(..)
|
||||
| hir::ExprKind::Repeat(..)
|
||||
| hir::ExprKind::InlineAsm(..)
|
||||
| hir::ExprKind::Box(..)
|
||||
| hir::ExprKind::Err(_) => Ok(self.cat_rvalue(expr.hir_id, expr.span, expr_ty)),
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -359,10 +359,12 @@ impl<'tcx> InferCtxt<'tcx> {
|
|||
pub fn get_impl_future_output_ty(&self, ty: Ty<'tcx>) -> Option<Ty<'tcx>> {
|
||||
let (def_id, substs) = match *ty.kind() {
|
||||
ty::Alias(_, ty::AliasTy { def_id, substs, .. })
|
||||
if matches!(
|
||||
self.tcx.def_kind(def_id),
|
||||
DefKind::OpaqueTy | DefKind::ImplTraitPlaceholder
|
||||
) =>
|
||||
if matches!(self.tcx.def_kind(def_id), DefKind::OpaqueTy) =>
|
||||
{
|
||||
(def_id, substs)
|
||||
}
|
||||
ty::Alias(_, ty::AliasTy { def_id, substs, .. })
|
||||
if self.tcx.is_impl_trait_in_trait(def_id) =>
|
||||
{
|
||||
(def_id, substs)
|
||||
}
|
||||
|
|
@ -1757,8 +1759,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
|
|||
)
|
||||
}
|
||||
(true, ty::Alias(ty::Projection, proj))
|
||||
if self.tcx.def_kind(proj.def_id)
|
||||
== DefKind::ImplTraitPlaceholder =>
|
||||
if self.tcx.is_impl_trait_in_trait(proj.def_id) =>
|
||||
{
|
||||
let sm = self.tcx.sess.source_map();
|
||||
let pos = sm.lookup_char_pos(self.tcx.def_span(proj.def_id).lo());
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
use super::TypeErrCtxt;
|
||||
use rustc_errors::Applicability::{MachineApplicable, MaybeIncorrect};
|
||||
use rustc_errors::{pluralize, Diagnostic, MultiSpan};
|
||||
use rustc_hir::{self as hir, def::DefKind};
|
||||
use rustc_hir as hir;
|
||||
use rustc_middle::traits::ObligationCauseCode;
|
||||
use rustc_middle::ty::error::ExpectedFound;
|
||||
use rustc_middle::ty::print::Printer;
|
||||
|
|
@ -75,7 +75,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
|
|||
diag.note("an associated type was expected, but a different one was found");
|
||||
}
|
||||
(ty::Param(p), ty::Alias(ty::Projection, proj)) | (ty::Alias(ty::Projection, proj), ty::Param(p))
|
||||
if tcx.def_kind(proj.def_id) != DefKind::ImplTraitPlaceholder =>
|
||||
if !tcx.is_impl_trait_in_trait(proj.def_id) =>
|
||||
{
|
||||
let p_def_id = tcx
|
||||
.generics_of(body_owner_def_id)
|
||||
|
|
@ -222,7 +222,7 @@ impl<T> Trait<T> for X {
|
|||
diag.span_label(p_span, "this type parameter");
|
||||
}
|
||||
}
|
||||
(ty::Alias(ty::Projection, proj_ty), _) if tcx.def_kind(proj_ty.def_id) != DefKind::ImplTraitPlaceholder => {
|
||||
(ty::Alias(ty::Projection, proj_ty), _) if !tcx.is_impl_trait_in_trait(proj_ty.def_id) => {
|
||||
self.expected_projection(
|
||||
diag,
|
||||
proj_ty,
|
||||
|
|
@ -231,7 +231,7 @@ impl<T> Trait<T> for X {
|
|||
cause.code(),
|
||||
);
|
||||
}
|
||||
(_, ty::Alias(ty::Projection, proj_ty)) if tcx.def_kind(proj_ty.def_id) != DefKind::ImplTraitPlaceholder => {
|
||||
(_, ty::Alias(ty::Projection, proj_ty)) if !tcx.is_impl_trait_in_trait(proj_ty.def_id) => {
|
||||
let msg = format!(
|
||||
"consider constraining the associated type `{}` to `{}`",
|
||||
values.found, values.expected,
|
||||
|
|
|
|||
|
|
@ -187,6 +187,16 @@ impl<'tcx> InferCtxtInner<'tcx> {
|
|||
self.projection_cache.with_log(&mut self.undo_log)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn try_type_variables_probe_ref(
|
||||
&self,
|
||||
vid: ty::TyVid,
|
||||
) -> Option<&type_variable::TypeVariableValue<'tcx>> {
|
||||
// Uses a read-only view of the unification table, this way we don't
|
||||
// need an undo log.
|
||||
self.type_variable_storage.eq_relations_ref().try_probe_value(vid)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn type_variables(&mut self) -> type_variable::TypeVariableTable<'_, 'tcx> {
|
||||
self.type_variable_storage.with_log(&mut self.undo_log)
|
||||
|
|
@ -1646,6 +1656,28 @@ impl<'tcx> InferCtxt<'tcx> {
|
|||
tcx.const_eval_resolve_for_typeck(param_env_erased, unevaluated, span)
|
||||
}
|
||||
|
||||
/// The returned function is used in a fast path. If it returns `true` the variable is
|
||||
/// unchanged, `false` indicates that the status is unknown.
|
||||
#[inline]
|
||||
pub fn is_ty_infer_var_definitely_unchanged<'a>(
|
||||
&'a self,
|
||||
) -> (impl Fn(TyOrConstInferVar<'tcx>) -> bool + 'a) {
|
||||
// This hoists the borrow/release out of the loop body.
|
||||
let inner = self.inner.try_borrow();
|
||||
|
||||
return move |infer_var: TyOrConstInferVar<'tcx>| match (infer_var, &inner) {
|
||||
(TyOrConstInferVar::Ty(ty_var), Ok(inner)) => {
|
||||
use self::type_variable::TypeVariableValue;
|
||||
|
||||
match inner.try_type_variables_probe_ref(ty_var) {
|
||||
Some(TypeVariableValue::Unknown { .. }) => true,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
_ => false,
|
||||
};
|
||||
}
|
||||
|
||||
/// `ty_or_const_infer_var_changed` is equivalent to one of these two:
|
||||
/// * `shallow_resolve(ty) != ty` (where `ty.kind = ty::Infer(_)`)
|
||||
/// * `shallow_resolve(ct) != ct` (where `ct.kind = ty::ConstKind::Infer(_)`)
|
||||
|
|
|
|||
|
|
@ -3,7 +3,6 @@ use super::{DefineOpaqueTypes, InferResult};
|
|||
use crate::errors::OpaqueHiddenTypeDiag;
|
||||
use crate::infer::{DefiningAnchor, InferCtxt, InferOk};
|
||||
use crate::traits;
|
||||
use hir::def::DefKind;
|
||||
use hir::def_id::{DefId, LocalDefId};
|
||||
use hir::OpaqueTyOrigin;
|
||||
use rustc_data_structures::sync::Lrc;
|
||||
|
|
@ -478,9 +477,7 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
ty::Alias(ty::Projection, proj)
|
||||
if self.tcx.def_kind(proj.def_id) == DefKind::ImplTraitPlaceholder =>
|
||||
{
|
||||
ty::Alias(ty::Projection, proj) if self.tcx.is_impl_trait_in_trait(proj.def_id) => {
|
||||
// Skip lifetime parameters that are not captures.
|
||||
let variances = self.tcx.variances_of(proj.def_id);
|
||||
|
||||
|
|
@ -559,8 +556,7 @@ impl<'tcx> InferCtxt<'tcx> {
|
|||
// FIXME(RPITIT): Don't replace RPITITs with inference vars.
|
||||
ty::Alias(ty::Projection, projection_ty)
|
||||
if !projection_ty.has_escaping_bound_vars()
|
||||
&& tcx.def_kind(projection_ty.def_id)
|
||||
!= DefKind::ImplTraitPlaceholder =>
|
||||
&& !tcx.is_impl_trait_in_trait(projection_ty.def_id) =>
|
||||
{
|
||||
self.infer_projection(
|
||||
param_env,
|
||||
|
|
|
|||
|
|
@ -190,6 +190,11 @@ impl<'tcx> TypeVariableStorage<'tcx> {
|
|||
) -> TypeVariableTable<'a, 'tcx> {
|
||||
TypeVariableTable { storage: self, undo_log }
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub(crate) fn eq_relations_ref(&self) -> &ut::UnificationTableStorage<TyVidEqKey<'tcx>> {
|
||||
&self.eq_relations
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> TypeVariableTable<'_, 'tcx> {
|
||||
|
|
|
|||
|
|
@ -224,8 +224,7 @@ impl<'a, T: EarlyLintPass> ast_visit::Visitor<'a> for EarlyContextAndPass<'a, T>
|
|||
ast::ExprKind::Closure(box ast::Closure {
|
||||
asyncness: ast::Async::Yes { closure_id, .. },
|
||||
..
|
||||
})
|
||||
| ast::ExprKind::Async(_, closure_id, ..) => self.check_id(closure_id),
|
||||
}) => self.check_id(closure_id),
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1028,7 +1028,7 @@ fn should_encode_type(tcx: TyCtxt<'_>, def_id: LocalDefId, def_kind: DefKind) ->
|
|||
| DefKind::InlineConst => true,
|
||||
|
||||
DefKind::ImplTraitPlaceholder => {
|
||||
let parent_def_id = tcx.impl_trait_in_trait_parent(def_id.to_def_id());
|
||||
let parent_def_id = tcx.impl_trait_in_trait_parent_fn(def_id.to_def_id());
|
||||
let assoc_item = tcx.associated_item(parent_def_id);
|
||||
match assoc_item.container {
|
||||
// Always encode an RPIT in an impl fn, since it always has a body
|
||||
|
|
|
|||
|
|
@ -1268,6 +1268,13 @@ impl<'tcx> BasicBlockData<'tcx> {
|
|||
}
|
||||
|
||||
impl<O> AssertKind<O> {
|
||||
/// Returns true if this an overflow checking assertion controlled by -C overflow-checks.
|
||||
pub fn is_optional_overflow_check(&self) -> bool {
|
||||
use AssertKind::*;
|
||||
use BinOp::*;
|
||||
matches!(self, OverflowNeg(..) | Overflow(Add | Sub | Mul | Shl | Shr, ..))
|
||||
}
|
||||
|
||||
/// Getting a description does not require `O` to be printable, and does not
|
||||
/// require allocation.
|
||||
/// The caller is expected to handle `BoundsCheck` separately.
|
||||
|
|
@ -1992,16 +1999,6 @@ impl BorrowKind {
|
|||
}
|
||||
}
|
||||
|
||||
impl BinOp {
|
||||
/// The checkable operators are those whose overflow checking behavior is controlled by
|
||||
/// -Coverflow-checks option. The remaining operators have either no overflow conditions (e.g.,
|
||||
/// BitAnd, BitOr, BitXor) or are always checked for overflow (e.g., Div, Rem).
|
||||
pub fn is_checkable(self) -> bool {
|
||||
use self::BinOp::*;
|
||||
matches!(self, Add | Sub | Mul | Shl | Shr)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> Debug for Rvalue<'tcx> {
|
||||
fn fmt(&self, fmt: &mut Formatter<'_>) -> fmt::Result {
|
||||
use self::Rvalue::*;
|
||||
|
|
|
|||
|
|
@ -646,8 +646,7 @@ pub enum TerminatorKind<'tcx> {
|
|||
/// When overflow checking is disabled and this is run-time MIR (as opposed to compile-time MIR
|
||||
/// that is used for CTFE), the following variants of this terminator behave as `goto target`:
|
||||
/// - `OverflowNeg(..)`,
|
||||
/// - `Overflow(op, ..)` if op is a "checkable" operation (add, sub, mul, shl, shr, but NOT
|
||||
/// div or rem).
|
||||
/// - `Overflow(op, ..)` if op is add, sub, mul, shl, shr, but NOT div or rem.
|
||||
Assert {
|
||||
cond: Operand<'tcx>,
|
||||
expected: bool,
|
||||
|
|
|
|||
|
|
@ -191,6 +191,7 @@ rustc_queries! {
|
|||
{
|
||||
desc { "determine whether the opaque is a type-alias impl trait" }
|
||||
separate_provide_extern
|
||||
feedable
|
||||
}
|
||||
|
||||
query unsizing_params_for_adt(key: DefId) -> &'tcx rustc_index::bit_set::BitSet<u32>
|
||||
|
|
|
|||
|
|
@ -305,8 +305,6 @@ pub enum ObligationCauseCode<'tcx> {
|
|||
SizedReturnType,
|
||||
/// Yield type must be `Sized`.
|
||||
SizedYieldType,
|
||||
/// Box expression result type must be `Sized`.
|
||||
SizedBoxType,
|
||||
/// Inline asm operand type must be `Sized`.
|
||||
InlineAsmSized,
|
||||
/// `[expr; N]` requires `type_of(expr): Copy`.
|
||||
|
|
|
|||
|
|
@ -2552,12 +2552,18 @@ impl<'tcx> TyCtxt<'tcx> {
|
|||
matches!(self.trait_of_item(def_id), Some(trait_id) if self.has_attr(trait_id, sym::const_trait))
|
||||
}
|
||||
|
||||
pub fn impl_trait_in_trait_parent(self, mut def_id: DefId) -> DefId {
|
||||
while let def_kind = self.def_kind(def_id) && def_kind != DefKind::AssocFn {
|
||||
debug_assert_eq!(def_kind, DefKind::ImplTraitPlaceholder);
|
||||
def_id = self.parent(def_id);
|
||||
pub fn impl_trait_in_trait_parent_fn(self, mut def_id: DefId) -> DefId {
|
||||
match self.opt_rpitit_info(def_id) {
|
||||
Some(ImplTraitInTraitData::Trait { fn_def_id, .. })
|
||||
| Some(ImplTraitInTraitData::Impl { fn_def_id, .. }) => fn_def_id,
|
||||
None => {
|
||||
while let def_kind = self.def_kind(def_id) && def_kind != DefKind::AssocFn {
|
||||
debug_assert_eq!(def_kind, DefKind::ImplTraitPlaceholder);
|
||||
def_id = self.parent(def_id);
|
||||
}
|
||||
def_id
|
||||
}
|
||||
}
|
||||
def_id
|
||||
}
|
||||
|
||||
pub fn impl_method_has_trait_impl_trait_tys(self, def_id: DefId) -> bool {
|
||||
|
|
@ -2572,6 +2578,10 @@ impl<'tcx> TyCtxt<'tcx> {
|
|||
|
||||
let Some(trait_item_def_id) = item.trait_item_def_id else { return false; };
|
||||
|
||||
if self.lower_impl_trait_in_trait_to_assoc_ty() {
|
||||
return !self.associated_items_for_impl_trait_in_trait(trait_item_def_id).is_empty();
|
||||
}
|
||||
|
||||
// FIXME(RPITIT): This does a somewhat manual walk through the signature
|
||||
// of the trait fn to look for any RPITITs, but that's kinda doing a lot
|
||||
// of work. We can probably remove this when we refactor RPITITs to be
|
||||
|
|
|
|||
|
|
@ -728,7 +728,7 @@ pub trait PrettyPrinter<'tcx>:
|
|||
}
|
||||
ty::Alias(ty::Projection, ref data) => {
|
||||
if !(self.should_print_verbose() || NO_QUERIES.with(|q| q.get()))
|
||||
&& self.tcx().def_kind(data.def_id) == DefKind::ImplTraitPlaceholder
|
||||
&& self.tcx().is_impl_trait_in_trait(data.def_id)
|
||||
{
|
||||
return self.pretty_print_opaque_impl_type(data.def_id, data.substs);
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -1288,7 +1288,7 @@ impl<'tcx> AliasTy<'tcx> {
|
|||
match tcx.def_kind(self.def_id) {
|
||||
DefKind::AssocTy | DefKind::AssocConst => tcx.parent(self.def_id),
|
||||
DefKind::ImplTraitPlaceholder => {
|
||||
tcx.parent(tcx.impl_trait_in_trait_parent(self.def_id))
|
||||
tcx.parent(tcx.impl_trait_in_trait_parent_fn(self.def_id))
|
||||
}
|
||||
kind => bug!("expected a projection AliasTy; found {kind:?}"),
|
||||
}
|
||||
|
|
|
|||
|
|
@ -73,19 +73,34 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
|||
}
|
||||
ExprKind::Binary { op, lhs, rhs } => {
|
||||
let lhs = unpack!(
|
||||
block =
|
||||
this.as_operand(block, scope, &this.thir[lhs], LocalInfo::Boring, NeedsTemporary::Maybe)
|
||||
block = this.as_operand(
|
||||
block,
|
||||
scope,
|
||||
&this.thir[lhs],
|
||||
LocalInfo::Boring,
|
||||
NeedsTemporary::Maybe
|
||||
)
|
||||
);
|
||||
let rhs = unpack!(
|
||||
block =
|
||||
this.as_operand(block, scope, &this.thir[rhs], LocalInfo::Boring, NeedsTemporary::No)
|
||||
block = this.as_operand(
|
||||
block,
|
||||
scope,
|
||||
&this.thir[rhs],
|
||||
LocalInfo::Boring,
|
||||
NeedsTemporary::No
|
||||
)
|
||||
);
|
||||
this.build_binary_op(block, op, expr_span, expr.ty, lhs, rhs)
|
||||
}
|
||||
ExprKind::Unary { op, arg } => {
|
||||
let arg = unpack!(
|
||||
block =
|
||||
this.as_operand(block, scope, &this.thir[arg], LocalInfo::Boring, NeedsTemporary::No)
|
||||
block = this.as_operand(
|
||||
block,
|
||||
scope,
|
||||
&this.thir[arg],
|
||||
LocalInfo::Boring,
|
||||
NeedsTemporary::No
|
||||
)
|
||||
);
|
||||
// Check for -MIN on signed integers
|
||||
if this.check_overflow && op == UnOp::Neg && expr.ty.is_signed() {
|
||||
|
|
@ -272,8 +287,13 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
|||
}
|
||||
ExprKind::Pointer { cast, source } => {
|
||||
let source = unpack!(
|
||||
block =
|
||||
this.as_operand(block, scope, &this.thir[source], LocalInfo::Boring, NeedsTemporary::No)
|
||||
block = this.as_operand(
|
||||
block,
|
||||
scope,
|
||||
&this.thir[source],
|
||||
LocalInfo::Boring,
|
||||
NeedsTemporary::No
|
||||
)
|
||||
);
|
||||
block.and(Rvalue::Cast(CastKind::Pointer(cast), source, expr.ty))
|
||||
}
|
||||
|
|
@ -502,8 +522,10 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
|||
Category::of(&expr.kind),
|
||||
Some(Category::Rvalue(RvalueFunc::AsRvalue) | Category::Constant)
|
||||
));
|
||||
let operand =
|
||||
unpack!(block = this.as_operand(block, scope, expr, LocalInfo::Boring, NeedsTemporary::No));
|
||||
let operand = unpack!(
|
||||
block =
|
||||
this.as_operand(block, scope, expr, LocalInfo::Boring, NeedsTemporary::No)
|
||||
);
|
||||
block.and(Rvalue::Use(operand))
|
||||
}
|
||||
}
|
||||
|
|
@ -662,8 +684,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
|||
// Repeating a const does nothing
|
||||
} else {
|
||||
// For a non-const, we may need to generate an appropriate `Drop`
|
||||
let value_operand =
|
||||
unpack!(block = this.as_operand(block, scope, value, LocalInfo::Boring, NeedsTemporary::No));
|
||||
let value_operand = unpack!(
|
||||
block = this.as_operand(block, scope, value, LocalInfo::Boring, NeedsTemporary::No)
|
||||
);
|
||||
if let Operand::Move(to_drop) = value_operand {
|
||||
let success = this.cfg.start_new_block();
|
||||
this.cfg.terminate(
|
||||
|
|
|
|||
|
|
@ -2252,7 +2252,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
|||
user_ty: None,
|
||||
source_info,
|
||||
internal: false,
|
||||
local_info: ClearCrossCrate::Set(Box::new(LocalInfo::User(BindingForm::RefForGuard))),
|
||||
local_info: ClearCrossCrate::Set(Box::new(LocalInfo::User(
|
||||
BindingForm::RefForGuard,
|
||||
))),
|
||||
});
|
||||
self.var_debug_info.push(VarDebugInfo {
|
||||
name,
|
||||
|
|
|
|||
|
|
@ -876,21 +876,18 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
|||
} => {
|
||||
self.local_decls[local].mutability = mutability;
|
||||
self.local_decls[local].source_info.scope = self.source_scope;
|
||||
**self.local_decls[local].local_info.as_mut().assert_crate_local() = if let Some(kind) = param.self_kind {
|
||||
LocalInfo::User(
|
||||
BindingForm::ImplicitSelf(kind),
|
||||
)
|
||||
} else {
|
||||
let binding_mode = ty::BindingMode::BindByValue(mutability);
|
||||
LocalInfo::User(BindingForm::Var(
|
||||
VarBindingForm {
|
||||
**self.local_decls[local].local_info.as_mut().assert_crate_local() =
|
||||
if let Some(kind) = param.self_kind {
|
||||
LocalInfo::User(BindingForm::ImplicitSelf(kind))
|
||||
} else {
|
||||
let binding_mode = ty::BindingMode::BindByValue(mutability);
|
||||
LocalInfo::User(BindingForm::Var(VarBindingForm {
|
||||
binding_mode,
|
||||
opt_ty_info: param.ty_span,
|
||||
opt_match_place: Some((None, span)),
|
||||
pat_span: span,
|
||||
},
|
||||
))
|
||||
};
|
||||
}))
|
||||
};
|
||||
self.var_indices.insert(var, LocalsForNode::One(local));
|
||||
}
|
||||
_ => {
|
||||
|
|
|
|||
|
|
@ -780,7 +780,6 @@ impl<'tcx> Cx<'tcx> {
|
|||
hir::ExprKind::DropTemps(ref source) => {
|
||||
ExprKind::Use { source: self.mirror_expr(source) }
|
||||
}
|
||||
hir::ExprKind::Box(ref value) => ExprKind::Box { value: self.mirror_expr(value) },
|
||||
hir::ExprKind::Array(ref fields) => {
|
||||
ExprKind::Array { fields: self.mirror_exprs(fields) }
|
||||
}
|
||||
|
|
|
|||
|
|
@ -655,26 +655,20 @@ where
|
|||
///
|
||||
/// ```text
|
||||
/// loop-block:
|
||||
/// can_go = cur == length_or_end
|
||||
/// can_go = cur == len
|
||||
/// if can_go then succ else drop-block
|
||||
/// drop-block:
|
||||
/// if ptr_based {
|
||||
/// ptr = cur
|
||||
/// cur = cur.offset(1)
|
||||
/// } else {
|
||||
/// ptr = &raw mut P[cur]
|
||||
/// cur = cur + 1
|
||||
/// }
|
||||
/// ptr = &raw mut P[cur]
|
||||
/// cur = cur + 1
|
||||
/// drop(ptr)
|
||||
/// ```
|
||||
fn drop_loop(
|
||||
&mut self,
|
||||
succ: BasicBlock,
|
||||
cur: Local,
|
||||
length_or_end: Place<'tcx>,
|
||||
len: Local,
|
||||
ety: Ty<'tcx>,
|
||||
unwind: Unwind,
|
||||
ptr_based: bool,
|
||||
) -> BasicBlock {
|
||||
let copy = |place: Place<'tcx>| Operand::Copy(place);
|
||||
let move_ = |place: Place<'tcx>| Operand::Move(place);
|
||||
|
|
@ -683,22 +677,19 @@ where
|
|||
let ptr_ty = tcx.mk_ptr(ty::TypeAndMut { ty: ety, mutbl: hir::Mutability::Mut });
|
||||
let ptr = Place::from(self.new_temp(ptr_ty));
|
||||
let can_go = Place::from(self.new_temp(tcx.types.bool));
|
||||
|
||||
let one = self.constant_usize(1);
|
||||
let (ptr_next, cur_next) = if ptr_based {
|
||||
(
|
||||
Rvalue::Use(copy(cur.into())),
|
||||
Rvalue::BinaryOp(BinOp::Offset, Box::new((move_(cur.into()), one))),
|
||||
)
|
||||
} else {
|
||||
(
|
||||
Rvalue::AddressOf(Mutability::Mut, tcx.mk_place_index(self.place, cur)),
|
||||
Rvalue::BinaryOp(BinOp::Add, Box::new((move_(cur.into()), one))),
|
||||
)
|
||||
};
|
||||
|
||||
let drop_block = BasicBlockData {
|
||||
statements: vec![self.assign(ptr, ptr_next), self.assign(Place::from(cur), cur_next)],
|
||||
statements: vec![
|
||||
self.assign(
|
||||
ptr,
|
||||
Rvalue::AddressOf(Mutability::Mut, tcx.mk_place_index(self.place, cur)),
|
||||
),
|
||||
self.assign(
|
||||
cur.into(),
|
||||
Rvalue::BinaryOp(BinOp::Add, Box::new((move_(cur.into()), one))),
|
||||
),
|
||||
],
|
||||
is_cleanup: unwind.is_cleanup(),
|
||||
terminator: Some(Terminator {
|
||||
source_info: self.source_info,
|
||||
|
|
@ -711,10 +702,7 @@ where
|
|||
let loop_block = BasicBlockData {
|
||||
statements: vec![self.assign(
|
||||
can_go,
|
||||
Rvalue::BinaryOp(
|
||||
BinOp::Eq,
|
||||
Box::new((copy(Place::from(cur)), copy(length_or_end))),
|
||||
),
|
||||
Rvalue::BinaryOp(BinOp::Eq, Box::new((copy(Place::from(cur)), copy(len.into())))),
|
||||
)],
|
||||
is_cleanup: unwind.is_cleanup(),
|
||||
terminator: Some(Terminator {
|
||||
|
|
@ -738,13 +726,6 @@ where
|
|||
|
||||
fn open_drop_for_array(&mut self, ety: Ty<'tcx>, opt_size: Option<u64>) -> BasicBlock {
|
||||
debug!("open_drop_for_array({:?}, {:?})", ety, opt_size);
|
||||
|
||||
// if size_of::<ety>() == 0 {
|
||||
// index_based_loop
|
||||
// } else {
|
||||
// ptr_based_loop
|
||||
// }
|
||||
|
||||
let tcx = self.tcx();
|
||||
|
||||
if let Some(size) = opt_size {
|
||||
|
|
@ -770,86 +751,36 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
let move_ = |place: Place<'tcx>| Operand::Move(place);
|
||||
let elem_size = Place::from(self.new_temp(tcx.types.usize));
|
||||
let len = Place::from(self.new_temp(tcx.types.usize));
|
||||
|
||||
let base_block = BasicBlockData {
|
||||
statements: vec![
|
||||
self.assign(elem_size, Rvalue::NullaryOp(NullOp::SizeOf, ety)),
|
||||
self.assign(len, Rvalue::Len(self.place)),
|
||||
],
|
||||
is_cleanup: self.unwind.is_cleanup(),
|
||||
terminator: Some(Terminator {
|
||||
source_info: self.source_info,
|
||||
kind: TerminatorKind::SwitchInt {
|
||||
discr: move_(elem_size),
|
||||
targets: SwitchTargets::static_if(
|
||||
0,
|
||||
self.drop_loop_pair(ety, false, len),
|
||||
self.drop_loop_pair(ety, true, len),
|
||||
),
|
||||
},
|
||||
}),
|
||||
};
|
||||
self.elaborator.patch().new_block(base_block)
|
||||
self.drop_loop_pair(ety)
|
||||
}
|
||||
|
||||
/// Creates a pair of drop-loops of `place`, which drops its contents, even
|
||||
/// in the case of 1 panic. If `ptr_based`, creates a pointer loop,
|
||||
/// otherwise create an index loop.
|
||||
fn drop_loop_pair(
|
||||
&mut self,
|
||||
ety: Ty<'tcx>,
|
||||
ptr_based: bool,
|
||||
length: Place<'tcx>,
|
||||
) -> BasicBlock {
|
||||
debug!("drop_loop_pair({:?}, {:?})", ety, ptr_based);
|
||||
/// in the case of 1 panic.
|
||||
fn drop_loop_pair(&mut self, ety: Ty<'tcx>) -> BasicBlock {
|
||||
debug!("drop_loop_pair({:?})", ety);
|
||||
let tcx = self.tcx();
|
||||
let iter_ty = if ptr_based { tcx.mk_mut_ptr(ety) } else { tcx.types.usize };
|
||||
let len = self.new_temp(tcx.types.usize);
|
||||
let cur = self.new_temp(tcx.types.usize);
|
||||
|
||||
let cur = self.new_temp(iter_ty);
|
||||
let length_or_end = if ptr_based { Place::from(self.new_temp(iter_ty)) } else { length };
|
||||
let unwind =
|
||||
self.unwind.map(|unwind| self.drop_loop(unwind, cur, len, ety, Unwind::InCleanup));
|
||||
|
||||
let unwind = self.unwind.map(|unwind| {
|
||||
self.drop_loop(unwind, cur, length_or_end, ety, Unwind::InCleanup, ptr_based)
|
||||
});
|
||||
let loop_block = self.drop_loop(self.succ, cur, len, ety, unwind);
|
||||
|
||||
let loop_block = self.drop_loop(self.succ, cur, length_or_end, ety, unwind, ptr_based);
|
||||
|
||||
let cur = Place::from(cur);
|
||||
let drop_block_stmts = if ptr_based {
|
||||
let tmp_ty = tcx.mk_mut_ptr(self.place_ty(self.place));
|
||||
let tmp = Place::from(self.new_temp(tmp_ty));
|
||||
// tmp = &raw mut P;
|
||||
// cur = tmp as *mut T;
|
||||
// end = Offset(cur, len);
|
||||
let mir_cast_kind = ty::cast::mir_cast_kind(iter_ty, tmp_ty);
|
||||
vec![
|
||||
self.assign(tmp, Rvalue::AddressOf(Mutability::Mut, self.place)),
|
||||
self.assign(cur, Rvalue::Cast(mir_cast_kind, Operand::Move(tmp), iter_ty)),
|
||||
self.assign(
|
||||
length_or_end,
|
||||
Rvalue::BinaryOp(
|
||||
BinOp::Offset,
|
||||
Box::new((Operand::Copy(cur), Operand::Move(length))),
|
||||
),
|
||||
),
|
||||
]
|
||||
} else {
|
||||
// cur = 0 (length already pushed)
|
||||
let zero = self.constant_usize(0);
|
||||
vec![self.assign(cur, Rvalue::Use(zero))]
|
||||
};
|
||||
let drop_block = self.elaborator.patch().new_block(BasicBlockData {
|
||||
statements: drop_block_stmts,
|
||||
let zero = self.constant_usize(0);
|
||||
let block = BasicBlockData {
|
||||
statements: vec![
|
||||
self.assign(len.into(), Rvalue::Len(self.place)),
|
||||
self.assign(cur.into(), Rvalue::Use(zero)),
|
||||
],
|
||||
is_cleanup: unwind.is_cleanup(),
|
||||
terminator: Some(Terminator {
|
||||
source_info: self.source_info,
|
||||
kind: TerminatorKind::Goto { target: loop_block },
|
||||
}),
|
||||
});
|
||||
};
|
||||
|
||||
let drop_block = self.elaborator.patch().new_block(block);
|
||||
// FIXME(#34708): handle partially-dropped array/slice elements.
|
||||
let reset_block = self.drop_flag_reset_block(DropFlagMode::Deep, drop_block, unwind);
|
||||
self.drop_flag_test_block(reset_block, self.succ, unwind)
|
||||
|
|
|
|||
|
|
@ -2917,7 +2917,7 @@ impl<'a> Parser<'a> {
|
|||
self.expect_keyword(kw::Async)?;
|
||||
let capture_clause = self.parse_capture_clause()?;
|
||||
let (attrs, body) = self.parse_inner_attrs_and_block()?;
|
||||
let kind = ExprKind::Async(capture_clause, DUMMY_NODE_ID, body);
|
||||
let kind = ExprKind::Async(capture_clause, body);
|
||||
Ok(self.mk_expr_with_attrs(lo.to(self.prev_token.span), kind, attrs))
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -300,7 +300,7 @@ impl<'v> hir_visit::Visitor<'v> for StatCollector<'v> {
|
|||
record_variants!(
|
||||
(self, e, e.kind, Id::Node(e.hir_id), hir, Expr, ExprKind),
|
||||
[
|
||||
Box, ConstBlock, Array, Call, MethodCall, Tup, Binary, Unary, Lit, Cast, Type,
|
||||
ConstBlock, Array, Call, MethodCall, Tup, Binary, Unary, Lit, Cast, Type,
|
||||
DropTemps, Let, If, Loop, Match, Closure, Block, Assign, AssignOp, Field, Index,
|
||||
Path, AddrOf, Break, Continue, Ret, InlineAsm, Struct, Repeat, Yield, Err
|
||||
]
|
||||
|
|
|
|||
|
|
@ -473,7 +473,6 @@ impl<'tcx> Visitor<'tcx> for IrMaps<'tcx> {
|
|||
| hir::ExprKind::Struct(..)
|
||||
| hir::ExprKind::Repeat(..)
|
||||
| hir::ExprKind::InlineAsm(..)
|
||||
| hir::ExprKind::Box(..)
|
||||
| hir::ExprKind::Type(..)
|
||||
| hir::ExprKind::Err(_)
|
||||
| hir::ExprKind::Path(hir::QPath::TypeRelative(..))
|
||||
|
|
@ -1059,8 +1058,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
|
|||
self.propagate_through_expr(&l, r_succ)
|
||||
}
|
||||
|
||||
hir::ExprKind::Box(ref e)
|
||||
| hir::ExprKind::AddrOf(_, _, ref e)
|
||||
hir::ExprKind::AddrOf(_, _, ref e)
|
||||
| hir::ExprKind::Cast(ref e, _)
|
||||
| hir::ExprKind::Type(ref e, _)
|
||||
| hir::ExprKind::DropTemps(ref e)
|
||||
|
|
@ -1425,7 +1423,6 @@ fn check_expr<'tcx>(this: &mut Liveness<'_, 'tcx>, expr: &'tcx Expr<'tcx>) {
|
|||
| hir::ExprKind::Closure { .. }
|
||||
| hir::ExprKind::Path(_)
|
||||
| hir::ExprKind::Yield(..)
|
||||
| hir::ExprKind::Box(..)
|
||||
| hir::ExprKind::Type(..)
|
||||
| hir::ExprKind::Err(_) => {}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -179,8 +179,7 @@ enum ItemKind {
|
|||
impl<'tcx> CheckInlineAssembly<'tcx> {
|
||||
fn check_expr(&mut self, expr: &'tcx hir::Expr<'tcx>, span: Span) {
|
||||
match expr.kind {
|
||||
ExprKind::Box(..)
|
||||
| ExprKind::ConstBlock(..)
|
||||
ExprKind::ConstBlock(..)
|
||||
| ExprKind::Array(..)
|
||||
| ExprKind::Call(..)
|
||||
| ExprKind::MethodCall(..)
|
||||
|
|
|
|||
|
|
@ -132,7 +132,7 @@ where
|
|||
projection.trait_ref_and_own_substs(tcx)
|
||||
} else {
|
||||
// HACK(RPITIT): Remove this when RPITITs are lowered to regular assoc tys
|
||||
let def_id = tcx.impl_trait_in_trait_parent(projection.def_id);
|
||||
let def_id = tcx.impl_trait_in_trait_parent_fn(projection.def_id);
|
||||
let trait_generics = tcx.generics_of(def_id);
|
||||
(
|
||||
tcx.mk_trait_ref(def_id, projection.substs.truncate_to(tcx, trait_generics)),
|
||||
|
|
|
|||
|
|
@ -260,9 +260,7 @@ impl<'a, 'b, 'tcx> visit::Visitor<'a> for DefCollector<'a, 'b, 'tcx> {
|
|||
Async::No => closure_def,
|
||||
}
|
||||
}
|
||||
ExprKind::Async(_, async_id, _) => {
|
||||
self.create_def(async_id, DefPathData::ClosureExpr, expr.span)
|
||||
}
|
||||
ExprKind::Async(_, _) => self.create_def(expr.id, DefPathData::ClosureExpr, expr.span),
|
||||
_ => self.parent_def,
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -85,20 +85,28 @@ impl<'a> std::fmt::Debug for ImportKind<'a> {
|
|||
Single {
|
||||
ref source,
|
||||
ref target,
|
||||
ref source_bindings,
|
||||
ref target_bindings,
|
||||
ref type_ns_only,
|
||||
ref nested,
|
||||
ref id,
|
||||
// Ignore the following to avoid an infinite loop while printing.
|
||||
source_bindings: _,
|
||||
target_bindings: _,
|
||||
} => f
|
||||
.debug_struct("Single")
|
||||
.field("source", source)
|
||||
.field("target", target)
|
||||
// Ignore the nested bindings to avoid an infinite loop while printing.
|
||||
.field(
|
||||
"source_bindings",
|
||||
&source_bindings.clone().map(|b| b.into_inner().map(|_| format_args!(".."))),
|
||||
)
|
||||
.field(
|
||||
"target_bindings",
|
||||
&target_bindings.clone().map(|b| b.into_inner().map(|_| format_args!(".."))),
|
||||
)
|
||||
.field("type_ns_only", type_ns_only)
|
||||
.field("nested", nested)
|
||||
.field("id", id)
|
||||
.finish_non_exhaustive(),
|
||||
.finish(),
|
||||
Glob { ref is_prelude, ref max_vis, ref id } => f
|
||||
.debug_struct("Glob")
|
||||
.field("is_prelude", is_prelude)
|
||||
|
|
|
|||
|
|
@ -1478,8 +1478,9 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
|
|||
} else {
|
||||
LifetimeUseSet::Many
|
||||
}),
|
||||
LifetimeRibKind::Generics { .. } => None,
|
||||
LifetimeRibKind::ConstGeneric | LifetimeRibKind::AnonConst => {
|
||||
LifetimeRibKind::Generics { .. }
|
||||
| LifetimeRibKind::ConstGeneric => None,
|
||||
LifetimeRibKind::AnonConst => {
|
||||
span_bug!(ident.span, "unexpected rib kind: {:?}", rib.kind)
|
||||
}
|
||||
})
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ use crate::spec::{CodeModel, SanitizerSet, Target, TargetOptions};
|
|||
|
||||
pub fn target() -> Target {
|
||||
Target {
|
||||
llvm_target: "riscv64gc-unknown-fuchsia".into(),
|
||||
llvm_target: "riscv64-unknown-fuchsia".into(),
|
||||
pointer_width: 64,
|
||||
data_layout: "e-m:e-p:64:64-i64:64-i128:128-n32:64-S128".into(),
|
||||
arch: "riscv64".into(),
|
||||
|
|
|
|||
|
|
@ -144,18 +144,22 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
|
|||
trait_ref: ty::PolyTraitRef<'tcx>,
|
||||
obligation: &PredicateObligation<'tcx>,
|
||||
) -> OnUnimplementedNote {
|
||||
if self.tcx.opt_rpitit_info(obligation.cause.body_id.to_def_id()).is_some() {
|
||||
return OnUnimplementedNote::default();
|
||||
}
|
||||
|
||||
let (def_id, substs) = self
|
||||
.impl_similar_to(trait_ref, obligation)
|
||||
.unwrap_or_else(|| (trait_ref.def_id(), trait_ref.skip_binder().substs));
|
||||
let trait_ref = trait_ref.skip_binder();
|
||||
|
||||
let body_hir = self.tcx.hir().local_def_id_to_hir_id(obligation.cause.body_id);
|
||||
let mut flags =
|
||||
vec![(sym::ItemContext, self.describe_enclosure(body_hir).map(|s| s.to_owned()))];
|
||||
let mut flags = vec![];
|
||||
// FIXME(-Zlower-impl-trait-in-trait-to-assoc-ty): HIR is not present for RPITITs,
|
||||
// but I guess we could synthesize one here. We don't see any errors that rely on
|
||||
// that yet, though.
|
||||
let enclosure =
|
||||
if let Some(body_hir) = self.tcx.opt_local_def_id_to_hir_id(obligation.cause.body_id) {
|
||||
self.describe_enclosure(body_hir).map(|s| s.to_owned())
|
||||
} else {
|
||||
None
|
||||
};
|
||||
flags.push((sym::ItemContext, enclosure));
|
||||
|
||||
match obligation.cause.code() {
|
||||
ObligationCauseCode::BuiltinDerivedObligation(..)
|
||||
|
|
|
|||
|
|
@ -2944,9 +2944,6 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
|
|||
ObligationCauseCode::SizedYieldType => {
|
||||
err.note("the yield type of a generator must have a statically known size");
|
||||
}
|
||||
ObligationCauseCode::SizedBoxType => {
|
||||
err.note("the type of a box expression must have a statically known size");
|
||||
}
|
||||
ObligationCauseCode::AssignmentLhsSized => {
|
||||
err.note("the left-hand-side of an assignment must have a statically known size");
|
||||
}
|
||||
|
|
|
|||
|
|
@ -211,6 +211,29 @@ impl<'a, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'tcx> {
|
|||
type Error = FulfillmentErrorCode<'tcx>;
|
||||
type OUT = Outcome<Self::Obligation, Self::Error>;
|
||||
|
||||
/// Compared to `needs_process_obligation` this and its callees
|
||||
/// contain some optimizations that come at the price of false negatives.
|
||||
///
|
||||
/// They
|
||||
/// - reduce branching by covering only the most common case
|
||||
/// - take a read-only view of the unification tables which allows skipping undo_log
|
||||
/// construction.
|
||||
/// - bail out on value-cache misses in ena to avoid pointer chasing
|
||||
/// - hoist RefCell locking out of the loop
|
||||
#[inline]
|
||||
fn skippable_obligations<'b>(
|
||||
&'b self,
|
||||
it: impl Iterator<Item = &'b Self::Obligation>,
|
||||
) -> usize {
|
||||
let is_unchanged = self.selcx.infcx.is_ty_infer_var_definitely_unchanged();
|
||||
|
||||
it.take_while(|o| match o.stalled_on.as_slice() {
|
||||
[o] => is_unchanged(*o),
|
||||
_ => false,
|
||||
})
|
||||
.count()
|
||||
}
|
||||
|
||||
/// Identifies whether a predicate obligation needs processing.
|
||||
///
|
||||
/// This is always inlined because it has a single callsite and it is
|
||||
|
|
|
|||
|
|
@ -1298,7 +1298,7 @@ fn assemble_candidate_for_impl_trait_in_trait<'cx, 'tcx>(
|
|||
) {
|
||||
let tcx = selcx.tcx();
|
||||
if tcx.def_kind(obligation.predicate.def_id) == DefKind::ImplTraitPlaceholder {
|
||||
let trait_fn_def_id = tcx.impl_trait_in_trait_parent(obligation.predicate.def_id);
|
||||
let trait_fn_def_id = tcx.impl_trait_in_trait_parent_fn(obligation.predicate.def_id);
|
||||
|
||||
let trait_def_id = tcx.parent(trait_fn_def_id);
|
||||
let trait_substs =
|
||||
|
|
@ -2200,7 +2200,7 @@ fn confirm_impl_trait_in_trait_candidate<'tcx>(
|
|||
let tcx = selcx.tcx();
|
||||
let mut obligations = data.nested;
|
||||
|
||||
let trait_fn_def_id = tcx.impl_trait_in_trait_parent(obligation.predicate.def_id);
|
||||
let trait_fn_def_id = tcx.impl_trait_in_trait_parent_fn(obligation.predicate.def_id);
|
||||
let leaf_def = match specialization_graph::assoc_def(tcx, data.impl_def_id, trait_fn_def_id) {
|
||||
Ok(assoc_ty) => assoc_ty,
|
||||
Err(guar) => return Progress::error(tcx, guar),
|
||||
|
|
|
|||
|
|
@ -244,7 +244,7 @@ fn associated_item_for_impl_trait_in_trait(
|
|||
tcx: TyCtxt<'_>,
|
||||
opaque_ty_def_id: LocalDefId,
|
||||
) -> LocalDefId {
|
||||
let fn_def_id = tcx.impl_trait_in_trait_parent(opaque_ty_def_id.to_def_id());
|
||||
let fn_def_id = tcx.impl_trait_in_trait_parent_fn(opaque_ty_def_id.to_def_id());
|
||||
let trait_def_id = tcx.parent(fn_def_id);
|
||||
assert_eq!(tcx.def_kind(trait_def_id), DefKind::Trait);
|
||||
|
||||
|
|
@ -289,8 +289,39 @@ fn associated_item_for_impl_trait_in_trait(
|
|||
InternalSubsts::identity_for_item(tcx, opaque_ty_def_id.to_def_id()),
|
||||
)));
|
||||
|
||||
// Copy generics_of of the opaque.
|
||||
trait_assoc_ty.generics_of(tcx.generics_of(opaque_ty_def_id).clone());
|
||||
trait_assoc_ty.is_type_alias_impl_trait(false);
|
||||
|
||||
// Copy generics_of of the opaque type item but the trait is the parent.
|
||||
trait_assoc_ty.generics_of({
|
||||
let opaque_ty_generics = tcx.generics_of(opaque_ty_def_id);
|
||||
let opaque_ty_parent_count = opaque_ty_generics.parent_count;
|
||||
let mut params = opaque_ty_generics.params.clone();
|
||||
|
||||
let parent_generics = tcx.generics_of(trait_def_id);
|
||||
let parent_count = parent_generics.parent_count + parent_generics.params.len();
|
||||
|
||||
let mut trait_fn_params = tcx.generics_of(fn_def_id).params.clone();
|
||||
|
||||
for param in &mut params {
|
||||
param.index = param.index + parent_count as u32 + trait_fn_params.len() as u32
|
||||
- opaque_ty_parent_count as u32;
|
||||
}
|
||||
|
||||
trait_fn_params.extend(params);
|
||||
params = trait_fn_params;
|
||||
|
||||
let param_def_id_to_index =
|
||||
params.iter().map(|param| (param.def_id, param.index)).collect();
|
||||
|
||||
ty::Generics {
|
||||
parent: Some(trait_def_id),
|
||||
parent_count,
|
||||
params,
|
||||
param_def_id_to_index,
|
||||
has_self: false,
|
||||
has_late_bound_regions: opaque_ty_generics.has_late_bound_regions,
|
||||
}
|
||||
});
|
||||
|
||||
// There are no predicates for the synthesized associated type.
|
||||
trait_assoc_ty.explicit_predicates_of(ty::GenericPredicates {
|
||||
|
|
|
|||
|
|
@ -117,16 +117,22 @@ fn adt_sized_constraint(tcx: TyCtxt<'_>, def_id: DefId) -> &[Ty<'_>] {
|
|||
|
||||
/// See `ParamEnv` struct definition for details.
|
||||
fn param_env(tcx: TyCtxt<'_>, def_id: DefId) -> ty::ParamEnv<'_> {
|
||||
// When computing the param_env of an RPITIT, copy param_env of the containing function. The
|
||||
// synthesized associated type doesn't have extra predicates to assume.
|
||||
if let Some(ImplTraitInTraitData::Trait { fn_def_id, .. }) = tcx.opt_rpitit_info(def_id) {
|
||||
return tcx.param_env(fn_def_id);
|
||||
}
|
||||
|
||||
// Compute the bounds on Self and the type parameters.
|
||||
let ty::InstantiatedPredicates { mut predicates, .. } =
|
||||
tcx.predicates_of(def_id).instantiate_identity(tcx);
|
||||
|
||||
// When computing the param_env of an RPITIT, use predicates of the containing function,
|
||||
// *except* for the additional assumption that the RPITIT normalizes to the trait method's
|
||||
// default opaque type. This is needed to properly check the item bounds of the assoc
|
||||
// type hold (`check_type_bounds`), since that method already installs a similar projection
|
||||
// bound, so they will conflict.
|
||||
// FIXME(-Zlower-impl-trait-in-trait-to-assoc-ty): I don't like this, we should
|
||||
// at least be making sure that the generics in RPITITs and their parent fn don't
|
||||
// get out of alignment, or else we do actually need to substitute these predicates.
|
||||
if let Some(ImplTraitInTraitData::Trait { fn_def_id, .. }) = tcx.opt_rpitit_info(def_id) {
|
||||
predicates = tcx.predicates_of(fn_def_id).instantiate_identity(tcx).predicates;
|
||||
}
|
||||
|
||||
// Finally, we have to normalize the bounds in the environment, in
|
||||
// case they contain any associated type projections. This process
|
||||
// can yield errors if the put in illegal associated types, like
|
||||
|
|
@ -160,7 +166,9 @@ fn param_env(tcx: TyCtxt<'_>, def_id: DefId) -> ty::ParamEnv<'_> {
|
|||
}
|
||||
|
||||
let local_did = def_id.as_local();
|
||||
let hir_id = local_did.map(|def_id| tcx.hir().local_def_id_to_hir_id(def_id));
|
||||
// FIXME(-Zlower-impl-trait-in-trait-to-assoc-ty): This isn't correct for
|
||||
// RPITITs in const trait fn.
|
||||
let hir_id = local_did.and_then(|def_id| tcx.opt_local_def_id_to_hir_id(def_id));
|
||||
|
||||
// FIXME(consts): This is not exactly in line with the constness query.
|
||||
let constness = match hir_id {
|
||||
|
|
@ -268,8 +276,8 @@ impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for ImplTraitInTraitFinder<'_, 'tcx> {
|
|||
|
||||
fn visit_ty(&mut self, ty: Ty<'tcx>) -> std::ops::ControlFlow<Self::BreakTy> {
|
||||
if let ty::Alias(ty::Projection, alias_ty) = *ty.kind()
|
||||
&& self.tcx.def_kind(alias_ty.def_id) == DefKind::ImplTraitPlaceholder
|
||||
&& self.tcx.impl_trait_in_trait_parent(alias_ty.def_id) == self.fn_def_id
|
||||
&& self.tcx.is_impl_trait_in_trait(alias_ty.def_id)
|
||||
&& self.tcx.impl_trait_in_trait_parent_fn(alias_ty.def_id) == self.fn_def_id
|
||||
&& self.seen.insert(alias_ty.def_id)
|
||||
{
|
||||
// We have entered some binders as we've walked into the
|
||||
|
|
@ -282,11 +290,24 @@ impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for ImplTraitInTraitFinder<'_, 'tcx> {
|
|||
re
|
||||
}
|
||||
});
|
||||
|
||||
// If we're lowering to associated item, install the opaque type which is just
|
||||
// the `type_of` of the trait's associated item. If we're using the old lowering
|
||||
// strategy, then just reinterpret the associated type like an opaque :^)
|
||||
let default_ty = if self.tcx.lower_impl_trait_in_trait_to_assoc_ty() {
|
||||
self
|
||||
.tcx
|
||||
.type_of(alias_ty.def_id)
|
||||
.subst(self.tcx, alias_ty.substs)
|
||||
} else {
|
||||
self.tcx.mk_alias(ty::Opaque, alias_ty)
|
||||
};
|
||||
|
||||
self.predicates.push(
|
||||
ty::Binder::bind_with_vars(
|
||||
ty::ProjectionPredicate {
|
||||
projection_ty: alias_ty,
|
||||
term: self.tcx.mk_alias(ty::Opaque, alias_ty).into(),
|
||||
term: default_ty.into(),
|
||||
},
|
||||
self.bound_vars,
|
||||
)
|
||||
|
|
|
|||
|
|
@ -87,7 +87,7 @@
|
|||
#![warn(missing_debug_implementations)]
|
||||
#![warn(missing_docs)]
|
||||
#![allow(explicit_outlives_requirements)]
|
||||
#![cfg_attr(not(bootstrap), warn(multiple_supertrait_upcastable))]
|
||||
#![warn(multiple_supertrait_upcastable)]
|
||||
//
|
||||
// Library features:
|
||||
#![feature(alloc_layout_extra)]
|
||||
|
|
@ -195,7 +195,7 @@
|
|||
#![feature(c_unwind)]
|
||||
#![feature(with_negative_coherence)]
|
||||
#![cfg_attr(test, feature(panic_update_hook))]
|
||||
#![cfg_attr(not(bootstrap), feature(multiple_supertrait_upcastable))]
|
||||
#![feature(multiple_supertrait_upcastable)]
|
||||
//
|
||||
// Rustdoc features:
|
||||
#![feature(doc_cfg)]
|
||||
|
|
|
|||
|
|
@ -28,7 +28,7 @@ use crate::fmt::{Debug, Display};
|
|||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
#[cfg_attr(not(test), rustc_diagnostic_item = "Error")]
|
||||
#[rustc_has_incoherent_inherent_impls]
|
||||
#[cfg_attr(not(bootstrap), allow(multiple_supertrait_upcastable))]
|
||||
#[allow(multiple_supertrait_upcastable)]
|
||||
pub trait Error: Debug + Display {
|
||||
/// The lower-level source of this error, if any.
|
||||
///
|
||||
|
|
@ -489,7 +489,7 @@ impl Error for crate::char::CharTryFromError {
|
|||
#[stable(feature = "duration_checked_float", since = "1.66.0")]
|
||||
impl Error for crate::time::TryFromFloatSecsError {}
|
||||
|
||||
#[stable(feature = "cstr_from_bytes_until_nul", since = "CURRENT_RUSTC_VERSION")]
|
||||
#[stable(feature = "cstr_from_bytes_until_nul", since = "1.69.0")]
|
||||
impl Error for crate::ffi::FromBytesUntilNulError {}
|
||||
|
||||
#[unstable(feature = "get_many_mut", issue = "104642")]
|
||||
|
|
|
|||
|
|
@ -153,10 +153,10 @@ impl Error for FromBytesWithNulError {
|
|||
/// This error is created by the [`CStr::from_bytes_until_nul`] method.
|
||||
///
|
||||
#[derive(Clone, PartialEq, Eq, Debug)]
|
||||
#[stable(feature = "cstr_from_bytes_until_nul", since = "CURRENT_RUSTC_VERSION")]
|
||||
#[stable(feature = "cstr_from_bytes_until_nul", since = "1.69.0")]
|
||||
pub struct FromBytesUntilNulError(());
|
||||
|
||||
#[stable(feature = "cstr_from_bytes_until_nul", since = "CURRENT_RUSTC_VERSION")]
|
||||
#[stable(feature = "cstr_from_bytes_until_nul", since = "1.69.0")]
|
||||
impl fmt::Display for FromBytesUntilNulError {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
write!(f, "data provided does not contain a nul")
|
||||
|
|
@ -324,8 +324,8 @@ impl CStr {
|
|||
/// ```
|
||||
///
|
||||
#[rustc_allow_const_fn_unstable(const_slice_index)]
|
||||
#[stable(feature = "cstr_from_bytes_until_nul", since = "CURRENT_RUSTC_VERSION")]
|
||||
#[rustc_const_stable(feature = "cstr_from_bytes_until_nul", since = "CURRENT_RUSTC_VERSION")]
|
||||
#[stable(feature = "cstr_from_bytes_until_nul", since = "1.69.0")]
|
||||
#[rustc_const_stable(feature = "cstr_from_bytes_until_nul", since = "1.69.0")]
|
||||
pub const fn from_bytes_until_nul(bytes: &[u8]) -> Result<&CStr, FromBytesUntilNulError> {
|
||||
let nul_pos = memchr::memchr(0, bytes);
|
||||
match nul_pos {
|
||||
|
|
|
|||
|
|
@ -267,7 +267,7 @@ extern "C" {
|
|||
/// family of functions. It contains a function to format the given value. At
|
||||
/// compile time it is ensured that the function and the value have the correct
|
||||
/// types, and then this struct is used to canonicalize arguments to one type.
|
||||
#[cfg_attr(not(bootstrap), lang = "format_argument")]
|
||||
#[lang = "format_argument"]
|
||||
#[derive(Copy, Clone)]
|
||||
#[allow(missing_debug_implementations)]
|
||||
#[unstable(feature = "fmt_internals", reason = "internal to format_args!", issue = "none")]
|
||||
|
|
@ -280,7 +280,7 @@ pub struct ArgumentV1<'a> {
|
|||
/// This struct represents the unsafety of constructing an `Arguments`.
|
||||
/// It exists, rather than an unsafe function, in order to simplify the expansion
|
||||
/// of `format_args!(..)` and reduce the scope of the `unsafe` block.
|
||||
#[cfg_attr(not(bootstrap), lang = "format_unsafe_arg")]
|
||||
#[lang = "format_unsafe_arg"]
|
||||
#[allow(missing_debug_implementations)]
|
||||
#[doc(hidden)]
|
||||
#[unstable(feature = "fmt_internals", reason = "internal to format_args!", issue = "none")]
|
||||
|
|
@ -497,7 +497,7 @@ impl<'a> Arguments<'a> {
|
|||
/// ```
|
||||
///
|
||||
/// [`format()`]: ../../std/fmt/fn.format.html
|
||||
#[cfg_attr(not(bootstrap), lang = "format_arguments")]
|
||||
#[lang = "format_arguments"]
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
#[derive(Copy, Clone)]
|
||||
pub struct Arguments<'a> {
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@
|
|||
//! these can be statically allocated and are slightly optimized for the runtime
|
||||
#![allow(missing_debug_implementations)]
|
||||
|
||||
#[cfg_attr(not(bootstrap), lang = "format_placeholder")]
|
||||
#[lang = "format_placeholder"]
|
||||
#[derive(Copy, Clone)]
|
||||
// FIXME: Rename this to Placeholder
|
||||
pub struct Argument {
|
||||
|
|
@ -37,7 +37,7 @@ impl Argument {
|
|||
}
|
||||
|
||||
/// Possible alignments that can be requested as part of a formatting directive.
|
||||
#[cfg_attr(not(bootstrap), lang = "format_alignment")]
|
||||
#[lang = "format_alignment"]
|
||||
#[derive(Copy, Clone, PartialEq, Eq)]
|
||||
pub enum Alignment {
|
||||
/// Indication that contents should be left-aligned.
|
||||
|
|
@ -51,7 +51,7 @@ pub enum Alignment {
|
|||
}
|
||||
|
||||
/// Used by [width](https://doc.rust-lang.org/std/fmt/#width) and [precision](https://doc.rust-lang.org/std/fmt/#precision) specifiers.
|
||||
#[cfg_attr(not(bootstrap), lang = "format_count")]
|
||||
#[lang = "format_count"]
|
||||
#[derive(Copy, Clone)]
|
||||
pub enum Count {
|
||||
/// Specified with a literal number, stores the value
|
||||
|
|
|
|||
|
|
@ -834,7 +834,7 @@ mod impls {
|
|||
|
||||
#[inline]
|
||||
fn hash_slice<H: ~const Hasher>(data: &[$ty], state: &mut H) {
|
||||
let newlen = data.len() * mem::size_of::<$ty>();
|
||||
let newlen = mem::size_of_val(data);
|
||||
let ptr = data.as_ptr() as *const u8;
|
||||
// SAFETY: `ptr` is valid and aligned, as this macro is only used
|
||||
// for numeric primitives which have no padding. The new slice only
|
||||
|
|
|
|||
|
|
@ -278,7 +278,7 @@
|
|||
//!
|
||||
//! ```
|
||||
//! # #![allow(unused_must_use)]
|
||||
//! # #![cfg_attr(not(bootstrap), allow(map_unit_fn))]
|
||||
//! # #![allow(map_unit_fn)]
|
||||
//! let v = vec![1, 2, 3, 4, 5];
|
||||
//! v.iter().map(|x| println!("{x}"));
|
||||
//! ```
|
||||
|
|
|
|||
|
|
@ -69,7 +69,7 @@ fn _assert_is_object_safe(_: &dyn Iterator<Item = ()>) {}
|
|||
#[doc(notable_trait)]
|
||||
#[rustc_diagnostic_item = "Iterator"]
|
||||
#[must_use = "iterators are lazy and do nothing unless consumed"]
|
||||
#[cfg_attr(not(bootstrap), const_trait)]
|
||||
#[const_trait]
|
||||
pub trait Iterator {
|
||||
/// The type of the elements being iterated over.
|
||||
#[rustc_diagnostic_item = "IteratorItem"]
|
||||
|
|
|
|||
|
|
@ -95,7 +95,7 @@
|
|||
#![warn(missing_docs)]
|
||||
#![allow(explicit_outlives_requirements)]
|
||||
#![allow(incomplete_features)]
|
||||
#![cfg_attr(not(bootstrap), warn(multiple_supertrait_upcastable))]
|
||||
#![warn(multiple_supertrait_upcastable)]
|
||||
//
|
||||
// Library features:
|
||||
#![feature(const_align_offset)]
|
||||
|
|
@ -241,7 +241,7 @@
|
|||
#![feature(unsized_fn_params)]
|
||||
#![feature(asm_const)]
|
||||
#![feature(const_transmute_copy)]
|
||||
#![cfg_attr(not(bootstrap), feature(multiple_supertrait_upcastable))]
|
||||
#![feature(multiple_supertrait_upcastable)]
|
||||
//
|
||||
// Target features:
|
||||
#![feature(arm_target_feature)]
|
||||
|
|
@ -254,7 +254,6 @@
|
|||
#![feature(sse4a_target_feature)]
|
||||
#![feature(tbm_target_feature)]
|
||||
#![feature(wasm_target_feature)]
|
||||
#![cfg_attr(bootstrap, feature(cmpxchg16b_target_feature))]
|
||||
|
||||
// allow using `core::` in intra-doc links
|
||||
#[allow(unused_extern_crates)]
|
||||
|
|
|
|||
|
|
@ -97,7 +97,7 @@ unsafe impl<T: Sync + ?Sized> Send for &T {}
|
|||
#[fundamental] // for Default, for example, which requires that `[T]: !Default` be evaluatable
|
||||
#[rustc_specialization_trait]
|
||||
#[rustc_deny_explicit_impl]
|
||||
#[cfg_attr(not(bootstrap), rustc_coinductive)]
|
||||
#[rustc_coinductive]
|
||||
pub trait Sized {
|
||||
// Empty.
|
||||
}
|
||||
|
|
@ -877,8 +877,7 @@ pub trait Tuple {}
|
|||
/// All types that have the same size and alignment as a `usize` or
|
||||
/// `*const ()` automatically implement this trait.
|
||||
#[unstable(feature = "pointer_like_trait", issue = "none")]
|
||||
#[cfg_attr(bootstrap, lang = "pointer_sized")]
|
||||
#[cfg_attr(not(bootstrap), lang = "pointer_like")]
|
||||
#[lang = "pointer_like"]
|
||||
#[rustc_on_unimplemented(
|
||||
message = "`{Self}` needs to have the same alignment and size as a pointer",
|
||||
label = "`{Self}` needs to be a pointer-like type"
|
||||
|
|
|
|||
|
|
@ -121,7 +121,7 @@ impl SocketAddr {
|
|||
/// ```
|
||||
#[stable(feature = "ip_addr", since = "1.7.0")]
|
||||
#[must_use]
|
||||
#[rustc_const_stable(feature = "const_socketaddr", since = "CURRENT_RUSTC_VERSION")]
|
||||
#[rustc_const_stable(feature = "const_socketaddr", since = "1.69.0")]
|
||||
pub const fn new(ip: IpAddr, port: u16) -> SocketAddr {
|
||||
match ip {
|
||||
IpAddr::V4(a) => SocketAddr::V4(SocketAddrV4::new(a, port)),
|
||||
|
|
@ -141,7 +141,7 @@ impl SocketAddr {
|
|||
/// ```
|
||||
#[must_use]
|
||||
#[stable(feature = "ip_addr", since = "1.7.0")]
|
||||
#[rustc_const_stable(feature = "const_socketaddr", since = "CURRENT_RUSTC_VERSION")]
|
||||
#[rustc_const_stable(feature = "const_socketaddr", since = "1.69.0")]
|
||||
pub const fn ip(&self) -> IpAddr {
|
||||
match *self {
|
||||
SocketAddr::V4(ref a) => IpAddr::V4(*a.ip()),
|
||||
|
|
@ -182,7 +182,7 @@ impl SocketAddr {
|
|||
/// ```
|
||||
#[must_use]
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
#[rustc_const_stable(feature = "const_socketaddr", since = "CURRENT_RUSTC_VERSION")]
|
||||
#[rustc_const_stable(feature = "const_socketaddr", since = "1.69.0")]
|
||||
pub const fn port(&self) -> u16 {
|
||||
match *self {
|
||||
SocketAddr::V4(ref a) => a.port(),
|
||||
|
|
@ -226,7 +226,7 @@ impl SocketAddr {
|
|||
/// ```
|
||||
#[must_use]
|
||||
#[stable(feature = "sockaddr_checker", since = "1.16.0")]
|
||||
#[rustc_const_stable(feature = "const_socketaddr", since = "CURRENT_RUSTC_VERSION")]
|
||||
#[rustc_const_stable(feature = "const_socketaddr", since = "1.69.0")]
|
||||
pub const fn is_ipv4(&self) -> bool {
|
||||
matches!(*self, SocketAddr::V4(_))
|
||||
}
|
||||
|
|
@ -248,7 +248,7 @@ impl SocketAddr {
|
|||
/// ```
|
||||
#[must_use]
|
||||
#[stable(feature = "sockaddr_checker", since = "1.16.0")]
|
||||
#[rustc_const_stable(feature = "const_socketaddr", since = "CURRENT_RUSTC_VERSION")]
|
||||
#[rustc_const_stable(feature = "const_socketaddr", since = "1.69.0")]
|
||||
pub const fn is_ipv6(&self) -> bool {
|
||||
matches!(*self, SocketAddr::V6(_))
|
||||
}
|
||||
|
|
@ -268,7 +268,7 @@ impl SocketAddrV4 {
|
|||
/// ```
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
#[must_use]
|
||||
#[rustc_const_stable(feature = "const_socketaddr", since = "CURRENT_RUSTC_VERSION")]
|
||||
#[rustc_const_stable(feature = "const_socketaddr", since = "1.69.0")]
|
||||
pub const fn new(ip: Ipv4Addr, port: u16) -> SocketAddrV4 {
|
||||
SocketAddrV4 { ip, port }
|
||||
}
|
||||
|
|
@ -285,7 +285,7 @@ impl SocketAddrV4 {
|
|||
/// ```
|
||||
#[must_use]
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
#[rustc_const_stable(feature = "const_socketaddr", since = "CURRENT_RUSTC_VERSION")]
|
||||
#[rustc_const_stable(feature = "const_socketaddr", since = "1.69.0")]
|
||||
pub const fn ip(&self) -> &Ipv4Addr {
|
||||
&self.ip
|
||||
}
|
||||
|
|
@ -318,7 +318,7 @@ impl SocketAddrV4 {
|
|||
/// ```
|
||||
#[must_use]
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
#[rustc_const_stable(feature = "const_socketaddr", since = "CURRENT_RUSTC_VERSION")]
|
||||
#[rustc_const_stable(feature = "const_socketaddr", since = "1.69.0")]
|
||||
pub const fn port(&self) -> u16 {
|
||||
self.port
|
||||
}
|
||||
|
|
@ -359,7 +359,7 @@ impl SocketAddrV6 {
|
|||
/// ```
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
#[must_use]
|
||||
#[rustc_const_stable(feature = "const_socketaddr", since = "CURRENT_RUSTC_VERSION")]
|
||||
#[rustc_const_stable(feature = "const_socketaddr", since = "1.69.0")]
|
||||
pub const fn new(ip: Ipv6Addr, port: u16, flowinfo: u32, scope_id: u32) -> SocketAddrV6 {
|
||||
SocketAddrV6 { ip, port, flowinfo, scope_id }
|
||||
}
|
||||
|
|
@ -376,7 +376,7 @@ impl SocketAddrV6 {
|
|||
/// ```
|
||||
#[must_use]
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
#[rustc_const_stable(feature = "const_socketaddr", since = "CURRENT_RUSTC_VERSION")]
|
||||
#[rustc_const_stable(feature = "const_socketaddr", since = "1.69.0")]
|
||||
pub const fn ip(&self) -> &Ipv6Addr {
|
||||
&self.ip
|
||||
}
|
||||
|
|
@ -409,7 +409,7 @@ impl SocketAddrV6 {
|
|||
/// ```
|
||||
#[must_use]
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
#[rustc_const_stable(feature = "const_socketaddr", since = "CURRENT_RUSTC_VERSION")]
|
||||
#[rustc_const_stable(feature = "const_socketaddr", since = "1.69.0")]
|
||||
pub const fn port(&self) -> u16 {
|
||||
self.port
|
||||
}
|
||||
|
|
@ -452,7 +452,7 @@ impl SocketAddrV6 {
|
|||
/// ```
|
||||
#[must_use]
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
#[rustc_const_stable(feature = "const_socketaddr", since = "CURRENT_RUSTC_VERSION")]
|
||||
#[rustc_const_stable(feature = "const_socketaddr", since = "1.69.0")]
|
||||
pub const fn flowinfo(&self) -> u32 {
|
||||
self.flowinfo
|
||||
}
|
||||
|
|
@ -492,7 +492,7 @@ impl SocketAddrV6 {
|
|||
/// ```
|
||||
#[must_use]
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
#[rustc_const_stable(feature = "const_socketaddr", since = "CURRENT_RUSTC_VERSION")]
|
||||
#[rustc_const_stable(feature = "const_socketaddr", since = "1.69.0")]
|
||||
pub const fn scope_id(&self) -> u32 {
|
||||
self.scope_id
|
||||
}
|
||||
|
|
|
|||
|
|
@ -392,14 +392,7 @@ impl<T> NeverShortCircuit<T> {
|
|||
pub fn wrap_mut_2<A, B>(
|
||||
mut f: impl ~const FnMut(A, B) -> T,
|
||||
) -> impl ~const FnMut(A, B) -> Self {
|
||||
cfg_if! {
|
||||
if #[cfg(bootstrap)] {
|
||||
#[allow(unused_parens)]
|
||||
(const move |a, b| NeverShortCircuit(f(a, b)))
|
||||
} else {
|
||||
const move |a, b| NeverShortCircuit(f(a, b))
|
||||
}
|
||||
}
|
||||
const move |a, b| NeverShortCircuit(f(a, b))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1951,8 +1951,7 @@ macro_rules! if_not_8_bit {
|
|||
($_:ident, $($tt:tt)*) => { $($tt)* };
|
||||
}
|
||||
|
||||
#[cfg_attr(not(bootstrap), cfg(target_has_atomic_load_store))]
|
||||
#[cfg_attr(bootstrap, cfg(target_has_atomic_load_store = "8"))]
|
||||
#[cfg(target_has_atomic_load_store)]
|
||||
macro_rules! atomic_int {
|
||||
($cfg_cas:meta,
|
||||
$cfg_align:meta,
|
||||
|
|
@ -3125,8 +3124,7 @@ atomic_int_ptr_sized! {
|
|||
}
|
||||
|
||||
#[inline]
|
||||
#[cfg_attr(not(bootstrap), cfg(target_has_atomic))]
|
||||
#[cfg_attr(bootstrap, cfg(target_has_atomic = "8"))]
|
||||
#[cfg(target_has_atomic)]
|
||||
fn strongest_failure_ordering(order: Ordering) -> Ordering {
|
||||
match order {
|
||||
Release => Relaxed,
|
||||
|
|
@ -3168,8 +3166,7 @@ unsafe fn atomic_load<T: Copy>(dst: *const T, order: Ordering) -> T {
|
|||
}
|
||||
|
||||
#[inline]
|
||||
#[cfg_attr(not(bootstrap), cfg(target_has_atomic))]
|
||||
#[cfg_attr(bootstrap, cfg(target_has_atomic = "8"))]
|
||||
#[cfg(target_has_atomic)]
|
||||
#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
|
||||
unsafe fn atomic_swap<T: Copy>(dst: *mut T, val: T, order: Ordering) -> T {
|
||||
// SAFETY: the caller must uphold the safety contract for `atomic_swap`.
|
||||
|
|
@ -3186,8 +3183,7 @@ unsafe fn atomic_swap<T: Copy>(dst: *mut T, val: T, order: Ordering) -> T {
|
|||
|
||||
/// Returns the previous value (like __sync_fetch_and_add).
|
||||
#[inline]
|
||||
#[cfg_attr(not(bootstrap), cfg(target_has_atomic))]
|
||||
#[cfg_attr(bootstrap, cfg(target_has_atomic = "8"))]
|
||||
#[cfg(target_has_atomic)]
|
||||
#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
|
||||
unsafe fn atomic_add<T: Copy>(dst: *mut T, val: T, order: Ordering) -> T {
|
||||
// SAFETY: the caller must uphold the safety contract for `atomic_add`.
|
||||
|
|
@ -3204,8 +3200,7 @@ unsafe fn atomic_add<T: Copy>(dst: *mut T, val: T, order: Ordering) -> T {
|
|||
|
||||
/// Returns the previous value (like __sync_fetch_and_sub).
|
||||
#[inline]
|
||||
#[cfg_attr(not(bootstrap), cfg(target_has_atomic))]
|
||||
#[cfg_attr(bootstrap, cfg(target_has_atomic = "8"))]
|
||||
#[cfg(target_has_atomic)]
|
||||
#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
|
||||
unsafe fn atomic_sub<T: Copy>(dst: *mut T, val: T, order: Ordering) -> T {
|
||||
// SAFETY: the caller must uphold the safety contract for `atomic_sub`.
|
||||
|
|
@ -3221,8 +3216,7 @@ unsafe fn atomic_sub<T: Copy>(dst: *mut T, val: T, order: Ordering) -> T {
|
|||
}
|
||||
|
||||
#[inline]
|
||||
#[cfg_attr(not(bootstrap), cfg(target_has_atomic))]
|
||||
#[cfg_attr(bootstrap, cfg(target_has_atomic = "8"))]
|
||||
#[cfg(target_has_atomic)]
|
||||
#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
|
||||
unsafe fn atomic_compare_exchange<T: Copy>(
|
||||
dst: *mut T,
|
||||
|
|
@ -3257,8 +3251,7 @@ unsafe fn atomic_compare_exchange<T: Copy>(
|
|||
}
|
||||
|
||||
#[inline]
|
||||
#[cfg_attr(not(bootstrap), cfg(target_has_atomic))]
|
||||
#[cfg_attr(bootstrap, cfg(target_has_atomic = "8"))]
|
||||
#[cfg(target_has_atomic)]
|
||||
#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
|
||||
unsafe fn atomic_compare_exchange_weak<T: Copy>(
|
||||
dst: *mut T,
|
||||
|
|
@ -3293,8 +3286,7 @@ unsafe fn atomic_compare_exchange_weak<T: Copy>(
|
|||
}
|
||||
|
||||
#[inline]
|
||||
#[cfg_attr(not(bootstrap), cfg(target_has_atomic))]
|
||||
#[cfg_attr(bootstrap, cfg(target_has_atomic = "8"))]
|
||||
#[cfg(target_has_atomic)]
|
||||
#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
|
||||
unsafe fn atomic_and<T: Copy>(dst: *mut T, val: T, order: Ordering) -> T {
|
||||
// SAFETY: the caller must uphold the safety contract for `atomic_and`
|
||||
|
|
@ -3310,8 +3302,7 @@ unsafe fn atomic_and<T: Copy>(dst: *mut T, val: T, order: Ordering) -> T {
|
|||
}
|
||||
|
||||
#[inline]
|
||||
#[cfg_attr(not(bootstrap), cfg(target_has_atomic))]
|
||||
#[cfg_attr(bootstrap, cfg(target_has_atomic = "8"))]
|
||||
#[cfg(target_has_atomic)]
|
||||
#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
|
||||
unsafe fn atomic_nand<T: Copy>(dst: *mut T, val: T, order: Ordering) -> T {
|
||||
// SAFETY: the caller must uphold the safety contract for `atomic_nand`
|
||||
|
|
@ -3327,8 +3318,7 @@ unsafe fn atomic_nand<T: Copy>(dst: *mut T, val: T, order: Ordering) -> T {
|
|||
}
|
||||
|
||||
#[inline]
|
||||
#[cfg_attr(not(bootstrap), cfg(target_has_atomic))]
|
||||
#[cfg_attr(bootstrap, cfg(target_has_atomic = "8"))]
|
||||
#[cfg(target_has_atomic)]
|
||||
#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
|
||||
unsafe fn atomic_or<T: Copy>(dst: *mut T, val: T, order: Ordering) -> T {
|
||||
// SAFETY: the caller must uphold the safety contract for `atomic_or`
|
||||
|
|
@ -3344,8 +3334,7 @@ unsafe fn atomic_or<T: Copy>(dst: *mut T, val: T, order: Ordering) -> T {
|
|||
}
|
||||
|
||||
#[inline]
|
||||
#[cfg_attr(not(bootstrap), cfg(target_has_atomic))]
|
||||
#[cfg_attr(bootstrap, cfg(target_has_atomic = "8"))]
|
||||
#[cfg(target_has_atomic)]
|
||||
#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
|
||||
unsafe fn atomic_xor<T: Copy>(dst: *mut T, val: T, order: Ordering) -> T {
|
||||
// SAFETY: the caller must uphold the safety contract for `atomic_xor`
|
||||
|
|
@ -3362,8 +3351,7 @@ unsafe fn atomic_xor<T: Copy>(dst: *mut T, val: T, order: Ordering) -> T {
|
|||
|
||||
/// returns the max value (signed comparison)
|
||||
#[inline]
|
||||
#[cfg_attr(not(bootstrap), cfg(target_has_atomic))]
|
||||
#[cfg_attr(bootstrap, cfg(target_has_atomic = "8"))]
|
||||
#[cfg(target_has_atomic)]
|
||||
#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
|
||||
unsafe fn atomic_max<T: Copy>(dst: *mut T, val: T, order: Ordering) -> T {
|
||||
// SAFETY: the caller must uphold the safety contract for `atomic_max`
|
||||
|
|
@ -3380,8 +3368,7 @@ unsafe fn atomic_max<T: Copy>(dst: *mut T, val: T, order: Ordering) -> T {
|
|||
|
||||
/// returns the min value (signed comparison)
|
||||
#[inline]
|
||||
#[cfg_attr(not(bootstrap), cfg(target_has_atomic))]
|
||||
#[cfg_attr(bootstrap, cfg(target_has_atomic = "8"))]
|
||||
#[cfg(target_has_atomic)]
|
||||
#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
|
||||
unsafe fn atomic_min<T: Copy>(dst: *mut T, val: T, order: Ordering) -> T {
|
||||
// SAFETY: the caller must uphold the safety contract for `atomic_min`
|
||||
|
|
@ -3398,8 +3385,7 @@ unsafe fn atomic_min<T: Copy>(dst: *mut T, val: T, order: Ordering) -> T {
|
|||
|
||||
/// returns the max value (unsigned comparison)
|
||||
#[inline]
|
||||
#[cfg_attr(not(bootstrap), cfg(target_has_atomic))]
|
||||
#[cfg_attr(bootstrap, cfg(target_has_atomic = "8"))]
|
||||
#[cfg(target_has_atomic)]
|
||||
#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
|
||||
unsafe fn atomic_umax<T: Copy>(dst: *mut T, val: T, order: Ordering) -> T {
|
||||
// SAFETY: the caller must uphold the safety contract for `atomic_umax`
|
||||
|
|
@ -3416,8 +3402,7 @@ unsafe fn atomic_umax<T: Copy>(dst: *mut T, val: T, order: Ordering) -> T {
|
|||
|
||||
/// returns the min value (unsigned comparison)
|
||||
#[inline]
|
||||
#[cfg_attr(not(bootstrap), cfg(target_has_atomic))]
|
||||
#[cfg_attr(bootstrap, cfg(target_has_atomic = "8"))]
|
||||
#[cfg(target_has_atomic)]
|
||||
#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
|
||||
unsafe fn atomic_umin<T: Copy>(dst: *mut T, val: T, order: Ordering) -> T {
|
||||
// SAFETY: the caller must uphold the safety contract for `atomic_umin`
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
//! Android-specific networking functionality.
|
||||
|
||||
#![unstable(feature = "tcp_quickack", issue = "96256")]
|
||||
#![stable(feature = "unix_socket_abstract", since = "CURRENT_RUSTC_VERSION")]
|
||||
|
||||
#[unstable(feature = "unix_socket_abstract", issue = "85410")]
|
||||
#[stable(feature = "unix_socket_abstract", since = "CURRENT_RUSTC_VERSION")]
|
||||
pub use crate::os::net::linux_ext::addr::SocketAddrExt;
|
||||
|
||||
#[unstable(feature = "tcp_quickack", issue = "96256")]
|
||||
|
|
|
|||
|
|
@ -399,7 +399,7 @@ impl<T: AsFd> AsFd for crate::sync::Arc<T> {
|
|||
}
|
||||
}
|
||||
|
||||
#[stable(feature = "asfd_rc", since = "CURRENT_RUSTC_VERSION")]
|
||||
#[stable(feature = "asfd_rc", since = "1.69.0")]
|
||||
impl<T: AsFd> AsFd for crate::rc::Rc<T> {
|
||||
#[inline]
|
||||
fn as_fd(&self) -> BorrowedFd<'_> {
|
||||
|
|
|
|||
|
|
@ -254,7 +254,7 @@ impl<T: AsRawFd> AsRawFd for crate::sync::Arc<T> {
|
|||
}
|
||||
}
|
||||
|
||||
#[stable(feature = "asfd_rc", since = "CURRENT_RUSTC_VERSION")]
|
||||
#[stable(feature = "asfd_rc", since = "1.69.0")]
|
||||
impl<T: AsRawFd> AsRawFd for crate::rc::Rc<T> {
|
||||
#[inline]
|
||||
fn as_raw_fd(&self) -> RawFd {
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
//! Linux-specific networking functionality.
|
||||
|
||||
#![unstable(feature = "tcp_quickack", issue = "96256")]
|
||||
#![stable(feature = "unix_socket_abstract", since = "CURRENT_RUSTC_VERSION")]
|
||||
|
||||
#[unstable(feature = "unix_socket_abstract", issue = "85410")]
|
||||
#[stable(feature = "unix_socket_abstract", since = "CURRENT_RUSTC_VERSION")]
|
||||
pub use crate::os::net::linux_ext::addr::SocketAddrExt;
|
||||
|
||||
#[unstable(feature = "tcp_quickack", issue = "96256")]
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ use crate::os::unix::net::SocketAddr;
|
|||
use crate::sealed::Sealed;
|
||||
|
||||
/// Platform-specific extensions to [`SocketAddr`].
|
||||
#[unstable(feature = "unix_socket_abstract", issue = "85410")]
|
||||
#[stable(feature = "unix_socket_abstract", since = "CURRENT_RUSTC_VERSION")]
|
||||
pub trait SocketAddrExt: Sealed {
|
||||
/// Creates a Unix socket address in the abstract namespace.
|
||||
///
|
||||
|
|
@ -22,7 +22,6 @@ pub trait SocketAddrExt: Sealed {
|
|||
/// # Examples
|
||||
///
|
||||
/// ```no_run
|
||||
/// #![feature(unix_socket_abstract)]
|
||||
/// use std::os::unix::net::{UnixListener, SocketAddr};
|
||||
/// use std::os::linux::net::SocketAddrExt;
|
||||
///
|
||||
|
|
@ -38,6 +37,7 @@ pub trait SocketAddrExt: Sealed {
|
|||
/// Ok(())
|
||||
/// }
|
||||
/// ```
|
||||
#[stable(feature = "unix_socket_abstract", since = "CURRENT_RUSTC_VERSION")]
|
||||
fn from_abstract_name<N>(name: N) -> crate::io::Result<SocketAddr>
|
||||
where
|
||||
N: AsRef<[u8]>;
|
||||
|
|
@ -47,7 +47,6 @@ pub trait SocketAddrExt: Sealed {
|
|||
/// # Examples
|
||||
///
|
||||
/// ```no_run
|
||||
/// #![feature(unix_socket_abstract)]
|
||||
/// use std::os::unix::net::{UnixListener, SocketAddr};
|
||||
/// use std::os::linux::net::SocketAddrExt;
|
||||
///
|
||||
|
|
@ -60,5 +59,6 @@ pub trait SocketAddrExt: Sealed {
|
|||
/// Ok(())
|
||||
/// }
|
||||
/// ```
|
||||
#[stable(feature = "unix_socket_abstract", since = "CURRENT_RUSTC_VERSION")]
|
||||
fn as_abstract_name(&self) -> Option<&[u8]>;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
#![doc(cfg(any(target_os = "linux", target_os = "android")))]
|
||||
|
||||
#[unstable(feature = "unix_socket_abstract", issue = "85410")]
|
||||
#[stable(feature = "unix_socket_abstract", since = "CURRENT_RUSTC_VERSION")]
|
||||
pub(crate) mod addr;
|
||||
|
||||
#[unstable(feature = "tcp_quickack", issue = "96256")]
|
||||
|
|
|
|||
|
|
@ -245,12 +245,12 @@ impl SocketAddr {
|
|||
}
|
||||
}
|
||||
|
||||
#[unstable(feature = "unix_socket_abstract", issue = "85410")]
|
||||
#[stable(feature = "unix_socket_abstract", since = "CURRENT_RUSTC_VERSION")]
|
||||
impl Sealed for SocketAddr {}
|
||||
|
||||
#[doc(cfg(any(target_os = "android", target_os = "linux")))]
|
||||
#[cfg(any(doc, target_os = "android", target_os = "linux"))]
|
||||
#[unstable(feature = "unix_socket_abstract", issue = "85410")]
|
||||
#[stable(feature = "unix_socket_abstract", since = "CURRENT_RUSTC_VERSION")]
|
||||
impl linux_ext::addr::SocketAddrExt for SocketAddr {
|
||||
fn as_abstract_name(&self) -> Option<&[u8]> {
|
||||
if let AddressKind::Abstract(name) = self.address() { Some(name) } else { None }
|
||||
|
|
|
|||
|
|
@ -102,7 +102,6 @@ impl UnixDatagram {
|
|||
/// # Examples
|
||||
///
|
||||
/// ```no_run
|
||||
/// #![feature(unix_socket_abstract)]
|
||||
/// use std::os::unix::net::{UnixDatagram};
|
||||
///
|
||||
/// fn main() -> std::io::Result<()> {
|
||||
|
|
@ -119,7 +118,7 @@ impl UnixDatagram {
|
|||
/// Ok(())
|
||||
/// }
|
||||
/// ```
|
||||
#[unstable(feature = "unix_socket_abstract", issue = "85410")]
|
||||
#[stable(feature = "unix_socket_abstract", since = "CURRENT_RUSTC_VERSION")]
|
||||
pub fn bind_addr(socket_addr: &SocketAddr) -> io::Result<UnixDatagram> {
|
||||
unsafe {
|
||||
let socket = UnixDatagram::unbound()?;
|
||||
|
|
@ -217,7 +216,6 @@ impl UnixDatagram {
|
|||
/// # Examples
|
||||
///
|
||||
/// ```no_run
|
||||
/// #![feature(unix_socket_abstract)]
|
||||
/// use std::os::unix::net::{UnixDatagram};
|
||||
///
|
||||
/// fn main() -> std::io::Result<()> {
|
||||
|
|
@ -235,7 +233,7 @@ impl UnixDatagram {
|
|||
/// Ok(())
|
||||
/// }
|
||||
/// ```
|
||||
#[unstable(feature = "unix_socket_abstract", issue = "85410")]
|
||||
#[stable(feature = "unix_socket_abstract", since = "CURRENT_RUSTC_VERSION")]
|
||||
pub fn connect_addr(&self, socket_addr: &SocketAddr) -> io::Result<()> {
|
||||
unsafe {
|
||||
cvt(libc::connect(
|
||||
|
|
@ -523,7 +521,6 @@ impl UnixDatagram {
|
|||
/// # Examples
|
||||
///
|
||||
/// ```no_run
|
||||
/// #![feature(unix_socket_abstract)]
|
||||
/// use std::os::unix::net::{UnixDatagram};
|
||||
///
|
||||
/// fn main() -> std::io::Result<()> {
|
||||
|
|
@ -535,7 +532,7 @@ impl UnixDatagram {
|
|||
/// Ok(())
|
||||
/// }
|
||||
/// ```
|
||||
#[unstable(feature = "unix_socket_abstract", issue = "85410")]
|
||||
#[stable(feature = "unix_socket_abstract", since = "CURRENT_RUSTC_VERSION")]
|
||||
pub fn send_to_addr(&self, buf: &[u8], socket_addr: &SocketAddr) -> io::Result<usize> {
|
||||
unsafe {
|
||||
let count = cvt(libc::sendto(
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue