Skip to content

Commit

Permalink
Auto merge of rust-lang#117769 - matthiaskrgr:rollup-4efjlg3, r=matth…
Browse files Browse the repository at this point in the history
…iaskrgr

Rollup of 6 pull requests

Successful merges:

 - rust-lang#114191 (Update exploit mitigations documentation)
 - rust-lang#117039 (Clarify UB in `get_unchecked(_mut)`)
 - rust-lang#117730 (Closure-consuming helper functions for `fmt::Debug` helpers)
 - rust-lang#117741 (Fix typo in internal.rs)
 - rust-lang#117743 (Suggest removing `;` for `;` within let-chains)
 - rust-lang#117751 (rustdoc-json: Fix test so it actually checks things)

r? `@ghost`
`@rustbot` modify labels: rollup
  • Loading branch information
bors committed Nov 10, 2023
2 parents 0f44eb3 + 186a3c8 commit d42d73b
Show file tree
Hide file tree
Showing 13 changed files with 442 additions and 229 deletions.
24 changes: 20 additions & 4 deletions compiler/rustc_parse/src/parser/expr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2441,10 +2441,26 @@ impl<'a> Parser<'a> {
self.error_on_extra_if(&cond)?;
// Parse block, which will always fail, but we can add a nice note to the error
self.parse_block().map_err(|mut err| {
err.span_note(
cond_span,
"the `if` expression is missing a block after this condition",
);
if self.prev_token == token::Semi
&& self.token == token::AndAnd
&& let maybe_let = self.look_ahead(1, |t| t.clone())
&& maybe_let.is_keyword(kw::Let)
{
err.span_suggestion(
self.prev_token.span,
"consider removing this semicolon to parse the `let` as part of the same chain",
"",
Applicability::MachineApplicable,
).span_note(
self.token.span.to(maybe_let.span),
"you likely meant to continue parsing the let-chain starting here",
);
} else {
err.span_note(
cond_span,
"the `if` expression is missing a block after this condition",
);
}
err
})?
}
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_smir/src/rustc_internal/internal.rs
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ fn ty_const<'tcx>(constant: &Const, tables: &mut Tables<'tcx>) -> rustc_ty::Cons
match constant.internal(tables) {
rustc_middle::mir::Const::Ty(c) => c,
cnst => {
panic!("Trying to covert constant `{constant:?}` to type constant, but found {cnst:?}")
panic!("Trying to convert constant `{constant:?}` to type constant, but found {cnst:?}")
}
}
}
Expand Down
2 changes: 2 additions & 0 deletions library/alloc/src/fmt.rs
Original file line number Diff line number Diff line change
Expand Up @@ -555,6 +555,8 @@
pub use core::fmt::Alignment;
#[stable(feature = "rust1", since = "1.0.0")]
pub use core::fmt::Error;
#[unstable(feature = "debug_closure_helpers", issue = "117729")]
pub use core::fmt::FormatterFn;
#[stable(feature = "rust1", since = "1.0.0")]
pub use core::fmt::{write, Arguments};
#[stable(feature = "rust1", since = "1.0.0")]
Expand Down
144 changes: 131 additions & 13 deletions library/core/src/fmt/builders.rs
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,18 @@ impl<'a, 'b: 'a> DebugStruct<'a, 'b> {
/// ```
#[stable(feature = "debug_builders", since = "1.2.0")]
pub fn field(&mut self, name: &str, value: &dyn fmt::Debug) -> &mut Self {
self.field_with(name, |f| value.fmt(f))
}

