From 805f569adc6691e4751baeb5301d24810eadc397 Mon Sep 17 00:00:00 2001 From: Nilstrieb <48135649+Nilstrieb@users.noreply.github.com> Date: Sun, 24 Mar 2024 13:53:55 +0100 Subject: [PATCH 1/6] Handle panicking like rustc CTFE does Instead of using `core::fmt::format` to format panic messages, which may in turn panic too and cause recursive panics and other messy things, redirect `panic_fmt` to `const_panic_fmt` like CTFE, which in turn goes to `panic_display` and does the things normally. See the tests for the full call stack. --- crates/hir-ty/src/mir/eval/tests.rs | 37 +++++++++++++++++++++++++++++ crates/test-utils/src/minicore.rs | 34 +++++++++++++++++++------- 2 files changed, 63 insertions(+), 8 deletions(-) diff --git a/crates/hir-ty/src/mir/eval/tests.rs b/crates/hir-ty/src/mir/eval/tests.rs index 381522c9ab..031ab51ed7 100644 --- a/crates/hir-ty/src/mir/eval/tests.rs +++ b/crates/hir-ty/src/mir/eval/tests.rs @@ -31,6 +31,7 @@ fn eval_main(db: &TestDB, file_id: FileId) -> Result<(String, String), MirEvalEr db.trait_environment(func_id.into()), ) .map_err(|e| MirEvalError::MirLowerError(func_id, e))?; + let (result, output) = interpret_mir(db, body, false, None); result?; Ok((output.stdout().into_owned(), output.stderr().into_owned())) @@ -87,6 +88,42 @@ fn main() { ); } +#[test] +fn panic_fmt() { + // panic! + // -> panic_2021 (builtin macro redirection) + // -> #[lang = "panic_fmt"] core::panicking::panic_fmt (hooked by CTFE for redirection) + // -> core::panicking::const_panic_fmt + // -> #[rustc_const_panic_str] core::panicking::panic_display (hooked by CTFE for builtin panic) + // -> Err(ConstEvalError::Panic) + check_pass( + r#" +//- minicore: fmt, panic +fn main() { + panic!("hello, world!"); +} + "#, + ); + panic!("a"); +} + +#[test] +fn panic_display() { + // panic! + // -> panic_2021 (builtin macro redirection) + // -> #[rustc_const_panic_str] core::panicking::panic_display (hooked by CTFE for builtin panic) + // -> Err(ConstEvalError::Panic) + check_pass( + r#" +//- minicore: fmt, panic + +fn main() { + panic!("{}", "hello, world!"); +} + "#, + ); +} + #[test] fn drop_basic() { check_pass( diff --git a/crates/test-utils/src/minicore.rs b/crates/test-utils/src/minicore.rs index f125792d12..15bee61381 100644 --- a/crates/test-utils/src/minicore.rs +++ b/crates/test-utils/src/minicore.rs @@ -1356,18 +1356,36 @@ pub mod iter { // region:panic mod panic { pub macro panic_2021 { - () => ( - $crate::panicking::panic("explicit panic") - ), - ($($t:tt)+) => ( - $crate::panicking::panic_fmt($crate::const_format_args!($($t)+)) - ), + () => ({ + const fn panic_cold_explicit() -> ! { + $crate::panicking::panic_explicit() + } + panic_cold_explicit(); + }), + // Special-case the single-argument case for const_panic. + ("{}", $arg:expr $(,)?) => ({ + #[rustc_const_panic_str] // enforce a &&str argument in const-check and hook this by const-eval + const fn panic_cold_display(arg: &T) -> ! { + loop {} + } + panic_cold_display(&$arg); + }), + ($($t:tt)+) => ({ + // Semicolon to prevent temporaries inside the formatting machinery from + // being considered alive in the caller after the panic_fmt call. + $crate::panicking::panic_fmt($crate::const_format_args!($($t)+)); + }), } } mod panicking { - #[lang = "panic_fmt"] - pub const fn panic_fmt(_fmt: crate::fmt::Arguments<'_>) -> ! { + #[rustc_const_panic_str] // enforce a &&str argument in const-check and hook this by const-eval + pub const fn panic_display(x: &T) -> ! { + panic_fmt(format_args!("{}", *x)); + } + + #[lang = "panic_fmt"] // needed for const-evaluated panics + pub const fn panic_fmt(fmt: fmt::Arguments<'_>) -> ! { loop {} } From 563bb6bd6cc9742847ccabe49e3a5c0790ce3307 Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Mon, 25 Mar 2024 16:58:15 +0000 Subject: [PATCH 2/6] Fix missing function body in minicore --- crates/test-utils/src/minicore.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/crates/test-utils/src/minicore.rs b/crates/test-utils/src/minicore.rs index 15bee61381..8ae3a56227 100644 --- a/crates/test-utils/src/minicore.rs +++ b/crates/test-utils/src/minicore.rs @@ -977,7 +977,9 @@ pub mod fmt { } impl UnsafeArg { - pub unsafe fn new() -> Self; + pub unsafe fn new() -> Self { + UnsafeArg { _private: () } + } } } @@ -1488,7 +1490,6 @@ mod macros { } // endregion:unimplemented - // region:derive pub(crate) mod builtin { #[rustc_builtin_macro] From 5df690e13fc5831c03a6abf599d7233adfb213c2 Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Tue, 26 Mar 2024 07:34:05 +0000 Subject: [PATCH 3/6] Fixup some issues with minicore --- Cargo.toml | 2 +- crates/hir-def/src/body/lower.rs | 80 ++++++++++++++++--------------- crates/syntax/rust.ungram | 1 + crates/test-utils/src/minicore.rs | 38 +++++++++++---- 4 files changed, 73 insertions(+), 48 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index f7e3ae51df..6895dcc3c8 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -12,7 +12,7 @@ authors = ["rust-analyzer team"] [profile.dev] # Disabling debug info speeds up builds a bunch, # and we don't rely on it for debugging that much. -debug = 0 +debug = 1 [profile.dev.package] # These speed up local tests. diff --git a/crates/hir-def/src/body/lower.rs b/crates/hir-def/src/body/lower.rs index 340e95dbc2..f58228c45f 100644 --- a/crates/hir-def/src/body/lower.rs +++ b/crates/hir-def/src/body/lower.rs @@ -1869,42 +1869,45 @@ impl ExprCollector<'_> { ) -> ExprId { match count { Some(FormatCount::Literal(n)) => { - match LangItem::FormatCount.ty_rel_path(self.db, self.krate, name![Is]) { - Some(count_is) => { - let count_is = self.alloc_expr_desugared(Expr::Path(count_is)); - let args = self.alloc_expr_desugared(Expr::Literal(Literal::Uint( - *n as u128, - Some(BuiltinUint::Usize), - ))); - self.alloc_expr_desugared(Expr::Call { - callee: count_is, - args: Box::new([args]), - is_assignee_expr: false, - }) - } - None => self.missing_expr(), - } + let args = self.alloc_expr_desugared(Expr::Literal(Literal::Uint( + *n as u128, + Some(BuiltinUint::Usize), + ))); + let count_is = + match LangItem::FormatCount.ty_rel_path(self.db, self.krate, name![Is]) { + Some(count_is) => self.alloc_expr_desugared(Expr::Path(count_is)), + None => self.missing_expr(), + }; + self.alloc_expr_desugared(Expr::Call { + callee: count_is, + args: Box::new([args]), + is_assignee_expr: false, + }) } Some(FormatCount::Argument(arg)) => { if let Ok(arg_index) = arg.index { let (i, _) = argmap.insert_full((arg_index, ArgumentType::Usize)); - match LangItem::FormatCount.ty_rel_path(self.db, self.krate, name![Param]) { - Some(count_param) => { - let count_param = self.alloc_expr_desugared(Expr::Path(count_param)); - let args = self.alloc_expr_desugared(Expr::Literal(Literal::Uint( - i as u128, - Some(BuiltinUint::Usize), - ))); - self.alloc_expr_desugared(Expr::Call { - callee: count_param, - args: Box::new([args]), - is_assignee_expr: false, - }) - } + let args = self.alloc_expr_desugared(Expr::Literal(Literal::Uint( + i as u128, + Some(BuiltinUint::Usize), + ))); + let count_param = match LangItem::FormatCount.ty_rel_path( + self.db, + self.krate, + name![Param], + ) { + Some(count_param) => self.alloc_expr_desugared(Expr::Path(count_param)), None => self.missing_expr(), - } + }; + self.alloc_expr_desugared(Expr::Call { + callee: count_param, + args: Box::new([args]), + is_assignee_expr: false, + }) } else { + // FIXME: This drops arg causing it to potentially not be resolved/type checked + // when typing? self.missing_expr() } } @@ -1925,7 +1928,8 @@ impl ExprCollector<'_> { fn make_argument(&mut self, arg: ExprId, ty: ArgumentType) -> ExprId { use ArgumentType::*; use FormatTrait::*; - match LangItem::FormatArgument.ty_rel_path( + + let new_fn = match LangItem::FormatArgument.ty_rel_path( self.db, self.krate, match ty { @@ -1941,16 +1945,14 @@ impl ExprCollector<'_> { Usize => name![from_usize], }, ) { - Some(new_fn) => { - let new_fn = self.alloc_expr_desugared(Expr::Path(new_fn)); - self.alloc_expr_desugared(Expr::Call { - callee: new_fn, - args: Box::new([arg]), - is_assignee_expr: false, - }) - } + Some(new_fn) => self.alloc_expr_desugared(Expr::Path(new_fn)), None => self.missing_expr(), - } + }; + self.alloc_expr_desugared(Expr::Call { + callee: new_fn, + args: Box::new([arg]), + is_assignee_expr: false, + }) } // endregion: format } diff --git a/crates/syntax/rust.ungram b/crates/syntax/rust.ungram index e1765b25fd..8a775dd874 100644 --- a/crates/syntax/rust.ungram +++ b/crates/syntax/rust.ungram @@ -391,6 +391,7 @@ FormatArgsExpr = FormatArgsArg = (Name '=')? Expr +# MacroCallExpr MacroExpr = MacroCall diff --git a/crates/test-utils/src/minicore.rs b/crates/test-utils/src/minicore.rs index 8ae3a56227..3018f2c133 100644 --- a/crates/test-utils/src/minicore.rs +++ b/crates/test-utils/src/minicore.rs @@ -913,6 +913,7 @@ pub mod fmt { } mod rt { + use super::*; extern "C" { type Opaque; @@ -930,8 +931,8 @@ pub mod fmt { unsafe { Argument { formatter: transmute(f), value: transmute(x) } } } - pub fn new_display<'b, T: Display>(x: &'b T) -> Argument<'_> { - Self::new(x, Display::fmt) + pub fn new_display<'b, T: crate::fmt::Display>(x: &'b T) -> Argument<'_> { + Self::new(x, crate::fmt::Display::fmt) } } @@ -968,7 +969,9 @@ pub mod fmt { flags: u32, precision: Count, width: Count, - ) -> Self; + ) -> Self { + Placeholder { position, fill, align, flags, precision, width } + } } #[lang = "format_unsafe_arg"] @@ -1007,6 +1010,14 @@ pub mod fmt { ) -> Arguments<'a> { Arguments { pieces, fmt: Some(fmt), args } } + + pub const fn as_str(&self) -> Option<&'static str> { + match (self.pieces, self.args) { + ([], []) => Some(""), + ([s], []) => Some(s), + _ => None, + } + } } // region:derive @@ -1156,8 +1167,8 @@ pub mod pin { pointer: P, } impl

