From 96057625c54de3547135e417e2fb73235e0f0398 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Mon, 3 Aug 2026 19:11:40 +0200 Subject: [PATCH] Add fast path to `escape_string_symbol` Co-Authored-By: Matthieu M --- compiler/rustc_ast/src/util/literal.rs | 30 +++++++++++++++++++++----- 1 file changed, 25 insertions(+), 5 deletions(-) diff --git a/compiler/rustc_ast/src/util/literal.rs b/compiler/rustc_ast/src/util/literal.rs index 0984702aa7c39..b5d8fc821ae0e 100644 --- a/compiler/rustc_ast/src/util/literal.rs +++ b/compiler/rustc_ast/src/util/literal.rs @@ -15,11 +15,31 @@ use crate::token::{self, Token}; // Escapes a string, represented as a symbol. Reuses the original symbol, // avoiding interning, if no changes are required. pub fn escape_string_symbol(symbol: Symbol) -> Symbol { - // Don't use escape_default() here, because using it in conjunction with to_string() - // is slow. let s = symbol.as_str(); - let mut escaped = String::with_capacity(s.len()); - for c in s.chars() { + + fn requires_escape(b: &u8) -> bool { + match *b { + b'\\' | b'\'' | b'"' => true, + b'\x20'..=b'\x7e' => false, + _ => true, + } + } + + // Fast-path: if we don't need escaping, just return the original symbol + let Some(position) = s.as_bytes().iter().position(requires_escape) else { + return symbol; + }; + + // At this point we know that we need to escape something in `suffix` + let (prefix, suffix) = s.split_at(position); + + // We set the capacity to the original size + 1, because the resulting string will be at least + // one character larger than the original, because of escaping. + let mut escaped = String::with_capacity(s.len() + 1); + escaped.push_str(prefix); + + // Don't use escape_default() here, because using it is slower than escaping manually. + for c in suffix.chars() { match c { '\t' => escaped.push_str("\\t"), '\r' => escaped.push_str("\\r"), @@ -31,7 +51,7 @@ pub fn escape_string_symbol(symbol: Symbol) -> Symbol { c => write!(escaped, "\\u{{{:x}}}", c as u32).unwrap(), } } - if s == escaped { symbol } else { Symbol::intern(&escaped) } + Symbol::intern(&escaped) } // Escapes a char.