/// Adds a new field to the generated struct output.
///
/// This method is equivalent to [`DebugStruct::field`], but formats the
/// value using a provided closure rather than by calling [`Debug::fmt`].
#[unstable(feature = "debug_closure_helpers", issue = "117729")]
pub fn field_with<F>(&mut self, name: &str, value_fmt: F) -> &mut Self
where
F: FnOnce(&mut fmt::Formatter<'_>) -> fmt::Result,
{
self.result = self.result.and_then(|_| {
if self.is_pretty() {
if !self.has_fields {
Expand All @@ -140,14 +152,14 @@ impl<'a, 'b: 'a> DebugStruct<'a, 'b> {
let mut writer = PadAdapter::wrap(self.fmt, &mut slot, &mut state);
writer.write_str(name)?;
writer.write_str(": ")?;
value.fmt(&mut writer)?;
value_fmt(&mut writer)?;
writer.write_str(",\n")
} else {
let prefix = if self.has_fields { ", " } else { " { " };
self.fmt.write_str(prefix)?;
self.fmt.write_str(name)?;
self.fmt.write_str(": ")?;
value.fmt(self.fmt)
value_fmt(self.fmt)
}
});

Expand Down Expand Up @@ -315,6 +327,18 @@ impl<'a, 'b: 'a> DebugTuple<'a, 'b> {
/// ```
#[stable(feature = "debug_builders", since = "1.2.0")]
pub fn field(&mut self, value: &dyn fmt::Debug) -> &mut Self {
self.field_with(|f| value.fmt(f))
}

/// Adds a new field to the generated tuple struct output.
///
/// This method is equivalent to [`DebugTuple::field`], but formats the
/// value using a provided closure rather than by calling [`Debug::fmt`].
#[unstable(feature = "debug_closure_helpers", issue = "117729")]
pub fn field_with<F>(&mut self, value_fmt: F) -> &mut Self
where
F: FnOnce(&mut fmt::Formatter<'_>) -> fmt::Result,
{
self.result = self.result.and_then(|_| {
if self.is_pretty() {
if self.fields == 0 {
Expand All @@ -323,12 +347,12 @@ impl<'a, 'b: 'a> DebugTuple<'a, 'b> {
let mut slot = None;
let mut state = Default::default();
let mut writer = PadAdapter::wrap(self.fmt, &mut slot, &mut state);
value.fmt(&mut writer)?;
value_fmt(&mut writer)?;
writer.write_str(",\n")
} else {
let prefix = if self.fields == 0 { "(" } else { ", " };
self.fmt.write_str(prefix)?;
value.fmt(self.fmt)
value_fmt(self.fmt)
}
});

Expand Down Expand Up @@ -385,7 +409,10 @@ struct DebugInner<'a, 'b: 'a> {
}

impl<'a, 'b: 'a> DebugInner<'a, 'b> {
fn entry(&mut self, entry: &dyn fmt::Debug) {
fn entry_with<F>(&mut self, entry_fmt: F)
where
F: FnOnce(&mut fmt::Formatter<'_>) -> fmt::Result,
{
self.result = self.result.and_then(|_| {
if self.is_pretty() {
if !self.has_fields {
Expand All @@ -394,13 +421,13 @@ impl<'a, 'b: 'a> DebugInner<'a, 'b> {
let mut slot = None;
let mut state = Default::default();
let mut writer = PadAdapter::wrap(self.fmt, &mut slot, &mut state);
entry.fmt(&mut writer)?;
entry_fmt(&mut writer)?;
writer.write_str(",\n")
} else {
if self.has_fields {
self.fmt.write_str(", ")?
}
entry.fmt(self.fmt)
entry_fmt(self.fmt)
}
});

Expand Down Expand Up @@ -475,7 +502,20 @@ impl<'a, 'b: 'a> DebugSet<'a, 'b> {
/// ```
#[stable(feature = "debug_builders", since = "1.2.0")]
pub fn entry(&mut self, entry: &dyn fmt::Debug) -> &mut Self {
self.inner.entry(entry);
self.inner.entry_with(|f| entry.fmt(f));
self
}

/// Adds a new entry to the set output.
///
/// This method is equivalent to [`DebugSet::entry`], but formats the
/// entry using a provided closure rather than by calling [`Debug::fmt`].
#[unstable(feature = "debug_closure_helpers", issue = "117729")]
pub fn entry_with<F>(&mut self, entry_fmt: F) -> &mut Self
where
F: FnOnce(&mut fmt::Formatter<'_>) -> fmt::Result,
{
self.inner.entry_with(entry_fmt);
self
}

Expand Down Expand Up @@ -605,7 +645,20 @@ impl<'a, 'b: 'a> DebugList<'a, 'b> {
/// ```
#[stable(feature = "debug_builders", since = "1.2.0")]
pub fn entry(&mut self, entry: &dyn fmt::Debug) -> &mut Self {
self.inner.entry(entry);
self.inner.entry_with(|f| entry.fmt(f));
self
}

/// Adds a new entry to the list output.
///
/// This method is equivalent to [`DebugList::entry`], but formats the
/// entry using a provided closure rather than by calling [`Debug::fmt`].
#[unstable(feature = "debug_closure_helpers", issue = "117729")]
pub fn entry_with<F>(&mut self, entry_fmt: F) -> &mut Self
where
F: FnOnce(&mut fmt::Formatter<'_>) -> fmt::Result,
{
self.inner.entry_with(entry_fmt);
self
}

Expand Down Expand Up @@ -775,6 +828,18 @@ impl<'a, 'b: 'a> DebugMap<'a, 'b> {
/// ```
#[stable(feature = "debug_map_key_value", since = "1.42.0")]
pub fn key(&mut self, key: &dyn fmt::Debug) -> &mut Self {
self.key_with(|f| key.fmt(f))
}

/// Adds the key part of a new entry to the map output.
///
/// This method is equivalent to [`DebugMap::key`], but formats the
/// key using a provided closure rather than by calling [`Debug::fmt`].
#[unstable(feature = "debug_closure_helpers", issue = "117729")]
pub fn key_with<F>(&mut self, key_fmt: F) -> &mut Self
where
F: FnOnce(&mut fmt::Formatter<'_>) -> fmt::Result,
{
self.result = self.result.and_then(|_| {
assert!(
!self.has_key,
Expand All @@ -789,13 +854,13 @@ impl<'a, 'b: 'a> DebugMap<'a, 'b> {
let mut slot = None;
self.state = Default::default();
let mut writer = PadAdapter::wrap(self.fmt, &mut slot, &mut self.state);
key.fmt(&mut writer)?;
key_fmt(&mut writer)?;
writer.write_str(": ")?;
} else {
if self.has_fields {
self.fmt.write_str(", ")?
}
key.fmt(self.fmt)?;
key_fmt(self.fmt)?;
self.fmt.write_str(": ")?;
}

Expand Down Expand Up @@ -839,16 +904,28 @@ impl<'a, 'b: 'a> DebugMap<'a, 'b> {
/// ```
#[stable(feature = "debug_map_key_value", since = "1.42.0")]
pub fn value(&mut self, value: &dyn fmt::Debug) -> &mut Self {
self.value_with(|f| value.fmt(f))
}

/// Adds the value part of a new entry to the map output.
///
/// This method is equivalent to [`DebugMap::value`], but formats the
/// value using a provided closure rather than by calling [`Debug::fmt`].
#[unstable(feature = "debug_closure_helpers", issue = "117729")]
pub fn value_with<F>(&mut self, value_fmt: F) -> &mut Self
where
F: FnOnce(&mut fmt::Formatter<'_>) -> fmt::Result,
{
self.result = self.result.and_then(|_| {
assert!(self.has_key, "attempted to format a map value before its key");

if self.is_pretty() {
let mut slot = None;
let mut writer = PadAdapter::wrap(self.fmt, &mut slot, &mut self.state);
value.fmt(&mut writer)?;
value_fmt(&mut writer)?;
writer.write_str(",\n")?;
} else {
value.fmt(self.fmt)?;
value_fmt(self.fmt)?;
}

self.has_key = false;
Expand Down Expand Up @@ -936,3 +1013,44 @@ impl<'a, 'b: 'a> DebugMap<'a, 'b> {
self.fmt.alternate()
}
}

/// Implements [`fmt::Debug`] and [`fmt::Display`] using a function.
///
/// # Examples
///
/// ```
/// #![feature(debug_closure_helpers)]
/// use std::fmt;
///
/// let value = 'a';
/// assert_eq!(format!("{}", value), "a");
/// assert_eq!(format!("{:?}", value), "'a'");
///
/// let wrapped = fmt::FormatterFn(|f| write!(f, "{:?}", &value));
/// assert_eq!(format!("{}", wrapped), "'a'");
/// assert_eq!(format!("{:?}", wrapped), "'a'");
/// ```
#[unstable(feature = "debug_closure_helpers", issue = "117729")]
pub struct FormatterFn<F>(pub F)
where
F: Fn(&mut fmt::Formatter<'_>) -> fmt::Result;

#[unstable(feature = "debug_closure_helpers", issue = "117729")]
impl<F> fmt::Debug for FormatterFn<F>
where
F: Fn(&mut fmt::Formatter<'_>) -> fmt::Result,
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
(self.0)(f)
}
}

#[unstable(feature = "debug_closure_helpers", issue = "117729")]
impl<F> fmt::Display for FormatterFn<F>
where
F: Fn(&mut fmt::Formatter<'_>) -> fmt::Result,
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
(self.0)(f)
}
}
3 changes: 3 additions & 0 deletions library/core/src/fmt/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,9 @@ pub enum Alignment {
#[stable(feature = "debug_builders", since = "1.2.0")]
pub use self::builders::{DebugList, DebugMap, DebugSet, DebugStruct, DebugTuple};

#[unstable(feature = "debug_closure_helpers", issue = "117729")]
pub use self::builders::FormatterFn;

/// The type returned by formatter methods.
///
/// # Examples
Expand Down
10 changes: 10 additions & 0 deletions library/core/src/slice/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -640,6 +640,11 @@ impl<T> [T] {
/// Calling this method with an out-of-bounds index is *[undefined behavior]*
/// even if the resulting reference is not used.
///
/// You can think of this like `.get(index).unwrap_unchecked()`. It's UB
/// to call `.get_unchecked(len)`, even if you immediately convert to a
/// pointer. And it's UB to call `.get_unchecked(..len + 1)`,
/// `.get_unchecked(..=len)`, or similar.
///
/// [`get`]: slice::get
/// [undefined behavior]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html
///
Expand Down Expand Up @@ -675,6 +680,11 @@ impl<T> [T] {
/// Calling this method with an out-of-bounds index is *[undefined behavior]*
/// even if the resulting reference is not used.
///
/// You can think of this like `.get_mut(index).unwrap_unchecked()`. It's
/// UB to call `.get_unchecked_mut(len)`, even if you immediately convert
/// to a pointer. And it's UB to call `.get_unchecked_mut(..len + 1)`,
/// `.get_unchecked_mut(..=len)`, or similar.
///
/// [`get_mut`]: slice::get_mut
/// [undefined behavior]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html
///
Expand Down
Loading

0 comments on commit d42d73b

Please sign in to comment.