mirror of
https://github.com/rust-lang/rust-analyzer
synced 2024-12-27 05:23:24 +00:00
Auto merge of #16938 - Nilstrieb:dont-panic-tests, r=Veykril
Implement `BeginPanic` handling in const eval for #16935, needs some figuring out of how to write these tests correctly
This commit is contained in:
commit
4c08e2d32f
12 changed files with 235 additions and 85 deletions
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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))
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
|
|
@ -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 {
|
||||
|
@ -1138,7 +1149,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`");
|
||||
}
|
||||
|
|
|
@ -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"),
|
||||
|
@ -131,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::<Result<Vec<_>>>()?;
|
||||
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);
|
||||
}
|
||||
|
@ -311,16 +310,20 @@ impl Evaluator<'_> {
|
|||
|
||||
fn detect_lang_function(&self, def: FunctionId) -> Option<LangItem> {
|
||||
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
|
||||
}
|
||||
|
||||
|
@ -328,18 +331,52 @@ impl Evaluator<'_> {
|
|||
&mut self,
|
||||
it: LangItem,
|
||||
generic_args: &Substitution,
|
||||
args: &[Vec<u8>],
|
||||
args: &[IntervalAndTy],
|
||||
locals: &Locals,
|
||||
span: MirSpan,
|
||||
) -> Result<Vec<u8>> {
|
||||
use LangItem::*;
|
||||
let mut args = args.iter();
|
||||
match it {
|
||||
BeginPanic => Err(MirEvalError::Panic("<unknown-panic-payload>".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())
|
||||
}
|
||||
|
@ -353,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,
|
||||
|
|
|
@ -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()))
|
||||
|
@ -72,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(
|
||||
|
@ -87,6 +95,43 @@ 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_panic(
|
||||
r#"
|
||||
//- minicore: fmt, panic
|
||||
fn main() {
|
||||
panic!("hello, world!");
|
||||
}
|
||||
"#,
|
||||
"hello, world!",
|
||||
);
|
||||
}
|
||||
|
||||
#[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_panic(
|
||||
r#"
|
||||
//- minicore: fmt, panic
|
||||
|
||||
fn main() {
|
||||
panic!("{}", "hello, world!");
|
||||
}
|
||||
"#,
|
||||
"hello, world!",
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn drop_basic() {
|
||||
check_pass(
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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",
|
||||
|
|
|
@ -49,5 +49,5 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
|
|||
|
||||
<span class="keyword">fn</span> <span class="function declaration">main</span><span class="parenthesis">(</span><span class="parenthesis">)</span> <span class="brace">{</span>
|
||||
<span class="keyword">let</span> <span class="variable declaration">foo</span> <span class="operator">=</span> <span class="enum_variant default_library library">Some</span><span class="parenthesis">(</span><span class="numeric_literal">92</span><span class="parenthesis">)</span><span class="semicolon">;</span>
|
||||
<span class="keyword">let</span> <span class="variable declaration">nums</span> <span class="operator">=</span> <span class="module default_library library">iter</span><span class="operator">::</span><span class="function default_library library">repeat</span><span class="parenthesis">(</span><span class="variable">foo</span><span class="operator">.</span><span class="method consuming default_library library">unwrap</span><span class="parenthesis">(</span><span class="parenthesis">)</span><span class="parenthesis">)</span><span class="semicolon">;</span>
|
||||
<span class="keyword">let</span> <span class="variable declaration">nums</span> <span class="operator">=</span> <span class="module default_library library">iter</span><span class="operator">::</span><span class="function default_library library">repeat</span><span class="parenthesis">(</span><span class="variable">foo</span><span class="operator">.</span><span class="method default_library library">unwrap</span><span class="parenthesis">(</span><span class="parenthesis">)</span><span class="parenthesis">)</span><span class="semicolon">;</span>
|
||||
<span class="brace">}</span></code></pre>
|
|
@ -158,9 +158,9 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
|
|||
<span class="macro">println</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="string_literal macro">"</span><span class="format_specifier">{</span><span class="variable">ничоси</span><span class="format_specifier">}</span><span class="string_literal macro">"</span><span class="comma macro">,</span> <span class="variable declaration macro">ничоси</span> <span class="operator macro">=</span> <span class="numeric_literal macro">92</span><span class="parenthesis macro">)</span><span class="semicolon">;</span>
|
||||
|
||||
<span class="macro">println</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="string_literal macro">"</span><span class="format_specifier">{</span><span class="format_specifier">:</span><span class="variable">x</span><span class="format_specifier">?</span><span class="format_specifier">}</span><span class="string_literal macro"> </span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal macro"> "</span><span class="comma macro">,</span> <span class="unresolved_reference macro">thingy</span><span class="comma macro">,</span> <span class="unresolved_reference macro">n2</span><span class="parenthesis macro">)</span><span class="semicolon">;</span>
|
||||
<span class="macro default_library library">panic</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="string_literal macro">"</span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal macro">"</span><span class="comma macro">,</span> <span class="numeric_literal macro">0</span><span class="parenthesis macro">)</span><span class="semicolon">;</span>
|
||||
<span class="macro default_library library">panic</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="string_literal macro">"{}"</span><span class="comma macro">,</span> <span class="numeric_literal macro">0</span><span class="parenthesis macro">)</span><span class="semicolon">;</span>
|
||||
<span class="macro default_library library">panic</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="string_literal macro">"more </span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal macro">"</span><span class="comma macro">,</span> <span class="numeric_literal macro">1</span><span class="parenthesis macro">)</span><span class="semicolon">;</span>
|
||||
<span class="macro default_library library">assert</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="bool_literal macro">true</span><span class="comma macro">,</span> <span class="string_literal macro">"</span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal macro">"</span><span class="comma macro">,</span> <span class="numeric_literal macro">1</span><span class="parenthesis macro">)</span><span class="semicolon">;</span>
|
||||
<span class="macro default_library library">assert</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="bool_literal macro">true</span><span class="comma macro">,</span> <span class="string_literal macro">"{}"</span><span class="comma macro">,</span> <span class="numeric_literal macro">1</span><span class="parenthesis macro">)</span><span class="semicolon">;</span>
|
||||
<span class="macro default_library library">assert</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="bool_literal macro">true</span><span class="comma macro">,</span> <span class="string_literal macro">"</span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal macro"> asdasd"</span><span class="comma macro">,</span> <span class="numeric_literal macro">1</span><span class="parenthesis macro">)</span><span class="semicolon">;</span>
|
||||
<span class="macro">toho</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="string_literal macro">"{}fmt"</span><span class="comma macro">,</span> <span class="numeric_literal macro">0</span><span class="parenthesis macro">)</span><span class="semicolon">;</span>
|
||||
<span class="keyword">let</span> <span class="variable declaration">i</span><span class="colon">:</span> <span class="builtin_type">u64</span> <span class="operator">=</span> <span class="numeric_literal">3</span><span class="semicolon">;</span>
|
||||
|
|
|
@ -391,6 +391,7 @@ FormatArgsExpr =
|
|||
FormatArgsArg =
|
||||
(Name '=')? Expr
|
||||
|
||||
# MacroCallExpr
|
||||
MacroExpr =
|
||||
MacroCall
|
||||
|
||||
|
|
|
@ -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
|
||||
|
@ -913,11 +913,13 @@ pub mod fmt {
|
|||
}
|
||||
|
||||
mod rt {
|
||||
use super::*;
|
||||
|
||||
extern "C" {
|
||||
type Opaque;
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
#[lang = "format_argument"]
|
||||
pub struct Argument<'a> {
|
||||
value: &'a Opaque,
|
||||
|
@ -930,8 +932,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 +970,9 @@ pub mod fmt {
|
|||
flags: u32,
|
||||
precision: Count,
|
||||
width: Count,
|
||||
) -> Self;
|
||||
) -> Self {
|
||||
Placeholder { position, fill, align, flags, precision, width }
|
||||
}
|
||||
}
|
||||
|
||||
#[lang = "format_unsafe_arg"]
|
||||
|
@ -977,10 +981,13 @@ pub mod fmt {
|
|||
}
|
||||
|
||||
impl UnsafeArg {
|
||||
pub unsafe fn new() -> Self;
|
||||
pub unsafe fn new() -> Self {
|
||||
UnsafeArg { _private: () }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
#[lang = "format_arguments"]
|
||||
pub struct Arguments<'a> {
|
||||
pieces: &'a [&'static str],
|
||||
|
@ -1005,6 +1012,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
|
||||
|
@ -1154,8 +1169,8 @@ pub mod pin {
|
|||
pointer: P,
|
||||
}
|
||||
impl<P> Pin<P> {
|
||||
pub fn new(_pointer: P) -> Pin<P> {
|
||||
loop {}
|
||||
pub fn new(pointer: P) -> Pin<P> {
|
||||
Pin { pointer }
|
||||
}
|
||||
}
|
||||
// region:deref
|
||||
|
@ -1356,18 +1371,48 @@ 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
|
||||
#[rustc_do_not_const_check] // hooked by const-eval
|
||||
const fn panic_cold_display<T: $crate::fmt::Display>(arg: &T) -> ! {
|
||||
$crate::panicking::panic_display(arg)
|
||||
}
|
||||
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<T: crate::fmt::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: crate::fmt::Arguments<'_>) -> ! {
|
||||
loop {}
|
||||
}
|
||||
|
||||
|
@ -1378,6 +1423,7 @@ mod panicking {
|
|||
}
|
||||
// endregion:panic
|
||||
|
||||
#[macro_use]
|
||||
mod macros {
|
||||
// region:panic
|
||||
#[macro_export]
|
||||
|
@ -1470,7 +1516,6 @@ mod macros {
|
|||
}
|
||||
// endregion:unimplemented
|
||||
|
||||
|
||||
// region:derive
|
||||
pub(crate) mod builtin {
|
||||
#[rustc_builtin_macro]
|
||||
|
|
Loading…
Reference in a new issue