Code change:
<!-- Thank you for filing a bug report! Please provide a short summary of the bug, along with any information you feel relevant to replicating the bug. --When using the syntax in the Display format in formatting macros, the is ignored and treated as a . I tried this code: I expected to see this happen: Getting an error that is out of the bounds for type . Instead, this happened: This function compiles and prints . <!-- If you're using the stable version of the compiler, you should also check if the bug also exists in the beta or nightly versions. --: </p</details<!-- TRIAGEBOTSTART --<!-- TRIAGEBOTASSIGNSTART --<!-- TRIAGEBOTASSIGNDATASTARTTRIAGEBOTASSIGNDATAEND --<!-- TRIAGEBOTASSIGNEND --<!-- TRIAGEBOTEND --
I went and looked through the implementation and found where the issue comes from. The check at ignores the integer type, and it blindly calls on the value of the literal.
claim
WG-prioritization assigning priority (). label -I-prioritize +P-medium
Did run a bisection on the reproducible provided (and duplicated ) Regression in nightly-2023-04-22, specifically I think commit or (as pointed out in PR ) found 11 bors merge commits in the specified range commit[0] 2023-04-20: Auto merge of - m-ou-se:fmt-lang-items, r=jyn514 commit[1] 2023-04-20: Auto merge of - m-ou-se:flatten-format-args, r=oli-obk commit[2] 2023-04-21: Auto merge of - c410-f3r:dqewdas, r=petrochenkov commit[3] 2023-04-21: Auto merge of - jsoref:spelling-src-etc, r=Mark-Simulacrum commit[4] 2023-04-21: Auto merge of - matthiaskrgr:rollup-, r=matthiaskrgr commit[5] 2023-04-21: Auto merge of - cjgillot:query-feed, r=oli-obk commit[6] 2023-04-21: Auto merge of - michaelvanstraten:master, r=petrochenkov commit[7] 2023-04-21: Auto merge of - petrochenkov:qcstore4, r=cjgillot commit[8] 2023-04-21: Auto merge of - saethlin:mir-pass-cooperation, r=cjgillot commit[9] 2023-04-21: Auto merge of - cjgillot:const-prop-lint-junk, r=oli-obk commit[10] 2023-04-21: Auto merge of - Dylan-DPC:rollup-em3ovcq, r=Dylan-DPC cc
Looks like it's not easy invoke the same integer-literal-range-checking code from the place where formatargs!() is expanded. So the easiest solution is probably to expand to something like when literals are removed, such that the literals are still be checked later.
Actually, looks like there is a much easier fix that mostly just involves removing code. ^^' Will send a PR soon, probably tomorrow.
Fix:

Related discussion:
text: let mut fmt = Cow::Borrowed(fmt); if self.tcx.sess.opts.unstable_opts.flatten_format_args { fmt = flatten_format_args(fmt); <del> fmt = inline_literals(fmt); </del> <ins> fmt = self.inline_literals(fmt); </ins> } expand_format_args(self, sp, &fmt, allow_const) } <ins> /// Try to convert a literal into an interned string fn try_inline_lit(&self, lit: token::Lit) -> Option<Symbol> { match LitKind::from_token_lit(lit) { Ok(LitKind::Str(s, _)) => Some(s), Ok(LitKind::Int(n, ty)) => { match ty { // unsuffixed integer literals are assumed to be i32's LitIntType::Unsuffixed => { (n <= i32::MAX as u128).then_some(Symbol::intern(&n.to_string())) } LitIntType::Signed(int_ty) => { let max_literal = self.int_ty_max(int_ty); (n <= max_literal).then_some(Symbol::intern(&n.to_string())) } LitIntType::Unsigned(uint_ty) => { let max_literal = self.uint_ty_max(uint_ty); (n <= max_literal).then_some(Symbol::intern(&n.to_string())) } } } _ => None, } } /// Get the maximum value of int_ty. It is platform-dependent due to the byte size of isize fn int_ty_max(&self, int_ty: IntTy) -> u128 { match int_ty { IntTy::Isize => self.tcx.data_layout.pointer_size.signed_int_max() as u128, IntTy::I8 => i8::MAX as u128, IntTy::I16 => i16::MAX as u128, IntTy::I32 => i32::MAX as u128, IntTy::I64 => i64::MAX as u128, IntTy::I128 => i128::MAX as u128, } } /// Get the maximum value of uint_ty. It is platform-dependent due to the byte size of usize fn uint_ty_max(&self, uint_ty: UintTy) -> u128 { match uint_ty { UintTy::Usize => self.tcx.data_layout.pointer_size.unsigned_int_max(), UintTy::U8 => u8::MAX as u128, UintTy::U16 => u16::MAX as u128, UintTy::U32 => u32::MAX as u128, UintTy::U64 => u64::MAX as u128, UintTy::U128 => u128::MAX as u128, } } /// Inline literals into the format string. /// /// Turns /// /// `format_args!("Hello, {}! {} {}", "World", 123, x)` /// /// into /// /// `format_args!("Hello, World! 123 {}", x)`. fn inline_literals<'fmt>(&self, mut fmt: Cow<'fmt, FormatArgs>) -> Cow<'fmt, FormatArgs> { let mut was_inlined = vec![false; fmt.arguments.all_args().len()]; let mut inlined_anything = false; for i in 0..fmt.template.len() { let FormatArgsPiece::Placeholder(placeholder) = &fmt.template[i] else { continue }; let Ok(arg_index) = placeholder.argument.index else { continue }; let mut literal = None; if let FormatTrait::Display = placeholder.format_trait && placeholder.format_options == Default::default() && let arg = fmt.arguments.all_args()[arg_index].expr.peel_parens_and_refs() && let ExprKind::Lit(lit) = arg.kind { literal = self.try_inline_lit(lit); } if let Some(literal) = literal { // Now we need to mutate the outer FormatArgs. // If this is the first time, this clones the outer FormatArgs. let fmt = fmt.to_mut(); // Replace the placeholder with the literal. fmt.template[i] = FormatArgsPiece::Literal(literal); was_inlined[arg_index] = true; inlined_anything = true; } } // Remove the arguments that were inlined. if inlined_anything { let fmt = fmt.to_mut(); let mut remove = was_inlined; // Don't remove anything that's still used. for_all_argument_indexes(&mut fmt.template, |index| remove[*index] = false); // Drop all the arguments that are marked for removal. let mut remove_it = remove.iter(); fmt.arguments.all_args_mut().retain(|_| remove_it.next() != Some(&true)); // Calculate the mapping of old to new indexes for the remaining arguments. let index_map: Vec<usize> = remove .into_iter() .scan(0, |i, remove| { let mapped = *i; *i += !remove as usize; Some(mapped) }) .collect(); // Correct the indexes that refer to arguments that have shifted position. for_all_argument_indexes(&mut fmt.template, |index| *index = index_map[*index]); } fmt } </ins> } /// Flattens nested `format_args!()` into one.