1
Fork 0

Create core::fmt::ArgumentV1 with generics instead of fn pointer

This commit is contained in:
Gary Guo 2021-10-18 00:41:57 +01:00
parent bfe1564676
commit a832f5f7bc
12 changed files with 98 additions and 72 deletions

View file

@ -877,11 +877,21 @@ impl<'a, 'b> Context<'a, 'b> {
return ecx.expr_call_global(macsp, path, vec![arg]); return ecx.expr_call_global(macsp, path, vec![arg]);
} }
}; };
let new_fn_name = match trait_ {
"Display" => "new_display",
"Debug" => "new_debug",
"LowerExp" => "new_lower_exp",
"UpperExp" => "new_upper_exp",
"Octal" => "new_octal",
"Pointer" => "new_pointer",
"Binary" => "new_binary",
"LowerHex" => "new_lower_hex",
"UpperHex" => "new_upper_hex",
_ => unreachable!(),
};
let path = ecx.std_path(&[sym::fmt, Symbol::intern(trait_), sym::fmt]); let path = ecx.std_path(&[sym::fmt, sym::ArgumentV1, Symbol::intern(new_fn_name)]);
let format_fn = ecx.path_global(sp, path); ecx.expr_call_global(sp, path, vec![arg])
let path = ecx.std_path(&[sym::fmt, sym::ArgumentV1, sym::new]);
ecx.expr_call_global(macsp, path, vec![arg, ecx.expr_path(format_fn)])
} }
} }

View file

@ -42,54 +42,28 @@ impl<'tcx> Visitor<'tcx> for FunctionItemRefChecker<'_, 'tcx> {
} = &terminator.kind } = &terminator.kind
{ {
let source_info = *self.body.source_info(location); let source_info = *self.body.source_info(location);
// Only handle function calls outside macros let func_ty = func.ty(self.body, self.tcx);
if !source_info.span.from_expansion() { if let ty::FnDef(def_id, substs_ref) = *func_ty.kind() {
let func_ty = func.ty(self.body, self.tcx); // Handle calls to `transmute`
if let ty::FnDef(def_id, substs_ref) = *func_ty.kind() { if self.tcx.is_diagnostic_item(sym::transmute, def_id) {
// Handle calls to `transmute` let arg_ty = args[0].ty(self.body, self.tcx);
if self.tcx.is_diagnostic_item(sym::transmute, def_id) { for generic_inner_ty in arg_ty.walk() {
let arg_ty = args[0].ty(self.body, self.tcx); if let GenericArgKind::Type(inner_ty) = generic_inner_ty.unpack() {
for generic_inner_ty in arg_ty.walk() { if let Some((fn_id, fn_substs)) =
if let GenericArgKind::Type(inner_ty) = generic_inner_ty.unpack() { FunctionItemRefChecker::is_fn_ref(inner_ty)
if let Some((fn_id, fn_substs)) = {
FunctionItemRefChecker::is_fn_ref(inner_ty) let span = self.nth_arg_span(&args, 0);
{ self.emit_lint(fn_id, fn_substs, source_info, span);
let span = self.nth_arg_span(&args, 0);
self.emit_lint(fn_id, fn_substs, source_info, span);
}
} }
} }
} else {
self.check_bound_args(def_id, substs_ref, &args, source_info);
} }
} else {
self.check_bound_args(def_id, substs_ref, &args, source_info);
} }
} }
} }
self.super_terminator(terminator, location); self.super_terminator(terminator, location);
} }
/// Emits a lint for function references formatted with `fmt::Pointer::fmt` by macros. These
/// cases are handled as operands instead of call terminators to avoid any dependence on
/// unstable, internal formatting details like whether `fmt` is called directly or not.
fn visit_operand(&mut self, operand: &Operand<'tcx>, location: Location) {
let source_info = *self.body.source_info(location);
if source_info.span.from_expansion() {
let op_ty = operand.ty(self.body, self.tcx);
if let ty::FnDef(def_id, substs_ref) = *op_ty.kind() {
if self.tcx.is_diagnostic_item(sym::pointer_trait_fmt, def_id) {
let param_ty = substs_ref.type_at(0);
if let Some((fn_id, fn_substs)) = FunctionItemRefChecker::is_fn_ref(param_ty) {
// The operand's ctxt wouldn't display the lint since it's inside a macro so
// we have to use the callsite's ctxt.
let callsite_ctxt = source_info.span.source_callsite().ctxt();
let span = source_info.span.with_ctxt(callsite_ctxt);
self.emit_lint(fn_id, fn_substs, source_info, span);
}
}
}
}
self.super_operand(operand, location);
}
} }
impl<'tcx> FunctionItemRefChecker<'_, 'tcx> { impl<'tcx> FunctionItemRefChecker<'_, 'tcx> {
@ -119,7 +93,13 @@ impl<'tcx> FunctionItemRefChecker<'_, 'tcx> {
if let Some((fn_id, fn_substs)) = if let Some((fn_id, fn_substs)) =
FunctionItemRefChecker::is_fn_ref(subst_ty) FunctionItemRefChecker::is_fn_ref(subst_ty)
{ {
let span = self.nth_arg_span(args, arg_num); let mut span = self.nth_arg_span(args, arg_num);
if span.from_expansion() {
// The operand's ctxt wouldn't display the lint since it's inside a macro so
// we have to use the callsite's ctxt.
let callsite_ctxt = span.source_callsite().ctxt();
span = span.with_ctxt(callsite_ctxt);
}
self.emit_lint(fn_id, fn_substs, source_info, span); self.emit_lint(fn_id, fn_substs, source_info, span);
} }
} }