Pin

{ - pub fn new(_pointer: P) -> Pin

{ - loop {} + pub fn new(pointer: P) -> Pin

{ + Pin { pointer } } } // region:deref @@ -1382,12 +1393,23 @@ mod panic { mod panicking { #[rustc_const_panic_str] // enforce a &&str argument in const-check and hook this by const-eval - pub const fn panic_display(x: &T) -> ! { - panic_fmt(format_args!("{}", *x)); + pub const fn panic_display(x: &T) -> ! { + panic_fmt(crate::format_args!("{}", *x)); + } + + // This function is used instead of panic_fmt in const eval. + #[lang = "const_panic_fmt"] + pub const fn const_panic_fmt(fmt: crate::fmt::Arguments<'_>) -> ! { + if let Some(msg) = fmt.as_str() { + // The panic_display function is hooked by const eval. + panic_display(&msg); + } else { + loop {} + } } #[lang = "panic_fmt"] // needed for const-evaluated panics - pub const fn panic_fmt(fmt: fmt::Arguments<'_>) -> ! { + pub const fn panic_fmt(fmt: crate::fmt::Arguments<'_>) -> ! { loop {} } From a9140e197c45fd67310a917a8fd1d40ebdcc0ff2 Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Thu, 18 Apr 2024 14:00:59 +0200 Subject: [PATCH 4/6] Fix #[rustc_const_panic_str] functions not actually being hooked --- crates/hir-def/src/body/tests.rs | 26 ++++++++++++++------------ crates/hir-ty/src/mir/eval/shim.rs | 15 ++++++++++----- crates/test-utils/src/minicore.rs | 3 ++- 3 files changed, 26 insertions(+), 18 deletions(-) diff --git a/crates/hir-def/src/body/tests.rs b/crates/hir-def/src/body/tests.rs index a27ffe2167..4c8a54f7c8 100644 --- a/crates/hir-def/src/body/tests.rs +++ b/crates/hir-def/src/body/tests.rs @@ -318,18 +318,20 @@ fn f() { expect![[r#" fn f() { - $crate::panicking::panic_fmt( - builtin#lang(Arguments::new_v1_formatted)( - &[ - "cc", - ], - &[], - &[], - unsafe { - builtin#lang(UnsafeArg::new)() - }, - ), - ); + { + $crate::panicking::panic_fmt( + builtin#lang(Arguments::new_v1_formatted)( + &[ + "cc", + ], + &[], + &[], + unsafe { + builtin#lang(UnsafeArg::new)() + }, + ), + ); + }; }"#]] .assert_eq(&body.pretty_print(&db, def)) } diff --git a/crates/hir-ty/src/mir/eval/shim.rs b/crates/hir-ty/src/mir/eval/shim.rs index fee3dd3ada..33fae866ec 100644 --- a/crates/hir-ty/src/mir/eval/shim.rs +++ b/crates/hir-ty/src/mir/eval/shim.rs @@ -49,6 +49,7 @@ impl Evaluator<'_> { if self.not_special_fn_cache.borrow().contains(&def) { return Ok(false); } + let function_data = self.db.function_data(def); let is_intrinsic = match &function_data.abi { Some(abi) => *abi == Interned::new_str("rust-intrinsic"), @@ -311,16 +312,20 @@ impl Evaluator<'_> { fn detect_lang_function(&self, def: FunctionId) -> Option { use LangItem::*; - let candidate = self.db.lang_attr(def.into())?; + let attrs = self.db.attrs(def.into()); + + if attrs.by_key("rustc_const_panic_str").exists() { + // `#[rustc_const_panic_str]` is treated like `lang = "begin_panic"` by rustc CTFE. + return Some(LangItem::BeginPanic); + } + + let candidate = attrs.by_key("lang").string_value().and_then(LangItem::from_str)?; // We want to execute these functions with special logic // `PanicFmt` is not detected here as it's redirected later. if [BeginPanic, SliceLen, DropInPlace].contains(&candidate) { return Some(candidate); } - if self.db.attrs(def.into()).by_key("rustc_const_panic_str").exists() { - // `#[rustc_const_panic_str]` is treated like `lang = "begin_panic"` by rustc CTFE. - return Some(LangItem::BeginPanic); - } + None } diff --git a/crates/test-utils/src/minicore.rs b/crates/test-utils/src/minicore.rs index 3018f2c133..c50a5fa669 100644 --- a/crates/test-utils/src/minicore.rs +++ b/crates/test-utils/src/minicore.rs @@ -1378,8 +1378,9 @@ mod panic { // Special-case the single-argument case for const_panic. ("{}", $arg:expr $(,)?) => ({ #[rustc_const_panic_str] // enforce a &&str argument in const-check and hook this by const-eval + #[rustc_do_not_const_check] // hooked by const-eval const fn panic_cold_display(arg: &T) -> ! { - loop {} + $crate::panicking::panic_display(arg) } panic_cold_display(&$arg); }), From 6de838c255426de8519e3b58e2ebd7e18ec60e4f Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Fri, 19 Apr 2024 12:42:32 +0200 Subject: [PATCH 5/6] Implement BeginPanic for mir eval --- crates/hir-ty/src/chalk_ext.rs | 5 ++++ crates/hir-ty/src/mir/eval.rs | 2 +- crates/hir-ty/src/mir/eval/shim.rs | 43 +++++++++++++++++++++++++---- crates/hir-ty/src/mir/eval/tests.rs | 1 - 4 files changed, 44 insertions(+), 7 deletions(-) diff --git a/crates/hir-ty/src/chalk_ext.rs b/crates/hir-ty/src/chalk_ext.rs index 0bf01b0bc6..d99ef6679e 100644 --- a/crates/hir-ty/src/chalk_ext.rs +++ b/crates/hir-ty/src/chalk_ext.rs @@ -27,6 +27,7 @@ pub trait TyExt { fn is_scalar(&self) -> bool; fn is_floating_point(&self) -> bool; fn is_never(&self) -> bool; + fn is_str(&self) -> bool; fn is_unknown(&self) -> bool; fn contains_unknown(&self) -> bool; fn is_ty_var(&self) -> bool; @@ -87,6 +88,10 @@ impl TyExt for Ty { matches!(self.kind(Interner), TyKind::Never) } + fn is_str(&self) -> bool { + matches!(self.kind(Interner), TyKind::Str) + } + fn is_unknown(&self) -> bool { matches!(self.kind(Interner), TyKind::Error) } diff --git a/crates/hir-ty/src/mir/eval.rs b/crates/hir-ty/src/mir/eval.rs index 045ffb418c..17ad85b6c5 100644 --- a/crates/hir-ty/src/mir/eval.rs +++ b/crates/hir-ty/src/mir/eval.rs @@ -1138,7 +1138,7 @@ impl Evaluator<'_> { let mut ty = self.operand_ty(lhs, locals)?; while let TyKind::Ref(_, _, z) = ty.kind(Interner) { ty = z.clone(); - let size = if ty.kind(Interner) == &TyKind::Str { + let size = if ty.is_str() { if *op != BinOp::Eq { never!("Only eq is builtin for `str`"); } diff --git a/crates/hir-ty/src/mir/eval/shim.rs b/crates/hir-ty/src/mir/eval/shim.rs index 33fae866ec..e2ff67a092 100644 --- a/crates/hir-ty/src/mir/eval/shim.rs +++ b/crates/hir-ty/src/mir/eval/shim.rs @@ -132,9 +132,7 @@ impl Evaluator<'_> { return Ok(true); } if let Some(it) = self.detect_lang_function(def) { - let arg_bytes = - args.iter().map(|it| Ok(it.get(self)?.to_owned())).collect::>>()?; - let result = self.exec_lang_item(it, generic_args, &arg_bytes, locals, span)?; + let result = self.exec_lang_item(it, generic_args, args, locals, span)?; destination.write_from_bytes(self, &result)?; return Ok(true); } @@ -333,18 +331,52 @@ impl Evaluator<'_> { &mut self, it: LangItem, generic_args: &Substitution, - args: &[Vec], + args: &[IntervalAndTy], locals: &Locals, span: MirSpan, ) -> Result> { use LangItem::*; let mut args = args.iter(); match it { - BeginPanic => Err(MirEvalError::Panic("".to_owned())), + BeginPanic => { + let mut arg = args + .next() + .ok_or(MirEvalError::InternalError( + "argument of BeginPanic is not provided".into(), + ))? + .clone(); + while let TyKind::Ref(_, _, ty) = arg.ty.kind(Interner) { + if ty.is_str() { + let (pointee, metadata) = arg.interval.get(self)?.split_at(self.ptr_size()); + let len = from_bytes!(usize, metadata); + + return { + Err(MirEvalError::Panic( + std::str::from_utf8( + self.read_memory(Address::from_bytes(pointee)?, len)?, + ) + .unwrap() + .to_owned(), + )) + }; + } + let size = self.size_of_sized(&ty, locals, "begin panic arg")?; + let pointee = arg.interval.get(self)?; + arg = IntervalAndTy { + interval: Interval::new(Address::from_bytes(pointee)?, size), + ty: ty.clone(), + }; + } + Err(MirEvalError::Panic(format!( + "unknown-panic-payload: {:?}", + arg.ty.kind(Interner) + ))) + } SliceLen => { let arg = args.next().ok_or(MirEvalError::InternalError( "argument of <[T]>::len() is not provided".into(), ))?; + let arg = arg.get(self)?; let ptr_size = arg.len() / 2; Ok(arg[ptr_size..].into()) } @@ -358,6 +390,7 @@ impl Evaluator<'_> { let arg = args.next().ok_or(MirEvalError::InternalError( "argument of drop_in_place is not provided".into(), ))?; + let arg = arg.interval.get(self)?.to_owned(); self.run_drop_glue_deep( ty.clone(), locals, diff --git a/crates/hir-ty/src/mir/eval/tests.rs b/crates/hir-ty/src/mir/eval/tests.rs index 031ab51ed7..e88fbd19a4 100644 --- a/crates/hir-ty/src/mir/eval/tests.rs +++ b/crates/hir-ty/src/mir/eval/tests.rs @@ -104,7 +104,6 @@ fn main() { } "#, ); - panic!("a"); } #[test] From 3b9a2af21fcae3e74d0ee499b45b090a5e9f1887 Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Fri, 19 Apr 2024 13:18:30 +0200 Subject: [PATCH 6/6] Peek for panic message in test output --- Cargo.toml | 2 +- crates/hir-ty/src/mir/eval.rs | 11 +++++++++++ crates/hir-ty/src/mir/eval/shim.rs | 2 +- crates/hir-ty/src/mir/eval/tests.rs | 13 +++++++++++-- crates/ide-diagnostics/src/tests.rs | 1 + crates/ide/src/hover/tests.rs | 8 ++++---- .../test_data/highlight_default_library.html | 2 +- .../test_data/highlight_strings.html | 4 ++-- crates/test-utils/src/minicore.rs | 5 ++++- 9 files changed, 36 insertions(+), 12 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 6895dcc3c8..f7e3ae51df 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -12,7 +12,7 @@ authors = ["rust-analyzer team"] [profile.dev] # Disabling debug info speeds up builds a bunch, # and we don't rely on it for debugging that much. -debug = 1 +debug = 0 [profile.dev.package] # These speed up local tests. diff --git a/crates/hir-ty/src/mir/eval.rs b/crates/hir-ty/src/mir/eval.rs index 17ad85b6c5..2de1aa30c9 100644 --- a/crates/hir-ty/src/mir/eval.rs +++ b/crates/hir-ty/src/mir/eval.rs @@ -428,6 +428,17 @@ impl MirEvalError { } Ok(()) } + + pub fn is_panic(&self) -> Option<&str> { + let mut err = self; + while let MirEvalError::InFunction(e, _) = err { + err = e; + } + match err { + MirEvalError::Panic(msg) => Some(msg), + _ => None, + } + } } impl std::fmt::Debug for MirEvalError { diff --git a/crates/hir-ty/src/mir/eval/shim.rs b/crates/hir-ty/src/mir/eval/shim.rs index e2ff67a092..3438712049 100644 --- a/crates/hir-ty/src/mir/eval/shim.rs +++ b/crates/hir-ty/src/mir/eval/shim.rs @@ -360,7 +360,7 @@ impl Evaluator<'_> { )) }; } - let size = self.size_of_sized(&ty, locals, "begin panic arg")?; + let size = self.size_of_sized(ty, locals, "begin panic arg")?; let pointee = arg.interval.get(self)?; arg = IntervalAndTy { interval: Interval::new(Address::from_bytes(pointee)?, size), diff --git a/crates/hir-ty/src/mir/eval/tests.rs b/crates/hir-ty/src/mir/eval/tests.rs index e88fbd19a4..4abbda56cb 100644 --- a/crates/hir-ty/src/mir/eval/tests.rs +++ b/crates/hir-ty/src/mir/eval/tests.rs @@ -73,6 +73,13 @@ fn check_pass_and_stdio(ra_fixture: &str, expected_stdout: &str, expected_stderr } } +fn check_panic(ra_fixture: &str, expected_panic: &str) { + let (db, file_ids) = TestDB::with_many_files(ra_fixture); + let file_id = *file_ids.last().unwrap(); + let e = eval_main(&db, file_id).unwrap_err(); + assert_eq!(e.is_panic().unwrap_or_else(|| panic!("unexpected error: {:?}", e)), expected_panic); +} + #[test] fn function_with_extern_c_abi() { check_pass( @@ -96,13 +103,14 @@ fn panic_fmt() { // -> core::panicking::const_panic_fmt // -> #[rustc_const_panic_str] core::panicking::panic_display (hooked by CTFE for builtin panic) // -> Err(ConstEvalError::Panic) - check_pass( + check_panic( r#" //- minicore: fmt, panic fn main() { panic!("hello, world!"); } "#, + "hello, world!", ); } @@ -112,7 +120,7 @@ fn panic_display() { // -> panic_2021 (builtin macro redirection) // -> #[rustc_const_panic_str] core::panicking::panic_display (hooked by CTFE for builtin panic) // -> Err(ConstEvalError::Panic) - check_pass( + check_panic( r#" //- minicore: fmt, panic @@ -120,6 +128,7 @@ fn main() { panic!("{}", "hello, world!"); } "#, + "hello, world!", ); } diff --git a/crates/ide-diagnostics/src/tests.rs b/crates/ide-diagnostics/src/tests.rs index bb5c2b7913..cd5e95cc1e 100644 --- a/crates/ide-diagnostics/src/tests.rs +++ b/crates/ide-diagnostics/src/tests.rs @@ -293,6 +293,7 @@ fn minicore_smoke_test() { // This should be ignored since we conditionally remove code which creates single item use with braces config.disabled.insert("unused_braces".to_owned()); config.disabled.insert("unused_variables".to_owned()); + config.disabled.insert("remove-unnecessary-else".to_owned()); check_diagnostics_with_config(config, &source); } diff --git a/crates/ide/src/hover/tests.rs b/crates/ide/src/hover/tests.rs index 67f10f0374..48a2775ce7 100644 --- a/crates/ide/src/hover/tests.rs +++ b/crates/ide/src/hover/tests.rs @@ -7864,8 +7864,8 @@ impl Iterator for S { file_id: FileId( 1, ), - full_range: 6290..6498, - focus_range: 6355..6361, + full_range: 7791..7999, + focus_range: 7856..7862, name: "Future", kind: Trait, container_name: "future", @@ -7878,8 +7878,8 @@ impl Iterator for S { file_id: FileId( 1, ), - full_range: 7128..7594, - focus_range: 7172..7180, + full_range: 8629..9095, + focus_range: 8673..8681, name: "Iterator", kind: Trait, container_name: "iterator", diff --git a/crates/ide/src/syntax_highlighting/test_data/highlight_default_library.html b/crates/ide/src/syntax_highlighting/test_data/highlight_default_library.html index 366895ce7e..893e3c0675 100644 --- a/crates/ide/src/syntax_highlighting/test_data/highlight_default_library.html +++ b/crates/ide/src/syntax_highlighting/test_data/highlight_default_library.html @@ -49,5 +49,5 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd fn main() { let foo = Some(92); - let nums = iter::repeat(foo.unwrap()); + let nums = iter::repeat(foo.unwrap()); } \ No newline at end of file diff --git a/crates/ide/src/syntax_highlighting/test_data/highlight_strings.html b/crates/ide/src/syntax_highlighting/test_data/highlight_strings.html index 7a07d17b27..22706dea1f 100644 --- a/crates/ide/src/syntax_highlighting/test_data/highlight_strings.html +++ b/crates/ide/src/syntax_highlighting/test_data/highlight_strings.html @@ -158,9 +158,9 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd println!("{ничоси}", ничоси = 92); println!("{:x?} {} ", thingy, n2); - panic!("{}", 0); + panic!("{}", 0); panic!("more {}", 1); - assert!(true, "{}", 1); + assert!(true, "{}", 1); assert!(true, "{} asdasd", 1); toho!("{}fmt", 0); let i: u64 = 3; diff --git a/crates/test-utils/src/minicore.rs b/crates/test-utils/src/minicore.rs index c50a5fa669..0257ed9ab4 100644 --- a/crates/test-utils/src/minicore.rs +++ b/crates/test-utils/src/minicore.rs @@ -28,7 +28,7 @@ //! env: option //! eq: sized //! error: fmt -//! fmt: option, result, transmute, coerce_unsized +//! fmt: option, result, transmute, coerce_unsized, copy, clone, derive //! fn: //! from: sized //! future: pin @@ -919,6 +919,7 @@ pub mod fmt { type Opaque; } + #[derive(Copy, Clone)] #[lang = "format_argument"] pub struct Argument<'a> { value: &'a Opaque, @@ -986,6 +987,7 @@ pub mod fmt { } } + #[derive(Copy, Clone)] #[lang = "format_arguments"] pub struct Arguments<'a> { pieces: &'a [&'static str], @@ -1421,6 +1423,7 @@ mod panicking { } // endregion:panic +#[macro_use] mod macros { // region:panic #[macro_export]