Auto merge of #133760 - GuillaumeGomez:rollup-2c1y8c3, r=GuillaumeGomez
Rollup of 13 pull requests Successful merges: - #133603 (Eliminate magic numbers from expression precedence) - #133715 (rustdoc-json: Include safety of `static`s) - #133721 (rustdoc-json: Add test for `impl Trait for dyn Trait`) - #133725 (Remove `//@ compare-output-lines-by-subset`) - #133730 (Add pretty-printer parenthesis insertion test) - #133736 (Add `needs-target-has-atomic` directive) - #133739 (Re-add myself to rotation) - #133743 (Fix docs for `<[T]>::as_array`.) - #133744 (Fix typo README.md) - #133745 (Remove static HashSet for default IDs list) - #133749 (mir validator: don't store mir phase) - #133751 (remove `Ty::is_copy_modulo_regions`) - #133757 (`impl Default for EarlyDiagCtxt`) r? `@ghost` `@rustbot` modify labels: rollup
This commit is contained in:
commit
d49be02cf6
54 changed files with 811 additions and 395 deletions
|
@ -39,9 +39,7 @@ pub use crate::format::*;
|
|||
use crate::ptr::P;
|
||||
use crate::token::{self, CommentKind, Delimiter};
|
||||
use crate::tokenstream::{DelimSpan, LazyAttrTokenStream, TokenStream};
|
||||
use crate::util::parser::{
|
||||
AssocOp, PREC_CLOSURE, PREC_JUMP, PREC_PREFIX, PREC_RANGE, PREC_UNAMBIGUOUS,
|
||||
};
|
||||
use crate::util::parser::{AssocOp, ExprPrecedence};
|
||||
|
||||
/// A "Label" is an identifier of some point in sources,
|
||||
/// e.g. in the following code:
|
||||
|
@ -1317,29 +1315,29 @@ impl Expr {
|
|||
Some(P(Ty { kind, id: self.id, span: self.span, tokens: None }))
|
||||
}
|
||||
|
||||
pub fn precedence(&self) -> i8 {
|
||||
pub fn precedence(&self) -> ExprPrecedence {
|
||||
match self.kind {
|
||||
ExprKind::Closure(..) => PREC_CLOSURE,
|
||||
ExprKind::Closure(..) => ExprPrecedence::Closure,
|
||||
|
||||
ExprKind::Break(..)
|
||||
| ExprKind::Continue(..)
|
||||
| ExprKind::Ret(..)
|
||||
| ExprKind::Yield(..)
|
||||
| ExprKind::Yeet(..)
|
||||
| ExprKind::Become(..) => PREC_JUMP,
|
||||
| ExprKind::Become(..) => ExprPrecedence::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,
|
||||
ExprKind::Range(..) => ExprPrecedence::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::Binary(op, ..) => AssocOp::from_ast_binop(op.node).precedence(),
|
||||
ExprKind::Cast(..) => ExprPrecedence::Cast,
|
||||
|
||||
ExprKind::Assign(..) |
|
||||
ExprKind::AssignOp(..) => AssocOp::Assign.precedence() as i8,
|
||||
ExprKind::AssignOp(..) => ExprPrecedence::Assign,
|
||||
|
||||
// Unary, prefix
|
||||
ExprKind::AddrOf(..)
|
||||
|
@ -1348,7 +1346,7 @@ impl Expr {
|
|||
// 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,
|
||||
| ExprKind::Unary(..) => ExprPrecedence::Prefix,
|
||||
|
||||
// Never need parens
|
||||
ExprKind::Array(_)
|
||||
|
@ -1381,7 +1379,7 @@ impl Expr {
|
|||
| ExprKind::Underscore
|
||||
| ExprKind::While(..)
|
||||
| ExprKind::Err(_)
|
||||
| ExprKind::Dummy => PREC_UNAMBIGUOUS,
|
||||
| ExprKind::Dummy => ExprPrecedence::Unambiguous,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -128,21 +128,21 @@ impl AssocOp {
|
|||
}
|
||||
|
||||
/// Gets the precedence of this operator
|
||||
pub fn precedence(&self) -> usize {
|
||||
pub fn precedence(&self) -> ExprPrecedence {
|
||||
use AssocOp::*;
|
||||
match *self {
|
||||
As => 14,
|
||||
Multiply | Divide | Modulus => 13,
|
||||
Add | Subtract => 12,
|
||||
ShiftLeft | ShiftRight => 11,
|
||||
BitAnd => 10,
|
||||
BitXor => 9,
|
||||
BitOr => 8,
|
||||
Less | Greater | LessEqual | GreaterEqual | Equal | NotEqual => 7,
|
||||
LAnd => 6,
|
||||
LOr => 5,
|
||||
DotDot | DotDotEq => 4,
|
||||
Assign | AssignOp(_) => 2,
|
||||
As => ExprPrecedence::Cast,
|
||||
Multiply | Divide | Modulus => ExprPrecedence::Product,
|
||||
Add | Subtract => ExprPrecedence::Sum,
|
||||
ShiftLeft | ShiftRight => ExprPrecedence::Shift,
|
||||
BitAnd => ExprPrecedence::BitAnd,
|
||||
BitXor => ExprPrecedence::BitXor,
|
||||
BitOr => ExprPrecedence::BitOr,
|
||||
Less | Greater | LessEqual | GreaterEqual | Equal | NotEqual => ExprPrecedence::Compare,
|
||||
LAnd => ExprPrecedence::LAnd,
|
||||
LOr => ExprPrecedence::LOr,
|
||||
DotDot | DotDotEq => ExprPrecedence::Range,
|
||||
Assign | AssignOp(_) => ExprPrecedence::Assign,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -229,17 +229,44 @@ impl AssocOp {
|
|||
}
|
||||
}
|
||||
|
||||
pub const PREC_CLOSURE: i8 = -40;
|
||||
pub const PREC_JUMP: i8 = -30;
|
||||
pub const PREC_RANGE: i8 = -10;
|
||||
// The range 2..=14 is reserved for AssocOp binary operator precedences.
|
||||
pub const PREC_PREFIX: i8 = 50;
|
||||
pub const PREC_UNAMBIGUOUS: i8 = 60;
|
||||
pub const PREC_FORCE_PAREN: i8 = 100;
|
||||
#[derive(Clone, Copy, PartialEq, PartialOrd)]
|
||||
pub enum ExprPrecedence {
|
||||
Closure,
|
||||
// return, break, yield
|
||||
Jump,
|
||||
// = += -= *= /= %= &= |= ^= <<= >>=
|
||||
Assign,
|
||||
// .. ..=
|
||||
Range,
|
||||
// ||
|
||||
LOr,
|
||||
// &&
|
||||
LAnd,
|
||||
// == != < > <= >=
|
||||
Compare,
|
||||
// |
|
||||
BitOr,
|
||||
// ^
|
||||
BitXor,
|
||||
// &
|
||||
BitAnd,
|
||||
// << >>
|
||||
Shift,
|
||||
// + -
|
||||
Sum,
|
||||
// * / %
|
||||
Product,
|
||||
// as
|
||||
Cast,
|
||||
// unary - * ! & &mut
|
||||
Prefix,
|
||||
// paths, loops, function calls, array indexing, field expressions, method calls
|
||||
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()
|
||||
pub fn prec_let_scrutinee_needs_par() -> ExprPrecedence {
|
||||
ExprPrecedence::LAnd
|
||||
}
|
||||
|
||||
/// Suppose we have `let _ = e` and the `order` of `e`.
|
||||
|
@ -247,8 +274,8 @@ pub fn prec_let_scrutinee_needs_par() -> usize {
|
|||
///
|
||||
/// Conversely, suppose that we have `(let _ = a) OP b` and `order` is that of `OP`.
|
||||
/// Can we print this as `let _ = a OP b`?
|
||||
pub fn needs_par_as_let_scrutinee(order: i8) -> bool {
|
||||
order <= prec_let_scrutinee_needs_par() as i8
|
||||
pub fn needs_par_as_let_scrutinee(order: ExprPrecedence) -> bool {
|
||||
order <= prec_let_scrutinee_needs_par()
|
||||
}
|
||||
|
||||
/// Expressions that syntactically contain an "exterior" struct literal i.e., not surrounded by any
|
||||
|
|
|
@ -5,7 +5,7 @@ use itertools::{Itertools, Position};
|
|||
use rustc_ast::ptr::P;
|
||||
use rustc_ast::util::classify;
|
||||
use rustc_ast::util::literal::escape_byte_str_symbol;
|
||||
use rustc_ast::util::parser::{self, AssocOp, Fixity};
|
||||
use rustc_ast::util::parser::{self, AssocOp, ExprPrecedence, Fixity};
|
||||
use rustc_ast::{
|
||||
self as ast, BlockCheckMode, FormatAlignment, FormatArgPosition, FormatArgsPiece, FormatCount,
|
||||
FormatDebugHex, FormatSign, FormatTrait, token,
|
||||
|
@ -212,9 +212,9 @@ impl<'a> State<'a> {
|
|||
}
|
||||
|
||||
fn print_expr_call(&mut self, func: &ast::Expr, args: &[P<ast::Expr>], fixup: FixupContext) {
|
||||
let prec = match func.kind {
|
||||
ast::ExprKind::Field(..) => parser::PREC_FORCE_PAREN,
|
||||
_ => parser::PREC_UNAMBIGUOUS,
|
||||
let needs_paren = match func.kind {
|
||||
ast::ExprKind::Field(..) => true,
|
||||
_ => func.precedence() < ExprPrecedence::Unambiguous,
|
||||
};
|
||||
|
||||
// Independent of parenthesization related to precedence, we must
|
||||
|
@ -233,7 +233,7 @@ impl<'a> State<'a> {
|
|||
// because the latter is valid syntax but with the incorrect meaning.
|
||||
// It's a match-expression followed by tuple-expression, not a function
|
||||
// call.
|
||||
self.print_expr_cond_paren(func, func.precedence() < prec, fixup.leftmost_subexpression());
|
||||
self.print_expr_cond_paren(func, needs_paren, fixup.leftmost_subexpression());
|
||||
|
||||
self.print_call_post(args)
|
||||
}
|
||||
|
@ -256,7 +256,7 @@ impl<'a> State<'a> {
|
|||
// a statement containing an expression.
|
||||
self.print_expr_cond_paren(
|
||||
receiver,
|
||||
receiver.precedence() < parser::PREC_UNAMBIGUOUS,
|
||||
receiver.precedence() < ExprPrecedence::Unambiguous,
|
||||
fixup,
|
||||
);
|
||||
|
||||
|
@ -276,21 +276,22 @@ impl<'a> State<'a> {
|
|||
fixup: FixupContext,
|
||||
) {
|
||||
let assoc_op = AssocOp::from_ast_binop(op.node);
|
||||
let prec = assoc_op.precedence() as i8;
|
||||
let fixity = assoc_op.fixity();
|
||||
let binop_prec = assoc_op.precedence();
|
||||
let left_prec = lhs.precedence();
|
||||
let right_prec = rhs.precedence();
|
||||
|
||||
let (left_prec, right_prec) = match fixity {
|
||||
Fixity::Left => (prec, prec + 1),
|
||||
Fixity::Right => (prec + 1, prec),
|
||||
Fixity::None => (prec + 1, prec + 1),
|
||||
let (mut left_needs_paren, right_needs_paren) = match assoc_op.fixity() {
|
||||
Fixity::Left => (left_prec < binop_prec, right_prec <= binop_prec),
|
||||
Fixity::Right => (left_prec <= binop_prec, right_prec < binop_prec),
|
||||
Fixity::None => (left_prec <= binop_prec, right_prec <= binop_prec),
|
||||
};
|
||||
|
||||
let left_prec = match (&lhs.kind, op.node) {
|
||||
match (&lhs.kind, op.node) {
|
||||
// These cases need parens: `x as i32 < y` has the parser thinking that `i32 < y` is
|
||||
// the beginning of a path type. It starts trying to parse `x as (i32 < y ...` instead
|
||||
// of `(x as i32) < ...`. We need to convince it _not_ to do that.
|
||||
(&ast::ExprKind::Cast { .. }, ast::BinOpKind::Lt | ast::BinOpKind::Shl) => {
|
||||
parser::PREC_FORCE_PAREN
|
||||
left_needs_paren = true;
|
||||
}
|
||||
// We are given `(let _ = a) OP b`.
|
||||
//
|
||||
|
@ -300,33 +301,23 @@ impl<'a> State<'a> {
|
|||
// - Otherwise, e.g. when we have `(let a = b) < c` in AST,
|
||||
// parens are required since the parser would interpret `let a = b < c` as
|
||||
// `let a = (b < c)`. To achieve this, we force parens.
|
||||
(&ast::ExprKind::Let { .. }, _) if !parser::needs_par_as_let_scrutinee(prec) => {
|
||||
parser::PREC_FORCE_PAREN
|
||||
(&ast::ExprKind::Let { .. }, _) if !parser::needs_par_as_let_scrutinee(binop_prec) => {
|
||||
left_needs_paren = true;
|
||||
}
|
||||
_ => left_prec,
|
||||
};
|
||||
|
||||
self.print_expr_cond_paren(
|
||||
lhs,
|
||||
lhs.precedence() < left_prec,
|
||||
fixup.leftmost_subexpression(),
|
||||
);
|
||||
_ => {}
|
||||
}
|
||||
|
||||
self.print_expr_cond_paren(lhs, left_needs_paren, fixup.leftmost_subexpression());
|
||||
self.space();
|
||||
self.word_space(op.node.as_str());
|
||||
|
||||
self.print_expr_cond_paren(
|
||||
rhs,
|
||||
rhs.precedence() < right_prec,
|
||||
fixup.subsequent_subexpression(),
|
||||
);
|
||||
self.print_expr_cond_paren(rhs, right_needs_paren, fixup.subsequent_subexpression());
|
||||
}
|
||||
|
||||
fn print_expr_unary(&mut self, op: ast::UnOp, expr: &ast::Expr, fixup: FixupContext) {
|
||||
self.word(op.as_str());
|
||||
self.print_expr_cond_paren(
|
||||
expr,
|
||||
expr.precedence() < parser::PREC_PREFIX,
|
||||
expr.precedence() < ExprPrecedence::Prefix,
|
||||
fixup.subsequent_subexpression(),
|
||||
);
|
||||
}
|
||||
|
@ -348,7 +339,7 @@ impl<'a> State<'a> {
|
|||
}
|
||||
self.print_expr_cond_paren(
|
||||
expr,
|
||||
expr.precedence() < parser::PREC_PREFIX,
|
||||
expr.precedence() < ExprPrecedence::Prefix,
|
||||
fixup.subsequent_subexpression(),
|
||||
);
|
||||
}
|
||||
|
@ -432,10 +423,9 @@ impl<'a> State<'a> {
|
|||
self.print_token_literal(lit, expr.span)
|
||||
}
|
||||
ast::ExprKind::Cast(expr, ty) => {
|
||||
let prec = AssocOp::As.precedence() as i8;
|
||||
self.print_expr_cond_paren(
|
||||
expr,
|
||||
expr.precedence() < prec,
|
||||
expr.precedence() < ExprPrecedence::Cast,
|
||||
fixup.leftmost_subexpression(),
|
||||
);
|
||||
self.space();
|
||||
|
@ -512,7 +502,7 @@ impl<'a> State<'a> {
|
|||
MatchKind::Postfix => {
|
||||
self.print_expr_cond_paren(
|
||||
expr,
|
||||
expr.precedence() < parser::PREC_UNAMBIGUOUS,
|
||||
expr.precedence() < ExprPrecedence::Unambiguous,
|
||||
fixup,
|
||||
);
|
||||
self.word_nbsp(".match");
|
||||
|
@ -576,31 +566,31 @@ impl<'a> State<'a> {
|
|||
ast::ExprKind::Await(expr, _) => {
|
||||
self.print_expr_cond_paren(
|
||||
expr,
|
||||
expr.precedence() < parser::PREC_UNAMBIGUOUS,
|
||||
expr.precedence() < ExprPrecedence::Unambiguous,
|
||||
fixup,
|
||||
);
|
||||
self.word(".await");
|
||||
}
|
||||
ast::ExprKind::Assign(lhs, rhs, _) => {
|
||||
let prec = AssocOp::Assign.precedence() as i8;
|
||||
self.print_expr_cond_paren(
|
||||
lhs,
|
||||
lhs.precedence() <= prec,
|
||||
// Ranges are allowed on the right-hand side of assignment,
|
||||
// but not the left. `(a..b) = c` needs parentheses.
|
||||
lhs.precedence() <= ExprPrecedence::Range,
|
||||
fixup.leftmost_subexpression(),
|
||||
);
|
||||
self.space();
|
||||
self.word_space("=");
|
||||
self.print_expr_cond_paren(
|
||||
rhs,
|
||||
rhs.precedence() < prec,
|
||||
rhs.precedence() < ExprPrecedence::Assign,
|
||||
fixup.subsequent_subexpression(),
|
||||
);
|
||||
}
|
||||
ast::ExprKind::AssignOp(op, lhs, rhs) => {
|
||||
let prec = AssocOp::Assign.precedence() as i8;
|
||||
self.print_expr_cond_paren(
|
||||
lhs,
|
||||
lhs.precedence() <= prec,
|
||||
lhs.precedence() <= ExprPrecedence::Range,
|
||||
fixup.leftmost_subexpression(),
|
||||
);
|
||||
self.space();
|
||||
|
@ -608,14 +598,14 @@ impl<'a> State<'a> {
|
|||
self.word_space("=");
|
||||
self.print_expr_cond_paren(
|
||||
rhs,
|
||||
rhs.precedence() < prec,
|
||||
rhs.precedence() < ExprPrecedence::Assign,
|
||||
fixup.subsequent_subexpression(),
|
||||
);
|
||||
}
|
||||
ast::ExprKind::Field(expr, ident) => {
|
||||
self.print_expr_cond_paren(
|
||||
expr,
|
||||
expr.precedence() < parser::PREC_UNAMBIGUOUS,
|
||||
expr.precedence() < ExprPrecedence::Unambiguous,
|
||||
fixup,
|
||||
);
|
||||
self.word(".");
|
||||
|
@ -624,7 +614,7 @@ impl<'a> State<'a> {
|
|||
ast::ExprKind::Index(expr, index, _) => {
|
||||
self.print_expr_cond_paren(
|
||||
expr,
|
||||
expr.precedence() < parser::PREC_UNAMBIGUOUS,
|
||||
expr.precedence() < ExprPrecedence::Unambiguous,
|
||||
fixup.leftmost_subexpression(),
|
||||
);
|
||||
self.word("[");
|
||||
|
@ -636,7 +626,7 @@ impl<'a> State<'a> {
|
|||
// than `Assign`, but `x .. x = x` gives a parse error instead of `x .. (x = x)`.
|
||||
// Here we use a fake precedence value so that any child with lower precedence than
|
||||
// a "normal" binop gets parenthesized. (`LOr` is the lowest-precedence binop.)
|
||||
let fake_prec = AssocOp::LOr.precedence() as i8;
|
||||
let fake_prec = ExprPrecedence::LOr;
|
||||
if let Some(e) = start {
|
||||
self.print_expr_cond_paren(
|
||||
e,
|
||||
|
@ -671,7 +661,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() < parser::PREC_JUMP
|
||||
expr.precedence() < ExprPrecedence::Jump
|
||||
|| (opt_label.is_none() && classify::leading_labeled_expr(expr)),
|
||||
fixup.subsequent_subexpression(),
|
||||
);
|
||||
|
@ -690,7 +680,7 @@ impl<'a> State<'a> {
|
|||
self.word(" ");
|
||||
self.print_expr_cond_paren(
|
||||
expr,
|
||||
expr.precedence() < parser::PREC_JUMP,
|
||||
expr.precedence() < ExprPrecedence::Jump,
|
||||
fixup.subsequent_subexpression(),
|
||||
);
|
||||
}
|
||||
|
@ -703,7 +693,7 @@ impl<'a> State<'a> {
|
|||
self.word(" ");
|
||||
self.print_expr_cond_paren(
|
||||
expr,
|
||||
expr.precedence() < parser::PREC_JUMP,
|
||||
expr.precedence() < ExprPrecedence::Jump,
|
||||
fixup.subsequent_subexpression(),
|
||||
);
|
||||
}
|
||||
|
@ -713,7 +703,7 @@ impl<'a> State<'a> {
|
|||
self.word(" ");
|
||||
self.print_expr_cond_paren(
|
||||
result,
|
||||
result.precedence() < parser::PREC_JUMP,
|
||||
result.precedence() < ExprPrecedence::Jump,
|
||||
fixup.subsequent_subexpression(),
|
||||
);
|
||||
}
|
||||
|
@ -767,13 +757,13 @@ impl<'a> State<'a> {
|
|||
self.space();
|
||||
self.print_expr_cond_paren(
|
||||
expr,
|
||||
expr.precedence() < parser::PREC_JUMP,
|
||||
expr.precedence() < ExprPrecedence::Jump,
|
||||
fixup.subsequent_subexpression(),
|
||||
);
|
||||
}
|
||||
}
|
||||
ast::ExprKind::Try(e) => {
|
||||
self.print_expr_cond_paren(e, e.precedence() < parser::PREC_UNAMBIGUOUS, fixup);
|
||||
self.print_expr_cond_paren(e, e.precedence() < ExprPrecedence::Unambiguous, fixup);
|
||||
self.word("?")
|
||||
}
|
||||
ast::ExprKind::TryBlock(blk) => {
|
||||
|
|
|
@ -6,6 +6,7 @@ use std::path::{Path, PathBuf};
|
|||
use std::process::ExitStatus;
|
||||
|
||||
use rustc_abi::TargetDataLayoutErrors;
|
||||
use rustc_ast::util::parser::ExprPrecedence;
|
||||
use rustc_ast_pretty::pprust;
|
||||
use rustc_macros::Subdiagnostic;
|
||||
use rustc_span::Span;
|
||||
|
@ -298,6 +299,12 @@ impl IntoDiagArg for hir::def::Namespace {
|
|||
}
|
||||
}
|
||||
|
||||
impl IntoDiagArg for ExprPrecedence {
|
||||
fn into_diag_arg(self) -> DiagArgValue {
|
||||
DiagArgValue::Number(self as i32)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct DiagSymbolList<S = Symbol>(Vec<S>);
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
use std::fmt;
|
||||
|
||||
use rustc_abi::ExternAbi;
|
||||
use rustc_ast::util::parser::{AssocOp, PREC_CLOSURE, PREC_JUMP, PREC_PREFIX, PREC_UNAMBIGUOUS};
|
||||
use rustc_ast::util::parser::{AssocOp, ExprPrecedence};
|
||||
use rustc_ast::{
|
||||
self as ast, Attribute, FloatTy, InlineAsmOptions, InlineAsmTemplatePiece, IntTy, Label,
|
||||
LitKind, TraitObjectSyntax, UintTy,
|
||||
|
@ -1695,22 +1695,22 @@ pub struct Expr<'hir> {
|
|||
}
|
||||
|
||||
impl Expr<'_> {
|
||||
pub fn precedence(&self) -> i8 {
|
||||
pub fn precedence(&self) -> ExprPrecedence {
|
||||
match self.kind {
|
||||
ExprKind::Closure { .. } => PREC_CLOSURE,
|
||||
ExprKind::Closure { .. } => ExprPrecedence::Closure,
|
||||
|
||||
ExprKind::Break(..)
|
||||
| ExprKind::Continue(..)
|
||||
| ExprKind::Ret(..)
|
||||
| ExprKind::Yield(..)
|
||||
| ExprKind::Become(..) => PREC_JUMP,
|
||||
| ExprKind::Become(..) => ExprPrecedence::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::Binary(op, ..) => AssocOp::from_ast_binop(op.node).precedence(),
|
||||
ExprKind::Cast(..) => ExprPrecedence::Cast,
|
||||
|
||||
ExprKind::Assign(..) |
|
||||
ExprKind::AssignOp(..) => AssocOp::Assign.precedence() as i8,
|
||||
ExprKind::AssignOp(..) => ExprPrecedence::Assign,
|
||||
|
||||
// Unary, prefix
|
||||
ExprKind::AddrOf(..)
|
||||
|
@ -1719,7 +1719,7 @@ impl Expr<'_> {
|
|||
// 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,
|
||||
| ExprKind::Unary(..) => ExprPrecedence::Prefix,
|
||||
|
||||
// Never need parens
|
||||
ExprKind::Array(_)
|
||||
|
@ -1740,7 +1740,7 @@ impl Expr<'_> {
|
|||
| ExprKind::Struct(..)
|
||||
| ExprKind::Tup(_)
|
||||
| ExprKind::Type(..)
|
||||
| ExprKind::Err(_) => PREC_UNAMBIGUOUS,
|
||||
| ExprKind::Err(_) => ExprPrecedence::Unambiguous,
|
||||
|
||||
ExprKind::DropTemps(ref expr, ..) => expr.precedence(),
|
||||
}
|
||||
|
|
|
@ -103,7 +103,7 @@ fn allowed_union_or_unsafe_field<'tcx>(
|
|||
// Fallback case: allow `ManuallyDrop` and things that are `Copy`,
|
||||
// also no need to report an error if the type is unresolved.
|
||||
ty.ty_adt_def().is_some_and(|adt_def| adt_def.is_manually_drop())
|
||||
|| ty.is_copy_modulo_regions(tcx, typing_env)
|
||||
|| tcx.type_is_copy_modulo_regions(typing_env, ty)
|
||||
|| ty.references_error()
|
||||
}
|
||||
};
|
||||
|
|
|
@ -178,7 +178,7 @@ impl<'a, 'tcx> InlineAsmCtxt<'a, 'tcx> {
|
|||
|
||||
// Check that the type implements Copy. The only case where this can
|
||||
// possibly fail is for SIMD types which don't #[derive(Copy)].
|
||||
if !ty.is_copy_modulo_regions(self.tcx, self.typing_env) {
|
||||
if !self.tcx.type_is_copy_modulo_regions(self.typing_env, ty) {
|
||||
let msg = "arguments for inline assembly must be copyable";
|
||||
self.tcx
|
||||
.dcx()
|
||||
|
|
|
@ -10,7 +10,7 @@ use std::cell::Cell;
|
|||
use std::vec;
|
||||
|
||||
use rustc_abi::ExternAbi;
|
||||
use rustc_ast::util::parser::{self, AssocOp, Fixity};
|
||||
use rustc_ast::util::parser::{self, AssocOp, ExprPrecedence, Fixity};
|
||||
use rustc_ast_pretty::pp::Breaks::{Consistent, Inconsistent};
|
||||
use rustc_ast_pretty::pp::{self, Breaks};
|
||||
use rustc_ast_pretty::pprust::{Comments, PrintState};
|
||||
|
@ -1125,12 +1125,12 @@ impl<'a> State<'a> {
|
|||
}
|
||||
|
||||
fn print_expr_call(&mut self, func: &hir::Expr<'_>, args: &[hir::Expr<'_>]) {
|
||||
let prec = match func.kind {
|
||||
hir::ExprKind::Field(..) => parser::PREC_FORCE_PAREN,
|
||||
_ => parser::PREC_UNAMBIGUOUS,
|
||||
let needs_paren = match func.kind {
|
||||
hir::ExprKind::Field(..) => true,
|
||||
_ => func.precedence() < ExprPrecedence::Unambiguous,
|
||||
};
|
||||
|
||||
self.print_expr_cond_paren(func, func.precedence() < prec);
|
||||
self.print_expr_cond_paren(func, needs_paren);
|
||||
self.print_call_post(args)
|
||||
}
|
||||
|
||||
|
@ -1141,7 +1141,7 @@ impl<'a> State<'a> {
|
|||
args: &[hir::Expr<'_>],
|
||||
) {
|
||||
let base_args = args;
|
||||
self.print_expr_cond_paren(receiver, receiver.precedence() < parser::PREC_UNAMBIGUOUS);
|
||||
self.print_expr_cond_paren(receiver, receiver.precedence() < ExprPrecedence::Unambiguous);
|
||||
self.word(".");
|
||||
self.print_ident(segment.ident);
|
||||
|
||||
|
@ -1155,37 +1155,38 @@ impl<'a> State<'a> {
|
|||
|
||||
fn print_expr_binary(&mut self, op: hir::BinOp, lhs: &hir::Expr<'_>, rhs: &hir::Expr<'_>) {
|
||||
let assoc_op = AssocOp::from_ast_binop(op.node);
|
||||
let prec = assoc_op.precedence() as i8;
|
||||
let fixity = assoc_op.fixity();
|
||||
let binop_prec = assoc_op.precedence();
|
||||
let left_prec = lhs.precedence();
|
||||
let right_prec = rhs.precedence();
|
||||
|
||||
let (left_prec, right_prec) = match fixity {
|
||||
Fixity::Left => (prec, prec + 1),
|
||||
Fixity::Right => (prec + 1, prec),
|
||||
Fixity::None => (prec + 1, prec + 1),
|
||||
let (mut left_needs_paren, right_needs_paren) = match assoc_op.fixity() {
|
||||
Fixity::Left => (left_prec < binop_prec, right_prec <= binop_prec),
|
||||
Fixity::Right => (left_prec <= binop_prec, right_prec < binop_prec),
|
||||
Fixity::None => (left_prec <= binop_prec, right_prec <= binop_prec),
|
||||
};
|
||||
|
||||
let left_prec = match (&lhs.kind, op.node) {
|
||||
match (&lhs.kind, op.node) {
|
||||
// These cases need parens: `x as i32 < y` has the parser thinking that `i32 < y` is
|
||||
// the beginning of a path type. It starts trying to parse `x as (i32 < y ...` instead
|
||||
// of `(x as i32) < ...`. We need to convince it _not_ to do that.
|
||||
(&hir::ExprKind::Cast { .. }, hir::BinOpKind::Lt | hir::BinOpKind::Shl) => {
|
||||
parser::PREC_FORCE_PAREN
|
||||
left_needs_paren = true;
|
||||
}
|
||||
(&hir::ExprKind::Let { .. }, _) if !parser::needs_par_as_let_scrutinee(prec) => {
|
||||
parser::PREC_FORCE_PAREN
|
||||
(&hir::ExprKind::Let { .. }, _) if !parser::needs_par_as_let_scrutinee(binop_prec) => {
|
||||
left_needs_paren = true;
|
||||
}
|
||||
_ => left_prec,
|
||||
};
|
||||
_ => {}
|
||||
}
|
||||
|
||||
self.print_expr_cond_paren(lhs, lhs.precedence() < left_prec);
|
||||
self.print_expr_cond_paren(lhs, left_needs_paren);
|
||||
self.space();
|
||||
self.word_space(op.node.as_str());
|
||||
self.print_expr_cond_paren(rhs, rhs.precedence() < right_prec)
|
||||
self.print_expr_cond_paren(rhs, right_needs_paren);
|
||||
}
|
||||
|
||||
fn print_expr_unary(&mut self, op: hir::UnOp, expr: &hir::Expr<'_>) {
|
||||
self.word(op.as_str());
|
||||
self.print_expr_cond_paren(expr, expr.precedence() < parser::PREC_PREFIX)
|
||||
self.print_expr_cond_paren(expr, expr.precedence() < ExprPrecedence::Prefix);
|
||||
}
|
||||
|
||||
fn print_expr_addr_of(
|
||||
|
@ -1202,7 +1203,7 @@ impl<'a> State<'a> {
|
|||
self.print_mutability(mutability, true);
|
||||
}
|
||||
}
|
||||
self.print_expr_cond_paren(expr, expr.precedence() < parser::PREC_PREFIX)
|
||||
self.print_expr_cond_paren(expr, expr.precedence() < ExprPrecedence::Prefix);
|
||||
}
|
||||
|
||||
fn print_literal(&mut self, lit: &hir::Lit) {
|
||||
|
@ -1340,8 +1341,7 @@ impl<'a> State<'a> {
|
|||
self.print_literal(lit);
|
||||
}
|
||||
hir::ExprKind::Cast(expr, ty) => {
|
||||
let prec = AssocOp::As.precedence() as i8;
|
||||
self.print_expr_cond_paren(expr, expr.precedence() < prec);
|
||||
self.print_expr_cond_paren(expr, expr.precedence() < ExprPrecedence::Cast);
|
||||
self.space();
|
||||
self.word_space("as");
|
||||
self.print_type(ty);
|
||||
|
@ -1442,27 +1442,25 @@ impl<'a> State<'a> {
|
|||
self.print_block(blk);
|
||||
}
|
||||
hir::ExprKind::Assign(lhs, rhs, _) => {
|
||||
let prec = AssocOp::Assign.precedence() as i8;
|
||||
self.print_expr_cond_paren(lhs, lhs.precedence() <= prec);
|
||||
self.print_expr_cond_paren(lhs, lhs.precedence() <= ExprPrecedence::Assign);
|
||||
self.space();
|
||||
self.word_space("=");
|
||||
self.print_expr_cond_paren(rhs, rhs.precedence() < prec);
|
||||
self.print_expr_cond_paren(rhs, rhs.precedence() < ExprPrecedence::Assign);
|
||||
}
|
||||
hir::ExprKind::AssignOp(op, lhs, rhs) => {
|
||||
let prec = AssocOp::Assign.precedence() as i8;
|
||||
self.print_expr_cond_paren(lhs, lhs.precedence() <= prec);
|
||||
self.print_expr_cond_paren(lhs, lhs.precedence() <= ExprPrecedence::Assign);
|
||||
self.space();
|
||||
self.word(op.node.as_str());
|
||||
self.word_space("=");
|
||||
self.print_expr_cond_paren(rhs, rhs.precedence() < prec);
|
||||
self.print_expr_cond_paren(rhs, rhs.precedence() < ExprPrecedence::Assign);
|
||||
}
|
||||
hir::ExprKind::Field(expr, ident) => {
|
||||
self.print_expr_cond_paren(expr, expr.precedence() < parser::PREC_UNAMBIGUOUS);
|
||||
self.print_expr_cond_paren(expr, expr.precedence() < ExprPrecedence::Unambiguous);
|
||||
self.word(".");
|
||||
self.print_ident(ident);
|
||||
}
|
||||
hir::ExprKind::Index(expr, index, _) => {
|
||||
self.print_expr_cond_paren(expr, expr.precedence() < parser::PREC_UNAMBIGUOUS);
|
||||
self.print_expr_cond_paren(expr, expr.precedence() < ExprPrecedence::Unambiguous);
|
||||
self.word("[");
|
||||
self.print_expr(index);
|
||||
self.word("]");
|
||||
|
@ -1476,7 +1474,7 @@ impl<'a> State<'a> {
|
|||
}
|
||||
if let Some(expr) = opt_expr {
|
||||
self.space();
|
||||
self.print_expr_cond_paren(expr, expr.precedence() < parser::PREC_JUMP);
|
||||
self.print_expr_cond_paren(expr, expr.precedence() < ExprPrecedence::Jump);
|
||||
}
|
||||
}
|
||||
hir::ExprKind::Continue(destination) => {
|
||||
|
@ -1490,13 +1488,13 @@ impl<'a> State<'a> {
|
|||
self.word("return");
|
||||
if let Some(expr) = result {
|
||||
self.word(" ");
|
||||
self.print_expr_cond_paren(expr, expr.precedence() < parser::PREC_JUMP);
|
||||
self.print_expr_cond_paren(expr, expr.precedence() < ExprPrecedence::Jump);
|
||||
}
|
||||
}
|
||||
hir::ExprKind::Become(result) => {
|
||||
self.word("become");
|
||||
self.word(" ");
|
||||
self.print_expr_cond_paren(result, result.precedence() < parser::PREC_JUMP);
|
||||
self.print_expr_cond_paren(result, result.precedence() < ExprPrecedence::Jump);
|
||||
}
|
||||
hir::ExprKind::InlineAsm(asm) => {
|
||||
self.word("asm!");
|
||||
|
@ -1521,7 +1519,7 @@ impl<'a> State<'a> {
|
|||
}
|
||||
hir::ExprKind::Yield(expr, _) => {
|
||||
self.word_space("yield");
|
||||
self.print_expr_cond_paren(expr, expr.precedence() < parser::PREC_JUMP);
|
||||
self.print_expr_cond_paren(expr, expr.precedence() < ExprPrecedence::Jump);
|
||||
}
|
||||
hir::ExprKind::Err(_) => {
|
||||
self.popen();
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
use std::iter;
|
||||
|
||||
use rustc_ast::util::parser::PREC_UNAMBIGUOUS;
|
||||
use rustc_ast::util::parser::ExprPrecedence;
|
||||
use rustc_errors::{Applicability, Diag, ErrorGuaranteed, StashKey};
|
||||
use rustc_hir::def::{self, CtorKind, Namespace, Res};
|
||||
use rustc_hir::def_id::DefId;
|
||||
|
@ -606,7 +606,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
};
|
||||
|
||||
if let Ok(rest_snippet) = rest_snippet {
|
||||
let sugg = if callee_expr.precedence() >= PREC_UNAMBIGUOUS {
|
||||
let sugg = if callee_expr.precedence() >= ExprPrecedence::Unambiguous {
|
||||
vec![
|
||||
(up_to_rcvr_span, "".to_string()),
|
||||
(rest_span, format!(".{}({rest_snippet}", segment.ident)),
|
||||
|
|
|
@ -28,6 +28,7 @@
|
|||
//! expression, `e as U2` is not necessarily so (in fact it will only be valid if
|
||||
//! `U1` coerces to `U2`).
|
||||
|
||||
use rustc_ast::util::parser::ExprPrecedence;
|
||||
use rustc_data_structures::fx::FxHashSet;
|
||||
use rustc_errors::codes::*;
|
||||
use rustc_errors::{Applicability, Diag, ErrorGuaranteed};
|
||||
|
@ -1108,7 +1109,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();
|
||||
let needs_parens = expr_prec < rustc_ast::util::parser::PREC_UNAMBIGUOUS;
|
||||
let needs_parens = expr_prec < ExprPrecedence::Unambiguous;
|
||||
|
||||
let needs_cast = !matches!(t_c, ty::cast::IntTy::U(ty::UintTy::Usize));
|
||||
let cast_span = self.expr_span.shrink_to_hi().to(self.cast_span);
|
||||
|
|
|
@ -228,7 +228,7 @@ impl<'tcx> TypeInformationCtxt<'tcx> for (&LateContext<'tcx>, LocalDefId) {
|
|||
}
|
||||
|
||||
fn type_is_copy_modulo_regions(&self, ty: Ty<'tcx>) -> bool {
|
||||
ty.is_copy_modulo_regions(self.0.tcx, self.0.typing_env())
|
||||
self.0.type_is_copy_modulo_regions(ty)
|
||||
}
|
||||
|
||||
fn body_owner_def_id(&self) -> LocalDefId {
|
||||
|
|
|
@ -2,7 +2,7 @@ use core::cmp::min;
|
|||
use core::iter;
|
||||
|
||||
use hir::def_id::LocalDefId;
|
||||
use rustc_ast::util::parser::PREC_UNAMBIGUOUS;
|
||||
use rustc_ast::util::parser::ExprPrecedence;
|
||||
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() < PREC_UNAMBIGUOUS {
|
||||
} else if expr.precedence() < ExprPrecedence::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() >= PREC_UNAMBIGUOUS {
|
||||
let mut sugg = if expr.precedence() >= ExprPrecedence::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() < PREC_UNAMBIGUOUS {
|
||||
let close_paren = if expr.precedence() < ExprPrecedence::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() < PREC_UNAMBIGUOUS {
|
||||
if expr.precedence() < ExprPrecedence::Unambiguous {
|
||||
// Readd `)`
|
||||
format!("{expected_ty})")
|
||||
} else {
|
||||
|
|
|
@ -586,7 +586,7 @@ impl<'tcx> LateLintPass<'tcx> for MissingCopyImplementations {
|
|||
return;
|
||||
}
|
||||
}
|
||||
if ty.is_copy_modulo_regions(cx.tcx, cx.typing_env()) {
|
||||
if cx.type_is_copy_modulo_regions(ty) {
|
||||
return;
|
||||
}
|
||||
if type_implements_negative_copy_modulo_regions(cx.tcx, ty, cx.typing_env()) {
|
||||
|
|
|
@ -710,6 +710,10 @@ impl<'tcx> LateContext<'tcx> {
|
|||
TypingEnv { typing_mode: self.typing_mode(), param_env: self.param_env }
|
||||
}
|
||||
|
||||
pub fn type_is_copy_modulo_regions(&self, ty: Ty<'tcx>) -> bool {
|
||||
self.tcx.type_is_copy_modulo_regions(self.typing_env(), ty)
|
||||
}
|
||||
|
||||
/// Gets the type-checking results for the current body,
|
||||
/// or `None` if outside a body.
|
||||
pub fn maybe_typeck_results(&self) -> Option<&'tcx ty::TypeckResults<'tcx>> {
|
||||
|
|
|
@ -144,7 +144,7 @@ impl<'tcx> LateLintPass<'tcx> for DropForgetUseless {
|
|||
&& let Some(fn_name) = cx.tcx.get_diagnostic_name(def_id)
|
||||
{
|
||||
let arg_ty = cx.typeck_results().expr_ty(arg);
|
||||
let is_copy = arg_ty.is_copy_modulo_regions(cx.tcx, cx.typing_env());
|
||||
let is_copy = cx.type_is_copy_modulo_regions(arg_ty);
|
||||
let drop_is_single_call_in_arm = is_single_call_in_arm(cx, arg, expr);
|
||||
let let_underscore_ignore_sugg = || {
|
||||
if let Some((_, node)) = cx.tcx.hir().parent_iter(expr.hir_id).nth(0)
|
||||
|
|
|
@ -242,17 +242,10 @@ fn is_ty_or_ty_ctxt(cx: &LateContext<'_>, path: &Path<'_>) -> Option<String> {
|
|||
}
|
||||
// Only lint on `&Ty` and `&TyCtxt` if it is used outside of a trait.
|
||||
Res::SelfTyAlias { alias_to: did, is_trait_impl: false, .. } => {
|
||||
if let ty::Adt(adt, args) = cx.tcx.type_of(did).instantiate_identity().kind() {
|
||||
if let Some(name @ (sym::Ty | sym::TyCtxt)) = cx.tcx.get_diagnostic_name(adt.did())
|
||||
{
|
||||
// NOTE: This path is currently unreachable as `Ty<'tcx>` is
|
||||
// defined as a type alias meaning that `impl<'tcx> Ty<'tcx>`
|
||||
// is not actually allowed.
|
||||
//
|
||||
// I(@lcnr) still kept this branch in so we don't miss this
|
||||
// if we ever change it in the future.
|
||||
return Some(format!("{}<{}>", name, args[0]));
|
||||
}
|
||||
if let ty::Adt(adt, args) = cx.tcx.type_of(did).instantiate_identity().kind()
|
||||
&& let Some(name @ (sym::Ty | sym::TyCtxt)) = cx.tcx.get_diagnostic_name(adt.did())
|
||||
{
|
||||
return Some(format!("{}<{}>", name, args[0]));
|
||||
}
|
||||
}
|
||||
_ => (),
|
||||
|
|
|
@ -172,6 +172,24 @@ impl<'tcx> TyCtxt<'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
/// Checks whether `ty: Copy` holds while ignoring region constraints.
|
||||
///
|
||||
/// This impacts whether values of `ty` are *moved* or *copied*
|
||||
/// when referenced. This means that we may generate MIR which
|
||||
/// does copies even when the type actually doesn't satisfy the
|
||||
/// full requirements for the `Copy` trait (cc #29149) -- this
|
||||
/// winds up being reported as an error during NLL borrow check.
|
||||
///
|
||||
/// This function should not be used if there is an `InferCtxt` available.
|
||||
/// Use `InferCtxt::type_is_copy_modulo_regions` instead.
|
||||
pub fn type_is_copy_modulo_regions(
|
||||
self,
|
||||
typing_env: ty::TypingEnv<'tcx>,
|
||||
ty: Ty<'tcx>,
|
||||
) -> bool {
|
||||
ty.is_trivially_pure_clone_copy() || self.is_copy_raw(typing_env.as_query_input(ty))
|
||||
}
|
||||
|
||||
/// Returns the deeply last field of nested structures, or the same type if
|
||||
/// not a structure at all. Corresponds to the only possible unsized field,
|
||||
/// and its type can be used to determine unsizing strategy.
|
||||
|
@ -1174,21 +1192,6 @@ impl<'tcx> Ty<'tcx> {
|
|||
.map(|(min, _)| ty::Const::from_bits(tcx, min, typing_env, self))
|
||||
}
|
||||
|
||||
/// Checks whether values of this type `T` are *moved* or *copied*
|
||||
/// when referenced -- this amounts to a check for whether `T:
|
||||
/// Copy`, but note that we **don't** consider lifetimes when
|
||||
/// doing this check. This means that we may generate MIR which
|
||||
/// does copies even when the type actually doesn't satisfy the
|
||||
/// full requirements for the `Copy` trait (cc #29149) -- this
|
||||
/// winds up being reported as an error during NLL borrow check.
|
||||
pub fn is_copy_modulo_regions(
|
||||
self,
|
||||
tcx: TyCtxt<'tcx>,
|
||||
typing_env: ty::TypingEnv<'tcx>,
|
||||
) -> bool {
|
||||
self.is_trivially_pure_clone_copy() || tcx.is_copy_raw(typing_env.as_query_input(self))
|
||||
}
|
||||
|
||||
/// Checks whether values of this type `T` have a size known at
|
||||
/// compile time (i.e., whether `T: Sized`). Lifetimes are ignored
|
||||
/// for the purposes of this check, so it can be an
|
||||
|
|
|
@ -176,7 +176,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
|||
let ty = expr.ty;
|
||||
if !ty.is_sized(tcx, this.typing_env()) {
|
||||
// !sized means !copy, so this is an unsized move
|
||||
assert!(!ty.is_copy_modulo_regions(tcx, this.typing_env()));
|
||||
assert!(!tcx.type_is_copy_modulo_regions(this.typing_env(), ty));
|
||||
|
||||
// As described above, detect the case where we are passing a value of unsized
|
||||
// type, and that value is coming from the deref of a box.
|
||||
|
|
|
@ -780,7 +780,7 @@ fn check_borrow_conflicts_in_at_patterns<'tcx>(cx: &MatchVisitor<'_, 'tcx>, pat:
|
|||
return;
|
||||
};
|
||||
|
||||
let is_binding_by_move = |ty: Ty<'tcx>| !ty.is_copy_modulo_regions(cx.tcx, cx.typing_env);
|
||||
let is_binding_by_move = |ty: Ty<'tcx>| !cx.tcx.type_is_copy_modulo_regions(cx.typing_env, ty);
|
||||
|
||||
let sess = cx.tcx.sess;
|
||||
|
||||
|
|
|
@ -220,15 +220,7 @@ impl<'tcx> Inliner<'tcx> {
|
|||
|
||||
// Normally, this shouldn't be required, but trait normalization failure can create a
|
||||
// validation ICE.
|
||||
if !validate_types(
|
||||
self.tcx,
|
||||
MirPhase::Runtime(RuntimePhase::Optimized),
|
||||
self.typing_env,
|
||||
&callee_body,
|
||||
&caller_body,
|
||||
)
|
||||
.is_empty()
|
||||
{
|
||||
if !validate_types(self.tcx, self.typing_env, &callee_body, &caller_body).is_empty() {
|
||||
return Err("failed to validate callee body");
|
||||
}
|
||||
|
||||
|
|
|
@ -292,7 +292,7 @@ fn run_passes_inner<'tcx>(
|
|||
}
|
||||
|
||||
pub(super) fn validate_body<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>, when: String) {
|
||||
validate::Validator { when, mir_phase: body.phase }.run_pass(tcx, body);
|
||||
validate::Validator { when }.run_pass(tcx, body);
|
||||
}
|
||||
|
||||
fn dump_mir_for_pass<'tcx>(tcx: TyCtxt<'tcx>, body: &Body<'tcx>, pass_name: &str, is_after: bool) {
|
||||
|
|
|
@ -29,12 +29,6 @@ enum EdgeKind {
|
|||
pub(super) struct Validator {
|
||||
/// Describes at which point in the pipeline this validation is happening.
|
||||
pub when: String,
|
||||
/// The phase for which we are upholding the dialect. If the given phase forbids a specific
|
||||
/// element, this validator will now emit errors if that specific element is encountered.
|
||||
/// Note that phases that change the dialect cause all *following* phases to check the
|
||||
/// invariants of the new dialect. A phase that changes dialects never checks the new invariants
|
||||
/// itself.
|
||||
pub mir_phase: MirPhase,
|
||||
}
|
||||
|
||||
impl<'tcx> crate::MirPass<'tcx> for Validator {
|
||||
|
@ -46,11 +40,9 @@ impl<'tcx> crate::MirPass<'tcx> for Validator {
|
|||
if matches!(body.source.instance, InstanceKind::Intrinsic(..) | InstanceKind::Virtual(..)) {
|
||||
return;
|
||||
}
|
||||
debug_assert_eq!(self.mir_phase, body.phase);
|
||||
let def_id = body.source.def_id();
|
||||
let mir_phase = body.phase;
|
||||
let typing_env = body.typing_env(tcx);
|
||||
let can_unwind = if mir_phase <= MirPhase::Runtime(RuntimePhase::Initial) {
|
||||
let can_unwind = if body.phase <= MirPhase::Runtime(RuntimePhase::Initial) {
|
||||
// In this case `AbortUnwindingCalls` haven't yet been executed.
|
||||
true
|
||||
} else if !tcx.def_kind(def_id).is_fn_like() {
|
||||
|
@ -64,9 +56,7 @@ impl<'tcx> crate::MirPass<'tcx> for Validator {
|
|||
ty::Coroutine(..) => ExternAbi::Rust,
|
||||
// No need to do MIR validation on error bodies
|
||||
ty::Error(_) => return,
|
||||
_ => {
|
||||
span_bug!(body.span, "unexpected body ty: {:?} phase {:?}", body_ty, mir_phase)
|
||||
}
|
||||
_ => span_bug!(body.span, "unexpected body ty: {body_ty:?}"),
|
||||
};
|
||||
|
||||
ty::layout::fn_can_unwind(tcx, Some(def_id), body_abi)
|
||||
|
@ -76,7 +66,6 @@ impl<'tcx> crate::MirPass<'tcx> for Validator {
|
|||
when: &self.when,
|
||||
body,
|
||||
tcx,
|
||||
mir_phase,
|
||||
unwind_edge_count: 0,
|
||||
reachable_blocks: traversal::reachable_as_bitset(body),
|
||||
value_cache: FxHashSet::default(),
|
||||
|
@ -86,7 +75,7 @@ impl<'tcx> crate::MirPass<'tcx> for Validator {
|
|||
cfg_checker.check_cleanup_control_flow();
|
||||
|
||||
// Also run the TypeChecker.
|
||||
for (location, msg) in validate_types(tcx, self.mir_phase, typing_env, body, body) {
|
||||
for (location, msg) in validate_types(tcx, typing_env, body, body) {
|
||||
cfg_checker.fail(location, msg);
|
||||
}
|
||||
|
||||
|
@ -107,7 +96,6 @@ struct CfgChecker<'a, 'tcx> {
|
|||
when: &'a str,
|
||||
body: &'a Body<'tcx>,
|
||||
tcx: TyCtxt<'tcx>,
|
||||
mir_phase: MirPhase,
|
||||
unwind_edge_count: usize,
|
||||
reachable_blocks: BitSet<BasicBlock>,
|
||||
value_cache: FxHashSet<u128>,
|
||||
|
@ -294,7 +282,7 @@ impl<'a, 'tcx> Visitor<'tcx> for CfgChecker<'a, 'tcx> {
|
|||
fn visit_statement(&mut self, statement: &Statement<'tcx>, location: Location) {
|
||||
match &statement.kind {
|
||||
StatementKind::AscribeUserType(..) => {
|
||||
if self.mir_phase >= MirPhase::Runtime(RuntimePhase::Initial) {
|
||||
if self.body.phase >= MirPhase::Runtime(RuntimePhase::Initial) {
|
||||
self.fail(
|
||||
location,
|
||||
"`AscribeUserType` should have been removed after drop lowering phase",
|
||||
|
@ -302,7 +290,7 @@ impl<'a, 'tcx> Visitor<'tcx> for CfgChecker<'a, 'tcx> {
|
|||
}
|
||||
}
|
||||
StatementKind::FakeRead(..) => {
|
||||
if self.mir_phase >= MirPhase::Runtime(RuntimePhase::Initial) {
|
||||
if self.body.phase >= MirPhase::Runtime(RuntimePhase::Initial) {
|
||||
self.fail(
|
||||
location,
|
||||
"`FakeRead` should have been removed after drop lowering phase",
|
||||
|
@ -310,17 +298,17 @@ impl<'a, 'tcx> Visitor<'tcx> for CfgChecker<'a, 'tcx> {
|
|||
}
|
||||
}
|
||||
StatementKind::SetDiscriminant { .. } => {
|
||||
if self.mir_phase < MirPhase::Runtime(RuntimePhase::Initial) {
|
||||
if self.body.phase < MirPhase::Runtime(RuntimePhase::Initial) {
|
||||
self.fail(location, "`SetDiscriminant`is not allowed until deaggregation");
|
||||
}
|
||||
}
|
||||
StatementKind::Deinit(..) => {
|
||||
if self.mir_phase < MirPhase::Runtime(RuntimePhase::Initial) {
|
||||
if self.body.phase < MirPhase::Runtime(RuntimePhase::Initial) {
|
||||
self.fail(location, "`Deinit`is not allowed until deaggregation");
|
||||
}
|
||||
}
|
||||
StatementKind::Retag(kind, _) => {
|
||||
// FIXME(JakobDegen) The validator should check that `self.mir_phase <
|
||||
// FIXME(JakobDegen) The validator should check that `self.body.phase <
|
||||
// DropsLowered`. However, this causes ICEs with generation of drop shims, which
|
||||
// seem to fail to set their `MirPhase` correctly.
|
||||
if matches!(kind, RetagKind::TwoPhase) {
|
||||
|
@ -328,7 +316,7 @@ impl<'a, 'tcx> Visitor<'tcx> for CfgChecker<'a, 'tcx> {
|
|||
}
|
||||
}
|
||||
StatementKind::Coverage(kind) => {
|
||||
if self.mir_phase >= MirPhase::Analysis(AnalysisPhase::PostCleanup)
|
||||
if self.body.phase >= MirPhase::Analysis(AnalysisPhase::PostCleanup)
|
||||
&& let CoverageKind::BlockMarker { .. } | CoverageKind::SpanMarker { .. } = kind
|
||||
{
|
||||
self.fail(
|
||||
|
@ -391,7 +379,7 @@ impl<'a, 'tcx> Visitor<'tcx> for CfgChecker<'a, 'tcx> {
|
|||
// the return edge from the call. FIXME(tmiasko): Since this is a strictly code
|
||||
// generation concern, the code generation should be responsible for handling
|
||||
// it.
|
||||
if self.mir_phase >= MirPhase::Runtime(RuntimePhase::Optimized)
|
||||
if self.body.phase >= MirPhase::Runtime(RuntimePhase::Optimized)
|
||||
&& self.is_critical_call_edge(target, unwind)
|
||||
{
|
||||
self.fail(
|
||||
|
@ -440,7 +428,7 @@ impl<'a, 'tcx> Visitor<'tcx> for CfgChecker<'a, 'tcx> {
|
|||
if self.body.coroutine.is_none() {
|
||||
self.fail(location, "`Yield` cannot appear outside coroutine bodies");
|
||||
}
|
||||
if self.mir_phase >= MirPhase::Runtime(RuntimePhase::Initial) {
|
||||
if self.body.phase >= MirPhase::Runtime(RuntimePhase::Initial) {
|
||||
self.fail(location, "`Yield` should have been replaced by coroutine lowering");
|
||||
}
|
||||
self.check_edge(location, *resume, EdgeKind::Normal);
|
||||
|
@ -449,7 +437,7 @@ impl<'a, 'tcx> Visitor<'tcx> for CfgChecker<'a, 'tcx> {
|
|||
}
|
||||
}
|
||||
TerminatorKind::FalseEdge { real_target, imaginary_target } => {
|
||||
if self.mir_phase >= MirPhase::Runtime(RuntimePhase::Initial) {
|
||||
if self.body.phase >= MirPhase::Runtime(RuntimePhase::Initial) {
|
||||
self.fail(
|
||||
location,
|
||||
"`FalseEdge` should have been removed after drop elaboration",
|
||||
|
@ -459,7 +447,7 @@ impl<'a, 'tcx> Visitor<'tcx> for CfgChecker<'a, 'tcx> {
|
|||
self.check_edge(location, *imaginary_target, EdgeKind::Normal);
|
||||
}
|
||||
TerminatorKind::FalseUnwind { real_target, unwind } => {
|
||||
if self.mir_phase >= MirPhase::Runtime(RuntimePhase::Initial) {
|
||||
if self.body.phase >= MirPhase::Runtime(RuntimePhase::Initial) {
|
||||
self.fail(
|
||||
location,
|
||||
"`FalseUnwind` should have been removed after drop elaboration",
|
||||
|
@ -478,7 +466,7 @@ impl<'a, 'tcx> Visitor<'tcx> for CfgChecker<'a, 'tcx> {
|
|||
if self.body.coroutine.is_none() {
|
||||
self.fail(location, "`CoroutineDrop` cannot appear outside coroutine bodies");
|
||||
}
|
||||
if self.mir_phase >= MirPhase::Runtime(RuntimePhase::Initial) {
|
||||
if self.body.phase >= MirPhase::Runtime(RuntimePhase::Initial) {
|
||||
self.fail(
|
||||
location,
|
||||
"`CoroutineDrop` should have been replaced by coroutine lowering",
|
||||
|
@ -532,13 +520,11 @@ impl<'a, 'tcx> Visitor<'tcx> for CfgChecker<'a, 'tcx> {
|
|||
/// `optimized_mir` is available.
|
||||
pub(super) fn validate_types<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
mir_phase: MirPhase,
|
||||
typing_env: ty::TypingEnv<'tcx>,
|
||||
body: &Body<'tcx>,
|
||||
caller_body: &Body<'tcx>,
|
||||
) -> Vec<(Location, String)> {
|
||||
let mut type_checker =
|
||||
TypeChecker { body, caller_body, tcx, typing_env, mir_phase, failures: Vec::new() };
|
||||
let mut type_checker = TypeChecker { body, caller_body, tcx, typing_env, failures: Vec::new() };
|
||||
type_checker.visit_body(body);
|
||||
type_checker.failures
|
||||
}
|
||||
|
@ -548,7 +534,6 @@ struct TypeChecker<'a, 'tcx> {
|
|||
caller_body: &'a Body<'tcx>,
|
||||
tcx: TyCtxt<'tcx>,
|
||||
typing_env: ty::TypingEnv<'tcx>,
|
||||
mir_phase: MirPhase,
|
||||
failures: Vec<(Location, String)>,
|
||||
}
|
||||
|
||||
|
@ -577,7 +562,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
|||
|
||||
// After borrowck subtyping should be fully explicit via
|
||||
// `Subtype` projections.
|
||||
let variance = if self.mir_phase >= MirPhase::Runtime(RuntimePhase::Initial) {
|
||||
let variance = if self.body.phase >= MirPhase::Runtime(RuntimePhase::Initial) {
|
||||
Variance::Invariant
|
||||
} else {
|
||||
Variance::Covariant
|
||||
|
@ -618,13 +603,13 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
|
|||
fn visit_operand(&mut self, operand: &Operand<'tcx>, location: Location) {
|
||||
// This check is somewhat expensive, so only run it when -Zvalidate-mir is passed.
|
||||
if self.tcx.sess.opts.unstable_opts.validate_mir
|
||||
&& self.mir_phase < MirPhase::Runtime(RuntimePhase::Initial)
|
||||
&& self.body.phase < MirPhase::Runtime(RuntimePhase::Initial)
|
||||
{
|
||||
// `Operand::Copy` is only supposed to be used with `Copy` types.
|
||||
if let Operand::Copy(place) = operand {
|
||||
let ty = place.ty(&self.body.local_decls, self.tcx).ty;
|
||||
|
||||
if !ty.is_copy_modulo_regions(self.tcx, self.typing_env) {
|
||||
if !self.tcx.type_is_copy_modulo_regions(self.typing_env, ty) {
|
||||
self.fail(location, format!("`Operand::Copy` with non-`Copy` type {ty}"));
|
||||
}
|
||||
}
|
||||
|
@ -642,7 +627,7 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
|
|||
) {
|
||||
match elem {
|
||||
ProjectionElem::OpaqueCast(ty)
|
||||
if self.mir_phase >= MirPhase::Runtime(RuntimePhase::Initial) =>
|
||||
if self.body.phase >= MirPhase::Runtime(RuntimePhase::Initial) =>
|
||||
{
|
||||
self.fail(
|
||||
location,
|
||||
|
@ -656,7 +641,7 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
|
|||
}
|
||||
}
|
||||
ProjectionElem::Deref
|
||||
if self.mir_phase >= MirPhase::Runtime(RuntimePhase::PostCleanup) =>
|
||||
if self.body.phase >= MirPhase::Runtime(RuntimePhase::PostCleanup) =>
|
||||
{
|
||||
let base_ty = place_ref.ty(&self.body.local_decls, self.tcx).ty;
|
||||
|
||||
|
@ -856,7 +841,7 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
|
|||
// Set off any `bug!`s in the type computation code
|
||||
let _ = place.ty(&self.body.local_decls, self.tcx);
|
||||
|
||||
if self.mir_phase >= MirPhase::Runtime(RuntimePhase::Initial)
|
||||
if self.body.phase >= MirPhase::Runtime(RuntimePhase::Initial)
|
||||
&& place.projection.len() > 1
|
||||
&& cntxt != PlaceContext::NonUse(NonUseContext::VarDebugInfo)
|
||||
&& place.projection[1..].contains(&ProjectionElem::Deref)
|
||||
|
@ -974,7 +959,7 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
|
|||
}
|
||||
}
|
||||
AggregateKind::RawPtr(pointee_ty, mutability) => {
|
||||
if !matches!(self.mir_phase, MirPhase::Runtime(_)) {
|
||||
if !matches!(self.body.phase, MirPhase::Runtime(_)) {
|
||||
// It would probably be fine to support this in earlier phases, but at the
|
||||
// time of writing it's only ever introduced from intrinsic lowering, so
|
||||
// earlier things just `bug!` on it.
|
||||
|
@ -1016,7 +1001,7 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
|
|||
}
|
||||
},
|
||||
Rvalue::Ref(_, BorrowKind::Fake(_), _) => {
|
||||
if self.mir_phase >= MirPhase::Runtime(RuntimePhase::Initial) {
|
||||
if self.body.phase >= MirPhase::Runtime(RuntimePhase::Initial) {
|
||||
self.fail(
|
||||
location,
|
||||
"`Assign` statement with a `Fake` borrow should have been removed in runtime MIR",
|
||||
|
@ -1130,7 +1115,7 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
|
|||
);
|
||||
}
|
||||
UnOp::PtrMetadata => {
|
||||
if !matches!(self.mir_phase, MirPhase::Runtime(_)) {
|
||||
if !matches!(self.body.phase, MirPhase::Runtime(_)) {
|
||||
// It would probably be fine to support this in earlier phases, but at
|
||||
// the time of writing it's only ever introduced from intrinsic
|
||||
// lowering or other runtime-phase optimization passes, so earlier
|
||||
|
@ -1206,7 +1191,7 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
|
|||
"CastKind::{kind:?} output must be a raw const pointer, not {:?}",
|
||||
ty::RawPtr(_, Mutability::Not)
|
||||
);
|
||||
if self.mir_phase >= MirPhase::Analysis(AnalysisPhase::PostCleanup) {
|
||||
if self.body.phase >= MirPhase::Analysis(AnalysisPhase::PostCleanup) {
|
||||
self.fail(location, format!("After borrowck, MIR disallows {kind:?}"));
|
||||
}
|
||||
}
|
||||
|
@ -1222,7 +1207,7 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
|
|||
"CastKind::{kind:?} output must be a raw pointer, not {:?}",
|
||||
ty::RawPtr(..)
|
||||
);
|
||||
if self.mir_phase >= MirPhase::Analysis(AnalysisPhase::PostCleanup) {
|
||||
if self.body.phase >= MirPhase::Analysis(AnalysisPhase::PostCleanup) {
|
||||
self.fail(location, format!("After borrowck, MIR disallows {kind:?}"));
|
||||
}
|
||||
}
|
||||
|
@ -1288,7 +1273,7 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
|
|||
}
|
||||
}
|
||||
CastKind::Transmute => {
|
||||
if let MirPhase::Runtime(..) = self.mir_phase {
|
||||
if let MirPhase::Runtime(..) = self.body.phase {
|
||||
// Unlike `mem::transmute`, a MIR `Transmute` is well-formed
|
||||
// for any two `Sized` types, just potentially UB to run.
|
||||
|
||||
|
@ -1317,7 +1302,7 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
|
|||
location,
|
||||
format!(
|
||||
"Transmute is not supported in non-runtime phase {:?}.",
|
||||
self.mir_phase
|
||||
self.body.phase
|
||||
),
|
||||
);
|
||||
}
|
||||
|
@ -1404,7 +1389,7 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
|
|||
}
|
||||
}
|
||||
StatementKind::AscribeUserType(..) => {
|
||||
if self.mir_phase >= MirPhase::Runtime(RuntimePhase::Initial) {
|
||||
if self.body.phase >= MirPhase::Runtime(RuntimePhase::Initial) {
|
||||
self.fail(
|
||||
location,
|
||||
"`AscribeUserType` should have been removed after drop lowering phase",
|
||||
|
@ -1412,7 +1397,7 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
|
|||
}
|
||||
}
|
||||
StatementKind::FakeRead(..) => {
|
||||
if self.mir_phase >= MirPhase::Runtime(RuntimePhase::Initial) {
|
||||
if self.body.phase >= MirPhase::Runtime(RuntimePhase::Initial) {
|
||||
self.fail(
|
||||
location,
|
||||
"`FakeRead` should have been removed after drop lowering phase",
|
||||
|
@ -1463,7 +1448,7 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
|
|||
}
|
||||
}
|
||||
StatementKind::SetDiscriminant { place, .. } => {
|
||||
if self.mir_phase < MirPhase::Runtime(RuntimePhase::Initial) {
|
||||
if self.body.phase < MirPhase::Runtime(RuntimePhase::Initial) {
|
||||
self.fail(location, "`SetDiscriminant`is not allowed until deaggregation");
|
||||
}
|
||||
let pty = place.ty(&self.body.local_decls, self.tcx).ty.kind();
|
||||
|
@ -1477,12 +1462,12 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
|
|||
}
|
||||
}
|
||||
StatementKind::Deinit(..) => {
|
||||
if self.mir_phase < MirPhase::Runtime(RuntimePhase::Initial) {
|
||||
if self.body.phase < MirPhase::Runtime(RuntimePhase::Initial) {
|
||||
self.fail(location, "`Deinit`is not allowed until deaggregation");
|
||||
}
|
||||
}
|
||||
StatementKind::Retag(kind, _) => {
|
||||
// FIXME(JakobDegen) The validator should check that `self.mir_phase <
|
||||
// FIXME(JakobDegen) The validator should check that `self.body.phase <
|
||||
// DropsLowered`. However, this causes ICEs with generation of drop shims, which
|
||||
// seem to fail to set their `MirPhase` correctly.
|
||||
if matches!(kind, RetagKind::TwoPhase) {
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
use std::borrow::Cow;
|
||||
|
||||
use rustc_ast::token::Token;
|
||||
use rustc_ast::util::parser::ExprPrecedence;
|
||||
use rustc_ast::{Path, Visibility};
|
||||
use rustc_errors::codes::*;
|
||||
use rustc_errors::{
|
||||
|
@ -2686,7 +2687,7 @@ pub(crate) struct UnexpectedExpressionInPattern {
|
|||
/// Was a `RangePatternBound` expected?
|
||||
pub is_bound: bool,
|
||||
/// The unexpected expr's precedence (used in match arm guard suggestions).
|
||||
pub expr_precedence: i8,
|
||||
pub expr_precedence: ExprPrecedence,
|
||||
}
|
||||
|
||||
#[derive(Subdiagnostic)]
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
// ignore-tidy-filelength
|
||||
|
||||
use core::mem;
|
||||
use core::ops::ControlFlow;
|
||||
use core::ops::{Bound, ControlFlow};
|
||||
|
||||
use ast::mut_visit::{self, MutVisitor};
|
||||
use ast::token::IdentIsRaw;
|
||||
|
@ -10,7 +10,7 @@ use rustc_ast::ptr::P;
|
|||
use rustc_ast::token::{self, Delimiter, Token, TokenKind};
|
||||
use rustc_ast::util::case::Case;
|
||||
use rustc_ast::util::classify;
|
||||
use rustc_ast::util::parser::{AssocOp, Fixity, prec_let_scrutinee_needs_par};
|
||||
use rustc_ast::util::parser::{AssocOp, ExprPrecedence, Fixity, prec_let_scrutinee_needs_par};
|
||||
use rustc_ast::visit::{Visitor, walk_expr};
|
||||
use rustc_ast::{
|
||||
self as ast, AnonConst, Arm, AttrStyle, AttrVec, BinOp, BinOpKind, BlockCheckMode, CaptureBy,
|
||||
|
@ -120,7 +120,7 @@ impl<'a> Parser<'a> {
|
|||
r: Restrictions,
|
||||
attrs: AttrWrapper,
|
||||
) -> PResult<'a, (P<Expr>, bool)> {
|
||||
self.with_res(r, |this| this.parse_expr_assoc_with(0, attrs))
|
||||
self.with_res(r, |this| this.parse_expr_assoc_with(Bound::Unbounded, attrs))
|
||||
}
|
||||
|
||||
/// Parses an associative expression with operators of at least `min_prec` precedence.
|
||||
|
@ -128,7 +128,7 @@ impl<'a> Parser<'a> {
|
|||
/// followed by a subexpression (e.g. `1 + 2`).
|
||||
pub(super) fn parse_expr_assoc_with(
|
||||
&mut self,
|
||||
min_prec: usize,
|
||||
min_prec: Bound<ExprPrecedence>,
|
||||
attrs: AttrWrapper,
|
||||
) -> PResult<'a, (P<Expr>, bool)> {
|
||||
let lhs = if self.token.is_range_separator() {
|
||||
|
@ -144,7 +144,7 @@ impl<'a> Parser<'a> {
|
|||
/// was actually parsed.
|
||||
pub(super) fn parse_expr_assoc_rest_with(
|
||||
&mut self,
|
||||
min_prec: usize,
|
||||
min_prec: Bound<ExprPrecedence>,
|
||||
starts_stmt: bool,
|
||||
mut lhs: P<Expr>,
|
||||
) -> PResult<'a, (P<Expr>, bool)> {
|
||||
|
@ -163,7 +163,11 @@ impl<'a> Parser<'a> {
|
|||
self.restrictions
|
||||
};
|
||||
let prec = op.node.precedence();
|
||||
if prec < min_prec {
|
||||
if match min_prec {
|
||||
Bound::Included(min_prec) => prec < min_prec,
|
||||
Bound::Excluded(min_prec) => prec <= min_prec,
|
||||
Bound::Unbounded => false,
|
||||
} {
|
||||
break;
|
||||
}
|
||||
// Check for deprecated `...` syntax
|
||||
|
@ -276,16 +280,16 @@ impl<'a> Parser<'a> {
|
|||
}
|
||||
|
||||
let fixity = op.fixity();
|
||||
let prec_adjustment = match fixity {
|
||||
Fixity::Right => 0,
|
||||
Fixity::Left => 1,
|
||||
let min_prec = match fixity {
|
||||
Fixity::Right => Bound::Included(prec),
|
||||
Fixity::Left => Bound::Excluded(prec),
|
||||
// We currently have no non-associative operators that are not handled above by
|
||||
// the special cases. The code is here only for future convenience.
|
||||
Fixity::None => 1,
|
||||
Fixity::None => Bound::Excluded(prec),
|
||||
};
|
||||
let (rhs, _) = self.with_res(restrictions - Restrictions::STMT_EXPR, |this| {
|
||||
let attrs = this.parse_outer_attributes()?;
|
||||
this.parse_expr_assoc_with(prec + prec_adjustment, attrs)
|
||||
this.parse_expr_assoc_with(min_prec, attrs)
|
||||
})?;
|
||||
|
||||
let span = self.mk_expr_sp(&lhs, lhs_span, rhs.span);
|
||||
|
@ -451,7 +455,7 @@ impl<'a> Parser<'a> {
|
|||
/// The other two variants are handled in `parse_prefix_range_expr` below.
|
||||
fn parse_expr_range(
|
||||
&mut self,
|
||||
prec: usize,
|
||||
prec: ExprPrecedence,
|
||||
lhs: P<Expr>,
|
||||
op: AssocOp,
|
||||
cur_op_span: Span,
|
||||
|
@ -460,7 +464,7 @@ impl<'a> Parser<'a> {
|
|||
let maybe_lt = self.token.clone();
|
||||
let attrs = self.parse_outer_attributes()?;
|
||||
Some(
|
||||
self.parse_expr_assoc_with(prec + 1, attrs)
|
||||
self.parse_expr_assoc_with(Bound::Excluded(prec), attrs)
|
||||
.map_err(|err| self.maybe_err_dotdotlt_syntax(maybe_lt, err))?
|
||||
.0,
|
||||
)
|
||||
|
@ -518,7 +522,7 @@ impl<'a> Parser<'a> {
|
|||
let (span, opt_end) = if this.is_at_start_of_range_notation_rhs() {
|
||||
// RHS must be parsed with more associativity than the dots.
|
||||
let attrs = this.parse_outer_attributes()?;
|
||||
this.parse_expr_assoc_with(op.unwrap().precedence() + 1, attrs)
|
||||
this.parse_expr_assoc_with(Bound::Excluded(op.unwrap().precedence()), attrs)
|
||||
.map(|(x, _)| (lo.to(x.span), Some(x)))
|
||||
.map_err(|err| this.maybe_err_dotdotlt_syntax(maybe_lt, err))?
|
||||
} else {
|
||||
|
@ -2643,7 +2647,8 @@ impl<'a> Parser<'a> {
|
|||
self.expect(&token::Eq)?;
|
||||
}
|
||||
let attrs = self.parse_outer_attributes()?;
|
||||
let (expr, _) = self.parse_expr_assoc_with(1 + prec_let_scrutinee_needs_par(), attrs)?;
|
||||
let (expr, _) =
|
||||
self.parse_expr_assoc_with(Bound::Excluded(prec_let_scrutinee_needs_par()), attrs)?;
|
||||
let span = lo.to(expr.span);
|
||||
Ok(self.mk_expr(span, ExprKind::Let(pat, expr, span, recovered)))
|
||||
}
|
||||
|
|
|
@ -1,12 +1,13 @@
|
|||
use std::ops::Bound;
|
||||
|
||||
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::util::parser::ExprPrecedence;
|
||||
use rustc_ast::visit::{self, Visitor};
|
||||
use rustc_ast::{
|
||||
self as ast, Arm, AttrVec, BinOpKind, BindingMode, ByRef, Expr, ExprKind, LocalKind, MacCall,
|
||||
Mutability, Pat, PatField, PatFieldsRest, PatKind, Path, QSelf, RangeEnd, RangeSyntax, Stmt,
|
||||
StmtKind,
|
||||
self as ast, Arm, AttrVec, 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};
|
||||
|
@ -435,8 +436,9 @@ impl<'a> Parser<'a> {
|
|||
|
||||
// Parse an associative expression such as `+ expr`, `% expr`, ...
|
||||
// Assignments, ranges and `|` are disabled by [`Restrictions::IS_PAT`].
|
||||
let Ok((expr, _)) =
|
||||
snapshot.parse_expr_assoc_rest_with(0, false, expr).map_err(|err| err.cancel())
|
||||
let Ok((expr, _)) = snapshot
|
||||
.parse_expr_assoc_rest_with(Bound::Unbounded, false, expr)
|
||||
.map_err(|err| err.cancel())
|
||||
else {
|
||||
// We got a trailing method/operator, but that wasn't an expression.
|
||||
return None;
|
||||
|
@ -545,10 +547,7 @@ impl<'a> Parser<'a> {
|
|||
// HACK: a neater way would be preferable.
|
||||
let expr = match &err.args["expr_precedence"] {
|
||||
DiagArgValue::Number(expr_precedence) => {
|
||||
if *expr_precedence
|
||||
<= AssocOp::from_ast_binop(BinOpKind::Eq).precedence()
|
||||
as i32
|
||||
{
|
||||
if *expr_precedence <= ExprPrecedence::Compare as i32 {
|
||||
format!("({expr})")
|
||||
} else {
|
||||
format!("{expr}")
|
||||
|
@ -570,9 +569,7 @@ impl<'a> Parser<'a> {
|
|||
}
|
||||
Some(guard) => {
|
||||
// Are parentheses required around the old guard?
|
||||
let wrap_guard = guard.precedence()
|
||||
<= AssocOp::from_ast_binop(BinOpKind::And).precedence()
|
||||
as i8;
|
||||
let wrap_guard = guard.precedence() <= ExprPrecedence::LAnd;
|
||||
|
||||
err.subdiagnostic(
|
||||
UnexpectedExpressionInPatternSugg::UpdateGuard {
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
use std::borrow::Cow;
|
||||
use std::mem;
|
||||
use std::ops::Bound;
|
||||
|
||||
use ast::Label;
|
||||
use rustc_ast as ast;
|
||||
|
@ -207,7 +208,7 @@ impl<'a> Parser<'a> {
|
|||
// Perform this outside of the `collect_tokens` closure, since our
|
||||
// outer attributes do not apply to this part of the expression.
|
||||
let (expr, _) = self.with_res(Restrictions::STMT_EXPR, |this| {
|
||||
this.parse_expr_assoc_rest_with(0, true, expr)
|
||||
this.parse_expr_assoc_rest_with(Bound::Unbounded, true, expr)
|
||||
})?;
|
||||
Ok(self.mk_stmt(lo.to(self.prev_token.span), StmtKind::Expr(expr)))
|
||||
} else {
|
||||
|
@ -240,7 +241,7 @@ impl<'a> Parser<'a> {
|
|||
let e = self.mk_expr(lo.to(hi), ExprKind::MacCall(mac));
|
||||
let e = self.maybe_recover_from_bad_qpath(e)?;
|
||||
let e = self.parse_expr_dot_or_call_with(attrs, e, lo)?;
|
||||
let (e, _) = self.parse_expr_assoc_rest_with(0, false, e)?;
|
||||
let (e, _) = self.parse_expr_assoc_rest_with(Bound::Unbounded, false, e)?;
|
||||
StmtKind::Expr(e)
|
||||
};
|
||||
Ok(self.mk_stmt(lo.to(hi), kind))
|
||||
|
|
|
@ -1358,6 +1358,12 @@ pub struct EarlyDiagCtxt {
|
|||
dcx: DiagCtxt,
|
||||
}
|
||||
|
||||
impl Default for EarlyDiagCtxt {
|
||||
fn default() -> Self {
|
||||
Self::new(ErrorOutputType::default())
|
||||
}
|
||||
}
|
||||
|
||||
impl EarlyDiagCtxt {
|
||||
pub fn new(output: ErrorOutputType) -> Self {
|
||||
let emitter = mk_emitter(output);
|
||||
|
|
|
@ -35,7 +35,7 @@ impl<'tcx> InferCtxt<'tcx> {
|
|||
// FIXME(#132279): This should be removed as it causes us to incorrectly
|
||||
// handle opaques in their defining scope.
|
||||
if !(param_env, ty).has_infer() {
|
||||
return ty.is_copy_modulo_regions(self.tcx, self.typing_env(param_env));
|
||||
return self.tcx.type_is_copy_modulo_regions(self.typing_env(param_env), ty);
|
||||
}
|
||||
|
||||
let copy_def_id = self.tcx.require_lang_item(LangItem::Copy, None);
|
||||
|
|
|
@ -202,7 +202,7 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
_ if component.is_copy_modulo_regions(tcx, self.typing_env) => {}
|
||||
_ if tcx.type_is_copy_modulo_regions(self.typing_env, component) => {}
|
||||
|
||||
ty::Closure(_, args) => {
|
||||
for upvar in args.as_closure().upvar_tys() {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue