Revert "Rollup merge of #122661 - estebank:assert-macro-span, r=petrochenkov"
This reverts commit1eeb8e8b15, reversing changes made to324bf2b9fd. Unfortunately the assert desugaring change is not backwards compatible, see RUST-145770. Code such as ```rust #[derive(Debug)] struct F { data: bool } impl std::ops::Not for F { type Output = bool; fn not(self) -> Self::Output { !self.data } } fn main() { let f = F { data: true }; assert!(f); } ``` would be broken by the assert desugaring change. We may need to land the change over an edition boundary, or limit the editions that the desugaring change impacts.
This commit is contained in:
@@ -1,8 +1,8 @@
|
||||
mod context;
|
||||
|
||||
use rustc_ast::token::{self, Delimiter};
|
||||
use rustc_ast::token::Delimiter;
|
||||
use rustc_ast::tokenstream::{DelimSpan, TokenStream};
|
||||
use rustc_ast::{DelimArgs, Expr, ExprKind, MacCall, Path, PathSegment};
|
||||
use rustc_ast::{DelimArgs, Expr, ExprKind, MacCall, Path, PathSegment, UnOp, token};
|
||||
use rustc_ast_pretty::pprust;
|
||||
use rustc_errors::PResult;
|
||||
use rustc_expand::base::{DummyResult, ExpandResult, ExtCtxt, MacEager, MacroExpanderResult};
|
||||
@@ -29,7 +29,7 @@ pub(crate) fn expand_assert<'cx>(
|
||||
|
||||
// `core::panic` and `std::panic` are different macros, so we use call-site
|
||||
// context to pick up whichever is currently in scope.
|
||||
let call_site_span = cx.with_call_site_ctxt(cond_expr.span);
|
||||
let call_site_span = cx.with_call_site_ctxt(span);
|
||||
|
||||
let panic_path = || {
|
||||
if use_panic_2021(span) {
|
||||
@@ -63,7 +63,7 @@ pub(crate) fn expand_assert<'cx>(
|
||||
}),
|
||||
})),
|
||||
);
|
||||
assert_cond_check(cx, call_site_span, cond_expr, then)
|
||||
expr_if_not(cx, call_site_span, cond_expr, then, None)
|
||||
}
|
||||
// If `generic_assert` is enabled, generates rich captured outputs
|
||||
//
|
||||
@@ -88,33 +88,26 @@ pub(crate) fn expand_assert<'cx>(
|
||||
)),
|
||||
)],
|
||||
);
|
||||
assert_cond_check(cx, call_site_span, cond_expr, then)
|
||||
expr_if_not(cx, call_site_span, cond_expr, then, None)
|
||||
};
|
||||
|
||||
ExpandResult::Ready(MacEager::expr(expr))
|
||||
}
|
||||
|
||||
/// `assert!($cond_expr, $custom_message)`
|
||||
struct Assert {
|
||||
cond_expr: Box<Expr>,
|
||||
custom_message: Option<TokenStream>,
|
||||
}
|
||||
|
||||
/// `match <cond> { true => {} _ => <then> }`
|
||||
fn assert_cond_check(cx: &ExtCtxt<'_>, span: Span, cond: Box<Expr>, then: Box<Expr>) -> Box<Expr> {
|
||||
// Instead of expanding to `if !<cond> { <then> }`, we expand to
|
||||
// `match <cond> { true => {} _ => <then> }`.
|
||||
// This allows us to always complain about mismatched types instead of "cannot apply unary
|
||||
// operator `!` to type `X`" when passing an invalid `<cond>`, while also allowing `<cond>` to
|
||||
// be `&true`.
|
||||
let els = cx.expr_block(cx.block(span, thin_vec![]));
|
||||
let mut arms = thin_vec![];
|
||||
arms.push(cx.arm(span, cx.pat_lit(span, cx.expr_bool(span, true)), els));
|
||||
arms.push(cx.arm(span, cx.pat_wild(span), then));
|
||||
|
||||
// We wrap the `match` in a statement to limit the length of any borrows introduced in the
|
||||
// condition.
|
||||
cx.expr_block(cx.block(span, [cx.stmt_expr(cx.expr_match(span, cond, arms))].into()))
|
||||
// if !{ ... } { ... } else { ... }
|
||||
fn expr_if_not(
|
||||
cx: &ExtCtxt<'_>,
|
||||
span: Span,
|
||||
cond: Box<Expr>,
|
||||
then: Box<Expr>,
|
||||
els: Option<Box<Expr>>,
|
||||
) -> Box<Expr> {
|
||||
cx.expr_if(span, cx.expr(span, ExprKind::Unary(UnOp::Not, cond)), then, els)
|
||||
}
|
||||
|
||||
fn parse_assert<'a>(cx: &ExtCtxt<'a>, sp: Span, stream: TokenStream) -> PResult<'a, Assert> {
|
||||
|
||||
@@ -1618,18 +1618,8 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
|
||||
{
|
||||
let e = self.tcx.erase_and_anonymize_regions(e);
|
||||
let f = self.tcx.erase_and_anonymize_regions(f);
|
||||
let mut expected = with_forced_trimmed_paths!(e.sort_string(self.tcx));
|
||||
let mut found = with_forced_trimmed_paths!(f.sort_string(self.tcx));
|
||||
if let ObligationCauseCode::Pattern { span, .. } = cause.code()
|
||||
&& let Some(span) = span
|
||||
&& !span.from_expansion()
|
||||
&& cause.span.from_expansion()
|
||||
{
|
||||
// When the type error comes from a macro like `assert!()`, and we are pointing at
|
||||
// code the user wrote the cause and effect are reversed as the expected value is
|
||||
// what the macro expanded to.
|
||||
(found, expected) = (expected, found);
|
||||
}
|
||||
let expected = with_forced_trimmed_paths!(e.sort_string(self.tcx));
|
||||
let found = with_forced_trimmed_paths!(f.sort_string(self.tcx));
|
||||
if expected == found {
|
||||
label_or_note(span, terr.to_string(self.tcx));
|
||||
} else {
|
||||
@@ -2152,9 +2142,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
|
||||
) -> Option<(DiagStyledString, DiagStyledString)> {
|
||||
match values {
|
||||
ValuePairs::Regions(exp_found) => self.expected_found_str(exp_found),
|
||||
ValuePairs::Terms(exp_found) => {
|
||||
self.expected_found_str_term(cause, exp_found, long_ty_path)
|
||||
}
|
||||
ValuePairs::Terms(exp_found) => self.expected_found_str_term(exp_found, long_ty_path),
|
||||
ValuePairs::Aliases(exp_found) => self.expected_found_str(exp_found),
|
||||
ValuePairs::ExistentialTraitRef(exp_found) => self.expected_found_str(exp_found),
|
||||
ValuePairs::ExistentialProjection(exp_found) => self.expected_found_str(exp_found),
|
||||
@@ -2193,7 +2181,6 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
|
||||
|
||||
fn expected_found_str_term(
|
||||
&self,
|
||||
cause: &ObligationCause<'tcx>,
|
||||
exp_found: ty::error::ExpectedFound<ty::Term<'tcx>>,
|
||||
long_ty_path: &mut Option<PathBuf>,
|
||||
) -> Option<(DiagStyledString, DiagStyledString)> {
|
||||
@@ -2201,27 +2188,8 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
|
||||
if exp_found.references_error() {
|
||||
return None;
|
||||
}
|
||||
let (mut expected, mut found) = (exp_found.expected, exp_found.found);
|
||||
|
||||
if let ObligationCauseCode::Pattern { span, .. } = cause.code()
|
||||
&& let Some(span) = span
|
||||
&& !span.from_expansion()
|
||||
&& cause.span.from_expansion()
|
||||
{
|
||||
// When the type error comes from a macro like `assert!()`, and we are pointing at
|
||||
// code the user wrote, the cause and effect are reversed as the expected value is
|
||||
// what the macro expanded to. So if the user provided a `Type` when the macro is
|
||||
// written in such a way that a `bool` was expected, we want to print:
|
||||
// = note: expected `bool`
|
||||
// found `Type`"
|
||||
// but as far as the compiler is concerned, after expansion what was expected was `Type`
|
||||
// = note: expected `Type`
|
||||
// found `bool`"
|
||||
// so we reverse them here to match user expectation.
|
||||
(expected, found) = (found, expected);
|
||||
}
|
||||
|
||||
Some(match (expected.kind(), found.kind()) {
|
||||
Some(match (exp_found.expected.kind(), exp_found.found.kind()) {
|
||||
(ty::TermKind::Ty(expected), ty::TermKind::Ty(found)) => {
|
||||
let (mut exp, mut fnd) = self.cmp(expected, found);
|
||||
// Use the terminal width as the basis to determine when to compress the printed
|
||||
|
||||
@@ -11,7 +11,7 @@ use rustc_ast::{BinOpKind, LitKind, RangeLimits};
|
||||
use rustc_data_structures::packed::Pu128;
|
||||
use rustc_data_structures::unhash::UnindexMap;
|
||||
use rustc_errors::{Applicability, Diag};
|
||||
use rustc_hir::{Body, Expr, ExprKind};
|
||||
use rustc_hir::{Block, Body, Expr, ExprKind, UnOp};
|
||||
use rustc_lint::{LateContext, LateLintPass};
|
||||
use rustc_session::declare_lint_pass;
|
||||
use rustc_span::source_map::Spanned;
|
||||
@@ -135,12 +135,12 @@ fn assert_len_expr<'hir>(
|
||||
cx: &LateContext<'_>,
|
||||
expr: &'hir Expr<'hir>,
|
||||
) -> Option<(LengthComparison, usize, &'hir Expr<'hir>)> {
|
||||
let (cmp, asserted_len, slice_len) = if let Some(
|
||||
higher::IfLetOrMatch::Match(cond, [_, then], _)
|
||||
) = higher::IfLetOrMatch::parse(cx, expr)
|
||||
&& let ExprKind::Binary(bin_op, left, right) = &cond.kind
|
||||
let (cmp, asserted_len, slice_len) = if let Some(higher::If { cond, then, .. }) = higher::If::hir(expr)
|
||||
&& let ExprKind::Unary(UnOp::Not, condition) = &cond.kind
|
||||
&& let ExprKind::Binary(bin_op, left, right) = &condition.kind
|
||||
// check if `then` block has a never type expression
|
||||
&& cx.typeck_results().expr_ty(then.body).is_never()
|
||||
&& let ExprKind::Block(Block { expr: Some(then_expr), .. }, _) = then.kind
|
||||
&& cx.typeck_results().expr_ty(then_expr).is_never()
|
||||
{
|
||||
len_comparison(bin_op.node, left, right)?
|
||||
} else if let Some((macro_call, bin_op)) = first_node_macro_backtrace(cx, expr).find_map(|macro_call| {
|
||||
|
||||
@@ -196,7 +196,6 @@ fn issue_13106() {
|
||||
|
||||
const {
|
||||
assert!(EMPTY_STR.is_empty());
|
||||
//~^ const_is_empty
|
||||
}
|
||||
|
||||
const {
|
||||
|
||||
@@ -158,16 +158,10 @@ LL | let _ = val.is_empty();
|
||||
| ^^^^^^^^^^^^^^
|
||||
|
||||
error: this expression always evaluates to true
|
||||
--> tests/ui/const_is_empty.rs:198:17
|
||||
|
|
||||
LL | assert!(EMPTY_STR.is_empty());
|
||||
| ^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: this expression always evaluates to true
|
||||
--> tests/ui/const_is_empty.rs:203:9
|
||||
--> tests/ui/const_is_empty.rs:202:9
|
||||
|
|
||||
LL | EMPTY_STR.is_empty();
|
||||
| ^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: aborting due to 28 previous errors
|
||||
error: aborting due to 27 previous errors
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#![warn(clippy::incompatible_msrv)]
|
||||
#![feature(custom_inner_attributes)]
|
||||
#![allow(stable_features, clippy::diverging_sub_expression)]
|
||||
#![allow(stable_features)]
|
||||
#![feature(strict_provenance)] // For use in test
|
||||
#![clippy::msrv = "1.3.0"]
|
||||
|
||||
|
||||
@@ -1,16 +1,4 @@
|
||||
fn main() {
|
||||
assert!("foo"); //~ ERROR mismatched types
|
||||
//~^ NOTE expected `bool`, found `str`
|
||||
//~| NOTE in this expansion of assert!
|
||||
let x = Some(&1);
|
||||
assert!(x); //~ ERROR mismatched types
|
||||
//~^ NOTE expected `bool`, found `Option<&{integer}>`
|
||||
//~| NOTE expected enum `bool`
|
||||
//~| NOTE in this expansion of assert!
|
||||
//~| NOTE in this expansion of assert!
|
||||
assert!(x, ""); //~ ERROR mismatched types
|
||||
//~^ NOTE expected `bool`, found `Option<&{integer}>`
|
||||
//~| NOTE expected enum `bool`
|
||||
//~| NOTE in this expansion of assert!
|
||||
//~| NOTE in this expansion of assert!
|
||||
assert!("foo");
|
||||
//~^ ERROR cannot apply unary operator `!`
|
||||
}
|
||||
|
||||
@@ -1,27 +1,9 @@
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/issue-28308.rs:2:13
|
||||
error[E0600]: cannot apply unary operator `!` to type `&'static str`
|
||||
--> $DIR/issue-28308.rs:2:5
|
||||
|
|
||||
LL | assert!("foo");
|
||||
| ^^^^^ expected `bool`, found `str`
|
||||
| ^^^^^^^^^^^^^^ cannot apply unary operator `!`
|
||||
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/issue-28308.rs:6:13
|
||||
|
|
||||
LL | assert!(x);
|
||||
| ^ expected `bool`, found `Option<&{integer}>`
|
||||
|
|
||||
= note: expected enum `bool`
|
||||
found type `Option<&{integer}>`
|
||||
error: aborting due to 1 previous error
|
||||
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/issue-28308.rs:11:13
|
||||
|
|
||||
LL | assert!(x, "");
|
||||
| ^ expected `bool`, found `Option<&{integer}>`
|
||||
|
|
||||
= note: expected enum `bool`
|
||||
found type `Option<&{integer}>`
|
||||
|
||||
error: aborting due to 3 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0308`.
|
||||
For more information about this error, try `rustc --explain E0600`.
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
error[E0080]: evaluation panicked: assertion failed: false
|
||||
--> $DIR/assert.rs:5:23
|
||||
--> $DIR/assert.rs:5:15
|
||||
|
|
||||
LL | const _: () = assert!(false);
|
||||
| ^^^^^ evaluation of `_` failed here
|
||||
| ^^^^^^^^^^^^^^ evaluation of `_` failed here
|
||||
|
||||
error: aborting due to 1 previous error
|
||||
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
error[E0080]: evaluation panicked: assertion failed: std::mem::size_of::<T>() == 0
|
||||
--> $DIR/post_monomorphization_error_backtrace.rs:6:31
|
||||
--> $DIR/post_monomorphization_error_backtrace.rs:6:23
|
||||
|
|
||||
LL | const V: () = assert!(std::mem::size_of::<T>() == 0);
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `assert_zst::F::<u32>::V` failed here
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `assert_zst::F::<u32>::V` failed here
|
||||
|
||||
note: erroneous constant encountered
|
||||
--> $DIR/post_monomorphization_error_backtrace.rs:14:5
|
||||
@@ -17,10 +17,10 @@ LL | assert_zst::<U>()
|
||||
| ^^^^^^^^^^^^^^^^^
|
||||
|
||||
error[E0080]: evaluation panicked: assertion failed: std::mem::size_of::<T>() == 0
|
||||
--> $DIR/post_monomorphization_error_backtrace.rs:6:31
|
||||
--> $DIR/post_monomorphization_error_backtrace.rs:6:23
|
||||
|
|
||||
LL | const V: () = assert!(std::mem::size_of::<T>() == 0);
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `assert_zst::F::<i32>::V` failed here
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `assert_zst::F::<i32>::V` failed here
|
||||
|
||||
note: erroneous constant encountered
|
||||
--> $DIR/post_monomorphization_error_backtrace.rs:14:5
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
error[E0080]: evaluation panicked: assertion failed: std::mem::size_of::<T>() == 0
|
||||
--> $DIR/const-expr-generic-err.rs:4:21
|
||||
--> $DIR/const-expr-generic-err.rs:4:13
|
||||
|
|
||||
LL | const { assert!(std::mem::size_of::<T>() == 0); }
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `foo::<i32>::{constant#0}` failed here
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `foo::<i32>::{constant#0}` failed here
|
||||
|
||||
note: erroneous constant encountered
|
||||
--> $DIR/const-expr-generic-err.rs:4:5
|
||||
|
||||
@@ -4,6 +4,8 @@
|
||||
//! backwards-incompatible, and may need to be done over an edition boundary or limit editions for
|
||||
//! which the desguaring change impacts.
|
||||
|
||||
//@ check-pass
|
||||
|
||||
#[derive(Debug)]
|
||||
struct F {
|
||||
data: bool
|
||||
@@ -18,5 +20,4 @@ fn main() {
|
||||
let f = F { data: true };
|
||||
|
||||
assert!(f);
|
||||
//~^ ERROR mismatched types
|
||||
}
|
||||
|
||||
@@ -1,14 +0,0 @@
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/assert-desugaring-145770.rs:20:11
|
||||
|
|
||||
LL | assert!(f);
|
||||
| ^ expected `bool`, found `F`
|
||||
|
|
||||
help: you might have meant to use field `data` whose type is `bool`
|
||||
|
|
||||
LL | assert!(f.data);
|
||||
| +++++
|
||||
|
||||
error: aborting due to 1 previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0308`.
|
||||
@@ -1,8 +0,0 @@
|
||||
//@ check-pass
|
||||
#[derive(PartialEq, Eq, Hash)]
|
||||
struct S;
|
||||
fn main() {
|
||||
let foo = std::rc::Rc::new(std::cell::RefCell::new(std::collections::HashMap::<S, S>::new()));
|
||||
// Ensure that the lifetimes of the borrow do not leak past the end of `main`.
|
||||
assert!(matches!(foo.borrow().get(&S).unwrap(), S))
|
||||
}
|
||||
@@ -12,7 +12,7 @@ fn main() {
|
||||
// Test that we can use addr_of! to get the address of a packed member which according to its
|
||||
// type is not aligned, but because it is a projection from a packed type is a valid place.
|
||||
let ptr0 = std::ptr::addr_of!(memory[0].tail);
|
||||
let ptr1 = std::ptr::addr_of!(memory[1].tail);
|
||||
let ptr1 = std::ptr::addr_of!(memory[0].tail);
|
||||
// Even if ptr0 happens to be aligned by chance, ptr1 is not.
|
||||
assert!(!ptr0.is_aligned() || !ptr1.is_aligned());
|
||||
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
error[E0080]: evaluation panicked: assertion failed: LANE < 4
|
||||
--> $DIR/const-err-trumps-simd-err.rs:17:21
|
||||
--> $DIR/const-err-trumps-simd-err.rs:17:13
|
||||
|
|
||||
LL | const { assert!(LANE < 4); } // the error should be here...
|
||||
| ^^^^^^^^ evaluation of `get_elem::<4>::{constant#0}` failed here
|
||||
| ^^^^^^^^^^^^^^^^^ evaluation of `get_elem::<4>::{constant#0}` failed here
|
||||
|
||||
note: erroneous constant encountered
|
||||
--> $DIR/const-err-trumps-simd-err.rs:17:5
|
||||
|
||||
@@ -41,10 +41,10 @@ LL | | }>
|
||||
| |__________^ required by this bound in `is_maybe_transmutable`
|
||||
|
||||
error[E0080]: evaluation panicked: assertion failed: false
|
||||
--> $DIR/uninhabited.rs:41:17
|
||||
--> $DIR/uninhabited.rs:41:9
|
||||
|
|
||||
LL | assert!(false);
|
||||
| ^^^^^ evaluation of `yawning_void_struct::_` failed here
|
||||
| ^^^^^^^^^^^^^^ evaluation of `yawning_void_struct::_` failed here
|
||||
|
||||
error[E0277]: `()` cannot be safely transmuted into `yawning_void_enum::Void`
|
||||
--> $DIR/uninhabited.rs:71:41
|
||||
@@ -68,10 +68,10 @@ LL | | }>
|
||||
| |__________^ required by this bound in `is_maybe_transmutable`
|
||||
|
||||
error[E0080]: evaluation panicked: assertion failed: false
|
||||
--> $DIR/uninhabited.rs:63:17
|
||||
--> $DIR/uninhabited.rs:63:9
|
||||
|
|
||||
LL | assert!(false);
|
||||
| ^^^^^ evaluation of `yawning_void_enum::_` failed here
|
||||
| ^^^^^^^^^^^^^^ evaluation of `yawning_void_enum::_` failed here
|
||||
|
||||
error[E0277]: `u128` cannot be safely transmuted into `DistantVoid`
|
||||
--> $DIR/uninhabited.rs:92:43
|
||||
@@ -95,10 +95,10 @@ LL | | }>
|
||||
| |__________^ required by this bound in `is_maybe_transmutable`
|
||||
|
||||
error[E0080]: evaluation panicked: assertion failed: false
|
||||
--> $DIR/uninhabited.rs:87:17
|
||||
--> $DIR/uninhabited.rs:87:9
|
||||
|
|
||||
LL | assert!(false);
|
||||
| ^^^^^ evaluation of `distant_void::_` failed here
|
||||
| ^^^^^^^^^^^^^^ evaluation of `distant_void::_` failed here
|
||||
|
||||
error[E0277]: `Src` cannot be safely transmuted into `issue_126267::Error`
|
||||
--> $DIR/uninhabited.rs:108:42
|
||||
|
||||
Reference in New Issue
Block a user