Auto merge of #133505 - compiler-errors:rollup-xjp8hdi, r=compiler-errors
Rollup of 12 pull requests Successful merges: - #133042 (btree: add `{Entry,VacantEntry}::insert_entry`) - #133070 (Lexer tweaks) - #133136 (Support ranges in `<[T]>::get_many_mut()`) - #133140 (Inline ExprPrecedence::order into Expr::precedence) - #133155 (Yet more `rustc_mir_dataflow` cleanups) - #133282 (Shorten the `MaybeUninit` `Debug` implementation) - #133326 (Remove the `DefinitelyInitializedPlaces` analysis.) - #133362 (No need to re-sort existential preds in relate impl) - #133367 (Simplify array length mismatch error reporting (to not try to turn consts into target usizes)) - #133394 (Bail on more errors in dyn ty lowering) - #133410 (target check_consistency: ensure target feature string makes some basic sense) - #133435 (miri: disable test_downgrade_observe test on macOS) r? `@ghost` `@rustbot` modify labels: rollup
This commit is contained in:
commit
dd2837ec5d
87 changed files with 1012 additions and 1508 deletions
|
@ -39,7 +39,9 @@ pub use crate::format::*;
|
|||
use crate::ptr::P;
|
||||
use crate::token::{self, CommentKind, Delimiter};
|
||||
use crate::tokenstream::{DelimSpan, LazyAttrTokenStream, TokenStream};
|
||||
pub use crate::util::parser::ExprPrecedence;
|
||||
use crate::util::parser::{
|
||||
AssocOp, PREC_CLOSURE, PREC_JUMP, PREC_PREFIX, PREC_RANGE, PREC_UNAMBIGUOUS,
|
||||
};
|
||||
|
||||
/// A "Label" is an identifier of some point in sources,
|
||||
/// e.g. in the following code:
|
||||
|
@ -1314,53 +1316,71 @@ impl Expr {
|
|||
Some(P(Ty { kind, id: self.id, span: self.span, tokens: None }))
|
||||
}
|
||||
|
||||
pub fn precedence(&self) -> ExprPrecedence {
|
||||
pub fn precedence(&self) -> i8 {
|
||||
match self.kind {
|
||||
ExprKind::Array(_) => ExprPrecedence::Array,
|
||||
ExprKind::ConstBlock(_) => ExprPrecedence::ConstBlock,
|
||||
ExprKind::Call(..) => ExprPrecedence::Call,
|
||||
ExprKind::MethodCall(..) => ExprPrecedence::MethodCall,
|
||||
ExprKind::Tup(_) => ExprPrecedence::Tup,
|
||||
ExprKind::Binary(op, ..) => ExprPrecedence::Binary(op.node),
|
||||
ExprKind::Unary(..) => ExprPrecedence::Unary,
|
||||
ExprKind::Lit(_) | ExprKind::IncludedBytes(..) => ExprPrecedence::Lit,
|
||||
ExprKind::Cast(..) => ExprPrecedence::Cast,
|
||||
ExprKind::Let(..) => ExprPrecedence::Let,
|
||||
ExprKind::If(..) => ExprPrecedence::If,
|
||||
ExprKind::While(..) => ExprPrecedence::While,
|
||||
ExprKind::ForLoop { .. } => ExprPrecedence::ForLoop,
|
||||
ExprKind::Loop(..) => ExprPrecedence::Loop,
|
||||
ExprKind::Match(_, _, MatchKind::Prefix) => ExprPrecedence::Match,
|
||||
ExprKind::Match(_, _, MatchKind::Postfix) => ExprPrecedence::PostfixMatch,
|
||||
ExprKind::Closure(..) => ExprPrecedence::Closure,
|
||||
ExprKind::Block(..) => ExprPrecedence::Block,
|
||||
ExprKind::TryBlock(..) => ExprPrecedence::TryBlock,
|
||||
ExprKind::Gen(..) => ExprPrecedence::Gen,
|
||||
ExprKind::Await(..) => ExprPrecedence::Await,
|
||||
ExprKind::Assign(..) => ExprPrecedence::Assign,
|
||||
ExprKind::AssignOp(..) => ExprPrecedence::AssignOp,
|
||||
ExprKind::Field(..) => ExprPrecedence::Field,
|
||||
ExprKind::Index(..) => ExprPrecedence::Index,
|
||||
ExprKind::Range(..) => ExprPrecedence::Range,
|
||||
ExprKind::Underscore => ExprPrecedence::Path,
|
||||
ExprKind::Path(..) => ExprPrecedence::Path,
|
||||
ExprKind::AddrOf(..) => ExprPrecedence::AddrOf,
|
||||
ExprKind::Break(..) => ExprPrecedence::Break,
|
||||
ExprKind::Continue(..) => ExprPrecedence::Continue,
|
||||
ExprKind::Ret(..) => ExprPrecedence::Ret,
|
||||
ExprKind::Struct(..) => ExprPrecedence::Struct,
|
||||
ExprKind::Repeat(..) => ExprPrecedence::Repeat,
|
||||
ExprKind::Paren(..) => ExprPrecedence::Paren,
|
||||
ExprKind::Try(..) => ExprPrecedence::Try,
|
||||
ExprKind::Yield(..) => ExprPrecedence::Yield,
|
||||
ExprKind::Yeet(..) => ExprPrecedence::Yeet,
|
||||
ExprKind::Become(..) => ExprPrecedence::Become,
|
||||
ExprKind::InlineAsm(..)
|
||||
| ExprKind::Type(..)
|
||||
| ExprKind::OffsetOf(..)
|
||||
ExprKind::Closure(..) => PREC_CLOSURE,
|
||||
|
||||
ExprKind::Break(..)
|
||||
| ExprKind::Continue(..)
|
||||
| ExprKind::Ret(..)
|
||||
| ExprKind::Yield(..)
|
||||
| ExprKind::Yeet(..)
|
||||
| ExprKind::Become(..) => PREC_JUMP,
|
||||
|
||||
// `Range` claims to have higher precedence than `Assign`, but `x .. x = x` fails to
|
||||
// parse, instead of parsing as `(x .. x) = x`. Giving `Range` a lower precedence
|
||||
// ensures that `pprust` will add parentheses in the right places to get the desired
|
||||
// parse.
|
||||
ExprKind::Range(..) => PREC_RANGE,
|
||||
|
||||
// Binop-like expr kinds, handled by `AssocOp`.
|
||||
ExprKind::Binary(op, ..) => AssocOp::from_ast_binop(op.node).precedence() as i8,
|
||||
ExprKind::Cast(..) => AssocOp::As.precedence() as i8,
|
||||
|
||||
ExprKind::Assign(..) |
|
||||
ExprKind::AssignOp(..) => AssocOp::Assign.precedence() as i8,
|
||||
|
||||
// Unary, prefix
|
||||
ExprKind::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`
|
||||
// but we need to print `(let _ = a) < b` as-is with parens.
|
||||
| ExprKind::Let(..)
|
||||
| ExprKind::Unary(..) => PREC_PREFIX,
|
||||
|
||||
// Never need parens
|
||||
ExprKind::Array(_)
|
||||
| ExprKind::Await(..)
|
||||
| ExprKind::Block(..)
|
||||
| ExprKind::Call(..)
|
||||
| ExprKind::ConstBlock(_)
|
||||
| ExprKind::Field(..)
|
||||
| ExprKind::ForLoop { .. }
|
||||
| ExprKind::FormatArgs(..)
|
||||
| ExprKind::MacCall(..) => ExprPrecedence::Mac,
|
||||
ExprKind::Err(_) | ExprKind::Dummy => ExprPrecedence::Err,
|
||||
| ExprKind::Gen(..)
|
||||
| ExprKind::If(..)
|
||||
| ExprKind::IncludedBytes(..)
|
||||
| ExprKind::Index(..)
|
||||
| ExprKind::InlineAsm(..)
|
||||
| ExprKind::Lit(_)
|
||||
| ExprKind::Loop(..)
|
||||
| ExprKind::MacCall(..)
|
||||
| ExprKind::Match(..)
|
||||
| ExprKind::MethodCall(..)
|
||||
| ExprKind::OffsetOf(..)
|
||||
| ExprKind::Paren(..)
|
||||
| ExprKind::Path(..)
|
||||
| ExprKind::Repeat(..)
|
||||
| ExprKind::Struct(..)
|
||||
| ExprKind::Try(..)
|
||||
| ExprKind::TryBlock(..)
|
||||
| ExprKind::Tup(_)
|
||||
| ExprKind::Type(..)
|
||||
| ExprKind::Underscore
|
||||
| ExprKind::While(..)
|
||||
| ExprKind::Err(_)
|
||||
| ExprKind::Dummy => PREC_UNAMBIGUOUS,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -237,121 +237,6 @@ pub const PREC_PREFIX: i8 = 50;
|
|||
pub const PREC_UNAMBIGUOUS: i8 = 60;
|
||||
pub const PREC_FORCE_PAREN: i8 = 100;
|
||||
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub enum ExprPrecedence {
|
||||
Closure,
|
||||
Break,
|
||||
Continue,
|
||||
Ret,
|
||||
Yield,
|
||||
Yeet,
|
||||
Become,
|
||||
|
||||
Range,
|
||||
|
||||
Binary(BinOpKind),
|
||||
|
||||
Cast,
|
||||
|
||||
Assign,
|
||||
AssignOp,
|
||||
|
||||
AddrOf,
|
||||
Let,
|
||||
Unary,
|
||||
|
||||
Call,
|
||||
MethodCall,
|
||||
Field,
|
||||
Index,
|
||||
Try,
|
||||
Mac,
|
||||
|
||||
Array,
|
||||
Repeat,
|
||||
Tup,
|
||||
Lit,
|
||||
Path,
|
||||
Paren,
|
||||
If,
|
||||
While,
|
||||
ForLoop,
|
||||
Loop,
|
||||
Match,
|
||||
PostfixMatch,
|
||||
ConstBlock,
|
||||
Block,
|
||||
TryBlock,
|
||||
Struct,
|
||||
Gen,
|
||||
Await,
|
||||
Err,
|
||||
}
|
||||
|
||||
impl ExprPrecedence {
|
||||
pub fn order(self) -> i8 {
|
||||
match self {
|
||||
ExprPrecedence::Closure => PREC_CLOSURE,
|
||||
|
||||
ExprPrecedence::Break
|
||||
| ExprPrecedence::Continue
|
||||
| ExprPrecedence::Ret
|
||||
| ExprPrecedence::Yield
|
||||
| ExprPrecedence::Yeet
|
||||
| ExprPrecedence::Become => PREC_JUMP,
|
||||
|
||||
// `Range` claims to have higher precedence than `Assign`, but `x .. x = x` fails to
|
||||
// parse, instead of parsing as `(x .. x) = x`. Giving `Range` a lower precedence
|
||||
// ensures that `pprust` will add parentheses in the right places to get the desired
|
||||
// parse.
|
||||
ExprPrecedence::Range => PREC_RANGE,
|
||||
|
||||
// Binop-like expr kinds, handled by `AssocOp`.
|
||||
ExprPrecedence::Binary(op) => AssocOp::from_ast_binop(op).precedence() as i8,
|
||||
ExprPrecedence::Cast => AssocOp::As.precedence() as i8,
|
||||
|
||||
ExprPrecedence::Assign |
|
||||
ExprPrecedence::AssignOp => AssocOp::Assign.precedence() as i8,
|
||||
|
||||
// Unary, prefix
|
||||
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`
|
||||
// but we need to print `(let _ = a) < b` as-is with parens.
|
||||
| ExprPrecedence::Let
|
||||
| ExprPrecedence::Unary => PREC_PREFIX,
|
||||
|
||||
// Never need parens
|
||||
ExprPrecedence::Array
|
||||
| ExprPrecedence::Await
|
||||
| ExprPrecedence::Block
|
||||
| ExprPrecedence::Call
|
||||
| ExprPrecedence::ConstBlock
|
||||
| ExprPrecedence::Field
|
||||
| ExprPrecedence::ForLoop
|
||||
| ExprPrecedence::Gen
|
||||
| ExprPrecedence::If
|
||||
| ExprPrecedence::Index
|
||||
| ExprPrecedence::Lit
|
||||
| ExprPrecedence::Loop
|
||||
| ExprPrecedence::Mac
|
||||
| ExprPrecedence::Match
|
||||
| ExprPrecedence::MethodCall
|
||||
| ExprPrecedence::Paren
|
||||
| ExprPrecedence::Path
|
||||
| ExprPrecedence::PostfixMatch
|
||||
| ExprPrecedence::Repeat
|
||||
| ExprPrecedence::Struct
|
||||
| ExprPrecedence::Try
|
||||
| ExprPrecedence::TryBlock
|
||||
| ExprPrecedence::Tup
|
||||
| ExprPrecedence::While
|
||||
| ExprPrecedence::Err => PREC_UNAMBIGUOUS,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// In `let p = e`, operators with precedence `<=` this one requires parentheses in `e`.
|
||||
pub fn prec_let_scrutinee_needs_par() -> usize {
|
||||
AssocOp::LAnd.precedence()
|
||||
|
|
|
@ -59,7 +59,7 @@ impl<'a> State<'a> {
|
|||
}
|
||||
|
||||
fn print_expr_maybe_paren(&mut self, expr: &ast::Expr, prec: i8, fixup: FixupContext) {
|
||||
self.print_expr_cond_paren(expr, expr.precedence().order() < prec, fixup);
|
||||
self.print_expr_cond_paren(expr, expr.precedence() < prec, fixup);
|
||||
}
|
||||
|
||||
/// Prints an expr using syntax that's acceptable in a condition position, such as the `cond` in
|
||||
|
@ -615,7 +615,7 @@ impl<'a> State<'a> {
|
|||
expr,
|
||||
// Parenthesize if required by precedence, or in the
|
||||
// case of `break 'inner: loop { break 'inner 1 } + 1`
|
||||
expr.precedence().order() < parser::PREC_JUMP
|
||||
expr.precedence() < parser::PREC_JUMP
|
||||
|| (opt_label.is_none() && classify::leading_labeled_expr(expr)),
|
||||
fixup.subsequent_subexpression(),
|
||||
);
|
||||
|
|
|
@ -191,6 +191,6 @@ impl FixupContext {
|
|||
/// "let chain".
|
||||
pub(crate) fn needs_par_as_let_scrutinee(self, expr: &Expr) -> bool {
|
||||
self.parenthesize_exterior_struct_lit && parser::contains_exterior_struct_lit(expr)
|
||||
|| parser::needs_par_as_let_scrutinee(expr.precedence().order())
|
||||
|| parser::needs_par_as_let_scrutinee(expr.precedence())
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
use std::fmt;
|
||||
|
||||
use rustc_abi::ExternAbi;
|
||||
use rustc_ast::util::parser::ExprPrecedence;
|
||||
use rustc_ast::util::parser::{AssocOp, PREC_CLOSURE, PREC_JUMP, PREC_PREFIX, PREC_UNAMBIGUOUS};
|
||||
use rustc_ast::{
|
||||
self as ast, Attribute, FloatTy, InlineAsmOptions, InlineAsmTemplatePiece, IntTy, Label,
|
||||
LitKind, TraitObjectSyntax, UintTy,
|
||||
|
@ -1708,41 +1708,54 @@ pub struct Expr<'hir> {
|
|||
}
|
||||
|
||||
impl Expr<'_> {
|
||||
pub fn precedence(&self) -> ExprPrecedence {
|
||||
pub fn precedence(&self) -> i8 {
|
||||
match self.kind {
|
||||
ExprKind::ConstBlock(_) => ExprPrecedence::ConstBlock,
|
||||
ExprKind::Array(_) => ExprPrecedence::Array,
|
||||
ExprKind::Call(..) => ExprPrecedence::Call,
|
||||
ExprKind::MethodCall(..) => ExprPrecedence::MethodCall,
|
||||
ExprKind::Tup(_) => ExprPrecedence::Tup,
|
||||
ExprKind::Binary(op, ..) => ExprPrecedence::Binary(op.node),
|
||||
ExprKind::Unary(..) => ExprPrecedence::Unary,
|
||||
ExprKind::Lit(_) => ExprPrecedence::Lit,
|
||||
ExprKind::Cast(..) => ExprPrecedence::Cast,
|
||||
ExprKind::Closure { .. } => PREC_CLOSURE,
|
||||
|
||||
ExprKind::Break(..)
|
||||
| ExprKind::Continue(..)
|
||||
| ExprKind::Ret(..)
|
||||
| ExprKind::Yield(..)
|
||||
| ExprKind::Become(..) => PREC_JUMP,
|
||||
|
||||
// Binop-like expr kinds, handled by `AssocOp`.
|
||||
ExprKind::Binary(op, ..) => AssocOp::from_ast_binop(op.node).precedence() as i8,
|
||||
ExprKind::Cast(..) => AssocOp::As.precedence() as i8,
|
||||
|
||||
ExprKind::Assign(..) |
|
||||
ExprKind::AssignOp(..) => AssocOp::Assign.precedence() as i8,
|
||||
|
||||
// Unary, prefix
|
||||
ExprKind::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`
|
||||
// but we need to print `(let _ = a) < b` as-is with parens.
|
||||
| ExprKind::Let(..)
|
||||
| ExprKind::Unary(..) => PREC_PREFIX,
|
||||
|
||||
// Never need parens
|
||||
ExprKind::Array(_)
|
||||
| ExprKind::Block(..)
|
||||
| ExprKind::Call(..)
|
||||
| ExprKind::ConstBlock(_)
|
||||
| ExprKind::Field(..)
|
||||
| ExprKind::If(..)
|
||||
| ExprKind::Index(..)
|
||||
| ExprKind::InlineAsm(..)
|
||||
| ExprKind::Lit(_)
|
||||
| ExprKind::Loop(..)
|
||||
| ExprKind::Match(..)
|
||||
| ExprKind::MethodCall(..)
|
||||
| ExprKind::OffsetOf(..)
|
||||
| ExprKind::Path(..)
|
||||
| ExprKind::Repeat(..)
|
||||
| ExprKind::Struct(..)
|
||||
| ExprKind::Tup(_)
|
||||
| ExprKind::Type(..)
|
||||
| ExprKind::Err(_) => PREC_UNAMBIGUOUS,
|
||||
|
||||
ExprKind::DropTemps(ref expr, ..) => expr.precedence(),
|
||||
ExprKind::If(..) => ExprPrecedence::If,
|
||||
ExprKind::Let(..) => ExprPrecedence::Let,
|
||||
ExprKind::Loop(..) => ExprPrecedence::Loop,
|
||||
ExprKind::Match(..) => ExprPrecedence::Match,
|
||||
ExprKind::Closure { .. } => ExprPrecedence::Closure,
|
||||
ExprKind::Block(..) => ExprPrecedence::Block,
|
||||
ExprKind::Assign(..) => ExprPrecedence::Assign,
|
||||
ExprKind::AssignOp(..) => ExprPrecedence::AssignOp,
|
||||
ExprKind::Field(..) => ExprPrecedence::Field,
|
||||
ExprKind::Index(..) => ExprPrecedence::Index,
|
||||
ExprKind::Path(..) => ExprPrecedence::Path,
|
||||
ExprKind::AddrOf(..) => ExprPrecedence::AddrOf,
|
||||
ExprKind::Break(..) => ExprPrecedence::Break,
|
||||
ExprKind::Continue(..) => ExprPrecedence::Continue,
|
||||
ExprKind::Ret(..) => ExprPrecedence::Ret,
|
||||
ExprKind::Become(..) => ExprPrecedence::Become,
|
||||
ExprKind::Struct(..) => ExprPrecedence::Struct,
|
||||
ExprKind::Repeat(..) => ExprPrecedence::Repeat,
|
||||
ExprKind::Yield(..) => ExprPrecedence::Yield,
|
||||
ExprKind::Type(..) | ExprKind::InlineAsm(..) | ExprKind::OffsetOf(..) => {
|
||||
ExprPrecedence::Mac
|
||||
}
|
||||
ExprKind::Err(_) => ExprPrecedence::Err,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -8,7 +8,8 @@ use rustc_lint_defs::builtin::UNUSED_ASSOCIATED_TYPE_BOUNDS;
|
|||
use rustc_middle::span_bug;
|
||||
use rustc_middle::ty::fold::BottomUpFolder;
|
||||
use rustc_middle::ty::{
|
||||
self, DynKind, ExistentialPredicateStableCmpExt as _, Ty, TyCtxt, TypeFoldable, Upcast,
|
||||
self, DynKind, ExistentialPredicateStableCmpExt as _, Ty, TyCtxt, TypeFoldable,
|
||||
TypeVisitableExt, Upcast,
|
||||
};
|
||||
use rustc_span::{ErrorGuaranteed, Span};
|
||||
use rustc_trait_selection::error_reporting::traits::report_dyn_incompatibility;
|
||||
|
@ -92,11 +93,20 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
|||
|
||||
let (mut auto_traits, regular_traits): (Vec<_>, Vec<_>) =
|
||||
expanded_traits.partition(|i| tcx.trait_is_auto(i.trait_ref().def_id()));
|
||||
|
||||
// We don't support >1 principal
|
||||
if regular_traits.len() > 1 {
|
||||
let _ = self.report_trait_object_addition_traits_error(®ular_traits);
|
||||
} else if regular_traits.is_empty() && auto_traits.is_empty() {
|
||||
let reported = self.report_trait_object_with_no_traits_error(span, &trait_bounds);
|
||||
return Ty::new_error(tcx, reported);
|
||||
let guar = self.report_trait_object_addition_traits_error(®ular_traits);
|
||||
return Ty::new_error(tcx, guar);
|
||||
}
|
||||
// We don't support empty trait objects.
|
||||
if regular_traits.is_empty() && auto_traits.is_empty() {
|
||||
let guar = self.report_trait_object_with_no_traits_error(span, &trait_bounds);
|
||||
return Ty::new_error(tcx, guar);
|
||||
}
|
||||
// Don't create a dyn trait if we have errors in the principal.
|
||||
if let Err(guar) = trait_bounds.error_reported() {
|
||||
return Ty::new_error(tcx, guar);
|
||||
}
|
||||
|
||||
// Check that there are no gross dyn-compatibility violations;
|
||||
|
|
|
@ -1011,7 +1011,7 @@ impl<'a> State<'a> {
|
|||
}
|
||||
|
||||
fn print_expr_maybe_paren(&mut self, expr: &hir::Expr<'_>, prec: i8) {
|
||||
self.print_expr_cond_paren(expr, expr.precedence().order() < prec)
|
||||
self.print_expr_cond_paren(expr, expr.precedence() < prec)
|
||||
}
|
||||
|
||||
/// Prints an expr using syntax that's acceptable in a condition position, such as the `cond` in
|
||||
|
@ -1045,7 +1045,7 @@ impl<'a> State<'a> {
|
|||
}
|
||||
self.space();
|
||||
self.word_space("=");
|
||||
let npals = || parser::needs_par_as_let_scrutinee(init.precedence().order());
|
||||
let npals = || parser::needs_par_as_let_scrutinee(init.precedence());
|
||||
self.print_expr_cond_paren(init, Self::cond_needs_par(init) || npals())
|
||||
}
|
||||
|
||||
|
|
|
@ -606,7 +606,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
};
|
||||
|
||||
if let Ok(rest_snippet) = rest_snippet {
|
||||
let sugg = if callee_expr.precedence().order() >= PREC_UNAMBIGUOUS {
|
||||
let sugg = if callee_expr.precedence() >= PREC_UNAMBIGUOUS {
|
||||
vec![
|
||||
(up_to_rcvr_span, "".to_string()),
|
||||
(rest_span, format!(".{}({rest_snippet}", segment.ident)),
|
||||
|
|
|
@ -1107,7 +1107,7 @@ impl<'a, 'tcx> CastCheck<'tcx> {
|
|||
}
|
||||
|
||||
fn lossy_provenance_ptr2int_lint(&self, fcx: &FnCtxt<'a, 'tcx>, t_c: ty::cast::IntTy) {
|
||||
let expr_prec = self.expr.precedence().order();
|
||||
let expr_prec = self.expr.precedence();
|
||||
let needs_parens = expr_prec < rustc_ast::util::parser::PREC_UNAMBIGUOUS;
|
||||
|
||||
let needs_cast = !matches!(t_c, ty::cast::IntTy::U(ty::UintTy::Usize));
|
||||
|
|
|
@ -2,7 +2,7 @@ use core::cmp::min;
|
|||
use core::iter;
|
||||
|
||||
use hir::def_id::LocalDefId;
|
||||
use rustc_ast::util::parser::{ExprPrecedence, PREC_UNAMBIGUOUS};
|
||||
use rustc_ast::util::parser::PREC_UNAMBIGUOUS;
|
||||
use rustc_data_structures::packed::Pu128;
|
||||
use rustc_errors::{Applicability, Diag, MultiSpan};
|
||||
use rustc_hir as hir;
|
||||
|
@ -398,7 +398,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
// so we remove the user's `clone` call.
|
||||
{
|
||||
vec![(receiver_method.ident.span, conversion_method.name.to_string())]
|
||||
} else if expr.precedence().order() < ExprPrecedence::MethodCall.order() {
|
||||
} else if expr.precedence() < PREC_UNAMBIGUOUS {
|
||||
vec![
|
||||
(expr.span.shrink_to_lo(), "(".to_string()),
|
||||
(expr.span.shrink_to_hi(), format!(").{}()", conversion_method.name)),
|
||||
|
@ -1376,7 +1376,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
{
|
||||
let span = expr.span.find_oldest_ancestor_in_same_ctxt();
|
||||
|
||||
let mut sugg = if expr.precedence().order() >= PREC_UNAMBIGUOUS {
|
||||
let mut sugg = if expr.precedence() >= PREC_UNAMBIGUOUS {
|
||||
vec![(span.shrink_to_hi(), ".into()".to_owned())]
|
||||
} else {
|
||||
vec![
|
||||
|
@ -3000,7 +3000,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
"change the type of the numeric literal from `{checked_ty}` to `{expected_ty}`",
|
||||
);
|
||||
|
||||
let close_paren = if expr.precedence().order() < PREC_UNAMBIGUOUS {
|
||||
let close_paren = if expr.precedence() < PREC_UNAMBIGUOUS {
|
||||
sugg.push((expr.span.shrink_to_lo(), "(".to_string()));
|
||||
")"
|
||||
} else {
|
||||
|
@ -3025,7 +3025,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
let len = src.trim_end_matches(&checked_ty.to_string()).len();
|
||||
expr.span.with_lo(expr.span.lo() + BytePos(len as u32))
|
||||
},
|
||||
if expr.precedence().order() < PREC_UNAMBIGUOUS {
|
||||
if expr.precedence() < PREC_UNAMBIGUOUS {
|
||||
// Readd `)`
|
||||
format!("{expected_ty})")
|
||||
} else {
|
||||
|
|
|
@ -566,19 +566,19 @@ impl Cursor<'_> {
|
|||
|
||||
fn c_or_byte_string(
|
||||
&mut self,
|
||||
mk_kind: impl FnOnce(bool) -> LiteralKind,
|
||||
mk_kind_raw: impl FnOnce(Option<u8>) -> LiteralKind,
|
||||
mk_kind: fn(bool) -> LiteralKind,
|
||||
mk_kind_raw: fn(Option<u8>) -> LiteralKind,
|
||||
single_quoted: Option<fn(bool) -> LiteralKind>,
|
||||
) -> TokenKind {
|
||||
match (self.first(), self.second(), single_quoted) {
|
||||
('\'', _, Some(mk_kind)) => {
|
||||
('\'', _, Some(single_quoted)) => {
|
||||
self.bump();
|
||||
let terminated = self.single_quoted_string();
|
||||
let suffix_start = self.pos_within_token();
|
||||
if terminated {
|
||||
self.eat_literal_suffix();
|
||||
}
|
||||
let kind = mk_kind(terminated);
|
||||
let kind = single_quoted(terminated);
|
||||
Literal { kind, suffix_start }
|
||||
}
|
||||
('"', _, _) => {
|
||||
|
|
|
@ -77,63 +77,53 @@ fn test_too_many_hashes() {
|
|||
check_raw_str(&s2, Err(RawStrError::TooManyDelimiters { found: u32::from(max_count) + 1 }));
|
||||
}
|
||||
|
||||
// https://github.com/rust-lang/rust/issues/70528
|
||||
#[test]
|
||||
fn test_valid_shebang() {
|
||||
// https://github.com/rust-lang/rust/issues/70528
|
||||
let input = "#!/usr/bin/rustrun\nlet x = 5;";
|
||||
assert_eq!(strip_shebang(input), Some(18));
|
||||
}
|
||||
let input = "#!/bin/bash";
|
||||
assert_eq!(strip_shebang(input), Some(input.len()));
|
||||
|
||||
#[test]
|
||||
fn test_invalid_shebang_valid_rust_syntax() {
|
||||
// https://github.com/rust-lang/rust/issues/70528
|
||||
let input = "#! [bad_attribute]";
|
||||
let input = "#![attribute]";
|
||||
assert_eq!(strip_shebang(input), None);
|
||||
|
||||
let input = "#! /bin/bash";
|
||||
assert_eq!(strip_shebang(input), Some(input.len()));
|
||||
|
||||
let input = "#! [attribute]";
|
||||
assert_eq!(strip_shebang(input), None);
|
||||
|
||||
let input = "#! /* blah */ /bin/bash";
|
||||
assert_eq!(strip_shebang(input), Some(input.len()));
|
||||
|
||||
let input = "#! /* blah */ [attribute]";
|
||||
assert_eq!(strip_shebang(input), None);
|
||||
|
||||
let input = "#! // blah\n/bin/bash";
|
||||
assert_eq!(strip_shebang(input), Some(10)); // strip up to the newline
|
||||
|
||||
let input = "#! // blah\n[attribute]";
|
||||
assert_eq!(strip_shebang(input), None);
|
||||
|
||||
let input = "#! /* blah\nblah\nblah */ /bin/bash";
|
||||
assert_eq!(strip_shebang(input), Some(10));
|
||||
|
||||
let input = "#! /* blah\nblah\nblah */ [attribute]";
|
||||
assert_eq!(strip_shebang(input), None);
|
||||
|
||||
let input = "#!\n/bin/sh";
|
||||
assert_eq!(strip_shebang(input), Some(2));
|
||||
|
||||
let input = "#!\n[attribute]";
|
||||
assert_eq!(strip_shebang(input), None);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_shebang_second_line() {
|
||||
// Because shebangs are interpreted by the kernel, they must be on the first line
|
||||
let input = "\n#!/bin/bash";
|
||||
assert_eq!(strip_shebang(input), None);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_shebang_space() {
|
||||
let input = "#! /bin/bash";
|
||||
assert_eq!(strip_shebang(input), Some(input.len()));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_shebang_empty_shebang() {
|
||||
let input = "#! \n[attribute(foo)]";
|
||||
let input = "\n#![attribute]";
|
||||
assert_eq!(strip_shebang(input), None);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_invalid_shebang_comment() {
|
||||
let input = "#!//bin/ami/a/comment\n[";
|
||||
assert_eq!(strip_shebang(input), None)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_invalid_shebang_another_comment() {
|
||||
let input = "#!/*bin/ami/a/comment*/\n[attribute";
|
||||
assert_eq!(strip_shebang(input), None)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_shebang_valid_rust_after() {
|
||||
let input = "#!/*bin/ami/a/comment*/\npub fn main() {}";
|
||||
assert_eq!(strip_shebang(input), Some(23))
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_shebang_followed_by_attrib() {
|
||||
let input = "#!/bin/rust-scripts\n#![allow_unused(true)]";
|
||||
assert_eq!(strip_shebang(input), Some(19));
|
||||
}
|
||||
|
||||
fn check_lexing(src: &str, expect: Expect) {
|
||||
let actual: String = tokenize(src).map(|token| format!("{:?}\n", token)).collect();
|
||||
expect.assert_eq(&actual)
|
||||
|
|
|
@ -151,10 +151,6 @@ impl<'tcx> Const<'tcx> {
|
|||
}
|
||||
|
||||
impl<'tcx> rustc_type_ir::inherent::Const<TyCtxt<'tcx>> for Const<'tcx> {
|
||||
fn try_to_target_usize(self, interner: TyCtxt<'tcx>) -> Option<u64> {
|
||||
self.try_to_target_usize(interner)
|
||||
}
|
||||
|
||||
fn new_infer(tcx: TyCtxt<'tcx>, infer: ty::InferConst) -> Self {
|
||||
Const::new_infer(tcx, infer)
|
||||
}
|
||||
|
|
|
@ -58,12 +58,9 @@ impl<'tcx> TypeError<'tcx> {
|
|||
pluralize!(values.found)
|
||||
)
|
||||
.into(),
|
||||
TypeError::FixedArraySize(values) => format!(
|
||||
"expected an array with a fixed size of {} element{}, found one with {} element{}",
|
||||
values.expected,
|
||||
pluralize!(values.expected),
|
||||
values.found,
|
||||
pluralize!(values.found)
|
||||
TypeError::ArraySize(values) => format!(
|
||||
"expected an array with a size of {}, found one with a size of {}",
|
||||
values.expected, values.found,
|
||||
)
|
||||
.into(),
|
||||
TypeError::ArgCount => "incorrect number of function parameters".into(),
|
||||
|
|
|
@ -3,7 +3,6 @@ use std::iter;
|
|||
pub use rustc_type_ir::relate::*;
|
||||
|
||||
use crate::ty::error::{ExpectedFound, TypeError};
|
||||
use crate::ty::predicate::ExistentialPredicateStableCmpExt as _;
|
||||
use crate::ty::{self as ty, Ty, TyCtxt};
|
||||
|
||||
pub type RelateResult<'tcx, T> = rustc_type_ir::relate::RelateResult<TyCtxt<'tcx>, T>;
|
||||
|
@ -86,10 +85,7 @@ impl<'tcx> Relate<TyCtxt<'tcx>> for &'tcx ty::List<ty::PolyExistentialPredicate<
|
|||
// in `a`.
|
||||
let mut a_v: Vec<_> = a.into_iter().collect();
|
||||
let mut b_v: Vec<_> = b.into_iter().collect();
|
||||
// `skip_binder` here is okay because `stable_cmp` doesn't look at binders
|
||||
a_v.sort_by(|a, b| a.skip_binder().stable_cmp(tcx, &b.skip_binder()));
|
||||
a_v.dedup();
|
||||
b_v.sort_by(|a, b| a.skip_binder().stable_cmp(tcx, &b.skip_binder()));
|
||||
b_v.dedup();
|
||||
if a_v.len() != b_v.len() {
|
||||
return Err(TypeError::ExistentialMismatch(ExpectedFound::new(a, b)));
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
//! Random access inspection of the results of a dataflow analysis.
|
||||
|
||||
use std::cmp::Ordering;
|
||||
use std::ops::{Deref, DerefMut};
|
||||
|
||||
#[cfg(debug_assertions)]
|
||||
use rustc_index::bit_set::BitSet;
|
||||
|
@ -8,18 +9,63 @@ use rustc_middle::mir::{self, BasicBlock, Location};
|
|||
|
||||
use super::{Analysis, Direction, Effect, EffectIndex, Results};
|
||||
|
||||
/// Allows random access inspection of the results of a dataflow analysis.
|
||||
/// Some `ResultsCursor`s want to own a `Results`, and some want to borrow a `Results`, either
|
||||
/// mutable or immutably. This type allows all of the above. It's similar to `Cow`.
|
||||
pub enum ResultsHandle<'a, 'tcx, A>
|
||||
where
|
||||
A: Analysis<'tcx>,
|
||||
{
|
||||
Borrowed(&'a Results<'tcx, A>),
|
||||
BorrowedMut(&'a mut Results<'tcx, A>),
|
||||
Owned(Results<'tcx, A>),
|
||||
}
|
||||
|
||||
impl<'tcx, A> Deref for ResultsHandle<'_, 'tcx, A>
|
||||
where
|
||||
A: Analysis<'tcx>,
|
||||
{
|
||||
type Target = Results<'tcx, A>;
|
||||
|
||||
fn deref(&self) -> &Results<'tcx, A> {
|
||||
match self {
|
||||
ResultsHandle::Borrowed(borrowed) => borrowed,
|
||||
ResultsHandle::BorrowedMut(borrowed) => borrowed,
|
||||
ResultsHandle::Owned(owned) => owned,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx, A> DerefMut for ResultsHandle<'_, 'tcx, A>
|
||||
where
|
||||
A: Analysis<'tcx>,
|
||||
{
|
||||
fn deref_mut(&mut self) -> &mut Results<'tcx, A> {
|
||||
match self {
|
||||
ResultsHandle::Borrowed(_borrowed) => {
|
||||
panic!("tried to deref_mut a `ResultsHandle::Borrowed")
|
||||
}
|
||||
ResultsHandle::BorrowedMut(borrowed) => borrowed,
|
||||
ResultsHandle::Owned(owned) => owned,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Allows random access inspection of the results of a dataflow analysis. Use this when you want
|
||||
/// to inspect domain values only in certain locations; use `ResultsVisitor` if you want to inspect
|
||||
/// domain values in many or all locations.
|
||||
///
|
||||
/// This cursor only has linear performance within a basic block when its statements are visited in
|
||||
/// the same order as the `DIRECTION` of the analysis. In the worst case—when statements are
|
||||
/// visited in *reverse* order—performance will be quadratic in the number of statements in the
|
||||
/// block. The order in which basic blocks are inspected has no impact on performance.
|
||||
/// Because `Results` only has domain values for the entry of each basic block, these inspections
|
||||
/// involve some amount of domain value recomputations. This cursor only has linear performance
|
||||
/// within a basic block when its statements are visited in the same order as the `DIRECTION` of
|
||||
/// the analysis. In the worst case—when statements are visited in *reverse* order—performance will
|
||||
/// be quadratic in the number of statements in the block. The order in which basic blocks are
|
||||
/// inspected has no impact on performance.
|
||||
pub struct ResultsCursor<'mir, 'tcx, A>
|
||||
where
|
||||
A: Analysis<'tcx>,
|
||||
{
|
||||
body: &'mir mir::Body<'tcx>,
|
||||
results: Results<'tcx, A>,
|
||||
results: ResultsHandle<'mir, 'tcx, A>,
|
||||
state: A::Domain,
|
||||
|
||||
pos: CursorPosition,
|
||||
|
@ -47,13 +93,8 @@ where
|
|||
self.body
|
||||
}
|
||||
|
||||
/// Unwraps this cursor, returning the underlying `Results`.
|
||||
pub fn into_results(self) -> Results<'tcx, A> {
|
||||
self.results
|
||||
}
|
||||
|
||||
/// Returns a new cursor that can inspect `results`.
|
||||
pub fn new(body: &'mir mir::Body<'tcx>, results: Results<'tcx, A>) -> Self {
|
||||
pub fn new(body: &'mir mir::Body<'tcx>, results: ResultsHandle<'mir, 'tcx, A>) -> Self {
|
||||
let bottom_value = results.analysis.bottom_value(body);
|
||||
ResultsCursor {
|
||||
body,
|
||||
|
|
|
@ -9,10 +9,21 @@ use super::{Analysis, Effect, EffectIndex, Results, SwitchIntTarget};
|
|||
|
||||
pub trait Direction {
|
||||
const IS_FORWARD: bool;
|
||||
|
||||
const IS_BACKWARD: bool = !Self::IS_FORWARD;
|
||||
|
||||
/// Applies all effects between the given `EffectIndex`s.
|
||||
/// Called by `iterate_to_fixpoint` during initial analysis computation.
|
||||
fn apply_effects_in_block<'mir, 'tcx, A>(
|
||||
analysis: &mut A,
|
||||
body: &mir::Body<'tcx>,
|
||||
state: &mut A::Domain,
|
||||
block: BasicBlock,
|
||||
block_data: &'mir mir::BasicBlockData<'tcx>,
|
||||
propagate: impl FnMut(BasicBlock, &A::Domain),
|
||||
) where
|
||||
A: Analysis<'tcx>;
|
||||
|
||||
/// Called by `ResultsCursor` to recompute the domain value for a location
|
||||
/// in a basic block. Applies all effects between the given `EffectIndex`s.
|
||||
///
|
||||
/// `effects.start()` must precede or equal `effects.end()` in this direction.
|
||||
fn apply_effects_in_range<'tcx, A>(
|
||||
|
@ -24,15 +35,9 @@ pub trait Direction {
|
|||
) where
|
||||
A: Analysis<'tcx>;
|
||||
|
||||
fn apply_effects_in_block<'mir, 'tcx, A>(
|
||||
analysis: &mut A,
|
||||
state: &mut A::Domain,
|
||||
block: BasicBlock,
|
||||
block_data: &'mir mir::BasicBlockData<'tcx>,
|
||||
) -> TerminatorEdges<'mir, 'tcx>
|
||||
where
|
||||
A: Analysis<'tcx>;
|
||||
|
||||
/// Called by `ResultsVisitor` to recompute the analysis domain values for
|
||||
/// all locations in a basic block (starting from the entry value stored
|
||||
/// in `Results`) and to visit them with `vis`.
|
||||
fn visit_results_in_block<'mir, 'tcx, A>(
|
||||
state: &mut A::Domain,
|
||||
block: BasicBlock,
|
||||
|
@ -41,16 +46,6 @@ pub trait Direction {
|
|||
vis: &mut impl ResultsVisitor<'mir, 'tcx, A>,
|
||||
) where
|
||||
A: Analysis<'tcx>;
|
||||
|
||||
fn join_state_into_successors_of<'tcx, A>(
|
||||
analysis: &mut A,
|
||||
body: &mir::Body<'tcx>,
|
||||
exit_state: &mut A::Domain,
|
||||
block: BasicBlock,
|
||||
edges: TerminatorEdges<'_, 'tcx>,
|
||||
propagate: impl FnMut(BasicBlock, &A::Domain),
|
||||
) where
|
||||
A: Analysis<'tcx>;
|
||||
}
|
||||
|
||||
/// Dataflow that runs from the exit of a block (terminator), to its entry (the first statement).
|
||||
|
@ -61,23 +56,84 @@ impl Direction for Backward {
|
|||
|
||||
fn apply_effects_in_block<'mir, 'tcx, A>(
|
||||
analysis: &mut A,
|
||||
body: &mir::Body<'tcx>,
|
||||
state: &mut A::Domain,
|
||||
block: BasicBlock,
|
||||
block_data: &'mir mir::BasicBlockData<'tcx>,
|
||||
) -> TerminatorEdges<'mir, 'tcx>
|
||||
where
|
||||
mut propagate: impl FnMut(BasicBlock, &A::Domain),
|
||||
) where
|
||||
A: Analysis<'tcx>,
|
||||
{
|
||||
let terminator = block_data.terminator();
|
||||
let location = Location { block, statement_index: block_data.statements.len() };
|
||||
analysis.apply_before_terminator_effect(state, terminator, location);
|
||||
let edges = analysis.apply_terminator_effect(state, terminator, location);
|
||||
analysis.apply_terminator_effect(state, terminator, location);
|
||||
for (statement_index, statement) in block_data.statements.iter().enumerate().rev() {
|
||||
let location = Location { block, statement_index };
|
||||
analysis.apply_before_statement_effect(state, statement, location);
|
||||
analysis.apply_statement_effect(state, statement, location);
|
||||
}
|
||||
edges
|
||||
|
||||
let exit_state = state;
|
||||
for pred in body.basic_blocks.predecessors()[block].iter().copied() {
|
||||
match body[pred].terminator().kind {
|
||||
// Apply terminator-specific edge effects.
|
||||
//
|
||||
// FIXME(ecstaticmorse): Avoid cloning the exit state unconditionally.
|
||||
mir::TerminatorKind::Call { destination, target: Some(dest), .. }
|
||||
if dest == block =>
|
||||
{
|
||||
let mut tmp = exit_state.clone();
|
||||
analysis.apply_call_return_effect(
|
||||
&mut tmp,
|
||||
pred,
|
||||
CallReturnPlaces::Call(destination),
|
||||
);
|
||||
propagate(pred, &tmp);
|
||||
}
|
||||
|
||||
mir::TerminatorKind::InlineAsm { ref targets, ref operands, .. }
|
||||
if targets.contains(&block) =>
|
||||
{
|
||||
let mut tmp = exit_state.clone();
|
||||
analysis.apply_call_return_effect(
|
||||
&mut tmp,
|
||||
pred,
|
||||
CallReturnPlaces::InlineAsm(operands),
|
||||
);
|
||||
propagate(pred, &tmp);
|
||||
}
|
||||
|
||||
mir::TerminatorKind::Yield { resume, resume_arg, .. } if resume == block => {
|
||||
let mut tmp = exit_state.clone();
|
||||
analysis.apply_call_return_effect(
|
||||
&mut tmp,
|
||||
resume,
|
||||
CallReturnPlaces::Yield(resume_arg),
|
||||
);
|
||||
propagate(pred, &tmp);
|
||||
}
|
||||
|
||||
mir::TerminatorKind::SwitchInt { targets: _, ref discr } => {
|
||||
let mut applier = BackwardSwitchIntEdgeEffectsApplier {
|
||||
body,
|
||||
pred,
|
||||
exit_state,
|
||||
block,
|
||||
propagate: &mut propagate,
|
||||
effects_applied: false,
|
||||
};
|
||||
|
||||
analysis.apply_switch_int_edge_effects(pred, discr, &mut applier);
|
||||
|
||||
if !applier.effects_applied {
|
||||
propagate(pred, exit_state)
|
||||
}
|
||||
}
|
||||
|
||||
_ => propagate(pred, exit_state),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn apply_effects_in_range<'tcx, A>(
|
||||
|
@ -170,7 +226,6 @@ impl Direction for Backward {
|
|||
|
||||
vis.visit_block_end(state);
|
||||
|
||||
// Terminator
|
||||
let loc = Location { block, statement_index: block_data.statements.len() };
|
||||
let term = block_data.terminator();
|
||||
results.analysis.apply_before_terminator_effect(state, term, loc);
|
||||
|
@ -188,82 +243,13 @@ impl Direction for Backward {
|
|||
|
||||
vis.visit_block_start(state);
|
||||
}
|
||||
|
||||
fn join_state_into_successors_of<'tcx, A>(
|
||||
analysis: &mut A,
|
||||
body: &mir::Body<'tcx>,
|
||||
exit_state: &mut A::Domain,
|
||||
bb: BasicBlock,
|
||||
_edges: TerminatorEdges<'_, 'tcx>,
|
||||
mut propagate: impl FnMut(BasicBlock, &A::Domain),
|
||||
) where
|
||||
A: Analysis<'tcx>,
|
||||
{
|
||||
for pred in body.basic_blocks.predecessors()[bb].iter().copied() {
|
||||
match body[pred].terminator().kind {
|
||||
// Apply terminator-specific edge effects.
|
||||
//
|
||||
// FIXME(ecstaticmorse): Avoid cloning the exit state unconditionally.
|
||||
mir::TerminatorKind::Call { destination, target: Some(dest), .. } if dest == bb => {
|
||||
let mut tmp = exit_state.clone();
|
||||
analysis.apply_call_return_effect(
|
||||
&mut tmp,
|
||||
pred,
|
||||
CallReturnPlaces::Call(destination),
|
||||
);
|
||||
propagate(pred, &tmp);
|
||||
}
|
||||
|
||||
mir::TerminatorKind::InlineAsm { ref targets, ref operands, .. }
|
||||
if targets.contains(&bb) =>
|
||||
{
|
||||
let mut tmp = exit_state.clone();
|
||||
analysis.apply_call_return_effect(
|
||||
&mut tmp,
|
||||
pred,
|
||||
CallReturnPlaces::InlineAsm(operands),
|
||||
);
|
||||
propagate(pred, &tmp);
|
||||
}
|
||||
|
||||
mir::TerminatorKind::Yield { resume, resume_arg, .. } if resume == bb => {
|
||||
let mut tmp = exit_state.clone();
|
||||
analysis.apply_call_return_effect(
|
||||
&mut tmp,
|
||||
resume,
|
||||
CallReturnPlaces::Yield(resume_arg),
|
||||
);
|
||||
propagate(pred, &tmp);
|
||||
}
|
||||
|
||||
mir::TerminatorKind::SwitchInt { targets: _, ref discr } => {
|
||||
let mut applier = BackwardSwitchIntEdgeEffectsApplier {
|
||||
body,
|
||||
pred,
|
||||
exit_state,
|
||||
bb,
|
||||
propagate: &mut propagate,
|
||||
effects_applied: false,
|
||||
};
|
||||
|
||||
analysis.apply_switch_int_edge_effects(pred, discr, &mut applier);
|
||||
|
||||
if !applier.effects_applied {
|
||||
propagate(pred, exit_state)
|
||||
}
|
||||
}
|
||||
|
||||
_ => propagate(pred, exit_state),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct BackwardSwitchIntEdgeEffectsApplier<'mir, 'tcx, D, F> {
|
||||
body: &'mir mir::Body<'tcx>,
|
||||
pred: BasicBlock,
|
||||
exit_state: &'mir mut D,
|
||||
bb: BasicBlock,
|
||||
block: BasicBlock,
|
||||
propagate: &'mir mut F,
|
||||
effects_applied: bool,
|
||||
}
|
||||
|
@ -276,8 +262,8 @@ where
|
|||
fn apply(&mut self, mut apply_edge_effect: impl FnMut(&mut D, SwitchIntTarget)) {
|
||||
assert!(!self.effects_applied);
|
||||
|
||||
let values = &self.body.basic_blocks.switch_sources()[&(self.bb, self.pred)];
|
||||
let targets = values.iter().map(|&value| SwitchIntTarget { value, target: self.bb });
|
||||
let values = &self.body.basic_blocks.switch_sources()[&(self.block, self.pred)];
|
||||
let targets = values.iter().map(|&value| SwitchIntTarget { value, target: self.block });
|
||||
|
||||
let mut tmp = None;
|
||||
for target in targets {
|
||||
|
@ -298,11 +284,12 @@ impl Direction for Forward {
|
|||
|
||||
fn apply_effects_in_block<'mir, 'tcx, A>(
|
||||
analysis: &mut A,
|
||||
_body: &mir::Body<'tcx>,
|
||||
state: &mut A::Domain,
|
||||
block: BasicBlock,
|
||||
block_data: &'mir mir::BasicBlockData<'tcx>,
|
||||
) -> TerminatorEdges<'mir, 'tcx>
|
||||
where
|
||||
mut propagate: impl FnMut(BasicBlock, &A::Domain),
|
||||
) where
|
||||
A: Analysis<'tcx>,
|
||||
{
|
||||
for (statement_index, statement) in block_data.statements.iter().enumerate() {
|
||||
|
@ -313,7 +300,53 @@ impl Direction for Forward {
|
|||
let terminator = block_data.terminator();
|
||||
let location = Location { block, statement_index: block_data.statements.len() };
|
||||
analysis.apply_before_terminator_effect(state, terminator, location);
|
||||
analysis.apply_terminator_effect(state, terminator, location)
|
||||
let edges = analysis.apply_terminator_effect(state, terminator, location);
|
||||
|
||||
let exit_state = state;
|
||||
match edges {
|
||||
TerminatorEdges::None => {}
|
||||
TerminatorEdges::Single(target) => propagate(target, exit_state),
|
||||
TerminatorEdges::Double(target, unwind) => {
|
||||
propagate(target, exit_state);
|
||||
propagate(unwind, exit_state);
|
||||
}
|
||||
TerminatorEdges::AssignOnReturn { return_, cleanup, place } => {
|
||||
// This must be done *first*, otherwise the unwind path will see the assignments.
|
||||
if let Some(cleanup) = cleanup {
|
||||
propagate(cleanup, exit_state);
|
||||
}
|
||||
|
||||
if !return_.is_empty() {
|
||||
analysis.apply_call_return_effect(exit_state, block, place);
|
||||
for &target in return_ {
|
||||
propagate(target, exit_state);
|
||||
}
|
||||
}
|
||||
}
|
||||
TerminatorEdges::SwitchInt { targets, discr } => {
|
||||
let mut applier = ForwardSwitchIntEdgeEffectsApplier {
|
||||
exit_state,
|
||||
targets,
|
||||
propagate,
|
||||
effects_applied: false,
|
||||
};
|
||||
|
||||
analysis.apply_switch_int_edge_effects(block, discr, &mut applier);
|
||||
|
||||
let ForwardSwitchIntEdgeEffectsApplier {
|
||||
exit_state,
|
||||
mut propagate,
|
||||
effects_applied,
|
||||
..
|
||||
} = applier;
|
||||
|
||||
if !effects_applied {
|
||||
for target in targets.all_targets() {
|
||||
propagate(*target, exit_state);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn apply_effects_in_range<'tcx, A>(
|
||||
|
@ -351,7 +384,8 @@ impl Direction for Forward {
|
|||
let statement = &block_data.statements[from.statement_index];
|
||||
analysis.apply_statement_effect(state, statement, location);
|
||||
|
||||
// If we only needed to apply the after effect of the statement at `idx`, we are done.
|
||||
// If we only needed to apply the after effect of the statement at `idx`, we are
|
||||
// done.
|
||||
if from == to {
|
||||
return;
|
||||
}
|
||||
|
@ -419,62 +453,6 @@ impl Direction for Forward {
|
|||
|
||||
vis.visit_block_end(state);
|
||||
}
|
||||
|
||||
fn join_state_into_successors_of<'tcx, A>(
|
||||
analysis: &mut A,
|
||||
_body: &mir::Body<'tcx>,
|
||||
exit_state: &mut A::Domain,
|
||||
bb: BasicBlock,
|
||||
edges: TerminatorEdges<'_, 'tcx>,
|
||||
mut propagate: impl FnMut(BasicBlock, &A::Domain),
|
||||
) where
|
||||
A: Analysis<'tcx>,
|
||||
{
|
||||
match edges {
|
||||
TerminatorEdges::None => {}
|
||||
TerminatorEdges::Single(target) => propagate(target, exit_state),
|
||||
TerminatorEdges::Double(target, unwind) => {
|
||||
propagate(target, exit_state);
|
||||
propagate(unwind, exit_state);
|
||||
}
|
||||
TerminatorEdges::AssignOnReturn { return_, cleanup, place } => {
|
||||
// This must be done *first*, otherwise the unwind path will see the assignments.
|
||||
if let Some(cleanup) = cleanup {
|
||||
propagate(cleanup, exit_state);
|
||||
}
|
||||
|
||||
if !return_.is_empty() {
|
||||
analysis.apply_call_return_effect(exit_state, bb, place);
|
||||
for &target in return_ {
|
||||
propagate(target, exit_state);
|
||||
}
|
||||
}
|
||||
}
|
||||
TerminatorEdges::SwitchInt { targets, discr } => {
|
||||
let mut applier = ForwardSwitchIntEdgeEffectsApplier {
|
||||
exit_state,
|
||||
targets,
|
||||
propagate,
|
||||
effects_applied: false,
|
||||
};
|
||||
|
||||
analysis.apply_switch_int_edge_effects(bb, discr, &mut applier);
|
||||
|
||||
let ForwardSwitchIntEdgeEffectsApplier {
|
||||
exit_state,
|
||||
mut propagate,
|
||||
effects_applied,
|
||||
..
|
||||
} = applier;
|
||||
|
||||
if !effects_applied {
|
||||
for target in targets.all_targets() {
|
||||
propagate(*target, exit_state);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct ForwardSwitchIntEdgeEffectsApplier<'mir, D, F> {
|
||||
|
|
|
@ -230,16 +230,3 @@ where
|
|||
write!(f, "{}", ctxt.move_data().move_paths[*self])
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, C> DebugWithContext<C> for crate::lattice::Dual<T>
|
||||
where
|
||||
T: DebugWithContext<C>,
|
||||
{
|
||||
fn fmt_with(&self, ctxt: &C, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
(self.0).fmt_with(ctxt, f)
|
||||
}
|
||||
|
||||
fn fmt_diff_with(&self, old: &Self, ctxt: &C, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
(self.0).fmt_diff_with(&old.0, ctxt, f)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -47,20 +47,16 @@ where
|
|||
{
|
||||
pub(crate) fn new(
|
||||
body: &'mir Body<'tcx>,
|
||||
results: Results<'tcx, A>,
|
||||
results: &'mir Results<'tcx, A>,
|
||||
style: OutputStyle,
|
||||
) -> Self {
|
||||
let reachable = mir::traversal::reachable_as_bitset(body);
|
||||
Formatter { cursor: results.into_results_cursor(body).into(), style, reachable }
|
||||
Formatter { cursor: results.as_results_cursor(body).into(), style, reachable }
|
||||
}
|
||||
|
||||
fn body(&self) -> &'mir Body<'tcx> {
|
||||
self.cursor.borrow().body()
|
||||
}
|
||||
|
||||
pub(crate) fn into_results(self) -> Results<'tcx, A> {
|
||||
self.cursor.into_inner().into_results()
|
||||
}
|
||||
}
|
||||
|
||||
/// A pair of a basic block and an index into that basic blocks `successors`.
|
||||
|
|
|
@ -25,8 +25,8 @@
|
|||
//!
|
||||
//! ## `PartialOrd`
|
||||
//!
|
||||
//! Given that they represent partially ordered sets, you may be surprised that [`JoinSemiLattice`]
|
||||
//! and [`MeetSemiLattice`] do not have [`PartialOrd`] as a supertrait. This
|
||||
//! Given that it represents a partially ordered set, you may be surprised that [`JoinSemiLattice`]
|
||||
//! does not have [`PartialOrd`] as a supertrait. This
|
||||
//! is because most standard library types use lexicographic ordering instead of set inclusion for
|
||||
//! their `PartialOrd` impl. Since we do not actually need to compare lattice elements to run a
|
||||
//! dataflow analysis, there's no need for a newtype wrapper with a custom `PartialOrd` impl. The
|
||||
|
@ -58,23 +58,6 @@ pub trait JoinSemiLattice: Eq {
|
|||
fn join(&mut self, other: &Self) -> bool;
|
||||
}
|
||||
|
||||
/// A [partially ordered set][poset] that has a [greatest lower bound][glb] for any pair of
|
||||
/// elements in the set.
|
||||
///
|
||||
/// Dataflow analyses only require that their domains implement [`JoinSemiLattice`], not
|
||||
/// `MeetSemiLattice`. However, types that will be used as dataflow domains should implement both
|
||||
/// so that they can be used with [`Dual`].
|
||||
///
|
||||
/// [glb]: https://en.wikipedia.org/wiki/Infimum_and_supremum
|
||||
/// [poset]: https://en.wikipedia.org/wiki/Partially_ordered_set
|
||||
pub trait MeetSemiLattice: Eq {
|
||||
/// Computes the greatest lower bound of two elements, storing the result in `self` and
|
||||
/// returning `true` if `self` has changed.
|
||||
///
|
||||
/// The lattice meet operator is abbreviated as `∧`.
|
||||
fn meet(&mut self, other: &Self) -> bool;
|
||||
}
|
||||
|
||||
/// A set that has a "bottom" element, which is less than or equal to any other element.
|
||||
pub trait HasBottom {
|
||||
const BOTTOM: Self;
|
||||
|
@ -105,17 +88,6 @@ impl JoinSemiLattice for bool {
|
|||
}
|
||||
}
|
||||
|
||||
impl MeetSemiLattice for bool {
|
||||
fn meet(&mut self, other: &Self) -> bool {
|
||||
if let (true, false) = (*self, *other) {
|
||||
*self = false;
|
||||
return true;
|
||||
}
|
||||
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
impl HasBottom for bool {
|
||||
const BOTTOM: Self = false;
|
||||
|
||||
|
@ -145,18 +117,6 @@ impl<I: Idx, T: JoinSemiLattice> JoinSemiLattice for IndexVec<I, T> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<I: Idx, T: MeetSemiLattice> MeetSemiLattice for IndexVec<I, T> {
|
||||
fn meet(&mut self, other: &Self) -> bool {
|
||||
assert_eq!(self.len(), other.len());
|
||||
|
||||
let mut changed = false;
|
||||
for (a, b) in iter::zip(self, other) {
|
||||
changed |= a.meet(b);
|
||||
}
|
||||
changed
|
||||
}
|
||||
}
|
||||
|
||||
/// A `BitSet` represents the lattice formed by the powerset of all possible values of
|
||||
/// the index type `T` ordered by inclusion. Equivalently, it is a tuple of "two-point" lattices,
|
||||
/// one for each possible value of `T`.
|
||||
|
@ -166,60 +126,12 @@ impl<T: Idx> JoinSemiLattice for BitSet<T> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<T: Idx> MeetSemiLattice for BitSet<T> {
|
||||
fn meet(&mut self, other: &Self) -> bool {
|
||||
self.intersect(other)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Idx> JoinSemiLattice for ChunkedBitSet<T> {
|
||||
fn join(&mut self, other: &Self) -> bool {
|
||||
self.union(other)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Idx> MeetSemiLattice for ChunkedBitSet<T> {
|
||||
fn meet(&mut self, other: &Self) -> bool {
|
||||
self.intersect(other)
|
||||
}
|
||||
}
|
||||
|
||||
/// The counterpart of a given semilattice `T` using the [inverse order].
|
||||
///
|
||||
/// The dual of a join-semilattice is a meet-semilattice and vice versa. For example, the dual of a
|
||||
/// powerset has the empty set as its top element and the full set as its bottom element and uses
|
||||
/// set *intersection* as its join operator.
|
||||
///
|
||||
/// [inverse order]: https://en.wikipedia.org/wiki/Duality_(order_theory)
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
||||
pub struct Dual<T>(pub T);
|
||||
|
||||
impl<T: Idx> BitSetExt<T> for Dual<BitSet<T>> {
|
||||
fn contains(&self, elem: T) -> bool {
|
||||
self.0.contains(elem)
|
||||
}
|
||||
|
||||
fn union(&mut self, other: &HybridBitSet<T>) {
|
||||
self.0.union(other);
|
||||
}
|
||||
|
||||
fn subtract(&mut self, other: &HybridBitSet<T>) {
|
||||
self.0.subtract(other);
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: MeetSemiLattice> JoinSemiLattice for Dual<T> {
|
||||
fn join(&mut self, other: &Self) -> bool {
|
||||
self.0.meet(&other.0)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: JoinSemiLattice> MeetSemiLattice for Dual<T> {
|
||||
fn meet(&mut self, other: &Self) -> bool {
|
||||
self.0.join(&other.0)
|
||||
}
|
||||
}
|
||||
|
||||
/// Extends a type `T` with top and bottom elements to make it a partially ordered set in which no
|
||||
/// value of `T` is comparable with any other.
|
||||
///
|
||||
|
@ -257,22 +169,6 @@ impl<T: Clone + Eq> JoinSemiLattice for FlatSet<T> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<T: Clone + Eq> MeetSemiLattice for FlatSet<T> {
|
||||
fn meet(&mut self, other: &Self) -> bool {
|
||||
let result = match (&*self, other) {
|
||||
(Self::Bottom, _) | (_, Self::Top) => return false,
|
||||
(Self::Elem(ref a), Self::Elem(ref b)) if a == b => return false,
|
||||
|
||||
(Self::Top, Self::Elem(ref x)) => Self::Elem(x.clone()),
|
||||
|
||||
_ => Self::Bottom,
|
||||
};
|
||||
|
||||
*self = result;
|
||||
true
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> HasBottom for FlatSet<T> {
|
||||
const BOTTOM: Self = Self::Bottom;
|
||||
|
||||
|
|
|
@ -8,8 +8,9 @@
|
|||
//! The `impls` module contains several examples of dataflow analyses.
|
||||
//!
|
||||
//! Then call `iterate_to_fixpoint` on your type that impls `Analysis` to get a `Results`. From
|
||||
//! there, you can use a `ResultsCursor` to inspect the fixpoint solution to your dataflow problem,
|
||||
//! or implement the `ResultsVisitor` interface and use `visit_results`. The following example uses
|
||||
//! there, you can use a `ResultsCursor` to inspect the fixpoint solution to your dataflow problem
|
||||
//! (good for inspecting a small number of locations), or implement the `ResultsVisitor` interface
|
||||
//! and use `visit_results` (good for inspecting many or all locations). The following example uses
|
||||
//! the `ResultsCursor` approach.
|
||||
//!
|
||||
//! ```ignore (cross-crate-imports)
|
||||
|
@ -278,22 +279,17 @@ pub trait Analysis<'tcx> {
|
|||
// every iteration.
|
||||
let mut state = self.bottom_value(body);
|
||||
while let Some(bb) = dirty_queue.pop() {
|
||||
let bb_data = &body[bb];
|
||||
|
||||
// Set the state to the entry state of the block.
|
||||
// This is equivalent to `state = entry_sets[bb].clone()`,
|
||||
// but it saves an allocation, thus improving compile times.
|
||||
state.clone_from(&entry_sets[bb]);
|
||||
|
||||
// Apply the block transfer function, using the cached one if it exists.
|
||||
let edges = Self::Direction::apply_effects_in_block(&mut self, &mut state, bb, bb_data);
|
||||
|
||||
Self::Direction::join_state_into_successors_of(
|
||||
Self::Direction::apply_effects_in_block(
|
||||
&mut self,
|
||||
body,
|
||||
&mut state,
|
||||
bb,
|
||||
edges,
|
||||
&body[bb],
|
||||
|target: BasicBlock, state: &Self::Domain| {
|
||||
let set_changed = entry_sets[target].join(state);
|
||||
if set_changed {
|
||||
|
@ -306,14 +302,13 @@ pub trait Analysis<'tcx> {
|
|||
let results = Results { analysis: self, entry_sets };
|
||||
|
||||
if tcx.sess.opts.unstable_opts.dump_mir_dataflow {
|
||||
let (res, results) = write_graphviz_results(tcx, body, results, pass_name);
|
||||
let res = write_graphviz_results(tcx, body, &results, pass_name);
|
||||
if let Err(e) = res {
|
||||
error!("Failed to write graphviz dataflow results: {}", e);
|
||||
}
|
||||
results
|
||||
} else {
|
||||
results
|
||||
}
|
||||
|
||||
results
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -378,16 +373,6 @@ impl<T, S: GenKill<T>> GenKill<T> for MaybeReachable<S> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<T: Idx> GenKill<T> for lattice::Dual<BitSet<T>> {
|
||||
fn gen_(&mut self, elem: T) {
|
||||
self.0.insert(elem);
|
||||
}
|
||||
|
||||
fn kill(&mut self, elem: T) {
|
||||
self.0.remove(elem);
|
||||
}
|
||||
}
|
||||
|
||||
// NOTE: DO NOT CHANGE VARIANT ORDER. The derived `Ord` impls rely on the current order.
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)]
|
||||
enum Effect {
|
||||
|
|
|
@ -17,10 +17,13 @@ use super::{Analysis, ResultsCursor, ResultsVisitor, graphviz, visit_results};
|
|||
use crate::errors::{
|
||||
DuplicateValuesFor, PathMustEndInFilename, RequiresAnArgument, UnknownFormatter,
|
||||
};
|
||||
use crate::framework::cursor::ResultsHandle;
|
||||
|
||||
pub type EntrySets<'tcx, A> = IndexVec<BasicBlock, <A as Analysis<'tcx>>::Domain>;
|
||||
|
||||
/// A dataflow analysis that has converged to fixpoint.
|
||||
/// A dataflow analysis that has converged to fixpoint. It only holds the domain values at the
|
||||
/// entry of each basic block. Domain values in other parts of the block are recomputed on the fly
|
||||
/// by visitors (i.e. `ResultsCursor`, or `ResultsVisitor` impls).
|
||||
#[derive(Clone)]
|
||||
pub struct Results<'tcx, A>
|
||||
where
|
||||
|
@ -34,12 +37,30 @@ impl<'tcx, A> Results<'tcx, A>
|
|||
where
|
||||
A: Analysis<'tcx>,
|
||||
{
|
||||
/// Creates a `ResultsCursor` that can inspect these `Results`.
|
||||
/// Creates a `ResultsCursor` that can inspect these `Results`. Immutably borrows the `Results`,
|
||||
/// which is appropriate when the `Results` is used outside the cursor.
|
||||
pub fn as_results_cursor<'mir>(
|
||||
&'mir self,
|
||||
body: &'mir mir::Body<'tcx>,
|
||||
) -> ResultsCursor<'mir, 'tcx, A> {
|
||||
ResultsCursor::new(body, ResultsHandle::Borrowed(self))
|
||||
}
|
||||
|
||||
/// Creates a `ResultsCursor` that can mutate these `Results`. Mutably borrows the `Results`,
|
||||
/// which is appropriate when the `Results` is used outside the cursor.
|
||||
pub fn as_results_cursor_mut<'mir>(
|
||||
&'mir mut self,
|
||||
body: &'mir mir::Body<'tcx>,
|
||||
) -> ResultsCursor<'mir, 'tcx, A> {
|
||||
ResultsCursor::new(body, ResultsHandle::BorrowedMut(self))
|
||||
}
|
||||
|
||||
/// Creates a `ResultsCursor` that takes ownership of the `Results`.
|
||||
pub fn into_results_cursor<'mir>(
|
||||
self,
|
||||
body: &'mir mir::Body<'tcx>,
|
||||
) -> ResultsCursor<'mir, 'tcx, A> {
|
||||
ResultsCursor::new(body, self)
|
||||
ResultsCursor::new(body, ResultsHandle::Owned(self))
|
||||
}
|
||||
|
||||
/// Gets the dataflow state for the given block.
|
||||
|
@ -74,9 +95,9 @@ where
|
|||
pub(super) fn write_graphviz_results<'tcx, A>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
body: &mir::Body<'tcx>,
|
||||
results: Results<'tcx, A>,
|
||||
results: &Results<'tcx, A>,
|
||||
pass_name: Option<&'static str>,
|
||||
) -> (std::io::Result<()>, Results<'tcx, A>)
|
||||
) -> std::io::Result<()>
|
||||
where
|
||||
A: Analysis<'tcx>,
|
||||
A::Domain: DebugWithContext<A>,
|
||||
|
@ -87,7 +108,7 @@ where
|
|||
let def_id = body.source.def_id();
|
||||
let Ok(attrs) = RustcMirAttrs::parse(tcx, def_id) else {
|
||||
// Invalid `rustc_mir` attrs are reported in `RustcMirAttrs::parse`
|
||||
return (Ok(()), results);
|
||||
return Ok(());
|
||||
};
|
||||
|
||||
let file = try {
|
||||
|
@ -104,12 +125,12 @@ where
|
|||
create_dump_file(tcx, "dot", false, A::NAME, &pass_name.unwrap_or("-----"), body)?
|
||||
}
|
||||
|
||||
_ => return (Ok(()), results),
|
||||
_ => return Ok(()),
|
||||
}
|
||||
};
|
||||
let mut file = match file {
|
||||
Ok(f) => f,
|
||||
Err(e) => return (Err(e), results),
|
||||
Err(e) => return Err(e),
|
||||
};
|
||||
|
||||
let style = match attrs.formatter {
|
||||
|
@ -132,7 +153,7 @@ where
|
|||
file.write_all(&buf)?;
|
||||
};
|
||||
|
||||
(lhs, graphviz.into_results())
|
||||
lhs
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
|
|
|
@ -26,7 +26,9 @@ pub fn visit_results<'mir, 'tcx, A>(
|
|||
}
|
||||
}
|
||||
|
||||
/// A visitor over the results of an `Analysis`.
|
||||
/// A visitor over the results of an `Analysis`. Use this when you want to inspect domain values in
|
||||
/// many or all locations; use `ResultsCursor` if you want to inspect domain values only in certain
|
||||
/// locations.
|
||||
pub trait ResultsVisitor<'mir, 'tcx, A>
|
||||
where
|
||||
A: Analysis<'tcx>,
|
||||
|
|
|
@ -15,7 +15,7 @@ use crate::{Analysis, GenKill};
|
|||
pub struct MaybeBorrowedLocals;
|
||||
|
||||
impl MaybeBorrowedLocals {
|
||||
pub(super) fn transfer_function<'a, T>(&'a self, trans: &'a mut T) -> TransferFunction<'a, T> {
|
||||
pub(super) fn transfer_function<'a, T>(trans: &'a mut T) -> TransferFunction<'a, T> {
|
||||
TransferFunction { trans }
|
||||
}
|
||||
}
|
||||
|
@ -39,7 +39,7 @@ impl<'tcx> Analysis<'tcx> for MaybeBorrowedLocals {
|
|||
statement: &Statement<'tcx>,
|
||||
location: Location,
|
||||
) {
|
||||
self.transfer_function(trans).visit_statement(statement, location);
|
||||
Self::transfer_function(trans).visit_statement(statement, location);
|
||||
}
|
||||
|
||||
fn apply_terminator_effect<'mir>(
|
||||
|
@ -48,7 +48,7 @@ impl<'tcx> Analysis<'tcx> for MaybeBorrowedLocals {
|
|||
terminator: &'mir Terminator<'tcx>,
|
||||
location: Location,
|
||||
) -> TerminatorEdges<'mir, 'tcx> {
|
||||
self.transfer_function(trans).visit_terminator(terminator, location);
|
||||
Self::transfer_function(trans).visit_terminator(terminator, location);
|
||||
terminator.edges()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -12,7 +12,7 @@ use crate::framework::SwitchIntEdgeEffects;
|
|||
use crate::move_paths::{HasMoveData, InitIndex, InitKind, LookupResult, MoveData, MovePathIndex};
|
||||
use crate::{
|
||||
Analysis, GenKill, MaybeReachable, drop_flag_effects, drop_flag_effects_for_function_entry,
|
||||
drop_flag_effects_for_location, lattice, on_all_children_bits, on_lookup_result_bits,
|
||||
drop_flag_effects_for_location, on_all_children_bits, on_lookup_result_bits,
|
||||
};
|
||||
|
||||
/// `MaybeInitializedPlaces` tracks all places that might be
|
||||
|
@ -42,10 +42,10 @@ use crate::{
|
|||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// To determine whether a place *must* be initialized at a
|
||||
/// particular control-flow point, one can take the set-difference
|
||||
/// between this data and the data from `MaybeUninitializedPlaces` at the
|
||||
/// corresponding control-flow point.
|
||||
/// To determine whether a place is *definitely* initialized at a
|
||||
/// particular control-flow point, one can take the set-complement
|
||||
/// of the data from `MaybeUninitializedPlaces` at the corresponding
|
||||
/// control-flow point.
|
||||
///
|
||||
/// Similarly, at a given `drop` statement, the set-intersection
|
||||
/// between this data and `MaybeUninitializedPlaces` yields the set of
|
||||
|
@ -117,10 +117,10 @@ impl<'a, 'tcx> HasMoveData<'tcx> for MaybeInitializedPlaces<'a, 'tcx> {
|
|||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// To determine whether a place *must* be uninitialized at a
|
||||
/// particular control-flow point, one can take the set-difference
|
||||
/// between this data and the data from `MaybeInitializedPlaces` at the
|
||||
/// corresponding control-flow point.
|
||||
/// To determine whether a place is *definitely* uninitialized at a
|
||||
/// particular control-flow point, one can take the set-complement
|
||||
/// of the data from `MaybeInitializedPlaces` at the corresponding
|
||||
/// control-flow point.
|
||||
///
|
||||
/// Similarly, at a given `drop` statement, the set-intersection
|
||||
/// between this data and `MaybeInitializedPlaces` yields the set of
|
||||
|
@ -170,57 +170,6 @@ impl<'tcx> HasMoveData<'tcx> for MaybeUninitializedPlaces<'_, 'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
/// `DefinitelyInitializedPlaces` tracks all places that are definitely
|
||||
/// initialized upon reaching a particular point in the control flow
|
||||
/// for a function.
|
||||
///
|
||||
/// For example, in code like the following, we have corresponding
|
||||
/// dataflow information shown in the right-hand comments.
|
||||
///
|
||||
/// ```rust
|
||||
/// struct S;
|
||||
/// fn foo(pred: bool) { // definite-init:
|
||||
/// // { }
|
||||
/// let a = S; let mut b = S; let c; let d; // {a, b }
|
||||
///
|
||||
/// if pred {
|
||||
/// drop(a); // { b, }
|
||||
/// b = S; // { b, }
|
||||
///
|
||||
/// } else {
|
||||
/// drop(b); // {a, }
|
||||
/// d = S; // {a, d}
|
||||
///
|
||||
/// } // { }
|
||||
///
|
||||
/// c = S; // { c }
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// To determine whether a place *may* be uninitialized at a
|
||||
/// particular control-flow point, one can take the set-complement
|
||||
/// of this data.
|
||||
///
|
||||
/// Similarly, at a given `drop` statement, the set-difference between
|
||||
/// this data and `MaybeInitializedPlaces` yields the set of places
|
||||
/// that would require a dynamic drop-flag at that statement.
|
||||
pub struct DefinitelyInitializedPlaces<'a, 'tcx> {
|
||||
body: &'a Body<'tcx>,
|
||||
move_data: &'a MoveData<'tcx>,
|
||||
}
|
||||
|
||||
impl<'a, 'tcx> DefinitelyInitializedPlaces<'a, 'tcx> {
|
||||
pub fn new(body: &'a Body<'tcx>, move_data: &'a MoveData<'tcx>) -> Self {
|
||||
DefinitelyInitializedPlaces { body, move_data }
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, 'tcx> HasMoveData<'tcx> for DefinitelyInitializedPlaces<'a, 'tcx> {
|
||||
fn move_data(&self) -> &MoveData<'tcx> {
|
||||
self.move_data
|
||||
}
|
||||
}
|
||||
|
||||
/// `EverInitializedPlaces` tracks all places that might have ever been
|
||||
/// initialized upon reaching a particular point in the control flow
|
||||
/// for a function, without an intervening `StorageDead`.
|
||||
|
@ -293,19 +242,6 @@ impl<'tcx> MaybeUninitializedPlaces<'_, 'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'a, 'tcx> DefinitelyInitializedPlaces<'a, 'tcx> {
|
||||
fn update_bits(
|
||||
trans: &mut <Self as Analysis<'tcx>>::Domain,
|
||||
path: MovePathIndex,
|
||||
state: DropFlagState,
|
||||
) {
|
||||
match state {
|
||||
DropFlagState::Absent => trans.kill(path),
|
||||
DropFlagState::Present => trans.gen_(path),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> Analysis<'tcx> for MaybeInitializedPlaces<'_, 'tcx> {
|
||||
/// There can be many more `MovePathIndex` than there are locals in a MIR body.
|
||||
/// We use a chunked bitset to avoid paying too high a memory footprint.
|
||||
|
@ -554,70 +490,6 @@ impl<'tcx> Analysis<'tcx> for MaybeUninitializedPlaces<'_, 'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'a, 'tcx> Analysis<'tcx> for DefinitelyInitializedPlaces<'a, 'tcx> {
|
||||
/// Use set intersection as the join operator.
|
||||
type Domain = lattice::Dual<BitSet<MovePathIndex>>;
|
||||
|
||||
const NAME: &'static str = "definite_init";
|
||||
|
||||
fn bottom_value(&self, _: &mir::Body<'tcx>) -> Self::Domain {
|
||||
// bottom = initialized (start_block_effect counters this at outset)
|
||||
lattice::Dual(BitSet::new_filled(self.move_data().move_paths.len()))
|
||||
}
|
||||
|
||||
// sets on_entry bits for Arg places
|
||||
fn initialize_start_block(&self, _: &mir::Body<'tcx>, state: &mut Self::Domain) {
|
||||
state.0.clear();
|
||||
|
||||
drop_flag_effects_for_function_entry(self.body, self.move_data, |path, s| {
|
||||
assert!(s == DropFlagState::Present);
|
||||
state.0.insert(path);
|
||||
});
|
||||
}
|
||||
|
||||
fn apply_statement_effect(
|
||||
&mut self,
|
||||
trans: &mut Self::Domain,
|
||||
_statement: &mir::Statement<'tcx>,
|
||||
location: Location,
|
||||
) {
|
||||
drop_flag_effects_for_location(self.body, self.move_data, location, |path, s| {
|
||||
Self::update_bits(trans, path, s)
|
||||
})
|
||||
}
|
||||
|
||||
fn apply_terminator_effect<'mir>(
|
||||
&mut self,
|
||||
trans: &mut Self::Domain,
|
||||
terminator: &'mir mir::Terminator<'tcx>,
|
||||
location: Location,
|
||||
) -> TerminatorEdges<'mir, 'tcx> {
|
||||
drop_flag_effects_for_location(self.body, self.move_data, location, |path, s| {
|
||||
Self::update_bits(trans, path, s)
|
||||
});
|
||||
terminator.edges()
|
||||
}
|
||||
|
||||
fn apply_call_return_effect(
|
||||
&mut self,
|
||||
trans: &mut Self::Domain,
|
||||
_block: mir::BasicBlock,
|
||||
return_places: CallReturnPlaces<'_, 'tcx>,
|
||||
) {
|
||||
return_places.for_each(|place| {
|
||||
// when a call returns successfully, that means we need to set
|
||||
// the bits for that dest_place to 1 (initialized).
|
||||
on_lookup_result_bits(
|
||||
self.move_data(),
|
||||
self.move_data().rev_lookup.find(place.as_ref()),
|
||||
|mpi| {
|
||||
trans.gen_(mpi);
|
||||
},
|
||||
);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> Analysis<'tcx> for EverInitializedPlaces<'_, 'tcx> {
|
||||
/// There can be many more `InitIndex` than there are locals in a MIR body.
|
||||
/// We use a chunked bitset to avoid paying too high a memory footprint.
|
||||
|
|
|
@ -9,8 +9,7 @@ mod storage_liveness;
|
|||
|
||||
pub use self::borrowed_locals::{MaybeBorrowedLocals, borrowed_locals};
|
||||
pub use self::initialized::{
|
||||
DefinitelyInitializedPlaces, EverInitializedPlaces, MaybeInitializedPlaces,
|
||||
MaybeUninitializedPlaces,
|
||||
EverInitializedPlaces, MaybeInitializedPlaces, MaybeUninitializedPlaces,
|
||||
};
|
||||
pub use self::liveness::{
|
||||
MaybeLiveLocals, MaybeTransitiveLiveLocals, TransferFunction as LivenessTransferFunction,
|
||||
|
|
|
@ -135,7 +135,7 @@ impl<'tcx> Analysis<'tcx> for MaybeRequiresStorage<'_, 'tcx> {
|
|||
loc: Location,
|
||||
) {
|
||||
// If a place is borrowed in a statement, it needs storage for that statement.
|
||||
self.borrowed_locals.mut_analysis().apply_statement_effect(trans, stmt, loc);
|
||||
MaybeBorrowedLocals::transfer_function(trans).visit_statement(stmt, loc);
|
||||
|
||||
match &stmt.kind {
|
||||
StatementKind::StorageDead(l) => trans.kill(*l),
|
||||
|
@ -180,10 +180,7 @@ impl<'tcx> Analysis<'tcx> for MaybeRequiresStorage<'_, 'tcx> {
|
|||
loc: Location,
|
||||
) {
|
||||
// If a place is borrowed in a terminator, it needs storage for that terminator.
|
||||
self.borrowed_locals
|
||||
.mut_analysis()
|
||||
.transfer_function(trans)
|
||||
.visit_terminator(terminator, loc);
|
||||
MaybeBorrowedLocals::transfer_function(trans).visit_terminator(terminator, loc);
|
||||
|
||||
match &terminator.kind {
|
||||
TerminatorKind::Call { destination, .. } => {
|
||||
|
|
|
@ -12,9 +12,7 @@ use crate::errors::{
|
|||
PeekMustBePlaceOrRefPlace, StopAfterDataFlowEndedCompilation,
|
||||
};
|
||||
use crate::framework::BitSetExt;
|
||||
use crate::impls::{
|
||||
DefinitelyInitializedPlaces, MaybeInitializedPlaces, MaybeLiveLocals, MaybeUninitializedPlaces,
|
||||
};
|
||||
use crate::impls::{MaybeInitializedPlaces, MaybeLiveLocals, MaybeUninitializedPlaces};
|
||||
use crate::move_paths::{HasMoveData, LookupResult, MoveData, MovePathIndex};
|
||||
use crate::{Analysis, JoinSemiLattice, ResultsCursor};
|
||||
|
||||
|
@ -56,13 +54,6 @@ pub fn sanity_check<'tcx>(tcx: TyCtxt<'tcx>, body: &Body<'tcx>) {
|
|||
sanity_check_via_rustc_peek(tcx, flow_uninits.into_results_cursor(body));
|
||||
}
|
||||
|
||||
if has_rustc_mir_with(tcx, def_id, sym::rustc_peek_definite_init).is_some() {
|
||||
let flow_def_inits =
|
||||
DefinitelyInitializedPlaces::new(body, &move_data).iterate_to_fixpoint(tcx, body, None);
|
||||
|
||||
sanity_check_via_rustc_peek(tcx, flow_def_inits.into_results_cursor(body));
|
||||
}
|
||||
|
||||
if has_rustc_mir_with(tcx, def_id, sym::rustc_peek_liveness).is_some() {
|
||||
let flow_liveness = MaybeLiveLocals.iterate_to_fixpoint(tcx, body, None);
|
||||
|
||||
|
|
|
@ -676,12 +676,11 @@ fn locals_live_across_suspend_points<'tcx>(
|
|||
|
||||
let mut borrowed_locals_cursor = borrowed_locals_results.clone().into_results_cursor(body);
|
||||
|
||||
// Calculate the MIR locals that we actually need to keep storage around
|
||||
// for.
|
||||
let mut requires_storage_cursor =
|
||||
// Calculate the MIR locals that we need to keep storage around for.
|
||||
let mut requires_storage_results =
|
||||
MaybeRequiresStorage::new(borrowed_locals_results.into_results_cursor(body))
|
||||
.iterate_to_fixpoint(tcx, body, None)
|
||||
.into_results_cursor(body);
|
||||
.iterate_to_fixpoint(tcx, body, None);
|
||||
let mut requires_storage_cursor = requires_storage_results.as_results_cursor_mut(body);
|
||||
|
||||
// Calculate the liveness of MIR locals ignoring borrows.
|
||||
let mut liveness =
|
||||
|
@ -754,7 +753,7 @@ fn locals_live_across_suspend_points<'tcx>(
|
|||
body,
|
||||
&saved_locals,
|
||||
always_live_locals.clone(),
|
||||
requires_storage_cursor.into_results(),
|
||||
requires_storage_results,
|
||||
);
|
||||
|
||||
LivenessInfo {
|
||||
|
|
|
@ -18,6 +18,7 @@ use rustc_span::symbol::Symbol;
|
|||
use rustc_span::{BytePos, Pos, Span};
|
||||
use tracing::debug;
|
||||
|
||||
use crate::lexer::diagnostics::TokenTreeDiagInfo;
|
||||
use crate::lexer::unicode_chars::UNICODE_ARRAY;
|
||||
use crate::{errors, make_unclosed_delims_error};
|
||||
|
||||
|
@ -56,7 +57,7 @@ pub(crate) fn lex_token_trees<'psess, 'src>(
|
|||
}
|
||||
|
||||
let cursor = Cursor::new(src);
|
||||
let string_reader = StringReader {
|
||||
let mut lexer = Lexer {
|
||||
psess,
|
||||
start_pos,
|
||||
pos: start_pos,
|
||||
|
@ -65,34 +66,31 @@ pub(crate) fn lex_token_trees<'psess, 'src>(
|
|||
override_span,
|
||||
nbsp_is_whitespace: false,
|
||||
last_lifetime: None,
|
||||
token: Token::dummy(),
|
||||
diag_info: TokenTreeDiagInfo::default(),
|
||||
};
|
||||
let (stream, res, unmatched_delims) =
|
||||
tokentrees::TokenTreesReader::lex_all_token_trees(string_reader);
|
||||
match res {
|
||||
Ok(()) if unmatched_delims.is_empty() => Ok(stream),
|
||||
_ => {
|
||||
// Return error if there are unmatched delimiters or unclosed delimiters.
|
||||
// We emit delimiter mismatch errors first, then emit the unclosing delimiter mismatch
|
||||
// because the delimiter mismatch is more likely to be the root cause of error
|
||||
let (_open_spacing, stream, res) = lexer.lex_token_trees(/* is_delimited */ false);
|
||||
let unmatched_delims = lexer.diag_info.unmatched_delims;
|
||||
|
||||
let mut buffer = Vec::with_capacity(1);
|
||||
for unmatched in unmatched_delims {
|
||||
if let Some(err) = make_unclosed_delims_error(unmatched, psess) {
|
||||
buffer.push(err);
|
||||
}
|
||||
}
|
||||
if let Err(errs) = res {
|
||||
// Add unclosing delimiter or diff marker errors
|
||||
for err in errs {
|
||||
buffer.push(err);
|
||||
}
|
||||
}
|
||||
Err(buffer)
|
||||
if res.is_ok() && unmatched_delims.is_empty() {
|
||||
Ok(stream)
|
||||
} else {
|
||||
// Return error if there are unmatched delimiters or unclosed delimiters.
|
||||
// We emit delimiter mismatch errors first, then emit the unclosing delimiter mismatch
|
||||
// because the delimiter mismatch is more likely to be the root cause of error
|
||||
let mut buffer: Vec<_> = unmatched_delims
|
||||
.into_iter()
|
||||
.filter_map(|unmatched_delim| make_unclosed_delims_error(unmatched_delim, psess))
|
||||
.collect();
|
||||
if let Err(errs) = res {
|
||||
// Add unclosing delimiter or diff marker errors
|
||||
buffer.extend(errs);
|
||||
}
|
||||
Err(buffer)
|
||||
}
|
||||
}
|
||||
|
||||
struct StringReader<'psess, 'src> {
|
||||
struct Lexer<'psess, 'src> {
|
||||
psess: &'psess ParseSess,
|
||||
/// Initial position, read-only.
|
||||
start_pos: BytePos,
|
||||
|
@ -111,9 +109,14 @@ struct StringReader<'psess, 'src> {
|
|||
/// Track the `Span` for the leading `'` of the last lifetime. Used for
|
||||
/// diagnostics to detect possible typo where `"` was meant.
|
||||
last_lifetime: Option<Span>,
|
||||
|
||||
/// The current token.
|
||||
token: Token,
|
||||
|
||||
diag_info: TokenTreeDiagInfo,
|
||||
}
|
||||
|
||||
impl<'psess, 'src> StringReader<'psess, 'src> {
|
||||
impl<'psess, 'src> Lexer<'psess, 'src> {
|
||||
fn dcx(&self) -> DiagCtxtHandle<'psess> {
|
||||
self.psess.dcx()
|
||||
}
|
||||
|
@ -124,7 +127,7 @@ impl<'psess, 'src> StringReader<'psess, 'src> {
|
|||
|
||||
/// Returns the next token, paired with a bool indicating if the token was
|
||||
/// preceded by whitespace.
|
||||
fn next_token(&mut self) -> (Token, bool) {
|
||||
fn next_token_from_cursor(&mut self) -> (Token, bool) {
|
||||
let mut preceded_by_whitespace = false;
|
||||
let mut swallow_next_invalid = 0;
|
||||
// Skip trivial (whitespace & comments) tokens
|
||||
|
@ -231,7 +234,8 @@ impl<'psess, 'src> StringReader<'psess, 'src> {
|
|||
.push(span);
|
||||
token::Ident(sym, IdentIsRaw::No)
|
||||
}
|
||||
// split up (raw) c string literals to an ident and a string literal when edition < 2021.
|
||||
// split up (raw) c string literals to an ident and a string literal when edition <
|
||||
// 2021.
|
||||
rustc_lexer::TokenKind::Literal {
|
||||
kind: kind @ (LiteralKind::CStr { .. } | LiteralKind::RawCStr { .. }),
|
||||
suffix_start: _,
|
||||
|
@ -252,7 +256,9 @@ impl<'psess, 'src> StringReader<'psess, 'src> {
|
|||
let prefix_span = self.mk_sp(start, lit_start);
|
||||
return (Token::new(self.ident(start), prefix_span), preceded_by_whitespace);
|
||||
}
|
||||
rustc_lexer::TokenKind::GuardedStrPrefix => self.maybe_report_guarded_str(start, str_before),
|
||||
rustc_lexer::TokenKind::GuardedStrPrefix => {
|
||||
self.maybe_report_guarded_str(start, str_before)
|
||||
}
|
||||
rustc_lexer::TokenKind::Literal { kind, suffix_start } => {
|
||||
let suffix_start = start + BytePos(suffix_start);
|
||||
let (kind, symbol) = self.cook_lexer_literal(start, suffix_start, kind);
|
||||
|
@ -296,13 +302,20 @@ impl<'psess, 'src> StringReader<'psess, 'src> {
|
|||
if prefix_span.at_least_rust_2021() {
|
||||
let span = self.mk_sp(start, self.pos);
|
||||
|
||||
let lifetime_name_without_tick = Symbol::intern(&self.str_from(ident_start));
|
||||
let lifetime_name_without_tick =
|
||||
Symbol::intern(&self.str_from(ident_start));
|
||||
if !lifetime_name_without_tick.can_be_raw() {
|
||||
self.dcx().emit_err(errors::CannotBeRawLifetime { span, ident: lifetime_name_without_tick });
|
||||
self.dcx().emit_err(
|
||||
errors::CannotBeRawLifetime {
|
||||
span,
|
||||
ident: lifetime_name_without_tick
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
// Put the `'` back onto the lifetime name.
|
||||
let mut lifetime_name = String::with_capacity(lifetime_name_without_tick.as_str().len() + 1);
|
||||
let mut lifetime_name =
|
||||
String::with_capacity(lifetime_name_without_tick.as_str().len() + 1);
|
||||
lifetime_name.push('\'');
|
||||
lifetime_name += lifetime_name_without_tick.as_str();
|
||||
let sym = Symbol::intern(&lifetime_name);
|
||||
|
|
|
@ -4,41 +4,19 @@ use rustc_ast_pretty::pprust::token_to_string;
|
|||
use rustc_errors::{Applicability, PErr};
|
||||
use rustc_span::symbol::kw;
|
||||
|
||||
use super::diagnostics::{
|
||||
TokenTreeDiagInfo, report_suspicious_mismatch_block, same_indentation_level,
|
||||
};
|
||||
use super::{StringReader, UnmatchedDelim};
|
||||
use super::diagnostics::{report_suspicious_mismatch_block, same_indentation_level};
|
||||
use super::{Lexer, UnmatchedDelim};
|
||||
use crate::Parser;
|
||||
|
||||
pub(super) struct TokenTreesReader<'psess, 'src> {
|
||||
string_reader: StringReader<'psess, 'src>,
|
||||
/// The "next" token, which has been obtained from the `StringReader` but
|
||||
/// not yet handled by the `TokenTreesReader`.
|
||||
token: Token,
|
||||
diag_info: TokenTreeDiagInfo,
|
||||
}
|
||||
|
||||
impl<'psess, 'src> TokenTreesReader<'psess, 'src> {
|
||||
pub(super) fn lex_all_token_trees(
|
||||
string_reader: StringReader<'psess, 'src>,
|
||||
) -> (TokenStream, Result<(), Vec<PErr<'psess>>>, Vec<UnmatchedDelim>) {
|
||||
let mut tt_reader = TokenTreesReader {
|
||||
string_reader,
|
||||
token: Token::dummy(),
|
||||
diag_info: TokenTreeDiagInfo::default(),
|
||||
};
|
||||
let (_open_spacing, stream, res) = tt_reader.lex_token_trees(/* is_delimited */ false);
|
||||
(stream, res, tt_reader.diag_info.unmatched_delims)
|
||||
}
|
||||
|
||||
impl<'psess, 'src> Lexer<'psess, 'src> {
|
||||
// Lex into a token stream. The `Spacing` in the result is that of the
|
||||
// opening delimiter.
|
||||
fn lex_token_trees(
|
||||
pub(super) fn lex_token_trees(
|
||||
&mut self,
|
||||
is_delimited: bool,
|
||||
) -> (Spacing, TokenStream, Result<(), Vec<PErr<'psess>>>) {
|
||||
// Move past the opening delimiter.
|
||||
let (_, open_spacing) = self.bump(false);
|
||||
let open_spacing = self.bump_minimal();
|
||||
|
||||
let mut buf = Vec::new();
|
||||
loop {
|
||||
|
@ -71,7 +49,7 @@ impl<'psess, 'src> TokenTreesReader<'psess, 'src> {
|
|||
}
|
||||
_ => {
|
||||
// Get the next normal token.
|
||||
let (this_tok, this_spacing) = self.bump(true);
|
||||
let (this_tok, this_spacing) = self.bump();
|
||||
buf.push(TokenTree::Token(this_tok, this_spacing));
|
||||
}
|
||||
}
|
||||
|
@ -80,7 +58,7 @@ impl<'psess, 'src> TokenTreesReader<'psess, 'src> {
|
|||
|
||||
fn eof_err(&mut self) -> PErr<'psess> {
|
||||
let msg = "this file contains an unclosed delimiter";
|
||||
let mut err = self.string_reader.dcx().struct_span_err(self.token.span, msg);
|
||||
let mut err = self.dcx().struct_span_err(self.token.span, msg);
|
||||
|
||||
let unclosed_delimiter_show_limit = 5;
|
||||
let len = usize::min(unclosed_delimiter_show_limit, self.diag_info.open_braces.len());
|
||||
|
@ -110,7 +88,7 @@ impl<'psess, 'src> TokenTreesReader<'psess, 'src> {
|
|||
report_suspicious_mismatch_block(
|
||||
&mut err,
|
||||
&self.diag_info,
|
||||
self.string_reader.psess.source_map(),
|
||||
self.psess.source_map(),
|
||||
*delim,
|
||||
)
|
||||
}
|
||||
|
@ -136,7 +114,7 @@ impl<'psess, 'src> TokenTreesReader<'psess, 'src> {
|
|||
|
||||
// Expand to cover the entire delimited token tree.
|
||||
let delim_span = DelimSpan::from_pair(pre_span, self.token.span);
|
||||
let sm = self.string_reader.psess.source_map();
|
||||
let sm = self.psess.source_map();
|
||||
|
||||
let close_spacing = match self.token.kind {
|
||||
// Correct delimiter.
|
||||
|
@ -160,7 +138,7 @@ impl<'psess, 'src> TokenTreesReader<'psess, 'src> {
|
|||
}
|
||||
|
||||
// Move past the closing delimiter.
|
||||
self.bump(false).1
|
||||
self.bump_minimal()
|
||||
}
|
||||
// Incorrect delimiter.
|
||||
token::CloseDelim(close_delim) => {
|
||||
|
@ -203,7 +181,7 @@ impl<'psess, 'src> TokenTreesReader<'psess, 'src> {
|
|||
// bar(baz(
|
||||
// } // Incorrect delimiter but matches the earlier `{`
|
||||
if !self.diag_info.open_braces.iter().any(|&(b, _)| b == close_delim) {
|
||||
self.bump(false).1
|
||||
self.bump_minimal()
|
||||
} else {
|
||||
// The choice of value here doesn't matter.
|
||||
Spacing::Alone
|
||||
|
@ -225,14 +203,14 @@ impl<'psess, 'src> TokenTreesReader<'psess, 'src> {
|
|||
}
|
||||
|
||||
// Move on to the next token, returning the current token and its spacing.
|
||||
// Will glue adjacent single-char tokens together if `glue` is set.
|
||||
fn bump(&mut self, glue: bool) -> (Token, Spacing) {
|
||||
// Will glue adjacent single-char tokens together.
|
||||
fn bump(&mut self) -> (Token, Spacing) {
|
||||
let (this_spacing, next_tok) = loop {
|
||||
let (next_tok, is_next_tok_preceded_by_whitespace) = self.string_reader.next_token();
|
||||
let (next_tok, is_next_tok_preceded_by_whitespace) = self.next_token_from_cursor();
|
||||
|
||||
if is_next_tok_preceded_by_whitespace {
|
||||
break (Spacing::Alone, next_tok);
|
||||
} else if glue && let Some(glued) = self.token.glue(&next_tok) {
|
||||
} else if let Some(glued) = self.token.glue(&next_tok) {
|
||||
self.token = glued;
|
||||
} else {
|
||||
let this_spacing = if next_tok.is_punct() {
|
||||
|
@ -249,6 +227,26 @@ impl<'psess, 'src> TokenTreesReader<'psess, 'src> {
|
|||
(this_tok, this_spacing)
|
||||
}
|
||||
|
||||
// Cut-down version of `bump` used when the token kind is known in advance.
|
||||
fn bump_minimal(&mut self) -> Spacing {
|
||||
let (next_tok, is_next_tok_preceded_by_whitespace) = self.next_token_from_cursor();
|
||||
|
||||
let this_spacing = if is_next_tok_preceded_by_whitespace {
|
||||
Spacing::Alone
|
||||
} else {
|
||||
if next_tok.is_punct() {
|
||||
Spacing::Joint
|
||||
} else if next_tok == token::Eof {
|
||||
Spacing::Alone
|
||||
} else {
|
||||
Spacing::JointHidden
|
||||
}
|
||||
};
|
||||
|
||||
self.token = next_tok;
|
||||
this_spacing
|
||||
}
|
||||
|
||||
fn unclosed_delim_err(
|
||||
&mut self,
|
||||
tts: TokenStream,
|
||||
|
@ -256,7 +254,7 @@ impl<'psess, 'src> TokenTreesReader<'psess, 'src> {
|
|||
) -> Vec<PErr<'psess>> {
|
||||
// If there are unclosed delims, see if there are diff markers and if so, point them
|
||||
// out instead of complaining about the unclosed delims.
|
||||
let mut parser = Parser::new(self.string_reader.psess, tts, None);
|
||||
let mut parser = Parser::new(self.psess, tts, None);
|
||||
let mut diff_errs = vec![];
|
||||
// Suggest removing a `{` we think appears in an `if`/`while` condition.
|
||||
// We want to suggest removing a `{` only if we think we're in an `if`/`while` condition,
|
||||
|
@ -314,14 +312,9 @@ impl<'psess, 'src> TokenTreesReader<'psess, 'src> {
|
|||
// An unexpected closing delimiter (i.e., there is no matching opening delimiter).
|
||||
let token_str = token_to_string(&self.token);
|
||||
let msg = format!("unexpected closing delimiter: `{token_str}`");
|
||||
let mut err = self.string_reader.dcx().struct_span_err(self.token.span, msg);
|
||||
let mut err = self.dcx().struct_span_err(self.token.span, msg);
|
||||
|
||||
report_suspicious_mismatch_block(
|
||||
&mut err,
|
||||
&self.diag_info,
|
||||
self.string_reader.psess.source_map(),
|
||||
delim,
|
||||
);
|
||||
report_suspicious_mismatch_block(&mut err, &self.diag_info, self.psess.source_map(), delim);
|
||||
err.span_label(self.token.span, "unexpected closing delimiter");
|
||||
err
|
||||
}
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
use rustc_span::symbol::kw;
|
||||
use rustc_span::{BytePos, Pos, Span};
|
||||
|
||||
use super::StringReader;
|
||||
use super::Lexer;
|
||||
use crate::errors::TokenSubstitution;
|
||||
use crate::token::{self, Delimiter};
|
||||
|
||||
|
@ -338,7 +338,7 @@ const ASCII_ARRAY: &[(&str, &str, Option<token::TokenKind>)] = &[
|
|||
];
|
||||
|
||||
pub(super) fn check_for_substitution(
|
||||
reader: &StringReader<'_, '_>,
|
||||
lexer: &Lexer<'_, '_>,
|
||||
pos: BytePos,
|
||||
ch: char,
|
||||
count: usize,
|
||||
|
@ -351,11 +351,11 @@ pub(super) fn check_for_substitution(
|
|||
|
||||
let Some((_, ascii_name, token)) = ASCII_ARRAY.iter().find(|&&(s, _, _)| s == ascii_str) else {
|
||||
let msg = format!("substitution character not found for '{ch}'");
|
||||
reader.dcx().span_bug(span, msg);
|
||||
lexer.dcx().span_bug(span, msg);
|
||||
};
|
||||
|
||||
// special help suggestion for "directed" double quotes
|
||||
let sugg = if let Some(s) = peek_delimited(&reader.src[reader.src_index(pos)..], '“', '”') {
|
||||
let sugg = if let Some(s) = peek_delimited(&lexer.src[lexer.src_index(pos)..], '“', '”') {
|
||||
let span = Span::with_root_ctxt(
|
||||
pos,
|
||||
pos + Pos::from_usize('“'.len_utf8() + s.len() + '”'.len_utf8()),
|
||||
|
|
|
@ -1,11 +1,12 @@
|
|||
use rustc_ast::mut_visit::{self, MutVisitor};
|
||||
use rustc_ast::ptr::P;
|
||||
use rustc_ast::token::{self, BinOpToken, Delimiter, IdentIsRaw, Token};
|
||||
use rustc_ast::util::parser::AssocOp;
|
||||
use rustc_ast::visit::{self, Visitor};
|
||||
use rustc_ast::{
|
||||
self as ast, Arm, AttrVec, BinOpKind, BindingMode, ByRef, Expr, ExprKind, ExprPrecedence,
|
||||
LocalKind, MacCall, Mutability, Pat, PatField, PatFieldsRest, PatKind, Path, QSelf, RangeEnd,
|
||||
RangeSyntax, Stmt, StmtKind,
|
||||
self as ast, Arm, AttrVec, BinOpKind, BindingMode, ByRef, Expr, ExprKind, LocalKind, MacCall,
|
||||
Mutability, Pat, PatField, PatFieldsRest, PatKind, Path, QSelf, RangeEnd, RangeSyntax, Stmt,
|
||||
StmtKind,
|
||||
};
|
||||
use rustc_ast_pretty::pprust;
|
||||
use rustc_errors::{Applicability, Diag, DiagArgValue, PResult, StashKey};
|
||||
|
@ -458,7 +459,7 @@ impl<'a> Parser<'a> {
|
|||
.create_err(UnexpectedExpressionInPattern {
|
||||
span,
|
||||
is_bound,
|
||||
expr_precedence: expr.precedence().order(),
|
||||
expr_precedence: expr.precedence(),
|
||||
})
|
||||
.stash(span, StashKey::ExprInPat)
|
||||
.unwrap(),
|
||||
|
@ -545,7 +546,8 @@ impl<'a> Parser<'a> {
|
|||
let expr = match &err.args["expr_precedence"] {
|
||||
DiagArgValue::Number(expr_precedence) => {
|
||||
if *expr_precedence
|
||||
<= ExprPrecedence::Binary(BinOpKind::Eq).order() as i32
|
||||
<= AssocOp::from_ast_binop(BinOpKind::Eq).precedence()
|
||||
as i32
|
||||
{
|
||||
format!("({expr})")
|
||||
} else {
|
||||
|
@ -568,8 +570,9 @@ impl<'a> Parser<'a> {
|
|||
}
|
||||
Some(guard) => {
|
||||
// Are parentheses required around the old guard?
|
||||
let wrap_guard = guard.precedence().order()
|
||||
<= ExprPrecedence::Binary(BinOpKind::And).order();
|
||||
let wrap_guard = guard.precedence()
|
||||
<= AssocOp::from_ast_binop(BinOpKind::And).precedence()
|
||||
as i8;
|
||||
|
||||
err.subdiagnostic(
|
||||
UnexpectedExpressionInPatternSugg::UpdateGuard {
|
||||
|
|
|
@ -1728,7 +1728,6 @@ symbols! {
|
|||
rustc_partition_reused,
|
||||
rustc_pass_by_value,
|
||||
rustc_peek,
|
||||
rustc_peek_definite_init,
|
||||
rustc_peek_liveness,
|
||||
rustc_peek_maybe_init,
|
||||
rustc_peek_maybe_uninit,
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
use std::assert_matches::assert_matches;
|
||||
|
||||
use rustc_data_structures::fx::FxHashSet;
|
||||
|
||||
use super::super::*;
|
||||
|
||||
// Test target self-consistency and JSON encoding/decoding roundtrip.
|
||||
|
@ -173,6 +175,27 @@ impl Target {
|
|||
}
|
||||
_ => {}
|
||||
}
|
||||
|
||||
// Check that the given target-features string makes some basic sense.
|
||||
if !self.features.is_empty() {
|
||||
let mut features_enabled = FxHashSet::default();
|
||||
let mut features_disabled = FxHashSet::default();
|
||||
for feat in self.features.split(',') {
|
||||
if let Some(feat) = feat.strip_prefix("+") {
|
||||
features_enabled.insert(feat);
|
||||
if features_disabled.contains(feat) {
|
||||
panic!("target feature `{feat}` is both enabled and disabled");
|
||||
}
|
||||
} else if let Some(feat) = feat.strip_prefix("-") {
|
||||
features_disabled.insert(feat);
|
||||
if features_enabled.contains(feat) {
|
||||
panic!("target feature `{feat}` is both enabled and disabled");
|
||||
}
|
||||
} else {
|
||||
panic!("target feature `{feat}` is invalid, must start with `+` or `-`");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Add your target to the whitelist if it has `std` library
|
||||
|
|
|
@ -1792,12 +1792,12 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
|
|||
|
||||
fn suggest_specify_actual_length(
|
||||
&self,
|
||||
terr: TypeError<'_>,
|
||||
trace: &TypeTrace<'_>,
|
||||
terr: TypeError<'tcx>,
|
||||
trace: &TypeTrace<'tcx>,
|
||||
span: Span,
|
||||
) -> Option<TypeErrorAdditionalDiags> {
|
||||
let hir = self.tcx.hir();
|
||||
let TypeError::FixedArraySize(sz) = terr else {
|
||||
let TypeError::ArraySize(sz) = terr else {
|
||||
return None;
|
||||
};
|
||||
let tykind = match self.tcx.hir_node_by_def_id(trace.cause.body_id) {
|
||||
|
@ -1838,9 +1838,14 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
|
|||
if let Some(tykind) = tykind
|
||||
&& let hir::TyKind::Array(_, length) = tykind
|
||||
&& let hir::ArrayLen::Body(ct) = length
|
||||
&& let Some((scalar, ty)) = sz.found.try_to_scalar()
|
||||
&& ty == self.tcx.types.usize
|
||||
{
|
||||
let span = ct.span();
|
||||
Some(TypeErrorAdditionalDiags::ConsiderSpecifyingLength { span, length: sz.found })
|
||||
Some(TypeErrorAdditionalDiags::ConsiderSpecifyingLength {
|
||||
span,
|
||||
length: scalar.to_target_usize(&self.tcx).unwrap(),
|
||||
})
|
||||
} else {
|
||||
None
|
||||
}
|
||||
|
|
|
@ -29,7 +29,7 @@ pub enum TypeError<I: Interner> {
|
|||
Mutability,
|
||||
ArgumentMutability(usize),
|
||||
TupleSize(ExpectedFound<usize>),
|
||||
FixedArraySize(ExpectedFound<u64>),
|
||||
ArraySize(ExpectedFound<I::Const>),
|
||||
ArgCount,
|
||||
|
||||
RegionsDoesNotOutlive(I::Region, I::Region),
|
||||
|
@ -69,7 +69,7 @@ impl<I: Interner> TypeError<I> {
|
|||
use self::TypeError::*;
|
||||
match self {
|
||||
CyclicTy(_) | CyclicConst(_) | SafetyMismatch(_) | PolarityMismatch(_) | Mismatch
|
||||
| AbiMismatch(_) | FixedArraySize(_) | ArgumentSorts(..) | Sorts(_)
|
||||
| AbiMismatch(_) | ArraySize(_) | ArgumentSorts(..) | Sorts(_)
|
||||
| VariadicMismatch(_) | TargetFeatureCast(_) => false,
|
||||
|
||||
Mutability
|
||||
|
|
|
@ -257,8 +257,6 @@ pub trait Const<I: Interner<Const = Self>>:
|
|||
+ Relate<I>
|
||||
+ Flags
|
||||
{
|
||||
fn try_to_target_usize(self, interner: I) -> Option<u64>;
|
||||
|
||||
fn new_infer(interner: I, var: ty::InferConst) -> Self;
|
||||
|
||||
fn new_var(interner: I, var: ty::ConstVid) -> Self;
|
||||
|
|
|
@ -501,19 +501,10 @@ pub fn structurally_relate_tys<I: Interner, R: TypeRelation<I>>(
|
|||
let t = relation.relate(a_t, b_t)?;
|
||||
match relation.relate(sz_a, sz_b) {
|
||||
Ok(sz) => Ok(Ty::new_array_with_const_len(cx, t, sz)),
|
||||
Err(err) => {
|
||||
// Check whether the lengths are both concrete/known values,
|
||||
// but are unequal, for better diagnostics.
|
||||
let sz_a = sz_a.try_to_target_usize(cx);
|
||||
let sz_b = sz_b.try_to_target_usize(cx);
|
||||
|
||||
match (sz_a, sz_b) {
|
||||
(Some(sz_a_val), Some(sz_b_val)) if sz_a_val != sz_b_val => {
|
||||
Err(TypeError::FixedArraySize(ExpectedFound::new(sz_a_val, sz_b_val)))
|
||||
}
|
||||
_ => Err(err),
|
||||
}
|
||||
Err(TypeError::ConstMismatch(_)) => {
|
||||
Err(TypeError::ArraySize(ExpectedFound::new(sz_a, sz_b)))
|
||||
}
|
||||
Err(e) => Err(e),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -269,6 +269,31 @@ impl<'a, K: Ord, V, A: Allocator + Clone> Entry<'a, K, V, A> {
|
|||
Vacant(entry) => Vacant(entry),
|
||||
}
|
||||
}
|
||||
|
||||
/// Sets the value of the entry, and returns an `OccupiedEntry`.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// #![feature(btree_entry_insert)]
|
||||
/// use std::collections::BTreeMap;
|
||||
///
|
||||
/// let mut map: BTreeMap<&str, String> = BTreeMap::new();
|
||||
/// let entry = map.entry("poneyland").insert_entry("hoho".to_string());
|
||||
///
|
||||
/// assert_eq!(entry.key(), &"poneyland");
|
||||
/// ```
|
||||
#[inline]
|
||||
#[unstable(feature = "btree_entry_insert", issue = "65225")]
|
||||
pub fn insert_entry(self, value: V) -> OccupiedEntry<'a, K, V, A> {
|
||||
match self {
|
||||
Occupied(mut entry) => {
|
||||
entry.insert(value);
|
||||
entry
|
||||
}
|
||||
Vacant(entry) => entry.insert_entry(value),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, K: Ord, V: Default, A: Allocator + Clone> Entry<'a, K, V, A> {
|
||||
|
@ -348,41 +373,61 @@ impl<'a, K: Ord, V, A: Allocator + Clone> VacantEntry<'a, K, V, A> {
|
|||
/// ```
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
#[rustc_confusables("push", "put")]
|
||||
pub fn insert(mut self, value: V) -> &'a mut V {
|
||||
let out_ptr = match self.handle {
|
||||
pub fn insert(self, value: V) -> &'a mut V {
|
||||
self.insert_entry(value).into_mut()
|
||||
}
|
||||
|
||||
/// Sets the value of the entry with the `VacantEntry`'s key,
|
||||
/// and returns an `OccupiedEntry`.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// #![feature(btree_entry_insert)]
|
||||
/// use std::collections::BTreeMap;
|
||||
/// use std::collections::btree_map::Entry;
|
||||
///
|
||||
/// let mut map: BTreeMap<&str, u32> = BTreeMap::new();
|
||||
///
|
||||
/// if let Entry::Vacant(o) = map.entry("poneyland") {
|
||||
/// let entry = o.insert_entry(37);
|
||||
/// assert_eq!(entry.get(), &37);
|
||||
/// }
|
||||
/// assert_eq!(map["poneyland"], 37);
|
||||
/// ```
|
||||
#[unstable(feature = "btree_entry_insert", issue = "65225")]
|
||||
pub fn insert_entry(mut self, value: V) -> OccupiedEntry<'a, K, V, A> {
|
||||
let handle = match self.handle {
|
||||
None => {
|
||||
// SAFETY: There is no tree yet so no reference to it exists.
|
||||
let map = unsafe { self.dormant_map.awaken() };
|
||||
let mut root = NodeRef::new_leaf(self.alloc.clone());
|
||||
let val_ptr = root.borrow_mut().push(self.key, value);
|
||||
map.root = Some(root.forget_type());
|
||||
map.length = 1;
|
||||
val_ptr
|
||||
}
|
||||
Some(handle) => {
|
||||
let new_handle =
|
||||
handle.insert_recursing(self.key, value, self.alloc.clone(), |ins| {
|
||||
drop(ins.left);
|
||||
// SAFETY: Pushing a new root node doesn't invalidate
|
||||
// handles to existing nodes.
|
||||
let map = unsafe { self.dormant_map.reborrow() };
|
||||
let root = map.root.as_mut().unwrap(); // same as ins.left
|
||||
root.push_internal_level(self.alloc).push(ins.kv.0, ins.kv.1, ins.right)
|
||||
});
|
||||
|
||||
// Get the pointer to the value
|
||||
let val_ptr = new_handle.into_val_mut();
|
||||
|
||||
// SAFETY: We have consumed self.handle.
|
||||
let map = unsafe { self.dormant_map.awaken() };
|
||||
map.length += 1;
|
||||
val_ptr
|
||||
let map = unsafe { self.dormant_map.reborrow() };
|
||||
let root = map.root.insert(NodeRef::new_leaf(self.alloc.clone()).forget_type());
|
||||
// SAFETY: We *just* created the root as a leaf, and we're
|
||||
// stacking the new handle on the original borrow lifetime.
|
||||
unsafe {
|
||||
let mut leaf = root.borrow_mut().cast_to_leaf_unchecked();
|
||||
leaf.push_with_handle(self.key, value)
|
||||
}
|
||||
}
|
||||
Some(handle) => handle.insert_recursing(self.key, value, self.alloc.clone(), |ins| {
|
||||
drop(ins.left);
|
||||
// SAFETY: Pushing a new root node doesn't invalidate
|
||||
// handles to existing nodes.
|
||||
let map = unsafe { self.dormant_map.reborrow() };
|
||||
let root = map.root.as_mut().unwrap(); // same as ins.left
|
||||
root.push_internal_level(self.alloc.clone()).push(ins.kv.0, ins.kv.1, ins.right)
|
||||
}),
|
||||
};
|
||||
|
||||
// Now that we have finished growing the tree using borrowed references,
|
||||
// dereference the pointer to a part of it, that we picked up along the way.
|
||||
unsafe { &mut *out_ptr }
|
||||
// SAFETY: modifying the length doesn't invalidate handles to existing nodes.
|
||||
unsafe { self.dormant_map.reborrow().length += 1 };
|
||||
|
||||
OccupiedEntry {
|
||||
handle: handle.forget_node_type(),
|
||||
dormant_map: self.dormant_map,
|
||||
alloc: self.alloc,
|
||||
_marker: PhantomData,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -739,7 +739,7 @@ impl<BorrowType, K, V> NodeRef<BorrowType, K, V, marker::LeafOrInternal> {
|
|||
|
||||
impl<'a, K, V> NodeRef<marker::Mut<'a>, K, V, marker::LeafOrInternal> {
|
||||
/// Unsafely asserts to the compiler the static information that this node is a `Leaf`.
|
||||
unsafe fn cast_to_leaf_unchecked(self) -> NodeRef<marker::Mut<'a>, K, V, marker::Leaf> {
|
||||
pub unsafe fn cast_to_leaf_unchecked(self) -> NodeRef<marker::Mut<'a>, K, V, marker::Leaf> {
|
||||
debug_assert!(self.height == 0);
|
||||
NodeRef { height: self.height, node: self.node, _marker: PhantomData }
|
||||
}
|
||||
|
|
|
@ -255,7 +255,11 @@ impl<T: Copy> Clone for MaybeUninit<T> {
|
|||
#[stable(feature = "maybe_uninit_debug", since = "1.41.0")]
|
||||
impl<T> fmt::Debug for MaybeUninit<T> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
f.pad(type_name::<Self>())
|
||||
// NB: there is no `.pad_fmt` so we can't use a simpler `format_args!("MaybeUninit<{..}>").
|
||||
// This needs to be adjusted if `MaybeUninit` moves modules.
|
||||
let full_name = type_name::<Self>();
|
||||
let short_name = full_name.split_once("mem::maybe_uninit::").unwrap().1;
|
||||
f.pad(short_name)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -10,10 +10,10 @@ use crate::cmp::Ordering::{self, Equal, Greater, Less};
|
|||
use crate::intrinsics::{exact_div, select_unpredictable, unchecked_sub};
|
||||
use crate::mem::{self, SizedTypeProperties};
|
||||
use crate::num::NonZero;
|
||||
use crate::ops::{Bound, OneSidedRange, Range, RangeBounds};
|
||||
use crate::ops::{Bound, OneSidedRange, Range, RangeBounds, RangeInclusive};
|
||||
use crate::simd::{self, Simd};
|
||||
use crate::ub_checks::assert_unsafe_precondition;
|
||||
use crate::{fmt, hint, ptr, slice};
|
||||
use crate::{fmt, hint, ptr, range, slice};
|
||||
|
||||
#[unstable(
|
||||
feature = "slice_internals",
|
||||
|
@ -4469,6 +4469,12 @@ impl<T> [T] {
|
|||
|
||||
/// Returns mutable references to many indices at once, without doing any checks.
|
||||
///
|
||||
/// An index can be either a `usize`, a [`Range`] or a [`RangeInclusive`]. Note
|
||||
/// that this method takes an array, so all indices must be of the same type.
|
||||
/// If passed an array of `usize`s this method gives back an array of mutable references
|
||||
/// to single elements, while if passed an array of ranges it gives back an array of
|
||||
/// mutable references to slices.
|
||||
///
|
||||
/// For a safe alternative see [`get_many_mut`].
|
||||
///
|
||||
/// # Safety
|
||||
|
@ -4489,30 +4495,49 @@ impl<T> [T] {
|
|||
/// *b *= 100;
|
||||
/// }
|
||||
/// assert_eq!(x, &[10, 2, 400]);
|
||||
///
|
||||
/// unsafe {
|
||||
/// let [a, b] = x.get_many_unchecked_mut([0..1, 1..3]);
|
||||
/// a[0] = 8;
|
||||
/// b[0] = 88;
|
||||
/// b[1] = 888;
|
||||
/// }
|
||||
/// assert_eq!(x, &[8, 88, 888]);
|
||||
///
|
||||
/// unsafe {
|
||||
/// let [a, b] = x.get_many_unchecked_mut([1..=2, 0..=0]);
|
||||
/// a[0] = 11;
|
||||
/// a[1] = 111;
|
||||
/// b[0] = 1;
|
||||
/// }
|
||||
/// assert_eq!(x, &[1, 11, 111]);
|
||||
/// ```
|
||||
///
|
||||
/// [`get_many_mut`]: slice::get_many_mut
|
||||
/// [undefined behavior]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html
|
||||
#[unstable(feature = "get_many_mut", issue = "104642")]
|
||||
#[inline]
|
||||
pub unsafe fn get_many_unchecked_mut<const N: usize>(
|
||||
pub unsafe fn get_many_unchecked_mut<I, const N: usize>(
|
||||
&mut self,
|
||||
indices: [usize; N],
|
||||
) -> [&mut T; N] {
|
||||
indices: [I; N],
|
||||
) -> [&mut I::Output; N]
|
||||
where
|
||||
I: GetManyMutIndex + SliceIndex<Self>,
|
||||
{
|
||||
// NB: This implementation is written as it is because any variation of
|
||||
// `indices.map(|i| self.get_unchecked_mut(i))` would make miri unhappy,
|
||||
// or generate worse code otherwise. This is also why we need to go
|
||||
// through a raw pointer here.
|
||||
let slice: *mut [T] = self;
|
||||
let mut arr: mem::MaybeUninit<[&mut T; N]> = mem::MaybeUninit::uninit();
|
||||
let mut arr: mem::MaybeUninit<[&mut I::Output; N]> = mem::MaybeUninit::uninit();
|
||||
let arr_ptr = arr.as_mut_ptr();
|
||||
|
||||
// SAFETY: We expect `indices` to contain disjunct values that are
|
||||
// in bounds of `self`.
|
||||
unsafe {
|
||||
for i in 0..N {
|
||||
let idx = *indices.get_unchecked(i);
|
||||
*(*arr_ptr).get_unchecked_mut(i) = &mut *slice.get_unchecked_mut(idx);
|
||||
let idx = indices.get_unchecked(i).clone();
|
||||
arr_ptr.cast::<&mut I::Output>().add(i).write(&mut *slice.get_unchecked_mut(idx));
|
||||
}
|
||||
arr.assume_init()
|
||||
}
|
||||
|
@ -4520,8 +4545,18 @@ impl<T> [T] {
|
|||
|
||||
/// Returns mutable references to many indices at once.
|
||||
///
|
||||
/// Returns an error if any index is out-of-bounds, or if the same index was
|
||||
/// passed more than once.
|
||||
/// An index can be either a `usize`, a [`Range`] or a [`RangeInclusive`]. Note
|
||||
/// that this method takes an array, so all indices must be of the same type.
|
||||
/// If passed an array of `usize`s this method gives back an array of mutable references
|
||||
/// to single elements, while if passed an array of ranges it gives back an array of
|
||||
/// mutable references to slices.
|
||||
///
|
||||
/// Returns an error if any index is out-of-bounds, or if there are overlapping indices.
|
||||
/// An empty range is not considered to overlap if it is located at the beginning or at
|
||||
/// the end of another range, but is considered to overlap if it is located in the middle.
|
||||
///
|
||||
/// This method does a O(n^2) check to check that there are no overlapping indices, so be careful
|
||||
/// when passing many indices.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
|
@ -4534,13 +4569,30 @@ impl<T> [T] {
|
|||
/// *b = 612;
|
||||
/// }
|
||||
/// assert_eq!(v, &[413, 2, 612]);
|
||||
///
|
||||
/// if let Ok([a, b]) = v.get_many_mut([0..1, 1..3]) {
|
||||
/// a[0] = 8;
|
||||
/// b[0] = 88;
|
||||
/// b[1] = 888;
|
||||
/// }
|
||||
/// assert_eq!(v, &[8, 88, 888]);
|
||||
///
|
||||
/// if let Ok([a, b]) = v.get_many_mut([1..=2, 0..=0]) {
|
||||
/// a[0] = 11;
|
||||
/// a[1] = 111;
|
||||
/// b[0] = 1;
|
||||
/// }
|
||||
/// assert_eq!(v, &[1, 11, 111]);
|
||||
/// ```
|
||||
#[unstable(feature = "get_many_mut", issue = "104642")]
|
||||
#[inline]
|
||||
pub fn get_many_mut<const N: usize>(
|
||||
pub fn get_many_mut<I, const N: usize>(
|
||||
&mut self,
|
||||
indices: [usize; N],
|
||||
) -> Result<[&mut T; N], GetManyMutError<N>> {
|
||||
indices: [I; N],
|
||||
) -> Result<[&mut I::Output; N], GetManyMutError<N>>
|
||||
where
|
||||
I: GetManyMutIndex + SliceIndex<Self>,
|
||||
{
|
||||
if !get_many_check_valid(&indices, self.len()) {
|
||||
return Err(GetManyMutError { _private: () });
|
||||
}
|
||||
|
@ -4885,14 +4937,15 @@ impl<T, const N: usize> SlicePattern for [T; N] {
|
|||
///
|
||||
/// This will do `binomial(N + 1, 2) = N * (N + 1) / 2 = 0, 1, 3, 6, 10, ..`
|
||||
/// comparison operations.
|
||||
fn get_many_check_valid<const N: usize>(indices: &[usize; N], len: usize) -> bool {
|
||||
#[inline]
|
||||
fn get_many_check_valid<I: GetManyMutIndex, const N: usize>(indices: &[I; N], len: usize) -> bool {
|
||||
// NB: The optimizer should inline the loops into a sequence
|
||||
// of instructions without additional branching.
|
||||
let mut valid = true;
|
||||
for (i, &idx) in indices.iter().enumerate() {
|
||||
valid &= idx < len;
|
||||
for &idx2 in &indices[..i] {
|
||||
valid &= idx != idx2;
|
||||
for (i, idx) in indices.iter().enumerate() {
|
||||
valid &= idx.is_in_bounds(len);
|
||||
for idx2 in &indices[..i] {
|
||||
valid &= !idx.is_overlapping(idx2);
|
||||
}
|
||||
}
|
||||
valid
|
||||
|
@ -4916,6 +4969,7 @@ fn get_many_check_valid<const N: usize>(indices: &[usize; N], len: usize) -> boo
|
|||
#[unstable(feature = "get_many_mut", issue = "104642")]
|
||||
// NB: The N here is there to be forward-compatible with adding more details
|
||||
// to the error type at a later point
|
||||
#[derive(Clone, PartialEq, Eq)]
|
||||
pub struct GetManyMutError<const N: usize> {
|
||||
_private: (),
|
||||
}
|
||||
|
@ -4933,3 +4987,111 @@ impl<const N: usize> fmt::Display for GetManyMutError<N> {
|
|||
fmt::Display::fmt("an index is out of bounds or appeared multiple times in the array", f)
|
||||
}
|
||||
}
|
||||
|
||||
mod private_get_many_mut_index {
|
||||
use super::{Range, RangeInclusive, range};
|
||||
|
||||
#[unstable(feature = "get_many_mut_helpers", issue = "none")]
|
||||
pub trait Sealed {}
|
||||
|
||||
#[unstable(feature = "get_many_mut_helpers", issue = "none")]
|
||||
impl Sealed for usize {}
|
||||
#[unstable(feature = "get_many_mut_helpers", issue = "none")]
|
||||
impl Sealed for Range<usize> {}
|
||||
#[unstable(feature = "get_many_mut_helpers", issue = "none")]
|
||||
impl Sealed for RangeInclusive<usize> {}
|
||||
#[unstable(feature = "get_many_mut_helpers", issue = "none")]
|
||||
impl Sealed for range::Range<usize> {}
|
||||
#[unstable(feature = "get_many_mut_helpers", issue = "none")]
|
||||
impl Sealed for range::RangeInclusive<usize> {}
|
||||
}
|
||||
|
||||
/// A helper trait for `<[T]>::get_many_mut()`.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// If `is_in_bounds()` returns `true` and `is_overlapping()` returns `false`,
|
||||
/// it must be safe to index the slice with the indices.
|
||||
#[unstable(feature = "get_many_mut_helpers", issue = "none")]
|
||||
pub unsafe trait GetManyMutIndex: Clone + private_get_many_mut_index::Sealed {
|
||||
/// Returns `true` if `self` is in bounds for `len` slice elements.
|
||||
#[unstable(feature = "get_many_mut_helpers", issue = "none")]
|
||||
fn is_in_bounds(&self, len: usize) -> bool;
|
||||
|
||||
/// Returns `true` if `self` overlaps with `other`.
|
||||
///
|
||||
/// Note that we don't consider zero-length ranges to overlap at the beginning or the end,
|
||||
/// but do consider them to overlap in the middle.
|
||||
#[unstable(feature = "get_many_mut_helpers", issue = "none")]
|
||||
fn is_overlapping(&self, other: &Self) -> bool;
|
||||
}
|
||||
|
||||
#[unstable(feature = "get_many_mut_helpers", issue = "none")]
|
||||
// SAFETY: We implement `is_in_bounds()` and `is_overlapping()` correctly.
|
||||
unsafe impl GetManyMutIndex for usize {
|
||||
#[inline]
|
||||
fn is_in_bounds(&self, len: usize) -> bool {
|
||||
*self < len
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn is_overlapping(&self, other: &Self) -> bool {
|
||||
*self == *other
|
||||
}
|
||||
}
|
||||
|
||||
#[unstable(feature = "get_many_mut_helpers", issue = "none")]
|
||||
// SAFETY: We implement `is_in_bounds()` and `is_overlapping()` correctly.
|
||||
unsafe impl GetManyMutIndex for Range<usize> {
|
||||
#[inline]
|
||||
fn is_in_bounds(&self, len: usize) -> bool {
|
||||
(self.start <= self.end) & (self.end <= len)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn is_overlapping(&self, other: &Self) -> bool {
|
||||
(self.start < other.end) & (other.start < self.end)
|
||||
}
|
||||
}
|
||||
|
||||
#[unstable(feature = "get_many_mut_helpers", issue = "none")]
|
||||
// SAFETY: We implement `is_in_bounds()` and `is_overlapping()` correctly.
|
||||
unsafe impl GetManyMutIndex for RangeInclusive<usize> {
|
||||
#[inline]
|
||||
fn is_in_bounds(&self, len: usize) -> bool {
|
||||
(self.start <= self.end) & (self.end < len)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn is_overlapping(&self, other: &Self) -> bool {
|
||||
(self.start <= other.end) & (other.start <= self.end)
|
||||
}
|
||||
}
|
||||
|
||||
#[unstable(feature = "get_many_mut_helpers", issue = "none")]
|
||||
// SAFETY: We implement `is_in_bounds()` and `is_overlapping()` correctly.
|
||||
unsafe impl GetManyMutIndex for range::Range<usize> {
|
||||
#[inline]
|
||||
fn is_in_bounds(&self, len: usize) -> bool {
|
||||
Range::from(*self).is_in_bounds(len)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn is_overlapping(&self, other: &Self) -> bool {
|
||||
Range::from(*self).is_overlapping(&Range::from(*other))
|
||||
}
|
||||
}
|
||||
|
||||
#[unstable(feature = "get_many_mut_helpers", issue = "none")]
|
||||
// SAFETY: We implement `is_in_bounds()` and `is_overlapping()` correctly.
|
||||
unsafe impl GetManyMutIndex for range::RangeInclusive<usize> {
|
||||
#[inline]
|
||||
fn is_in_bounds(&self, len: usize) -> bool {
|
||||
RangeInclusive::from(*self).is_in_bounds(len)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn is_overlapping(&self, other: &Self) -> bool {
|
||||
RangeInclusive::from(*self).is_overlapping(&RangeInclusive::from(*other))
|
||||
}
|
||||
}
|
||||
|
|
|
@ -43,3 +43,10 @@ fn pad_integral_resets() {
|
|||
|
||||
assert_eq!(format!("{Bar:<03}"), "1 0051 ");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_maybe_uninit_short() {
|
||||
// Ensure that the trimmed `MaybeUninit` Debug implementation doesn't break
|
||||
let x = core::mem::MaybeUninit::new(0u32);
|
||||
assert_eq!(format!("{x:?}"), "MaybeUninit<u32>");
|
||||
}
|
||||
|
|
|
@ -2,6 +2,7 @@ use core::cell::Cell;
|
|||
use core::cmp::Ordering;
|
||||
use core::mem::MaybeUninit;
|
||||
use core::num::NonZero;
|
||||
use core::ops::{Range, RangeInclusive};
|
||||
use core::slice;
|
||||
|
||||
#[test]
|
||||
|
@ -2553,6 +2554,14 @@ fn test_get_many_mut_normal_2() {
|
|||
*a += 10;
|
||||
*b += 100;
|
||||
assert_eq!(v, vec![101, 2, 3, 14, 5]);
|
||||
|
||||
let [a, b] = v.get_many_mut([0..=1, 2..=2]).unwrap();
|
||||
assert_eq!(a, &mut [101, 2][..]);
|
||||
assert_eq!(b, &mut [3][..]);
|
||||
a[0] += 10;
|
||||
a[1] += 20;
|
||||
b[0] += 100;
|
||||
assert_eq!(v, vec![111, 22, 103, 14, 5]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -2563,12 +2572,23 @@ fn test_get_many_mut_normal_3() {
|
|||
*b += 100;
|
||||
*c += 1000;
|
||||
assert_eq!(v, vec![11, 2, 1003, 4, 105]);
|
||||
|
||||
let [a, b, c] = v.get_many_mut([0..1, 4..5, 1..4]).unwrap();
|
||||
assert_eq!(a, &mut [11][..]);
|
||||
assert_eq!(b, &mut [105][..]);
|
||||
assert_eq!(c, &mut [2, 1003, 4][..]);
|
||||
a[0] += 10;
|
||||
b[0] += 100;
|
||||
c[0] += 1000;
|
||||
assert_eq!(v, vec![21, 1002, 1003, 4, 205]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_get_many_mut_empty() {
|
||||
let mut v = vec![1, 2, 3, 4, 5];
|
||||
let [] = v.get_many_mut([]).unwrap();
|
||||
let [] = v.get_many_mut::<usize, 0>([]).unwrap();
|
||||
let [] = v.get_many_mut::<RangeInclusive<usize>, 0>([]).unwrap();
|
||||
let [] = v.get_many_mut::<Range<usize>, 0>([]).unwrap();
|
||||
assert_eq!(v, vec![1, 2, 3, 4, 5]);
|
||||
}
|
||||
|
||||
|
@ -2606,6 +2626,54 @@ fn test_get_many_mut_duplicate() {
|
|||
assert!(v.get_many_mut([1, 3, 3, 4]).is_err());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_get_many_mut_range_oob() {
|
||||
let mut v = vec![1, 2, 3, 4, 5];
|
||||
assert!(v.get_many_mut([0..6]).is_err());
|
||||
assert!(v.get_many_mut([5..6]).is_err());
|
||||
assert!(v.get_many_mut([6..6]).is_err());
|
||||
assert!(v.get_many_mut([0..=5]).is_err());
|
||||
assert!(v.get_many_mut([0..=6]).is_err());
|
||||
assert!(v.get_many_mut([5..=5]).is_err());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_get_many_mut_range_overlapping() {
|
||||
let mut v = vec![1, 2, 3, 4, 5];
|
||||
assert!(v.get_many_mut([0..1, 0..2]).is_err());
|
||||
assert!(v.get_many_mut([0..1, 1..2, 0..1]).is_err());
|
||||
assert!(v.get_many_mut([0..3, 1..1]).is_err());
|
||||
assert!(v.get_many_mut([0..3, 1..2]).is_err());
|
||||
assert!(v.get_many_mut([0..=0, 2..=2, 0..=1]).is_err());
|
||||
assert!(v.get_many_mut([0..=4, 0..=0]).is_err());
|
||||
assert!(v.get_many_mut([4..=4, 0..=0, 3..=4]).is_err());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_get_many_mut_range_empty_at_edge() {
|
||||
let mut v = vec![1, 2, 3, 4, 5];
|
||||
assert_eq!(
|
||||
v.get_many_mut([0..0, 0..5, 5..5]),
|
||||
Ok([&mut [][..], &mut [1, 2, 3, 4, 5], &mut []]),
|
||||
);
|
||||
assert_eq!(
|
||||
v.get_many_mut([0..0, 0..1, 1..1, 1..2, 2..2, 2..3, 3..3, 3..4, 4..4, 4..5, 5..5]),
|
||||
Ok([
|
||||
&mut [][..],
|
||||
&mut [1],
|
||||
&mut [],
|
||||
&mut [2],
|
||||
&mut [],
|
||||
&mut [3],
|
||||
&mut [],
|
||||
&mut [4],
|
||||
&mut [],
|
||||
&mut [5],
|
||||
&mut [],
|
||||
]),
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_slice_from_raw_parts_in_const() {
|
||||
static FANCY: i32 = 4;
|
||||
|
|
|
@ -511,12 +511,15 @@ fn test_downgrade_basic() {
|
|||
}
|
||||
|
||||
#[test]
|
||||
// FIXME: On macOS we use a provenance-incorrect implementation and Miri catches that issue.
|
||||
// See <https://github.com/rust-lang/rust/issues/121950> for details.
|
||||
#[cfg_attr(all(miri, target_os = "macos"), ignore)]
|
||||
fn test_downgrade_observe() {
|
||||
// Taken from the test `test_rwlock_downgrade` from:
|
||||
// https://github.com/Amanieu/parking_lot/blob/master/src/rwlock.rs
|
||||
|
||||
const W: usize = 20;
|
||||
const N: usize = 100;
|
||||
const N: usize = if cfg!(miri) { 40 } else { 100 };
|
||||
|
||||
// This test spawns `W` writer threads, where each will increment a counter `N` times, ensuring
|
||||
// that the value they wrote has not changed after downgrading.
|
||||
|
|
|
@ -963,7 +963,7 @@ fn report<'tcx>(
|
|||
// expr_str (the suggestion) is never shown if is_final_ufcs is true, since it's
|
||||
// `expr.kind == ExprKind::Call`. Therefore, this is, afaik, always unnecessary.
|
||||
/*
|
||||
expr_str = if !expr_is_macro_call && is_final_ufcs && expr.precedence().order() < PREC_PREFIX {
|
||||
expr_str = if !expr_is_macro_call && is_final_ufcs && expr.precedence() < PREC_PREFIX {
|
||||
Cow::Owned(format!("({expr_str})"))
|
||||
} else {
|
||||
expr_str
|
||||
|
@ -1003,7 +1003,7 @@ fn report<'tcx>(
|
|||
Node::Expr(e) => match e.kind {
|
||||
ExprKind::Call(callee, _) if callee.hir_id != data.first_expr.hir_id => (0, false),
|
||||
ExprKind::Call(..) => (PREC_UNAMBIGUOUS, matches!(expr.kind, ExprKind::Field(..))),
|
||||
_ => (e.precedence().order(), false),
|
||||
_ => (e.precedence(), false),
|
||||
},
|
||||
_ => (0, false),
|
||||
};
|
||||
|
@ -1016,7 +1016,7 @@ fn report<'tcx>(
|
|||
);
|
||||
|
||||
let sugg = if !snip_is_macro
|
||||
&& (calls_field || expr.precedence().order() < precedence)
|
||||
&& (calls_field || expr.precedence() < precedence)
|
||||
&& !has_enclosing_paren(&snip)
|
||||
&& !is_in_tuple
|
||||
{
|
||||
|
@ -1071,7 +1071,7 @@ fn report<'tcx>(
|
|||
let (snip, snip_is_macro) =
|
||||
snippet_with_context(cx, expr.span, data.first_expr.span.ctxt(), "..", &mut app);
|
||||
let sugg =
|
||||
if !snip_is_macro && expr.precedence().order() < precedence && !has_enclosing_paren(&snip) {
|
||||
if !snip_is_macro && expr.precedence() < precedence && !has_enclosing_paren(&snip) {
|
||||
format!("{prefix}({snip})")
|
||||
} else {
|
||||
format!("{prefix}{snip}")
|
||||
|
@ -1158,7 +1158,7 @@ impl<'tcx> Dereferencing<'tcx> {
|
|||
},
|
||||
Some(parent) if !parent.span.from_expansion() => {
|
||||
// Double reference might be needed at this point.
|
||||
if parent.precedence().order() == PREC_UNAMBIGUOUS {
|
||||
if parent.precedence() == PREC_UNAMBIGUOUS {
|
||||
// Parentheses would be needed here, don't lint.
|
||||
*outer_pat = None;
|
||||
} else {
|
||||
|
|
|
@ -84,7 +84,7 @@ pub(super) fn check<'tcx>(
|
|||
if !prefix.is_empty()
|
||||
&& (
|
||||
// Precedence of internal expression is less than or equal to precedence of `&expr`.
|
||||
arg_expression.precedence().order() <= PREC_PREFIX || is_range_literal(arg_expression)
|
||||
arg_expression.precedence() <= PREC_PREFIX || is_range_literal(arg_expression)
|
||||
)
|
||||
{
|
||||
arg_snip = format!("({arg_snip})").into();
|
||||
|
|
|
@ -117,7 +117,7 @@ where
|
|||
// it's being passed by value.
|
||||
let scrutinee = peel_hir_expr_refs(scrutinee).0;
|
||||
let (scrutinee_str, _) = snippet_with_context(cx, scrutinee.span, expr_ctxt, "..", &mut app);
|
||||
let scrutinee_str = if scrutinee.span.eq_ctxt(expr.span) && scrutinee.precedence().order() < PREC_UNAMBIGUOUS {
|
||||
let scrutinee_str = if scrutinee.span.eq_ctxt(expr.span) && scrutinee.precedence() < PREC_UNAMBIGUOUS {
|
||||
format!("({scrutinee_str})")
|
||||
} else {
|
||||
scrutinee_str.into()
|
||||
|
|
|
@ -58,7 +58,7 @@ fn check_mul(cx: &LateContext<'_>, span: Span, lit: &Expr<'_>, exp: &Expr<'_>) {
|
|||
{
|
||||
let mut applicability = Applicability::MachineApplicable;
|
||||
let (snip, from_macro) = snippet_with_context(cx, exp.span, span.ctxt(), "..", &mut applicability);
|
||||
let suggestion = if !from_macro && exp.precedence().order() < PREC_PREFIX && !has_enclosing_paren(&snip) {
|
||||
let suggestion = if !from_macro && exp.precedence() < PREC_PREFIX && !has_enclosing_paren(&snip) {
|
||||
format!("-({snip})")
|
||||
} else {
|
||||
format!("-{snip}")
|
||||
|
|
|
@ -85,7 +85,7 @@ impl<'tcx> LateLintPass<'tcx> for RedundantSlicing {
|
|||
let (expr_ty, expr_ref_count) = peel_middle_ty_refs(cx.typeck_results().expr_ty(expr));
|
||||
let (indexed_ty, indexed_ref_count) = peel_middle_ty_refs(cx.typeck_results().expr_ty(indexed));
|
||||
let parent_expr = get_parent_expr(cx, expr);
|
||||
let needs_parens_for_prefix = parent_expr.is_some_and(|parent| parent.precedence().order() > PREC_PREFIX);
|
||||
let needs_parens_for_prefix = parent_expr.is_some_and(|parent| parent.precedence() > PREC_PREFIX);
|
||||
|
||||
if expr_ty == indexed_ty {
|
||||
if expr_ref_count > indexed_ref_count {
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
use super::TRANSMUTES_EXPRESSIBLE_AS_PTR_CASTS;
|
||||
use clippy_utils::diagnostics::span_lint_and_sugg;
|
||||
use clippy_utils::sugg::Sugg;
|
||||
use rustc_ast::ExprPrecedence;
|
||||
use rustc_ast::util::parser::AssocOp;
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_hir::{Expr, Node};
|
||||
use rustc_hir_typeck::cast::check_cast;
|
||||
|
@ -44,7 +44,7 @@ pub(super) fn check<'tcx>(
|
|||
};
|
||||
|
||||
if let Node::Expr(parent) = cx.tcx.parent_hir_node(e.hir_id)
|
||||
&& parent.precedence().order() > ExprPrecedence::Cast.order()
|
||||
&& parent.precedence() > AssocOp::As.precedence() as i8
|
||||
{
|
||||
sugg = format!("({sugg})");
|
||||
}
|
||||
|
|
|
@ -1,9 +0,0 @@
|
|||
//@ known-bug: rust-lang/rust#126359
|
||||
|
||||
struct OppOrder<const N: u8 = 3, T = u32> {
|
||||
arr: [T; N],
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let _ = OppOrder::<3, u32> { arr: [0, 0, 0] };
|
||||
}
|
|
@ -1,7 +1,7 @@
|
|||
//@ known-bug: #130521
|
||||
|
||||
#![feature(dyn_compatible_for_dispatch)]
|
||||
struct Vtable(dyn Cap);
|
||||
struct Vtable(dyn Cap<'static>);
|
||||
|
||||
trait Cap<'a> {}
|
||||
|
||||
|
|
|
@ -1,12 +0,0 @@
|
|||
//@ known-bug: #131101
|
||||
trait Foo<const N: u8> {
|
||||
fn do_x(&self) -> [u8; N];
|
||||
}
|
||||
|
||||
struct Bar;
|
||||
|
||||
impl Foo<const 3> for Bar {
|
||||
fn do_x(&self) -> [u8; 3] {
|
||||
[0u8; 3]
|
||||
}
|
||||
}
|
|
@ -3,7 +3,6 @@
|
|||
pub struct Foo<'a, 'b, T> {
|
||||
field1: dyn Bar<'a, 'b>,
|
||||
//~^ ERROR
|
||||
//~| ERROR
|
||||
}
|
||||
|
||||
pub trait Bar<'x, 's, U>
|
||||
|
|
|
@ -5,7 +5,7 @@ LL | field1: dyn Bar<'a, 'b>,
|
|||
| ^^^ expected 1 generic argument
|
||||
|
|
||||
note: trait defined here, with 1 generic parameter: `U`
|
||||
--> $DIR/unable-fulfill-trait.rs:9:11
|
||||
--> $DIR/unable-fulfill-trait.rs:8:11
|
||||
|
|
||||
LL | pub trait Bar<'x, 's, U>
|
||||
| ^^^ -
|
||||
|
@ -14,13 +14,6 @@ help: add missing generic argument
|
|||
LL | field1: dyn Bar<'a, 'b, U>,
|
||||
| +++
|
||||
|
||||
error[E0227]: ambiguous lifetime bound, explicit lifetime bound required
|
||||
--> $DIR/unable-fulfill-trait.rs:4:13
|
||||
|
|
||||
LL | field1: dyn Bar<'a, 'b>,
|
||||
| ^^^^^^^^^^^^^^^
|
||||
error: aborting due to 1 previous error
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
|
||||
Some errors have detailed explanations: E0107, E0227.
|
||||
For more information about an error, try `rustc --explain E0107`.
|
||||
For more information about this error, try `rustc --explain E0107`.
|
||||
|
|
|
@ -2,10 +2,7 @@ error[E0308]: mismatched types
|
|||
--> $DIR/match_arr_unknown_len.rs:3:9
|
||||
|
|
||||
LL | [1, 2] => true,
|
||||
| ^^^^^^ expected `2`, found `N`
|
||||
|
|
||||
= note: expected array `[u32; 2]`
|
||||
found array `[u32; N]`
|
||||
| ^^^^^^ expected an array with a size of 2, found one with a size of N
|
||||
|
||||
error: aborting due to 1 previous error
|
||||
|
||||
|
|
|
@ -7,9 +7,6 @@ trait Sub<Rhs=Self> {
|
|||
}
|
||||
|
||||
type Test = dyn Add + Sub;
|
||||
//~^ ERROR E0393
|
||||
//~| ERROR E0191
|
||||
//~| ERROR E0393
|
||||
//~| ERROR E0225
|
||||
//~^ ERROR E0225
|
||||
|
||||
fn main() { }
|
||||
|
|
|
@ -9,56 +9,6 @@ LL | type Test = dyn Add + Sub;
|
|||
= help: consider creating a new trait with all of these as supertraits and using that trait here instead: `trait NewTrait: Add + Sub {}`
|
||||
= note: auto-traits like `Send` and `Sync` are traits that have special properties; for more information on them, visit <https://doc.rust-lang.org/reference/special-types-and-traits.html#auto-traits>
|
||||
|
||||
error[E0191]: the value of the associated types `Output` in `Add`, `Output` in `Sub` must be specified
|
||||
--> $DIR/issue-22560.rs:9:17
|
||||
|
|
||||
LL | type Output;
|
||||
| ----------- `Output` defined here
|
||||
...
|
||||
LL | type Output;
|
||||
| ----------- `Output` defined here
|
||||
...
|
||||
LL | type Test = dyn Add + Sub;
|
||||
| ^^^ ^^^ associated type `Output` must be specified
|
||||
| |
|
||||
| associated type `Output` must be specified
|
||||
|
|
||||
help: specify the associated types
|
||||
|
|
||||
LL | type Test = dyn Add<Output = Type> + Sub<Output = Type>;
|
||||
| ~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~
|
||||
error: aborting due to 1 previous error
|
||||
|
||||
error[E0393]: the type parameter `Rhs` must be explicitly specified
|
||||
--> $DIR/issue-22560.rs:9:17
|
||||
|
|
||||
LL | trait Add<Rhs=Self> {
|
||||
| ------------------- type parameter `Rhs` must be specified for this
|
||||
...
|
||||
LL | type Test = dyn Add + Sub;
|
||||
| ^^^
|
||||
|
|
||||
= note: because of the default `Self` reference, type parameters must be specified on object types
|
||||
help: set the type parameter to the desired type
|
||||
|
|
||||
LL | type Test = dyn Add<Rhs> + Sub;
|
||||
| +++++
|
||||
|
||||
error[E0393]: the type parameter `Rhs` must be explicitly specified
|
||||
--> $DIR/issue-22560.rs:9:23
|
||||
|
|
||||
LL | trait Sub<Rhs=Self> {
|
||||
| ------------------- type parameter `Rhs` must be specified for this
|
||||
...
|
||||
LL | type Test = dyn Add + Sub;
|
||||
| ^^^
|
||||
|
|
||||
= note: because of the default `Self` reference, type parameters must be specified on object types
|
||||
help: set the type parameter to the desired type
|
||||
|
|
||||
LL | type Test = dyn Add + Sub<Rhs>;
|
||||
| +++++
|
||||
|
||||
error: aborting due to 4 previous errors
|
||||
|
||||
Some errors have detailed explanations: E0191, E0225, E0393.
|
||||
For more information about an error, try `rustc --explain E0191`.
|
||||
For more information about this error, try `rustc --explain E0225`.
|
||||
|
|
|
@ -11,16 +11,12 @@ trait Fine<Rhs>: Div<Rhs, Output = Rhs> {}
|
|||
|
||||
type Foo<Rhs> = dyn Add<Rhs> + Sub<Rhs> + X<Rhs> + Y<Rhs>;
|
||||
//~^ ERROR only auto traits can be used as additional traits in a trait object
|
||||
//~| ERROR the value of the associated types
|
||||
type Bar<Rhs> = dyn Add<Rhs> + Sub<Rhs> + X<Rhs> + Z<Rhs>;
|
||||
//~^ ERROR only auto traits can be used as additional traits in a trait object
|
||||
//~| ERROR the value of the associated types
|
||||
type Baz<Rhs> = dyn Add<Rhs> + Sub<Rhs> + Y<Rhs>;
|
||||
//~^ ERROR only auto traits can be used as additional traits in a trait object
|
||||
//~| ERROR the value of the associated types
|
||||
type Bat<Rhs> = dyn Add<Rhs> + Sub<Rhs> + Fine<Rhs>;
|
||||
//~^ ERROR only auto traits can be used as additional traits in a trait object
|
||||
//~| ERROR the value of the associated types
|
||||
type Bal<Rhs> = dyn X<Rhs>;
|
||||
//~^ ERROR the value of the associated types
|
||||
|
||||
|
|
|
@ -9,26 +9,8 @@ LL | type Foo<Rhs> = dyn Add<Rhs> + Sub<Rhs> + X<Rhs> + Y<Rhs>;
|
|||
= help: consider creating a new trait with all of these as supertraits and using that trait here instead: `trait NewTrait: Add<Rhs> + Sub<Rhs> + X<Rhs> + Y<Rhs> {}`
|
||||
= note: auto-traits like `Send` and `Sync` are traits that have special properties; for more information on them, visit <https://doc.rust-lang.org/reference/special-types-and-traits.html#auto-traits>
|
||||
|
||||
error[E0191]: the value of the associated types `A` in `Y`, `Output` in `Add`, `Output` in `Mul`, `Output` in `Sub` must be specified
|
||||
--> $DIR/missing-associated-types.rs:12:21
|
||||
|
|
||||
LL | type A;
|
||||
| ------ `A` defined here
|
||||
...
|
||||
LL | type Foo<Rhs> = dyn Add<Rhs> + Sub<Rhs> + X<Rhs> + Y<Rhs>;
|
||||
| ^^^^^^^^ ^^^^^^^^ ^^^^^^ ^^^^^^ associated type `A` must be specified
|
||||
| | | |
|
||||
| | | associated type `Output` must be specified
|
||||
| | associated type `Output` must be specified
|
||||
| associated type `Output` must be specified
|
||||
|
|
||||
help: specify the associated types
|
||||
|
|
||||
LL | type Foo<Rhs> = dyn Add<Rhs, Output = Type> + Sub<Rhs, Output = Type> + X<Rhs, Output = Type> + Y<Rhs, A = Type>;
|
||||
| ~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~
|
||||
|
||||
error[E0225]: only auto traits can be used as additional traits in a trait object
|
||||
--> $DIR/missing-associated-types.rs:15:32
|
||||
--> $DIR/missing-associated-types.rs:14:32
|
||||
|
|
||||
LL | type Bar<Rhs> = dyn Add<Rhs> + Sub<Rhs> + X<Rhs> + Z<Rhs>;
|
||||
| -------- ^^^^^^^^ additional non-auto trait
|
||||
|
@ -38,33 +20,8 @@ LL | type Bar<Rhs> = dyn Add<Rhs> + Sub<Rhs> + X<Rhs> + Z<Rhs>;
|
|||
= help: consider creating a new trait with all of these as supertraits and using that trait here instead: `trait NewTrait: Add<Rhs> + Sub<Rhs> + X<Rhs> + Z<Rhs> {}`
|
||||
= note: auto-traits like `Send` and `Sync` are traits that have special properties; for more information on them, visit <https://doc.rust-lang.org/reference/special-types-and-traits.html#auto-traits>
|
||||
|
||||
error[E0191]: the value of the associated types `A` and `B` in `Z`, `Output` and `Output` in `Div`, `Output` in `Add`, `Output` in `Mul`, `Output` in `Sub` must be specified
|
||||
--> $DIR/missing-associated-types.rs:15:21
|
||||
|
|
||||
LL | type A;
|
||||
| ------ `A` defined here
|
||||
LL | type B;
|
||||
| ------ `B` defined here
|
||||
...
|
||||
LL | type Bar<Rhs> = dyn Add<Rhs> + Sub<Rhs> + X<Rhs> + Z<Rhs>;
|
||||
| ^^^^^^^^ ^^^^^^^^ ^^^^^^ ^^^^^^ associated types `A`, `B`, `Output` must be specified
|
||||
| | | |
|
||||
| | | associated types `Output` (from trait `Div`), `Output` (from trait `Mul`) must be specified
|
||||
| | associated type `Output` must be specified
|
||||
| associated type `Output` must be specified
|
||||
|
|
||||
help: consider introducing a new type parameter, adding `where` constraints using the fully-qualified path to the associated types
|
||||
--> $DIR/missing-associated-types.rs:15:43
|
||||
|
|
||||
LL | type Bar<Rhs> = dyn Add<Rhs> + Sub<Rhs> + X<Rhs> + Z<Rhs>;
|
||||
| ^^^^^^
|
||||
help: specify the associated types
|
||||
|
|
||||
LL | type Bar<Rhs> = dyn Add<Rhs, Output = Type> + Sub<Rhs, Output = Type> + X<Rhs> + Z<Rhs, A = Type, B = Type, Output = Type>;
|
||||
| ~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
error[E0225]: only auto traits can be used as additional traits in a trait object
|
||||
--> $DIR/missing-associated-types.rs:18:32
|
||||
--> $DIR/missing-associated-types.rs:16:32
|
||||
|
|
||||
LL | type Baz<Rhs> = dyn Add<Rhs> + Sub<Rhs> + Y<Rhs>;
|
||||
| -------- ^^^^^^^^ additional non-auto trait
|
||||
|
@ -74,25 +31,8 @@ LL | type Baz<Rhs> = dyn Add<Rhs> + Sub<Rhs> + Y<Rhs>;
|
|||
= help: consider creating a new trait with all of these as supertraits and using that trait here instead: `trait NewTrait: Add<Rhs> + Sub<Rhs> + Y<Rhs> {}`
|
||||
= note: auto-traits like `Send` and `Sync` are traits that have special properties; for more information on them, visit <https://doc.rust-lang.org/reference/special-types-and-traits.html#auto-traits>
|
||||
|
||||
error[E0191]: the value of the associated types `A` in `Y`, `Output` in `Add`, `Output` in `Sub` must be specified
|
||||
--> $DIR/missing-associated-types.rs:18:21
|
||||
|
|
||||
LL | type A;
|
||||
| ------ `A` defined here
|
||||
...
|
||||
LL | type Baz<Rhs> = dyn Add<Rhs> + Sub<Rhs> + Y<Rhs>;
|
||||
| ^^^^^^^^ ^^^^^^^^ ^^^^^^ associated type `A` must be specified
|
||||
| | |
|
||||
| | associated type `Output` must be specified
|
||||
| associated type `Output` must be specified
|
||||
|
|
||||
help: specify the associated types
|
||||
|
|
||||
LL | type Baz<Rhs> = dyn Add<Rhs, Output = Type> + Sub<Rhs, Output = Type> + Y<Rhs, A = Type>;
|
||||
| ~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~
|
||||
|
||||
error[E0225]: only auto traits can be used as additional traits in a trait object
|
||||
--> $DIR/missing-associated-types.rs:21:32
|
||||
--> $DIR/missing-associated-types.rs:18:32
|
||||
|
|
||||
LL | type Bat<Rhs> = dyn Add<Rhs> + Sub<Rhs> + Fine<Rhs>;
|
||||
| -------- ^^^^^^^^ additional non-auto trait
|
||||
|
@ -102,28 +42,15 @@ LL | type Bat<Rhs> = dyn Add<Rhs> + Sub<Rhs> + Fine<Rhs>;
|
|||
= help: consider creating a new trait with all of these as supertraits and using that trait here instead: `trait NewTrait: Add<Rhs> + Sub<Rhs> + Fine<Rhs> {}`
|
||||
= note: auto-traits like `Send` and `Sync` are traits that have special properties; for more information on them, visit <https://doc.rust-lang.org/reference/special-types-and-traits.html#auto-traits>
|
||||
|
||||
error[E0191]: the value of the associated types `Output` in `Add`, `Output` in `Sub` must be specified
|
||||
--> $DIR/missing-associated-types.rs:21:21
|
||||
|
|
||||
LL | type Bat<Rhs> = dyn Add<Rhs> + Sub<Rhs> + Fine<Rhs>;
|
||||
| ^^^^^^^^ ^^^^^^^^ associated type `Output` must be specified
|
||||
| |
|
||||
| associated type `Output` must be specified
|
||||
|
|
||||
help: specify the associated types
|
||||
|
|
||||
LL | type Bat<Rhs> = dyn Add<Rhs, Output = Type> + Sub<Rhs, Output = Type> + Fine<Rhs>;
|
||||
| ~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
error[E0191]: the value of the associated types `Output` in `Div`, `Output` in `Mul` must be specified
|
||||
--> $DIR/missing-associated-types.rs:24:21
|
||||
--> $DIR/missing-associated-types.rs:20:21
|
||||
|
|
||||
LL | type Bal<Rhs> = dyn X<Rhs>;
|
||||
| ^^^^^^ associated types `Output` (from trait `Div`), `Output` (from trait `Mul`) must be specified
|
||||
|
|
||||
= help: consider introducing a new type parameter, adding `where` constraints using the fully-qualified path to the associated types
|
||||
|
||||
error: aborting due to 9 previous errors
|
||||
error: aborting due to 5 previous errors
|
||||
|
||||
Some errors have detailed explanations: E0191, E0225.
|
||||
For more information about an error, try `rustc --explain E0191`.
|
||||
|
|
|
@ -2,7 +2,7 @@ error[E0308]: mismatched types
|
|||
--> $DIR/const-argument-cross-crate-mismatch.rs:6:67
|
||||
|
|
||||
LL | let _ = const_generic_lib::function(const_generic_lib::Struct([0u8, 1u8]));
|
||||
| ------------------------- ^^^^^^^^^^ expected an array with a fixed size of 3 elements, found one with 2 elements
|
||||
| ------------------------- ^^^^^^^^^^ expected an array with a size of 3, found one with a size of 2
|
||||
| |
|
||||
| arguments to this struct are incorrect
|
||||
|
|
||||
|
@ -16,7 +16,7 @@ error[E0308]: mismatched types
|
|||
--> $DIR/const-argument-cross-crate-mismatch.rs:8:65
|
||||
|
|
||||
LL | let _: const_generic_lib::Alias = const_generic_lib::Struct([0u8, 1u8, 2u8]);
|
||||
| ------------------------- ^^^^^^^^^^^^^^^ expected an array with a fixed size of 2 elements, found one with 3 elements
|
||||
| ------------------------- ^^^^^^^^^^^^^^^ expected an array with a size of 2, found one with a size of 3
|
||||
| |
|
||||
| arguments to this struct are incorrect
|
||||
|
|
||||
|
|
|
@ -4,10 +4,7 @@ error[E0308]: mismatched types
|
|||
LL | fn test<const N: usize, const M: usize>() -> [u8; M] {
|
||||
| ------- expected `[u8; M]` because of return type
|
||||
LL | [0; N]
|
||||
| ^^^^^^ expected `M`, found `N`
|
||||
|
|
||||
= note: expected array `[u8; M]`
|
||||
found array `[u8; N]`
|
||||
| ^^^^^^ expected an array with a size of M, found one with a size of N
|
||||
|
||||
error: aborting due to 1 previous error
|
||||
|
||||
|
|
|
@ -10,12 +10,10 @@ error[E0308]: mismatched types
|
|||
--> $DIR/issue-62504.rs:18:21
|
||||
|
|
||||
LL | ArrayHolder([0; Self::SIZE])
|
||||
| ----------- ^^^^^^^^^^^^^^^ expected `X`, found `Self::SIZE`
|
||||
| ----------- ^^^^^^^^^^^^^^^ expected an array with a size of X, found one with a size of Self::SIZE
|
||||
| |
|
||||
| arguments to this struct are incorrect
|
||||
|
|
||||
= note: expected array `[u32; X]`
|
||||
found array `[u32; Self::SIZE]`
|
||||
note: tuple struct defined here
|
||||
--> $DIR/issue-62504.rs:14:8
|
||||
|
|
||||
|
|
|
@ -3,9 +3,6 @@
|
|||
trait Trait<const N: dyn Trait = bar> {
|
||||
//~^ ERROR: cannot find value `bar` in this scope
|
||||
//~| ERROR: cycle detected when computing type of `Trait::N`
|
||||
//~| ERROR: the trait `Trait` cannot be made into an object
|
||||
//~| ERROR: the trait `Trait` cannot be made into an object
|
||||
//~| ERROR: the trait `Trait` cannot be made into an object
|
||||
async fn a() {}
|
||||
}
|
||||
|
||||
|
|
|
@ -18,77 +18,7 @@ LL | trait Trait<const N: dyn Trait = bar> {
|
|||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
= note: see https://rustc-dev-guide.rust-lang.org/overview.html#queries and https://rustc-dev-guide.rust-lang.org/query.html for more information
|
||||
|
||||
error[E0038]: the trait `Trait` cannot be made into an object
|
||||
--> $DIR/not_wf_param_in_rpitit.rs:3:22
|
||||
|
|
||||
LL | trait Trait<const N: dyn Trait = bar> {
|
||||
| ^^^^^^^^^ `Trait` cannot be made into an object
|
||||
|
|
||||
note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
|
||||
--> $DIR/not_wf_param_in_rpitit.rs:9:14
|
||||
|
|
||||
LL | trait Trait<const N: dyn Trait = bar> {
|
||||
| ----- this trait cannot be made into an object...
|
||||
...
|
||||
LL | async fn a() {}
|
||||
| ^ ...because associated function `a` has no `self` parameter
|
||||
help: consider turning `a` into a method by giving it a `&self` argument
|
||||
|
|
||||
LL | async fn a(&self) {}
|
||||
| +++++
|
||||
help: alternatively, consider constraining `a` so it does not apply to trait objects
|
||||
|
|
||||
LL | async fn a() where Self: Sized {}
|
||||
| +++++++++++++++++
|
||||
error: aborting due to 2 previous errors
|
||||
|
||||
error[E0038]: the trait `Trait` cannot be made into an object
|
||||
--> $DIR/not_wf_param_in_rpitit.rs:3:13
|
||||
|
|
||||
LL | trait Trait<const N: dyn Trait = bar> {
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^ `Trait` cannot be made into an object
|
||||
|
|
||||
note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
|
||||
--> $DIR/not_wf_param_in_rpitit.rs:9:14
|
||||
|
|
||||
LL | trait Trait<const N: dyn Trait = bar> {
|
||||
| ----- this trait cannot be made into an object...
|
||||
...
|
||||
LL | async fn a() {}
|
||||
| ^ ...because associated function `a` has no `self` parameter
|
||||
help: consider turning `a` into a method by giving it a `&self` argument
|
||||
|
|
||||
LL | async fn a(&self) {}
|
||||
| +++++
|
||||
help: alternatively, consider constraining `a` so it does not apply to trait objects
|
||||
|
|
||||
LL | async fn a() where Self: Sized {}
|
||||
| +++++++++++++++++
|
||||
|
||||
error[E0038]: the trait `Trait` cannot be made into an object
|
||||
--> $DIR/not_wf_param_in_rpitit.rs:3:13
|
||||
|
|
||||
LL | trait Trait<const N: dyn Trait = bar> {
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^ `Trait` cannot be made into an object
|
||||
|
|
||||
note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
|
||||
--> $DIR/not_wf_param_in_rpitit.rs:9:14
|
||||
|
|
||||
LL | trait Trait<const N: dyn Trait = bar> {
|
||||
| ----- this trait cannot be made into an object...
|
||||
...
|
||||
LL | async fn a() {}
|
||||
| ^ ...because associated function `a` has no `self` parameter
|
||||
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
|
||||
help: consider turning `a` into a method by giving it a `&self` argument
|
||||
|
|
||||
LL | async fn a(&self) {}
|
||||
| +++++
|
||||
help: alternatively, consider constraining `a` so it does not apply to trait objects
|
||||
|
|
||||
LL | async fn a() where Self: Sized {}
|
||||
| +++++++++++++++++
|
||||
|
||||
error: aborting due to 5 previous errors
|
||||
|
||||
Some errors have detailed explanations: E0038, E0391, E0425.
|
||||
For more information about an error, try `rustc --explain E0038`.
|
||||
Some errors have detailed explanations: E0391, E0425.
|
||||
For more information about an error, try `rustc --explain E0391`.
|
||||
|
|
|
@ -2,7 +2,7 @@ error[E0308]: mismatched types
|
|||
--> $DIR/array-literal-len-mismatch.rs:1:26
|
||||
|
|
||||
LL | const NUMBERS: [u8; 3] = [10, 20];
|
||||
| - ^^^^^^^^ expected an array with a fixed size of 3 elements, found one with 2 elements
|
||||
| - ^^^^^^^^ expected an array with a size of 3, found one with a size of 2
|
||||
| |
|
||||
| help: consider specifying the actual array length: `2`
|
||||
|
||||
|
|
10
tests/ui/consts/bad-array-size-in-type-err.rs
Normal file
10
tests/ui/consts/bad-array-size-in-type-err.rs
Normal file
|
@ -0,0 +1,10 @@
|
|||
struct BadArraySize<const N: u8> {
|
||||
arr: [i32; N],
|
||||
//~^ ERROR the constant `N` is not of type `usize`
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let _ = BadArraySize::<2> { arr: [0, 0, 0] };
|
||||
//~^ ERROR mismatched types
|
||||
//~| ERROR the constant `2` is not of type `usize`
|
||||
}
|
21
tests/ui/consts/bad-array-size-in-type-err.stderr
Normal file
21
tests/ui/consts/bad-array-size-in-type-err.stderr
Normal file
|
@ -0,0 +1,21 @@
|
|||
error: the constant `N` is not of type `usize`
|
||||
--> $DIR/bad-array-size-in-type-err.rs:2:10
|
||||
|
|
||||
LL | arr: [i32; N],
|
||||
| ^^^^^^^^ expected `usize`, found `u8`
|
||||
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/bad-array-size-in-type-err.rs:7:38
|
||||
|
|
||||
LL | let _ = BadArraySize::<2> { arr: [0, 0, 0] };
|
||||
| ^^^^^^^^^ expected an array with a size of 2, found one with a size of 3
|
||||
|
||||
error: the constant `2` is not of type `usize`
|
||||
--> $DIR/bad-array-size-in-type-err.rs:7:38
|
||||
|
|
||||
LL | let _ = BadArraySize::<2> { arr: [0, 0, 0] };
|
||||
| ^^^^^^^^^ expected `usize`, found `u8`
|
||||
|
||||
error: aborting due to 3 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0308`.
|
|
@ -4,10 +4,10 @@ const VAL: i32 = ARR[IDX];
|
|||
const BONG: [i32; (ARR[0] - 41) as usize] = [5];
|
||||
const BLUB: [i32; (ARR[0] - 40) as usize] = [5];
|
||||
//~^ ERROR: mismatched types
|
||||
//~| expected an array with a fixed size of 2 elements, found one with 1 element
|
||||
//~| expected an array
|
||||
const BOO: [i32; (ARR[0] - 41) as usize] = [5, 99];
|
||||
//~^ ERROR: mismatched types
|
||||
//~| expected an array with a fixed size of 1 element, found one with 2 elements
|
||||
//~| expected an array
|
||||
|
||||
fn main() {
|
||||
let _ = VAL;
|
||||
|
|
|
@ -2,7 +2,7 @@ error[E0308]: mismatched types
|
|||
--> $DIR/const-array-oob-arith.rs:5:45
|
||||
|
|
||||
LL | const BLUB: [i32; (ARR[0] - 40) as usize] = [5];
|
||||
| ---------------------- ^^^ expected an array with a fixed size of 2 elements, found one with 1 element
|
||||
| ---------------------- ^^^ expected an array with a size of 2, found one with a size of 1
|
||||
| |
|
||||
| help: consider specifying the actual array length: `1`
|
||||
|
||||
|
@ -10,7 +10,7 @@ error[E0308]: mismatched types
|
|||
--> $DIR/const-array-oob-arith.rs:8:44
|
||||
|
|
||||
LL | const BOO: [i32; (ARR[0] - 41) as usize] = [5, 99];
|
||||
| ---------------------- ^^^^^^^ expected an array with a fixed size of 1 element, found one with 2 elements
|
||||
| ---------------------- ^^^^^^^ expected an array with a size of 1, found one with a size of 2
|
||||
| |
|
||||
| help: consider specifying the actual array length: `2`
|
||||
|
||||
|
|
|
@ -2,7 +2,7 @@ error[E0308]: mismatched types
|
|||
--> $DIR/array-len-mismatch.rs:6:26
|
||||
|
|
||||
LL | let wrong: [u8; 3] = [10, 20];
|
||||
| ------- ^^^^^^^^ expected an array with a fixed size of 3 elements, found one with 2 elements
|
||||
| ------- ^^^^^^^^ expected an array with a size of 3, found one with a size of 2
|
||||
| | |
|
||||
| | help: consider specifying the actual array length: `2`
|
||||
| expected due to this
|
||||
|
@ -11,7 +11,7 @@ error[E0308]: mismatched types
|
|||
--> $DIR/array-len-mismatch.rs:9:26
|
||||
|
|
||||
LL | let wrong: [u8; 3] = returns_arr();
|
||||
| ------- ^^^^^^^^^^^^^ expected an array with a fixed size of 3 elements, found one with 2 elements
|
||||
| ------- ^^^^^^^^^^^^^ expected an array with a size of 3, found one with a size of 2
|
||||
| | |
|
||||
| | help: consider specifying the actual array length: `2`
|
||||
| expected due to this
|
||||
|
|
|
@ -8,5 +8,4 @@ fn main()
|
|||
println!("{:?}",(vfnfer[0] as dyn Fn)(3));
|
||||
//~^ ERROR the precise format of `Fn`-family traits'
|
||||
//~| ERROR missing generics for trait `Fn`
|
||||
//~| ERROR the value of the associated type `Output` in `FnOnce`
|
||||
}
|
||||
|
|
|
@ -19,13 +19,7 @@ help: add missing generic argument
|
|||
LL | println!("{:?}",(vfnfer[0] as dyn Fn<Args>)(3));
|
||||
| ++++++
|
||||
|
||||
error[E0191]: the value of the associated type `Output` in `FnOnce` must be specified
|
||||
--> $DIR/issue-23024.rs:8:39
|
||||
|
|
||||
LL | println!("{:?}",(vfnfer[0] as dyn Fn)(3));
|
||||
| ^^ help: specify the associated type: `Fn::<Output = Type>`
|
||||
error: aborting due to 2 previous errors
|
||||
|
||||
error: aborting due to 3 previous errors
|
||||
|
||||
Some errors have detailed explanations: E0107, E0191, E0658.
|
||||
Some errors have detailed explanations: E0107, E0658.
|
||||
For more information about an error, try `rustc --explain E0107`.
|
||||
|
|
|
@ -6,7 +6,6 @@ trait Trait<T> {
|
|||
|
||||
pub struct Foo<T = Box<Trait<DefaultFoo>>>; //~ ERROR cycle detected
|
||||
//~^ ERROR `T` is never used
|
||||
//~| ERROR `Trait` cannot be made into an object
|
||||
type DefaultFoo = Foo;
|
||||
|
||||
fn main() {
|
||||
|
|
|
@ -5,7 +5,7 @@ LL | pub struct Foo<T = Box<Trait<DefaultFoo>>>;
|
|||
| ^^^^^^^^^^
|
||||
|
|
||||
note: ...which requires expanding type alias `DefaultFoo`...
|
||||
--> $DIR/issue-34373.rs:10:19
|
||||
--> $DIR/issue-34373.rs:9:19
|
||||
|
|
||||
LL | type DefaultFoo = Foo;
|
||||
| ^^^
|
||||
|
@ -17,28 +17,6 @@ LL | pub struct Foo<T = Box<Trait<DefaultFoo>>>;
|
|||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
= note: see https://rustc-dev-guide.rust-lang.org/overview.html#queries and https://rustc-dev-guide.rust-lang.org/query.html for more information
|
||||
|
||||
error[E0038]: the trait `Trait` cannot be made into an object
|
||||
--> $DIR/issue-34373.rs:7:24
|
||||
|
|
||||
LL | pub struct Foo<T = Box<Trait<DefaultFoo>>>;
|
||||
| ^^^^^^^^^^^^^^^^^ `Trait` cannot be made into an object
|
||||
|
|
||||
note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
|
||||
--> $DIR/issue-34373.rs:4:8
|
||||
|
|
||||
LL | trait Trait<T> {
|
||||
| ----- this trait cannot be made into an object...
|
||||
LL | fn foo(_: T) {}
|
||||
| ^^^ ...because associated function `foo` has no `self` parameter
|
||||
help: consider turning `foo` into a method by giving it a `&self` argument
|
||||
|
|
||||
LL | fn foo(&self, _: T) {}
|
||||
| ++++++
|
||||
help: alternatively, consider constraining `foo` so it does not apply to trait objects
|
||||
|
|
||||
LL | fn foo(_: T) where Self: Sized {}
|
||||
| +++++++++++++++++
|
||||
|
||||
error[E0392]: type parameter `T` is never used
|
||||
--> $DIR/issue-34373.rs:7:16
|
||||
|
|
||||
|
@ -48,7 +26,7 @@ LL | pub struct Foo<T = Box<Trait<DefaultFoo>>>;
|
|||
= help: consider removing `T`, referring to it in a field, or using a marker such as `PhantomData`
|
||||
= help: if you intended `T` to be a const parameter, use `const T: /* Type */` instead
|
||||
|
||||
error: aborting due to 3 previous errors
|
||||
error: aborting due to 2 previous errors
|
||||
|
||||
Some errors have detailed explanations: E0038, E0391, E0392.
|
||||
For more information about an error, try `rustc --explain E0038`.
|
||||
Some errors have detailed explanations: E0391, E0392.
|
||||
For more information about an error, try `rustc --explain E0391`.
|
||||
|
|
|
@ -1,51 +0,0 @@
|
|||
// General test of maybe_uninits state computed by MIR dataflow.
|
||||
|
||||
#![feature(core_intrinsics, rustc_attrs)]
|
||||
|
||||
use std::intrinsics::rustc_peek;
|
||||
use std::mem::{drop, replace};
|
||||
|
||||
struct S(i32);
|
||||
|
||||
#[rustc_mir(rustc_peek_definite_init,stop_after_dataflow)]
|
||||
fn foo(test: bool, x: &mut S, y: S, mut z: S) -> S {
|
||||
let ret;
|
||||
// `ret` starts off uninitialized
|
||||
rustc_peek(&ret); //~ ERROR rustc_peek: bit not set
|
||||
|
||||
// All function formal parameters start off initialized.
|
||||
|
||||
rustc_peek(&x);
|
||||
rustc_peek(&y);
|
||||
rustc_peek(&z);
|
||||
|
||||
ret = if test {
|
||||
::std::mem::replace(x, y)
|
||||
} else {
|
||||
z = y;
|
||||
z
|
||||
};
|
||||
|
||||
// `z` may be uninitialized here.
|
||||
rustc_peek(&z); //~ ERROR rustc_peek: bit not set
|
||||
|
||||
// `y` is definitely uninitialized here.
|
||||
rustc_peek(&y); //~ ERROR rustc_peek: bit not set
|
||||
|
||||
// `x` is still (definitely) initialized (replace above is a reborrow).
|
||||
rustc_peek(&x);
|
||||
|
||||
::std::mem::drop(x);
|
||||
|
||||
// `x` is *definitely* uninitialized here
|
||||
rustc_peek(&x); //~ ERROR rustc_peek: bit not set
|
||||
|
||||
// `ret` is now definitely initialized (via `if` above).
|
||||
rustc_peek(&ret);
|
||||
|
||||
ret
|
||||
}
|
||||
fn main() {
|
||||
foo(true, &mut S(13), S(14), S(15));
|
||||
foo(false, &mut S(13), S(14), S(15));
|
||||
}
|
|
@ -1,28 +0,0 @@
|
|||
error: rustc_peek: bit not set
|
||||
--> $DIR/def-inits-1.rs:14:5
|
||||
|
|
||||
LL | rustc_peek(&ret);
|
||||
| ^^^^^^^^^^^^^^^^
|
||||
|
||||
error: rustc_peek: bit not set
|
||||
--> $DIR/def-inits-1.rs:30:5
|
||||
|
|
||||
LL | rustc_peek(&z);
|
||||
| ^^^^^^^^^^^^^^
|
||||
|
||||
error: rustc_peek: bit not set
|
||||
--> $DIR/def-inits-1.rs:33:5
|
||||
|
|
||||
LL | rustc_peek(&y);
|
||||
| ^^^^^^^^^^^^^^
|
||||
|
||||
error: rustc_peek: bit not set
|
||||
--> $DIR/def-inits-1.rs:41:5
|
||||
|
|
||||
LL | rustc_peek(&x);
|
||||
| ^^^^^^^^^^^^^^
|
||||
|
||||
error: stop_after_dataflow ended compilation
|
||||
|
||||
error: aborting due to 5 previous errors
|
||||
|
|
@ -5,8 +5,7 @@ pub trait T<X, Y> {
|
|||
}
|
||||
pub struct Foo {
|
||||
i: Box<dyn T<usize, usize, usize, usize, B=usize>>,
|
||||
//~^ ERROR must be specified
|
||||
//~| ERROR trait takes 2 generic arguments but 4 generic arguments were supplied
|
||||
//~^ ERROR trait takes 2 generic arguments but 4 generic arguments were supplied
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -14,19 +14,6 @@ help: replace the generic bounds with the associated types
|
|||
LL | i: Box<dyn T<usize, usize, A = usize, C = usize, B=usize>>,
|
||||
| +++ +++
|
||||
|
||||
error[E0191]: the value of the associated types `C` and `A` in `T` must be specified
|
||||
--> $DIR/use-type-argument-instead-of-assoc-type.rs:7:16
|
||||
|
|
||||
LL | type A;
|
||||
| ------ `A` defined here
|
||||
LL | type B;
|
||||
LL | type C;
|
||||
| ------ `C` defined here
|
||||
...
|
||||
LL | i: Box<dyn T<usize, usize, usize, usize, B=usize>>,
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ associated types `A`, `C` must be specified
|
||||
error: aborting due to 1 previous error
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
|
||||
Some errors have detailed explanations: E0107, E0191.
|
||||
For more information about an error, try `rustc --explain E0107`.
|
||||
For more information about this error, try `rustc --explain E0107`.
|
||||
|
|
|
@ -3,7 +3,4 @@ trait Trait {}
|
|||
pub fn main() {
|
||||
let x: Vec<dyn Trait + Sized> = Vec::new();
|
||||
//~^ ERROR only auto traits can be used as additional traits in a trait object
|
||||
//~| ERROR the size for values of type
|
||||
//~| ERROR the size for values of type
|
||||
//~| ERROR the size for values of type
|
||||
}
|
||||
|
|
|
@ -9,37 +9,6 @@ LL | let x: Vec<dyn Trait + Sized> = Vec::new();
|
|||
= help: consider creating a new trait with all of these as supertraits and using that trait here instead: `trait NewTrait: Trait + Sized {}`
|
||||
= note: auto-traits like `Send` and `Sync` are traits that have special properties; for more information on them, visit <https://doc.rust-lang.org/reference/special-types-and-traits.html#auto-traits>
|
||||
|
||||
error[E0277]: the size for values of type `dyn Trait` cannot be known at compilation time
|
||||
--> $DIR/bad-sized.rs:4:12
|
||||
|
|
||||
LL | let x: Vec<dyn Trait + Sized> = Vec::new();
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
|
||||
|
|
||||
= help: the trait `Sized` is not implemented for `dyn Trait`
|
||||
note: required by an implicit `Sized` bound in `Vec`
|
||||
--> $SRC_DIR/alloc/src/vec/mod.rs:LL:COL
|
||||
error: aborting due to 1 previous error
|
||||
|
||||
error[E0277]: the size for values of type `dyn Trait` cannot be known at compilation time
|
||||
--> $DIR/bad-sized.rs:4:37
|
||||
|
|
||||
LL | let x: Vec<dyn Trait + Sized> = Vec::new();
|
||||
| ^^^^^^^^^^ doesn't have a size known at compile-time
|
||||
|
|
||||
= help: the trait `Sized` is not implemented for `dyn Trait`
|
||||
note: required by a bound in `Vec::<T>::new`
|
||||
--> $SRC_DIR/alloc/src/vec/mod.rs:LL:COL
|
||||
|
||||
error[E0277]: the size for values of type `dyn Trait` cannot be known at compilation time
|
||||
--> $DIR/bad-sized.rs:4:37
|
||||
|
|
||||
LL | let x: Vec<dyn Trait + Sized> = Vec::new();
|
||||
| ^^^ doesn't have a size known at compile-time
|
||||
|
|
||||
= help: the trait `Sized` is not implemented for `dyn Trait`
|
||||
note: required by an implicit `Sized` bound in `Vec`
|
||||
--> $SRC_DIR/alloc/src/vec/mod.rs:LL:COL
|
||||
|
||||
error: aborting due to 4 previous errors
|
||||
|
||||
Some errors have detailed explanations: E0225, E0277.
|
||||
For more information about an error, try `rustc --explain E0225`.
|
||||
For more information about this error, try `rustc --explain E0225`.
|
||||
|
|
|
@ -7,5 +7,4 @@ fn size_of_copy<T: Copy+?Sized>() -> usize { mem::size_of::<T>() }
|
|||
fn main() {
|
||||
size_of_copy::<dyn Misc + Copy>();
|
||||
//~^ ERROR only auto traits can be used as additional traits in a trait object
|
||||
//~| ERROR the trait bound `dyn Misc: Copy` is not satisfied
|
||||
}
|
||||
|
|
|
@ -9,19 +9,6 @@ LL | size_of_copy::<dyn Misc + Copy>();
|
|||
= help: consider creating a new trait with all of these as supertraits and using that trait here instead: `trait NewTrait: Misc + Copy {}`
|
||||
= note: auto-traits like `Send` and `Sync` are traits that have special properties; for more information on them, visit <https://doc.rust-lang.org/reference/special-types-and-traits.html#auto-traits>
|
||||
|
||||
error[E0277]: the trait bound `dyn Misc: Copy` is not satisfied
|
||||
--> $DIR/issue-32963.rs:8:20
|
||||
|
|
||||
LL | size_of_copy::<dyn Misc + Copy>();
|
||||
| ^^^^^^^^^^^^^^^ the trait `Copy` is not implemented for `dyn Misc`
|
||||
|
|
||||
note: required by a bound in `size_of_copy`
|
||||
--> $DIR/issue-32963.rs:5:20
|
||||
|
|
||||
LL | fn size_of_copy<T: Copy+?Sized>() -> usize { mem::size_of::<T>() }
|
||||
| ^^^^ required by this bound in `size_of_copy`
|
||||
error: aborting due to 1 previous error
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
|
||||
Some errors have detailed explanations: E0225, E0277.
|
||||
For more information about an error, try `rustc --explain E0225`.
|
||||
For more information about this error, try `rustc --explain E0225`.
|
||||
|
|
|
@ -1,11 +1,6 @@
|
|||
trait Trait<const N: Trait = bar> {
|
||||
//~^ ERROR cannot find value `bar` in this scope
|
||||
//~| ERROR cycle detected when computing type of `Trait::N`
|
||||
//~| ERROR the trait `Trait` cannot be made into an object
|
||||
//~| ERROR the trait `Trait` cannot be made into an object
|
||||
//~| ERROR the trait `Trait` cannot be made into an object
|
||||
//~| WARN trait objects without an explicit `dyn` are deprecated [bare_trait_objects]
|
||||
//~| WARN this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021!
|
||||
//~| WARN trait objects without an explicit `dyn` are deprecated [bare_trait_objects]
|
||||
//~| WARN this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021!
|
||||
fn fnc<const N: Trait = u32>(&self) -> Trait {
|
||||
|
@ -13,9 +8,6 @@ trait Trait<const N: Trait = bar> {
|
|||
//~| ERROR expected value, found builtin type `u32`
|
||||
//~| ERROR defaults for const parameters are only allowed in `struct`, `enum`, `type`, or `trait` definitions
|
||||
//~| ERROR associated item referring to unboxed trait object for its own trait
|
||||
//~| ERROR the trait `Trait` cannot be made into an object
|
||||
//~| WARN trait objects without an explicit `dyn` are deprecated [bare_trait_objects]
|
||||
//~| WARN this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021!
|
||||
//~| WARN trait objects without an explicit `dyn` are deprecated [bare_trait_objects]
|
||||
//~| WARN this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021!
|
||||
//~| WARN trait objects without an explicit `dyn` are deprecated [bare_trait_objects]
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
error[E0403]: the name `N` is already used for a generic parameter in this item's generic parameters
|
||||
--> $DIR/ice-hir-wf-check-anon-const-issue-122199.rs:11:18
|
||||
--> $DIR/ice-hir-wf-check-anon-const-issue-122199.rs:6:18
|
||||
|
|
||||
LL | trait Trait<const N: Trait = bar> {
|
||||
| - first use of `N`
|
||||
|
@ -14,13 +14,13 @@ LL | trait Trait<const N: Trait = bar> {
|
|||
| ^^^ not found in this scope
|
||||
|
||||
error[E0423]: expected value, found builtin type `u32`
|
||||
--> $DIR/ice-hir-wf-check-anon-const-issue-122199.rs:11:29
|
||||
--> $DIR/ice-hir-wf-check-anon-const-issue-122199.rs:6:29
|
||||
|
|
||||
LL | fn fnc<const N: Trait = u32>(&self) -> Trait {
|
||||
| ^^^ not a value
|
||||
|
||||
error[E0425]: cannot find value `bar` in this scope
|
||||
--> $DIR/ice-hir-wf-check-anon-const-issue-122199.rs:23:9
|
||||
--> $DIR/ice-hir-wf-check-anon-const-issue-122199.rs:15:9
|
||||
|
|
||||
LL | bar
|
||||
| ^^^ not found in this scope
|
||||
|
@ -53,27 +53,8 @@ LL | trait Trait<const N: Trait = bar> {
|
|||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
= note: see https://rustc-dev-guide.rust-lang.org/overview.html#queries and https://rustc-dev-guide.rust-lang.org/query.html for more information
|
||||
|
||||
error: defaults for const parameters are only allowed in `struct`, `enum`, `type`, or `trait` definitions
|
||||
--> $DIR/ice-hir-wf-check-anon-const-issue-122199.rs:11:12
|
||||
|
|
||||
LL | fn fnc<const N: Trait = u32>(&self) -> Trait {
|
||||
| ^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
warning: trait objects without an explicit `dyn` are deprecated
|
||||
--> $DIR/ice-hir-wf-check-anon-const-issue-122199.rs:11:21
|
||||
|
|
||||
LL | fn fnc<const N: Trait = u32>(&self) -> Trait {
|
||||
| ^^^^^
|
||||
|
|
||||
= warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021!
|
||||
= note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/warnings-promoted-to-error.html>
|
||||
help: if this is a dyn-compatible trait, use `dyn`
|
||||
|
|
||||
LL | fn fnc<const N: dyn Trait = u32>(&self) -> Trait {
|
||||
| +++
|
||||
|
||||
warning: trait objects without an explicit `dyn` are deprecated
|
||||
--> $DIR/ice-hir-wf-check-anon-const-issue-122199.rs:11:44
|
||||
--> $DIR/ice-hir-wf-check-anon-const-issue-122199.rs:6:44
|
||||
|
|
||||
LL | fn fnc<const N: Trait = u32>(&self) -> Trait {
|
||||
| ^^^^^
|
||||
|
@ -85,54 +66,27 @@ help: if this is a dyn-compatible trait, use `dyn`
|
|||
LL | fn fnc<const N: Trait = u32>(&self) -> dyn Trait {
|
||||
| +++
|
||||
|
||||
warning: trait objects without an explicit `dyn` are deprecated
|
||||
--> $DIR/ice-hir-wf-check-anon-const-issue-122199.rs:1:22
|
||||
error: defaults for const parameters are only allowed in `struct`, `enum`, `type`, or `trait` definitions
|
||||
--> $DIR/ice-hir-wf-check-anon-const-issue-122199.rs:6:12
|
||||
|
|
||||
LL | trait Trait<const N: Trait = bar> {
|
||||
| ^^^^^
|
||||
LL | fn fnc<const N: Trait = u32>(&self) -> Trait {
|
||||
| ^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
warning: trait objects without an explicit `dyn` are deprecated
|
||||
--> $DIR/ice-hir-wf-check-anon-const-issue-122199.rs:6:21
|
||||
|
|
||||
LL | fn fnc<const N: Trait = u32>(&self) -> Trait {
|
||||
| ^^^^^
|
||||
|
|
||||
= warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021!
|
||||
= note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/warnings-promoted-to-error.html>
|
||||
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
|
||||
help: if this is a dyn-compatible trait, use `dyn`
|
||||
|
|
||||
LL | trait Trait<const N: dyn Trait = bar> {
|
||||
| +++
|
||||
|
||||
error[E0038]: the trait `Trait` cannot be made into an object
|
||||
--> $DIR/ice-hir-wf-check-anon-const-issue-122199.rs:1:22
|
||||
|
|
||||
LL | trait Trait<const N: Trait = bar> {
|
||||
| ^^^^^ `Trait` cannot be made into an object
|
||||
|
|
||||
note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
|
||||
--> $DIR/ice-hir-wf-check-anon-const-issue-122199.rs:11:8
|
||||
|
|
||||
LL | trait Trait<const N: Trait = bar> {
|
||||
| ----- this trait cannot be made into an object...
|
||||
...
|
||||
LL | fn fnc<const N: Trait = u32>(&self) -> Trait {
|
||||
| ^^^ ...because method `fnc` has generic type parameters
|
||||
= help: consider moving `fnc` to another trait
|
||||
|
||||
error[E0038]: the trait `Trait` cannot be made into an object
|
||||
--> $DIR/ice-hir-wf-check-anon-const-issue-122199.rs:1:13
|
||||
|
|
||||
LL | trait Trait<const N: Trait = bar> {
|
||||
| ^^^^^^^^^^^^^^^^^^^^ `Trait` cannot be made into an object
|
||||
|
|
||||
note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
|
||||
--> $DIR/ice-hir-wf-check-anon-const-issue-122199.rs:11:8
|
||||
|
|
||||
LL | trait Trait<const N: Trait = bar> {
|
||||
| ----- this trait cannot be made into an object...
|
||||
...
|
||||
LL | fn fnc<const N: Trait = u32>(&self) -> Trait {
|
||||
| ^^^ ...because method `fnc` has generic type parameters
|
||||
= help: consider moving `fnc` to another trait
|
||||
LL | fn fnc<const N: dyn Trait = u32>(&self) -> Trait {
|
||||
| +++
|
||||
|
||||
error: associated item referring to unboxed trait object for its own trait
|
||||
--> $DIR/ice-hir-wf-check-anon-const-issue-122199.rs:11:44
|
||||
--> $DIR/ice-hir-wf-check-anon-const-issue-122199.rs:6:44
|
||||
|
|
||||
LL | trait Trait<const N: Trait = bar> {
|
||||
| ----- in this trait
|
||||
|
@ -145,54 +99,7 @@ help: you might have meant to use `Self` to refer to the implementing type
|
|||
LL | fn fnc<const N: Trait = u32>(&self) -> Self {
|
||||
| ~~~~
|
||||
|
||||
warning: trait objects without an explicit `dyn` are deprecated
|
||||
--> $DIR/ice-hir-wf-check-anon-const-issue-122199.rs:11:21
|
||||
|
|
||||
LL | fn fnc<const N: Trait = u32>(&self) -> Trait {
|
||||
| ^^^^^
|
||||
|
|
||||
= warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021!
|
||||
= note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/warnings-promoted-to-error.html>
|
||||
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
|
||||
help: if this is a dyn-compatible trait, use `dyn`
|
||||
|
|
||||
LL | fn fnc<const N: dyn Trait = u32>(&self) -> Trait {
|
||||
| +++
|
||||
error: aborting due to 7 previous errors; 3 warnings emitted
|
||||
|
||||
error[E0038]: the trait `Trait` cannot be made into an object
|
||||
--> $DIR/ice-hir-wf-check-anon-const-issue-122199.rs:11:21
|
||||
|
|
||||
LL | fn fnc<const N: Trait = u32>(&self) -> Trait {
|
||||
| ^^^^^ `Trait` cannot be made into an object
|
||||
|
|
||||
note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
|
||||
--> $DIR/ice-hir-wf-check-anon-const-issue-122199.rs:11:8
|
||||
|
|
||||
LL | trait Trait<const N: Trait = bar> {
|
||||
| ----- this trait cannot be made into an object...
|
||||
...
|
||||
LL | fn fnc<const N: Trait = u32>(&self) -> Trait {
|
||||
| ^^^ ...because method `fnc` has generic type parameters
|
||||
= help: consider moving `fnc` to another trait
|
||||
|
||||
error[E0038]: the trait `Trait` cannot be made into an object
|
||||
--> $DIR/ice-hir-wf-check-anon-const-issue-122199.rs:1:13
|
||||
|
|
||||
LL | trait Trait<const N: Trait = bar> {
|
||||
| ^^^^^^^^^^^^^^^^^^^^ `Trait` cannot be made into an object
|
||||
|
|
||||
note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
|
||||
--> $DIR/ice-hir-wf-check-anon-const-issue-122199.rs:11:8
|
||||
|
|
||||
LL | trait Trait<const N: Trait = bar> {
|
||||
| ----- this trait cannot be made into an object...
|
||||
...
|
||||
LL | fn fnc<const N: Trait = u32>(&self) -> Trait {
|
||||
| ^^^ ...because method `fnc` has generic type parameters
|
||||
= help: consider moving `fnc` to another trait
|
||||
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
|
||||
|
||||
error: aborting due to 11 previous errors; 5 warnings emitted
|
||||
|
||||
Some errors have detailed explanations: E0038, E0391, E0403, E0423, E0425.
|
||||
For more information about an error, try `rustc --explain E0038`.
|
||||
Some errors have detailed explanations: E0391, E0403, E0423, E0425.
|
||||
For more information about an error, try `rustc --explain E0391`.
|
||||
|
|
Loading…
Add table
Reference in a new issue