about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2021-03-26 09:11:18 +0000
committerbors <bors@rust-lang.org>2021-03-26 09:11:18 +0000
commit4137088d9da94f693b287f35e2b17782c0b1a283 (patch)
tree360ed146f262275cd00ee0074e5c07084a1b9632
parent13167029c2fa01e498f92b2f2ac1ce0b2b9f294a (diff)
parent819247f179c0af011ea7219dc361209851eb487d (diff)
downloadrust-4137088d9da94f693b287f35e2b17782c0b1a283.tar.gz
rust-4137088d9da94f693b287f35e2b17782c0b1a283.zip
Auto merge of #83079 - osa1:issue83046, r=m-ou-se
Update char::escape_debug_ext to handle different escapes in strings and chars

Fixes #83046

The program

    fn main() {
        println!("{:?}", '"');
        println!("{:?}", "'");
    }

would previously print

    '\"'
    "\'"

With this patch it now prints:

    '"'
    "'"
-rw-r--r--library/alloc/tests/fmt.rs5
-rw-r--r--library/core/src/char/methods.rs35
-rw-r--r--library/core/src/char/mod.rs2
-rw-r--r--library/core/src/fmt/mod.rs13
-rw-r--r--library/core/src/str/mod.rs10
-rw-r--r--src/test/rustdoc-ui/check-doc-alias-attr.stderr4
-rw-r--r--src/test/ui/rustdoc/check-doc-alias-attr.stderr4
7 files changed, 54 insertions, 19 deletions
diff --git a/library/alloc/tests/fmt.rs b/library/alloc/tests/fmt.rs
index 757fddd2418..a121c54428c 100644
--- a/library/alloc/tests/fmt.rs
+++ b/library/alloc/tests/fmt.rs
@@ -68,10 +68,7 @@ fn test_format_macro_interface() {
     t!(format!("{:?}", 10_usize), "10");
     t!(format!("{:?}", "true"), "\"true\"");
     t!(format!("{:?}", "foo\nbar"), "\"foo\\nbar\"");
-    t!(
-        format!("{:?}", "foo\n\"bar\"\r\n\'baz\'\t\\qux\\"),
-        r#""foo\n\"bar\"\r\n\'baz\'\t\\qux\\""#
-    );
+    t!(format!("{:?}", "foo\n\"bar\"\r\n\'baz\'\t\\qux\\"), r#""foo\n\"bar\"\r\n'baz'\t\\qux\\""#);
     t!(format!("{:?}", "foo\0bar\x01baz\u{7f}q\u{75}x"), r#""foo\u{0}bar\u{1}baz\u{7f}qux""#);
     t!(format!("{:o}", 10_usize), "12");
     t!(format!("{:x}", 10_usize), "a");
diff --git a/library/core/src/char/methods.rs b/library/core/src/char/methods.rs
index 87a3d375a69..dcab2cd2d9d 100644
--- a/library/core/src/char/methods.rs
+++ b/library/core/src/char/methods.rs
@@ -403,16 +403,20 @@ impl char {
     }
 
     /// An extended version of `escape_debug` that optionally permits escaping
-    /// Extended Grapheme codepoints. This allows us to format characters like
-    /// nonspacing marks better when they're at the start of a string.
+    /// Extended Grapheme codepoints, single quotes, and double quotes. This
+    /// allows us to format characters like nonspacing marks better when they're
+    /// at the start of a string, and allows escaping single quotes in
+    /// characters, and double quotes in strings.
     #[inline]
-    pub(crate) fn escape_debug_ext(self, escape_grapheme_extended: bool) -> EscapeDebug {
+    pub(crate) fn escape_debug_ext(self, args: EscapeDebugExtArgs) -> EscapeDebug {
         let init_state = match self {
             '\t' => EscapeDefaultState::Backslash('t'),
             '\r' => EscapeDefaultState::Backslash('r'),
             '\n' => EscapeDefaultState::Backslash('n'),
-            '\\' | '\'' | '"' => EscapeDefaultState::Backslash(self),
-            _ if escape_grapheme_extended && self.is_grapheme_extended() => {
+            '\\' => EscapeDefaultState::Backslash(self),
+            '"' if args.escape_double_quote => EscapeDefaultState::Backslash(self),
+            '\'' if args.escape_single_quote => EscapeDefaultState::Backslash(self),
+            _ if args.escape_grapheme_extended && self.is_grapheme_extended() => {
                 EscapeDefaultState::Unicode(self.escape_unicode())
             }
             _ if is_printable(self) => EscapeDefaultState::Char(self),
@@ -458,7 +462,7 @@ impl char {
     #[stable(feature = "char_escape_debug", since = "1.20.0")]
     #[inline]
     pub fn escape_debug(self) -> EscapeDebug {
-        self.escape_debug_ext(true)
+        self.escape_debug_ext(EscapeDebugExtArgs::ESCAPE_ALL)
     }
 
     /// Returns an iterator that yields the literal escape code of a character
@@ -1565,6 +1569,25 @@ impl char {
     }
 }
 
+pub(crate) struct EscapeDebugExtArgs {
+    /// Escape Extended Grapheme codepoints?
+    pub(crate) escape_grapheme_extended: bool,
+
+    /// Escape single quotes?
+    pub(crate) escape_single_quote: bool,
+
+    /// Escape double quotes?
+    pub(crate) escape_double_quote: bool,
+}
+
+impl EscapeDebugExtArgs {
+    pub(crate) const ESCAPE_ALL: Self = Self {
+        escape_grapheme_extended: true,
+        escape_single_quote: true,
+        escape_double_quote: true,
+    };
+}
+
 #[inline]
 const fn len_utf8(code: u32) -> usize {
     if code < MAX_ONE_B {
diff --git a/library/core/src/char/mod.rs b/library/core/src/char/mod.rs
index 788fafa0adc..25a7c1de9de 100644
--- a/library/core/src/char/mod.rs
+++ b/library/core/src/char/mod.rs
@@ -45,6 +45,8 @@ pub use self::methods::encode_utf8_raw;
 use crate::fmt::{self, Write};
 use crate::iter::FusedIterator;
 
+pub(crate) use self::methods::EscapeDebugExtArgs;
+
 // UTF-8 ranges and tags for encoding characters
 const TAG_CONT: u8 = 0b1000_0000;
 const TAG_TWO_B: u8 = 0b1100_0000;
diff --git a/library/core/src/fmt/mod.rs b/library/core/src/fmt/mod.rs
index 2df5e562745..d211ad4b2f7 100644
--- a/library/core/src/fmt/mod.rs
+++ b/library/core/src/fmt/mod.rs
@@ -3,6 +3,7 @@
 #![stable(feature = "rust1", since = "1.0.0")]
 
 use crate::cell::{Cell, Ref, RefCell, RefMut, UnsafeCell};
+use crate::char::EscapeDebugExtArgs;
 use crate::marker::PhantomData;
 use crate::mem;
 use crate::num::flt2dec;
@@ -2054,7 +2055,11 @@ impl Debug for str {
         f.write_char('"')?;
         let mut from = 0;
         for (i, c) in self.char_indices() {
-            let esc = c.escape_debug();
+            let esc = c.escape_debug_ext(EscapeDebugExtArgs {
+                escape_grapheme_extended: true,
+                escape_single_quote: false,
+                escape_double_quote: true,
+            });
             // If char needs escaping, flush backlog so far and write, else skip
             if esc.len() != 1 {
                 f.write_str(&self[from..i])?;
@@ -2080,7 +2085,11 @@ impl Display for str {
 impl Debug for char {
     fn fmt(&self, f: &mut Formatter<'_>) -> Result {
         f.write_char('\'')?;
-        for c in self.escape_debug() {
+        for c in self.escape_debug_ext(EscapeDebugExtArgs {
+            escape_grapheme_extended: true,
+            escape_single_quote: true,
+            escape_double_quote: false,
+        }) {
             f.write_char(c)?
         }
         f.write_char('\'')
diff --git a/library/core/src/str/mod.rs b/library/core/src/str/mod.rs
index 03ed301eacf..95dd54976b2 100644
--- a/library/core/src/str/mod.rs
+++ b/library/core/src/str/mod.rs
@@ -15,7 +15,7 @@ mod validations;
 use self::pattern::Pattern;
 use self::pattern::{DoubleEndedSearcher, ReverseSearcher, Searcher};
 
-use crate::char;
+use crate::char::{self, EscapeDebugExtArgs};
 use crate::mem;
 use crate::slice::{self, SliceIndex};
 
@@ -2342,7 +2342,7 @@ impl str {
         EscapeDebug {
             inner: chars
                 .next()
-                .map(|first| first.escape_debug_ext(true))
+                .map(|first| first.escape_debug_ext(EscapeDebugExtArgs::ESCAPE_ALL))
                 .into_iter()
                 .flatten()
                 .chain(chars.flat_map(CharEscapeDebugContinue)),
@@ -2460,7 +2460,11 @@ impl_fn_for_zst! {
 
     #[derive(Clone)]
     struct CharEscapeDebugContinue impl Fn = |c: char| -> char::EscapeDebug {
-        c.escape_debug_ext(false)
+        c.escape_debug_ext(EscapeDebugExtArgs {
+            escape_grapheme_extended: false,
+            escape_single_quote: true,
+            escape_double_quote: true
+        })
     };
 
     #[derive(Clone)]
diff --git a/src/test/rustdoc-ui/check-doc-alias-attr.stderr b/src/test/rustdoc-ui/check-doc-alias-attr.stderr
index f99d69dc101..250568be333 100644
--- a/src/test/rustdoc-ui/check-doc-alias-attr.stderr
+++ b/src/test/rustdoc-ui/check-doc-alias-attr.stderr
@@ -10,7 +10,7 @@ error: doc alias attribute expects a string `#[doc(alias = "a")]` or a list of s
 LL | #[doc(alias = 0)]
    |       ^^^^^^^^^
 
-error: '\"' character isn't allowed in `#[doc(alias = "...")]`
+error: '"' character isn't allowed in `#[doc(alias = "...")]`
   --> $DIR/check-doc-alias-attr.rs:9:15
    |
 LL | #[doc(alias = "\"")]
@@ -60,7 +60,7 @@ error: `#[doc(alias("a"))]` expects string literals
 LL | #[doc(alias(0))]
    |             ^
 
-error: '\"' character isn't allowed in `#[doc(alias("..."))]`
+error: '"' character isn't allowed in `#[doc(alias("..."))]`
   --> $DIR/check-doc-alias-attr.rs:20:13
    |
 LL | #[doc(alias("\""))]
diff --git a/src/test/ui/rustdoc/check-doc-alias-attr.stderr b/src/test/ui/rustdoc/check-doc-alias-attr.stderr
index f99d69dc101..250568be333 100644
--- a/src/test/ui/rustdoc/check-doc-alias-attr.stderr
+++ b/src/test/ui/rustdoc/check-doc-alias-attr.stderr
@@ -10,7 +10,7 @@ error: doc alias attribute expects a string `#[doc(alias = "a")]` or a list of s
 LL | #[doc(alias = 0)]
    |       ^^^^^^^^^
 
-error: '\"' character isn't allowed in `#[doc(alias = "...")]`
+error: '"' character isn't allowed in `#[doc(alias = "...")]`
   --> $DIR/check-doc-alias-attr.rs:9:15
    |
 LL | #[doc(alias = "\"")]
@@ -60,7 +60,7 @@ error: `#[doc(alias("a"))]` expects string literals
 LL | #[doc(alias(0))]
    |             ^
 
-error: '\"' character isn't allowed in `#[doc(alias("..."))]`
+error: '"' character isn't allowed in `#[doc(alias("..."))]`
   --> $DIR/check-doc-alias-attr.rs:20:13
    |
 LL | #[doc(alias("\""))]