View file

@ -308,9 +308,21 @@ static USIZE_MARKER: fn(&usize, &mut Formatter<'_>) -> Result = |ptr, _| {
loop {} loop {}
}; };
macro_rules! arg_new {
($f: ident, $t: ident) => {
#[doc(hidden)]
#[unstable(feature = "fmt_internals", reason = "internal to format_args!", issue = "none")]
#[inline]
pub fn $f<'b, T: $t>(x: &'b T) -> ArgumentV1<'_> {
Self::new(x, $t::fmt)
}
};
}
impl<'a> ArgumentV1<'a> { impl<'a> ArgumentV1<'a> {
#[doc(hidden)] #[doc(hidden)]
#[unstable(feature = "fmt_internals", reason = "internal to format_args!", issue = "none")] #[unstable(feature = "fmt_internals", reason = "internal to format_args!", issue = "none")]
#[inline]
pub fn new<'b, T>(x: &'b T, f: fn(&T, &mut Formatter<'_>) -> Result) -> ArgumentV1<'b> { pub fn new<'b, T>(x: &'b T, f: fn(&T, &mut Formatter<'_>) -> Result) -> ArgumentV1<'b> {
// SAFETY: `mem::transmute(x)` is safe because // SAFETY: `mem::transmute(x)` is safe because
// 1. `&'b T` keeps the lifetime it originated with `'b` // 1. `&'b T` keeps the lifetime it originated with `'b`
@ -323,6 +335,16 @@ impl<'a> ArgumentV1<'a> {
unsafe { ArgumentV1 { formatter: mem::transmute(f), value: mem::transmute(x) } } unsafe { ArgumentV1 { formatter: mem::transmute(f), value: mem::transmute(x) } }
} }
arg_new!(new_display, Display);
arg_new!(new_debug, Debug);
arg_new!(new_octal, Octal);
arg_new!(new_lower_hex, LowerHex);
arg_new!(new_upper_hex, UpperHex);
arg_new!(new_pointer, Pointer);
arg_new!(new_binary, Binary);
arg_new!(new_lower_exp, LowerExp);
arg_new!(new_upper_exp, UpperExp);
#[doc(hidden)] #[doc(hidden)]
#[unstable(feature = "fmt_internals", reason = "internal to format_args!", issue = "none")] #[unstable(feature = "fmt_internals", reason = "internal to format_args!", issue = "none")]
pub fn from_usize(x: &usize) -> ArgumentV1<'_> { pub fn from_usize(x: &usize) -> ArgumentV1<'_> {

View file

@ -29,8 +29,8 @@
29| 1| some_string = Some(String::from("the string content")); 29| 1| some_string = Some(String::from("the string content"));
30| 1| let 30| 1| let
31| 1| a 31| 1| a
32| | = 32| 1| =
33| | || 33| 1| ||
34| 0| { 34| 0| {
35| 0| let mut countdown = 0; 35| 0| let mut countdown = 0;
36| 0| if is_false { 36| 0| if is_false {
@ -116,8 +116,8 @@
116| 1| 116| 1|
117| 1| let 117| 1| let
118| 1| _unused_closure 118| 1| _unused_closure
119| 1| = 119| | =
120| 1| | 120| | |
121| | mut countdown 121| | mut countdown
122| | | 122| | |
123| 0| { 123| 0| {

View file

@ -19,12 +19,12 @@
18| 2| println!("used_only_from_bin_crate_generic_function with {:?}", arg); 18| 2| println!("used_only_from_bin_crate_generic_function with {:?}", arg);
19| 2|} 19| 2|}
------------------ ------------------
| used_crate::used_only_from_bin_crate_generic_function::<&alloc::vec::Vec<i32>>: | used_crate::used_only_from_bin_crate_generic_function::<&str>:
| 17| 1|pub fn used_only_from_bin_crate_generic_function<T: Debug>(arg: T) { | 17| 1|pub fn used_only_from_bin_crate_generic_function<T: Debug>(arg: T) {
| 18| 1| println!("used_only_from_bin_crate_generic_function with {:?}", arg); | 18| 1| println!("used_only_from_bin_crate_generic_function with {:?}", arg);
| 19| 1|} | 19| 1|}
------------------ ------------------
| used_crate::used_only_from_bin_crate_generic_function::<&str>: | used_crate::used_only_from_bin_crate_generic_function::<&alloc::vec::Vec<i32>>:
| 17| 1|pub fn used_only_from_bin_crate_generic_function<T: Debug>(arg: T) { | 17| 1|pub fn used_only_from_bin_crate_generic_function<T: Debug>(arg: T) {
| 18| 1| println!("used_only_from_bin_crate_generic_function with {:?}", arg); | 18| 1| println!("used_only_from_bin_crate_generic_function with {:?}", arg);
| 19| 1|} | 19| 1|}
@ -36,12 +36,12 @@
22| 2| println!("used_only_from_this_lib_crate_generic_function with {:?}", arg); 22| 2| println!("used_only_from_this_lib_crate_generic_function with {:?}", arg);
23| 2|} 23| 2|}
------------------ ------------------
| used_crate::used_only_from_this_lib_crate_generic_function::<alloc::vec::Vec<i32>>: | used_crate::used_only_from_this_lib_crate_generic_function::<&str>:
| 21| 1|pub fn used_only_from_this_lib_crate_generic_function<T: Debug>(arg: T) { | 21| 1|pub fn used_only_from_this_lib_crate_generic_function<T: Debug>(arg: T) {
| 22| 1| println!("used_only_from_this_lib_crate_generic_function with {:?}", arg); | 22| 1| println!("used_only_from_this_lib_crate_generic_function with {:?}", arg);
| 23| 1|} | 23| 1|}
------------------ ------------------
| used_crate::used_only_from_this_lib_crate_generic_function::<&str>: | used_crate::used_only_from_this_lib_crate_generic_function::<alloc::vec::Vec<i32>>:
| 21| 1|pub fn used_only_from_this_lib_crate_generic_function<T: Debug>(arg: T) { | 21| 1|pub fn used_only_from_this_lib_crate_generic_function<T: Debug>(arg: T) {
| 22| 1| println!("used_only_from_this_lib_crate_generic_function with {:?}", arg); | 22| 1| println!("used_only_from_this_lib_crate_generic_function with {:?}", arg);
| 23| 1|} | 23| 1|}

View file

@ -42,12 +42,12 @@
40| 2| println!("used_only_from_bin_crate_generic_function with {:?}", arg); 40| 2| println!("used_only_from_bin_crate_generic_function with {:?}", arg);
41| 2|} 41| 2|}
------------------ ------------------
| used_inline_crate::used_only_from_bin_crate_generic_function::<&str>: | used_inline_crate::used_only_from_bin_crate_generic_function::<&alloc::vec::Vec<i32>>:
| 39| 1|pub fn used_only_from_bin_crate_generic_function<T: Debug>(arg: T) { | 39| 1|pub fn used_only_from_bin_crate_generic_function<T: Debug>(arg: T) {
| 40| 1| println!("used_only_from_bin_crate_generic_function with {:?}", arg); | 40| 1| println!("used_only_from_bin_crate_generic_function with {:?}", arg);
| 41| 1|} | 41| 1|}
------------------ ------------------
| used_inline_crate::used_only_from_bin_crate_generic_function::<&alloc::vec::Vec<i32>>: | used_inline_crate::used_only_from_bin_crate_generic_function::<&str>:
| 39| 1|pub fn used_only_from_bin_crate_generic_function<T: Debug>(arg: T) { | 39| 1|pub fn used_only_from_bin_crate_generic_function<T: Debug>(arg: T) {
| 40| 1| println!("used_only_from_bin_crate_generic_function with {:?}", arg); | 40| 1| println!("used_only_from_bin_crate_generic_function with {:?}", arg);
| 41| 1|} | 41| 1|}
@ -61,12 +61,12 @@
46| 4| println!("used_only_from_this_lib_crate_generic_function with {:?}", arg); 46| 4| println!("used_only_from_this_lib_crate_generic_function with {:?}", arg);
47| 4|} 47| 4|}
------------------ ------------------
| used_inline_crate::used_only_from_this_lib_crate_generic_function::<&str>: | used_inline_crate::used_only_from_this_lib_crate_generic_function::<alloc::vec::Vec<i32>>:
| 45| 2|pub fn used_only_from_this_lib_crate_generic_function<T: Debug>(arg: T) { | 45| 2|pub fn used_only_from_this_lib_crate_generic_function<T: Debug>(arg: T) {
| 46| 2| println!("used_only_from_this_lib_crate_generic_function with {:?}", arg); | 46| 2| println!("used_only_from_this_lib_crate_generic_function with {:?}", arg);
| 47| 2|} | 47| 2|}
------------------ ------------------
| used_inline_crate::used_only_from_this_lib_crate_generic_function::<alloc::vec::Vec<i32>>: | used_inline_crate::used_only_from_this_lib_crate_generic_function::<&str>:
| 45| 2|pub fn used_only_from_this_lib_crate_generic_function<T: Debug>(arg: T) { | 45| 2|pub fn used_only_from_this_lib_crate_generic_function<T: Debug>(arg: T) {
| 46| 2| println!("used_only_from_this_lib_crate_generic_function with {:?}", arg); | 46| 2| println!("used_only_from_this_lib_crate_generic_function with {:?}", arg);
| 47| 2|} | 47| 2|}

View file

@ -18,8 +18,7 @@ LL | bug!();
error: unexpected token: `{ error: unexpected token: `{
let res = let res =
::alloc::fmt::format(::core::fmt::Arguments::new_v1(&[""], ::alloc::fmt::format(::core::fmt::Arguments::new_v1(&[""],
&[::core::fmt::ArgumentV1::new(&"u8", &[::core::fmt::ArgumentV1::new_display(&"u8")]));
::core::fmt::Display::fmt)]));
res res
}.as_str()` }.as_str()`
--> $DIR/key-value-expansion.rs:48:23 --> $DIR/key-value-expansion.rs:48:23

View file

@ -9,7 +9,7 @@ LL | let c1 : () = c;
| expected due to this | expected due to this
| |
= note: expected unit type `()` = note: expected unit type `()`
found closure `[mod1::f<T>::{closure#0} closure_substs=(unavailable) substs=[T, _#19t, extern "rust-call" fn(()), _#20t]]` found closure `[mod1::f<T>::{closure#0} closure_substs=(unavailable) substs=[T, _#16t, extern "rust-call" fn(()), _#15t]]`
help: use parentheses to call this closure help: use parentheses to call this closure
| |
LL | let c1 : () = c(); LL | let c1 : () = c();

View file

@ -9,7 +9,7 @@ LL | let c1 : () = c;
| expected due to this | expected due to this
| |
= note: expected unit type `()` = note: expected unit type `()`
found closure `[f<T>::{closure#0} closure_substs=(unavailable) substs=[T, _#19t, extern "rust-call" fn(()), _#20t]]` found closure `[f<T>::{closure#0} closure_substs=(unavailable) substs=[T, _#16t, extern "rust-call" fn(()), _#15t]]`
help: use parentheses to call this closure help: use parentheses to call this closure
| |
LL | let c1 : () = c(); LL | let c1 : () = c();

View file

@ -5,6 +5,11 @@ LL | format!("{:X}", "3");
| ^^^ the trait `UpperHex` is not implemented for `str` | ^^^ the trait `UpperHex` is not implemented for `str`
| |
= note: required because of the requirements on the impl of `UpperHex` for `&str` = note: required because of the requirements on the impl of `UpperHex` for `&str`
note: required by a bound in `ArgumentV1::<'a>::new_upper_hex`
--> $SRC_DIR/core/src/fmt/mod.rs:LL:COL
|
LL | arg_new!(new_upper_hex, UpperHex);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `ArgumentV1::<'a>::new_upper_hex`
= note: this error originates in the macro `$crate::__export::format_args` (in Nightly builds, run with -Z macro-backtrace for more info) = note: this error originates in the macro `$crate::__export::format_args` (in Nightly builds, run with -Z macro-backtrace for more info)
error: aborting due to previous error error: aborting due to previous error

View file

@ -1,14 +1,14 @@
error[E0282]: type annotations needed error[E0282]: type annotations needed
--> $DIR/issue-69455.rs:29:5 --> $DIR/issue-69455.rs:29:20
| |
LL | type Output; LL | type Output;
| ------------ `<Self as Test<Rhs>>::Output` defined here | ------------ `<Self as Test<Rhs>>::Output` defined here
... ...
LL | println!("{}", 23u64.test(xs.iter().sum())); LL | println!("{}", 23u64.test(xs.iter().sum()));
| ^^^^^^^^^^^^^^^---------------------------^ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^
| | | | |
| | this method call resolves to `<Self as Test<Rhs>>::Output` | this method call resolves to `<Self as Test<Rhs>>::Output`
| cannot infer type for type parameter `T` declared on the associated function `new` | cannot infer type for type parameter `T` declared on the associated function `new_display`
| |
= note: this error originates in the macro `$crate::format_args_nl` (in Nightly builds, run with -Z macro-backtrace for more info) = note: this error originates in the macro `$crate::format_args_nl` (in Nightly builds, run with -Z macro-backtrace for more info)

View file

@ -339,15 +339,13 @@ impl<'tcx> FormatArgsExpn<'tcx> {
expr_visitor_no_bodies(|e| { expr_visitor_no_bodies(|e| {
// if we're still inside of the macro definition... // if we're still inside of the macro definition...
if e.span.ctxt() == expr.span.ctxt() { if e.span.ctxt() == expr.span.ctxt() {
// ArgumnetV1::new(<value>, <format_trait>::fmt) // ArgumnetV1::new_<format_trait>(<value>)
if_chain! { if_chain! {
if let ExprKind::Call(callee, [val, fmt_path]) = e.kind; if let ExprKind::Call(callee, [val]) = e.kind;
if let ExprKind::Path(QPath::TypeRelative(ty, seg)) = callee.kind; if let ExprKind::Path(QPath::TypeRelative(ty, seg)) = callee.kind;
if seg.ident.name == sym::new;
if let hir::TyKind::Path(QPath::Resolved(_, path)) = ty.kind; if let hir::TyKind::Path(QPath::Resolved(_, path)) = ty.kind;
if path.segments.last().unwrap().ident.name == sym::ArgumentV1; if path.segments.last().unwrap().ident.name == sym::ArgumentV1;
if let ExprKind::Path(QPath::Resolved(_, path)) = fmt_path.kind; if seg.ident.name.as_str().starts_with("new_");
if let [.., fmt_trait, _fmt] = path.segments;
then { then {
let val_idx = if_chain! { let val_idx = if_chain! {
if val.span.ctxt() == expr.span.ctxt(); if val.span.ctxt() == expr.span.ctxt();
@ -361,7 +359,19 @@ impl<'tcx> FormatArgsExpn<'tcx> {
formatters.len() formatters.len()
} }
}; };
formatters.push((val_idx, fmt_trait.ident.name)); let fmt_trait = match seg.ident.name.as_str() {
"new_display" => "Display",
"new_debug" => "Debug",
"new_lower_exp" => "LowerExp",
"new_upper_exp" => "UpperExp",
"new_octal" => "Octal",
"new_pointer" => "Pointer",
"new_binary" => "Binary",
"new_lower_hex" => "LowerHex",
"new_upper_hex" => "UpperHex",
_ => unreachable!(),
};
formatters.push((val_idx, Symbol::intern(fmt_trait)));
} }
} }
if let ExprKind::Struct(QPath::Resolved(_, path), ..) = e.kind { if let ExprKind::Struct(QPath::Resolved(_, path), ..) = e.kind {