diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs index 7b103126e4599..2e61d5740373f 100644 --- a/compiler/rustc_ast/src/ast.rs +++ b/compiler/rustc_ast/src/ast.rs @@ -32,7 +32,7 @@ use rustc_data_structures::tagged_ptr::Tag; use rustc_macros::{Decodable, Encodable, HashStable_Generic}; pub use rustc_span::AttrId; use rustc_span::source_map::{Spanned, respan}; -use rustc_span::{DUMMY_SP, ErrorGuaranteed, Ident, Span, Symbol, kw, sym}; +use rustc_span::{ByteSymbol, DUMMY_SP, ErrorGuaranteed, Ident, Span, Symbol, kw, sym}; use thin_vec::{ThinVec, thin_vec}; pub use crate::format::*; @@ -1766,7 +1766,7 @@ pub enum ExprKind { /// Added for optimization purposes to avoid the need to escape /// large binary blobs - should always behave like [`ExprKind::Lit`] /// with a `ByteStr` literal. - IncludedBytes(Arc<[u8]>), + IncludedBytes(Arc<[u8]>), // njn: change to ByteSymbol? /// A `format_args!()` expression. FormatArgs(P), @@ -2024,7 +2024,8 @@ impl YieldKind { } /// A literal in a meta item. -#[derive(Clone, Encodable, Decodable, Debug, HashStable_Generic)] +// njn: look for clones +#[derive(Clone, Copy, Encodable, Decodable, Debug, HashStable_Generic)] pub struct MetaItemLit { /// The original literal as written in the source code. pub symbol: Symbol, @@ -2087,16 +2088,17 @@ pub enum LitFloatType { /// deciding the `LitKind`. This means that float literals like `1f32` are /// classified by this type as `Float`. This is different to `token::LitKind` /// which does *not* consider the suffix. -#[derive(Clone, Encodable, Decodable, Debug, Hash, Eq, PartialEq, HashStable_Generic)] +#[derive(Clone, Copy, Encodable, Decodable, Debug, Hash, Eq, PartialEq, HashStable_Generic)] +// njn: look for clones pub enum LitKind { /// A string literal (`"foo"`). The symbol is unescaped, and so may differ /// from the original token's symbol. Str(Symbol, StrStyle), /// A byte string (`b"foo"`). Not stored as a symbol because it might be /// non-utf8, and symbols only allow utf8 strings. - ByteStr(Arc<[u8]>, StrStyle), + ByteStr(ByteSymbol, StrStyle), /// A C String (`c"foo"`). Guaranteed to only have `\0` at the end. - CStr(Arc<[u8]>, StrStyle), + CStr(ByteSymbol, StrStyle), /// A byte char (`b'f'`). Byte(u8), /// A character literal (`'a'`). diff --git a/compiler/rustc_ast/src/util/literal.rs b/compiler/rustc_ast/src/util/literal.rs index b8526cf9d9529..dc9b480429af4 100644 --- a/compiler/rustc_ast/src/util/literal.rs +++ b/compiler/rustc_ast/src/util/literal.rs @@ -5,7 +5,7 @@ use std::{ascii, fmt, str}; use rustc_literal_escaper::{ MixedUnit, Mode, byte_from_char, unescape_byte, unescape_char, unescape_mixed, unescape_unicode, }; -use rustc_span::{Span, Symbol, kw, sym}; +use rustc_span::{ByteSymbol, Span, Symbol, kw, sym}; use tracing::debug; use crate::ast::{self, LitKind, MetaItemLit, StrStyle}; @@ -117,13 +117,13 @@ impl LitKind { assert!(!err.is_fatal(), "failed to unescape string literal") } }); - LitKind::ByteStr(buf.into(), StrStyle::Cooked) + LitKind::ByteStr(ByteSymbol::intern(&buf), StrStyle::Cooked) } token::ByteStrRaw(n) => { // Raw strings have no escapes so we can convert the symbol // directly to a `Arc`. let buf = symbol.as_str().to_owned().into_bytes(); - LitKind::ByteStr(buf.into(), StrStyle::Raw(n)) + LitKind::ByteStr(ByteSymbol::intern(&buf), StrStyle::Raw(n)) } token::CStr => { let s = symbol.as_str(); @@ -138,7 +138,7 @@ impl LitKind { } }); buf.push(0); - LitKind::CStr(buf.into(), StrStyle::Cooked) + LitKind::CStr(ByteSymbol::intern(&buf), StrStyle::Cooked) } token::CStrRaw(n) => { // Raw strings have no escapes so we can convert the symbol @@ -146,7 +146,7 @@ impl LitKind { // char. let mut buf = symbol.as_str().to_owned().into_bytes(); buf.push(0); - LitKind::CStr(buf.into(), StrStyle::Raw(n)) + LitKind::CStr(ByteSymbol::intern(&buf), StrStyle::Raw(n)) } token::Err(guar) => LitKind::Err(guar), }) @@ -169,11 +169,11 @@ impl fmt::Display for LitKind { string = sym )?, LitKind::ByteStr(ref bytes, StrStyle::Cooked) => { - write!(f, "b\"{}\"", escape_byte_str_symbol(bytes))? + write!(f, "b\"{}\"", escape_byte_str_symbol(bytes.as_byte_str()))? } LitKind::ByteStr(ref bytes, StrStyle::Raw(n)) => { // Unwrap because raw byte string literals can only contain ASCII. - let symbol = str::from_utf8(bytes).unwrap(); + let symbol = str::from_utf8(bytes.as_byte_str()).unwrap(); write!( f, "br{delim}\"{string}\"{delim}", @@ -182,11 +182,11 @@ impl fmt::Display for LitKind { )?; } LitKind::CStr(ref bytes, StrStyle::Cooked) => { - write!(f, "c\"{}\"", escape_byte_str_symbol(bytes))? + write!(f, "c\"{}\"", escape_byte_str_symbol(bytes.as_byte_str()))? } LitKind::CStr(ref bytes, StrStyle::Raw(n)) => { // This can only be valid UTF-8. - let symbol = str::from_utf8(bytes).unwrap(); + let symbol = str::from_utf8(bytes.as_byte_str()).unwrap(); write!(f, "cr{delim}\"{symbol}\"{delim}", delim = "#".repeat(n as usize),)?; } LitKind::Int(n, ty) => { diff --git a/compiler/rustc_ast_lowering/src/expr.rs b/compiler/rustc_ast_lowering/src/expr.rs index 9f3aed9216c2d..02dcf4d763b6a 100644 --- a/compiler/rustc_ast_lowering/src/expr.rs +++ b/compiler/rustc_ast_lowering/src/expr.rs @@ -13,7 +13,7 @@ use rustc_middle::span_bug; use rustc_middle::ty::TyCtxt; use rustc_session::errors::report_lit_error; use rustc_span::source_map::{Spanned, respan}; -use rustc_span::{DUMMY_SP, DesugaringKind, Ident, Span, Symbol, sym}; +use rustc_span::{ByteSymbol, DUMMY_SP, DesugaringKind, Ident, Span, Symbol, sym}; use thin_vec::{ThinVec, thin_vec}; use visit::{Visitor, walk_expr}; @@ -146,10 +146,10 @@ impl<'hir> LoweringContext<'_, 'hir> { } ExprKind::Lit(token_lit) => hir::ExprKind::Lit(self.lower_lit(token_lit, e.span)), ExprKind::IncludedBytes(bytes) => { - let lit = self.arena.alloc(respan( + let lit = respan( self.lower_span(e.span), - LitKind::ByteStr(Arc::clone(bytes), StrStyle::Cooked), - )); + LitKind::ByteStr(ByteSymbol::intern(&bytes), StrStyle::Cooked), + ); hir::ExprKind::Lit(lit) } ExprKind::Cast(expr, ty) => { @@ -422,11 +422,7 @@ impl<'hir> LoweringContext<'_, 'hir> { }) } - pub(crate) fn lower_lit( - &mut self, - token_lit: &token::Lit, - span: Span, - ) -> &'hir Spanned { + pub(crate) fn lower_lit(&mut self, token_lit: &token::Lit, span: Span) -> hir::Lit { let lit_kind = match LitKind::from_token_lit(*token_lit) { Ok(lit_kind) => lit_kind, Err(err) => { @@ -434,7 +430,7 @@ impl<'hir> LoweringContext<'_, 'hir> { LitKind::Err(guar) } }; - self.arena.alloc(respan(self.lower_span(span), lit_kind)) + respan(self.lower_span(span), lit_kind) } fn lower_unop(&mut self, u: UnOp) -> hir::UnOp { @@ -2140,10 +2136,10 @@ impl<'hir> LoweringContext<'_, 'hir> { } fn expr_uint(&mut self, sp: Span, ty: ast::UintTy, value: u128) -> hir::Expr<'hir> { - let lit = self.arena.alloc(hir::Lit { + let lit = hir::Lit { span: sp, node: ast::LitKind::Int(value.into(), ast::LitIntType::Unsigned(ty)), - }); + }; self.expr(sp, hir::ExprKind::Lit(lit)) } @@ -2160,9 +2156,7 @@ impl<'hir> LoweringContext<'_, 'hir> { } pub(super) fn expr_str(&mut self, sp: Span, value: Symbol) -> hir::Expr<'hir> { - let lit = self - .arena - .alloc(hir::Lit { span: sp, node: ast::LitKind::Str(value, ast::StrStyle::Cooked) }); + let lit = hir::Lit { span: sp, node: ast::LitKind::Str(value, ast::StrStyle::Cooked) }; self.expr(sp, hir::ExprKind::Lit(lit)) } diff --git a/compiler/rustc_ast_lowering/src/pat.rs b/compiler/rustc_ast_lowering/src/pat.rs index 58dea472f1d3b..7c9b7922d2fc2 100644 --- a/compiler/rustc_ast_lowering/src/pat.rs +++ b/compiler/rustc_ast_lowering/src/pat.rs @@ -7,7 +7,7 @@ use rustc_hir::def::{DefKind, Res}; use rustc_hir::{self as hir, LangItem}; use rustc_middle::span_bug; use rustc_span::source_map::{Spanned, respan}; -use rustc_span::{DesugaringKind, Ident, Span}; +use rustc_span::{ByteSymbol, DesugaringKind, Ident, Span}; use super::errors::{ ArbitraryExpressionInPattern, ExtraDoubleDot, MisplacedDoubleDot, SubTupleBinding, @@ -390,19 +390,15 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { allow_paths: bool, ) -> &'hir hir::PatExpr<'hir> { let span = self.lower_span(expr.span); - let err = |guar| hir::PatExprKind::Lit { - lit: self.arena.alloc(respan(span, LitKind::Err(guar))), - negated: false, - }; + let err = + |guar| hir::PatExprKind::Lit { lit: respan(span, LitKind::Err(guar)), negated: false }; let kind = match &expr.kind { ExprKind::Lit(lit) => { hir::PatExprKind::Lit { lit: self.lower_lit(lit, span), negated: false } } ExprKind::ConstBlock(c) => hir::PatExprKind::ConstBlock(self.lower_const_block(c)), ExprKind::IncludedBytes(bytes) => hir::PatExprKind::Lit { - lit: self - .arena - .alloc(respan(span, LitKind::ByteStr(Arc::clone(bytes), StrStyle::Cooked))), + lit: respan(span, LitKind::ByteStr(ByteSymbol::intern(bytes), StrStyle::Cooked)), negated: false, }, ExprKind::Err(guar) => err(*guar), diff --git a/compiler/rustc_builtin_macros/src/concat_bytes.rs b/compiler/rustc_builtin_macros/src/concat_bytes.rs index 456f2b9ab31de..3ec5d98730267 100644 --- a/compiler/rustc_builtin_macros/src/concat_bytes.rs +++ b/compiler/rustc_builtin_macros/src/concat_bytes.rs @@ -158,7 +158,7 @@ pub(crate) fn expand_concat_bytes( accumulator.push(val); } Ok(LitKind::ByteStr(ref bytes, _)) => { - accumulator.extend_from_slice(bytes); + accumulator.extend_from_slice(bytes.as_byte_str()); } _ => { guar.get_or_insert_with(|| invalid_type_err(cx, token_lit, e.span, false)); diff --git a/compiler/rustc_hir/src/arena.rs b/compiler/rustc_hir/src/arena.rs index 88c0d223fd39a..9548b0933f4fd 100644 --- a/compiler/rustc_hir/src/arena.rs +++ b/compiler/rustc_hir/src/arena.rs @@ -9,7 +9,6 @@ macro_rules! arena_types { [] attribute: rustc_hir::Attribute, [] owner_info: rustc_hir::OwnerInfo<'tcx>, [] use_path: rustc_hir::UsePath<'tcx>, - [] lit: rustc_hir::Lit, [] macro_def: rustc_ast::MacroDef, ]); ) diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index b4fcc16c09c85..379a441261b84 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -1809,7 +1809,7 @@ pub struct PatExpr<'hir> { #[derive(Debug, Clone, Copy, HashStable_Generic)] pub enum PatExprKind<'hir> { Lit { - lit: &'hir Lit, + lit: Lit, // FIXME: move this into `Lit` and handle negated literal expressions // once instead of matching on unop neg expressions everywhere. negated: bool, @@ -2722,7 +2722,7 @@ pub enum ExprKind<'hir> { /// A unary operation (e.g., `!x`, `*x`). Unary(UnOp, &'hir Expr<'hir>), /// A literal (e.g., `1`, `"foo"`). - Lit(&'hir Lit), + Lit(Lit), /// A cast (e.g., `foo as f64`). Cast(&'hir Expr<'hir>, &'hir Ty<'hir>), /// A type ascription (e.g., `x: Foo`). See RFC 3307. diff --git a/compiler/rustc_hir/src/intravisit.rs b/compiler/rustc_hir/src/intravisit.rs index 1fd44e44b9ce0..80bfd0049e121 100644 --- a/compiler/rustc_hir/src/intravisit.rs +++ b/compiler/rustc_hir/src/intravisit.rs @@ -343,7 +343,7 @@ pub trait Visitor<'v>: Sized { fn visit_pat_expr(&mut self, expr: &'v PatExpr<'v>) -> Self::Result { walk_pat_expr(self, expr) } - fn visit_lit(&mut self, _hir_id: HirId, _lit: &'v Lit, _negated: bool) -> Self::Result { + fn visit_lit(&mut self, _hir_id: HirId, _lit: Lit, _negated: bool) -> Self::Result { Self::Result::output() } fn visit_anon_const(&mut self, c: &'v AnonConst) -> Self::Result { @@ -768,7 +768,7 @@ pub fn walk_pat_field<'v, V: Visitor<'v>>(visitor: &mut V, field: &'v PatField<' pub fn walk_pat_expr<'v, V: Visitor<'v>>(visitor: &mut V, expr: &'v PatExpr<'v>) -> V::Result { try_visit!(visitor.visit_id(expr.hir_id)); match &expr.kind { - PatExprKind::Lit { lit, negated } => visitor.visit_lit(expr.hir_id, lit, *negated), + PatExprKind::Lit { lit, negated } => visitor.visit_lit(expr.hir_id, *lit, *negated), PatExprKind::ConstBlock(c) => visitor.visit_inline_const(c), PatExprKind::Path(qpath) => visitor.visit_qpath(qpath, expr.hir_id, expr.span), } diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs index 2a37a8bdbd47d..75bd459e4d26a 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs @@ -2433,9 +2433,9 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { }; let lit_input = match expr.kind { - hir::ExprKind::Lit(lit) => Some(LitToConstInput { lit: &lit.node, ty, neg: false }), + hir::ExprKind::Lit(lit) => Some(LitToConstInput { lit: lit.node, ty, neg: false }), hir::ExprKind::Unary(hir::UnOp::Neg, expr) => match expr.kind { - hir::ExprKind::Lit(lit) => Some(LitToConstInput { lit: &lit.node, ty, neg: true }), + hir::ExprKind::Lit(lit) => Some(LitToConstInput { lit: lit.node, ty, neg: true }), _ => None, }, _ => None, diff --git a/compiler/rustc_hir_pretty/src/lib.rs b/compiler/rustc_hir_pretty/src/lib.rs index b23b3125c59a3..be9ad5d683d52 100644 --- a/compiler/rustc_hir_pretty/src/lib.rs +++ b/compiler/rustc_hir_pretty/src/lib.rs @@ -1480,7 +1480,7 @@ impl<'a> State<'a> { self.print_expr_addr_of(k, m, expr); } hir::ExprKind::Lit(lit) => { - self.print_literal(lit); + self.print_literal(&lit); } hir::ExprKind::Cast(expr, ty) => { self.print_expr_cond_paren(expr, expr.precedence() < ExprPrecedence::Cast); diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs index 59aba6fae5e45..fc595e89db6bc 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs @@ -1631,10 +1631,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { match lit.node { ast::LitKind::Str(..) => Ty::new_static_str(tcx), + // njn: why is this an array, not a slice? ast::LitKind::ByteStr(ref v, _) => Ty::new_imm_ref( tcx, tcx.lifetimes.re_static, - Ty::new_array(tcx, tcx.types.u8, v.len() as u64), + Ty::new_array(tcx, tcx.types.u8, v.as_byte_str().len() as u64), ), ast::LitKind::Byte(_) => tcx.types.u8, ast::LitKind::Char(_) => tcx.types.char, diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs index 1c3bc338d85b2..818c03d5d38b0 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs @@ -1624,7 +1624,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { node: rustc_ast::LitKind::Int(lit, rustc_ast::LitIntType::Unsuffixed), span, }) => { - let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(*span) else { + let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(span) else { return false; }; if !(snippet.starts_with("0x") || snippet.starts_with("0X")) { @@ -1683,7 +1683,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // We have satisfied all requirements to provide a suggestion. Emit it. err.span_suggestion( - *span, + span, format!("if you meant to create a null pointer, use `{null_path_str}()`"), null_path_str + "()", Applicability::MachineApplicable, diff --git a/compiler/rustc_lint/src/invalid_from_utf8.rs b/compiler/rustc_lint/src/invalid_from_utf8.rs index 11eb079ddc09d..decc9e8260983 100644 --- a/compiler/rustc_lint/src/invalid_from_utf8.rs +++ b/compiler/rustc_lint/src/invalid_from_utf8.rs @@ -108,8 +108,9 @@ impl<'tcx> LateLintPass<'tcx> for InvalidFromUtf8 { } match init.kind { ExprKind::Lit(Spanned { node: lit, .. }) => { + // njn: rename bytes as byte_sym, here and elsewhere if let LitKind::ByteStr(bytes, _) = &lit - && let Err(utf8_error) = std::str::from_utf8(bytes) + && let Err(utf8_error) = std::str::from_utf8(bytes.as_byte_str()) { lint(init.span, utf8_error); } diff --git a/compiler/rustc_lint/src/late.rs b/compiler/rustc_lint/src/late.rs index 852bb01c09655..c681deea779df 100644 --- a/compiler/rustc_lint/src/late.rs +++ b/compiler/rustc_lint/src/late.rs @@ -152,7 +152,7 @@ impl<'tcx, T: LateLintPass<'tcx>> hir_visit::Visitor<'tcx> for LateContextAndPas hir_visit::walk_pat(self, p); } - fn visit_lit(&mut self, hir_id: HirId, lit: &'tcx hir::Lit, negated: bool) { + fn visit_lit(&mut self, hir_id: HirId, lit: hir::Lit, negated: bool) { lint_callback!(self, check_lit, hir_id, lit, negated); } diff --git a/compiler/rustc_lint/src/passes.rs b/compiler/rustc_lint/src/passes.rs index 409a23d1da039..affea1b80ec54 100644 --- a/compiler/rustc_lint/src/passes.rs +++ b/compiler/rustc_lint/src/passes.rs @@ -23,7 +23,7 @@ macro_rules! late_lint_methods { fn check_stmt(a: &'tcx rustc_hir::Stmt<'tcx>); fn check_arm(a: &'tcx rustc_hir::Arm<'tcx>); fn check_pat(a: &'tcx rustc_hir::Pat<'tcx>); - fn check_lit(hir_id: rustc_hir::HirId, a: &'tcx rustc_hir::Lit, negated: bool); + fn check_lit(hir_id: rustc_hir::HirId, a: rustc_hir::Lit, negated: bool); fn check_expr(a: &'tcx rustc_hir::Expr<'tcx>); fn check_expr_post(a: &'tcx rustc_hir::Expr<'tcx>); fn check_ty(a: &'tcx rustc_hir::Ty<'tcx, rustc_hir::AmbigArg>); diff --git a/compiler/rustc_lint/src/types.rs b/compiler/rustc_lint/src/types.rs index 77dc63351136c..8bffd9e9bf0d3 100644 --- a/compiler/rustc_lint/src/types.rs +++ b/compiler/rustc_lint/src/types.rs @@ -548,18 +548,12 @@ fn lint_fn_pointer<'tcx>( } impl<'tcx> LateLintPass<'tcx> for TypeLimits { - fn check_lit( - &mut self, - cx: &LateContext<'tcx>, - hir_id: HirId, - lit: &'tcx hir::Lit, - negated: bool, - ) { + fn check_lit(&mut self, cx: &LateContext<'tcx>, hir_id: HirId, lit: hir::Lit, negated: bool) { if negated { self.negated_expr_id = Some(hir_id); self.negated_expr_span = Some(lit.span); } - lint_literal(cx, self, hir_id, lit.span, lit, negated); + lint_literal(cx, self, hir_id, lit.span, &lit, negated); } fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &'tcx hir::Expr<'tcx>) { diff --git a/compiler/rustc_metadata/src/rmeta/decoder.rs b/compiler/rustc_metadata/src/rmeta/decoder.rs index 1dae858b7ef1a..067839543312d 100644 --- a/compiler/rustc_metadata/src/rmeta/decoder.rs +++ b/compiler/rustc_metadata/src/rmeta/decoder.rs @@ -32,7 +32,10 @@ use rustc_session::Session; use rustc_session::config::TargetModifier; use rustc_session::cstore::{CrateSource, ExternCrate}; use rustc_span::hygiene::HygieneDecodeContext; -use rustc_span::{BytePos, DUMMY_SP, Pos, SpanData, SpanDecoder, SyntaxContext, kw}; +// njn: Symbol wasn't being imported here...? +use rustc_span::{ + BytePos, ByteSymbol, DUMMY_SP, Pos, SpanData, SpanDecoder, Symbol, SyntaxContext, kw, +}; use tracing::debug; use crate::creader::CStore; @@ -569,6 +572,32 @@ impl<'a, 'tcx> SpanDecoder for DecodeContext<'a, 'tcx> { _ => unreachable!(), } } + + fn decode_byte_symbol(&mut self) -> ByteSymbol { + let tag = self.read_u8(); + + match tag { + SYMBOL_STR => { + let s = self.read_byte_str(); + ByteSymbol::intern(s) + } + SYMBOL_OFFSET => { + // read str offset + let pos = self.read_usize(); + + // move to str offset and read + self.opaque.with_position(pos, |d| { + let s = d.read_byte_str(); + ByteSymbol::intern(s) + }) + } + SYMBOL_PREDEFINED => { + let symbol_index = self.read_u32(); + ByteSymbol::new(symbol_index) + } + _ => unreachable!(), + } + } } impl<'a, 'tcx> Decodable> for SpanData { diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs index 3ab989d2d3ba7..b89b391b7a8b3 100644 --- a/compiler/rustc_metadata/src/rmeta/encoder.rs +++ b/compiler/rustc_metadata/src/rmeta/encoder.rs @@ -29,7 +29,15 @@ use rustc_serialize::{Decodable, Decoder, Encodable, Encoder, opaque}; use rustc_session::config::{CrateType, OptLevel, TargetModifier}; use rustc_span::hygiene::HygieneEncodeContext; use rustc_span::{ - ExternalSource, FileName, SourceFile, SpanData, SpanEncoder, StableSourceFileId, SyntaxContext, + // njn: why is Symbol not here? + ByteSymbol, + ExternalSource, + FileName, + SourceFile, + SpanData, + SpanEncoder, + StableSourceFileId, + SyntaxContext, sym, }; use tracing::{debug, instrument, trace}; @@ -64,6 +72,7 @@ pub(super) struct EncodeContext<'a, 'tcx> { is_proc_macro: bool, hygiene_ctxt: &'a HygieneEncodeContext, symbol_table: FxHashMap, + byte_symbol_table: FxHashMap, } /// If the current crate is a proc-macro, returns early with `LazyArray::default()`. @@ -222,6 +231,29 @@ impl<'a, 'tcx> SpanEncoder for EncodeContext<'a, 'tcx> { } } } + + fn encode_byte_symbol(&mut self, symbol: ByteSymbol) { + // if byte symbol predefined, emit tag and symbol index + if symbol.is_predefined() { + self.opaque.emit_u8(SYMBOL_PREDEFINED); + self.opaque.emit_u32(symbol.as_u32()); + } else { + // otherwise write it as string or as offset to it + match self.byte_symbol_table.entry(symbol) { + Entry::Vacant(o) => { + self.opaque.emit_u8(SYMBOL_STR); + let pos = self.opaque.position(); + o.insert(pos); + self.emit_byte_str(symbol.as_byte_str()); + } + Entry::Occupied(o) => { + let x = *o.get(); + self.emit_u8(SYMBOL_OFFSET); + self.emit_usize(x); + } + } + } + } } fn bytes_needed(n: usize) -> usize { @@ -2409,6 +2441,7 @@ fn with_encode_metadata_header( is_proc_macro: tcx.crate_types().contains(&CrateType::ProcMacro), hygiene_ctxt: &hygiene_ctxt, symbol_table: Default::default(), + byte_symbol_table: Default::default(), }; // Encode the rustc version string in a predictable location. diff --git a/compiler/rustc_middle/src/mir/interpret/mod.rs b/compiler/rustc_middle/src/mir/interpret/mod.rs index c2438af6a1e19..95676be1ae161 100644 --- a/compiler/rustc_middle/src/mir/interpret/mod.rs +++ b/compiler/rustc_middle/src/mir/interpret/mod.rs @@ -77,7 +77,7 @@ impl<'tcx> GlobalId<'tcx> { #[derive(Copy, Clone, Debug, Eq, PartialEq, Hash, HashStable)] pub struct LitToConstInput<'tcx> { /// The absolute value of the resultant constant. - pub lit: &'tcx LitKind, + pub lit: LitKind, /// The type of the constant. pub ty: Ty<'tcx>, /// If the constant is negative. diff --git a/compiler/rustc_middle/src/query/on_disk_cache.rs b/compiler/rustc_middle/src/query/on_disk_cache.rs index e1876f8f0f9b6..df168f3680100 100644 --- a/compiler/rustc_middle/src/query/on_disk_cache.rs +++ b/compiler/rustc_middle/src/query/on_disk_cache.rs @@ -20,8 +20,8 @@ use rustc_span::hygiene::{ }; use rustc_span::source_map::Spanned; use rustc_span::{ - BytePos, CachingSourceMapView, ExpnData, ExpnHash, Pos, RelativeBytePos, SourceFile, Span, - SpanDecoder, SpanEncoder, StableSourceFileId, Symbol, + BytePos, ByteSymbol, CachingSourceMapView, ExpnData, ExpnHash, Pos, RelativeBytePos, + SourceFile, Span, SpanDecoder, SpanEncoder, StableSourceFileId, Symbol, }; use crate::dep_graph::{DepNodeIndex, SerializedDepNodeIndex}; @@ -42,7 +42,7 @@ const TAG_RELATIVE_SPAN: u8 = 2; const TAG_SYNTAX_CONTEXT: u8 = 0; const TAG_EXPN_DATA: u8 = 1; -// Tags for encoding Symbol's +// Tags for encoding Symbols and ByteSymbols const SYMBOL_STR: u8 = 0; const SYMBOL_OFFSET: u8 = 1; const SYMBOL_PREDEFINED: u8 = 2; @@ -254,6 +254,7 @@ impl OnDiskCache { file_to_file_index, hygiene_context: &hygiene_encode_context, symbol_table: Default::default(), + byte_symbol_table: Default::default(), }; // Encode query results. @@ -653,6 +654,7 @@ impl<'a, 'tcx> SpanDecoder for CacheDecoder<'a, 'tcx> { Span::new(lo, hi, ctxt, parent) } + // njn: gross // copy&paste impl from rustc_metadata #[inline] fn decode_symbol(&mut self) -> Symbol { @@ -681,6 +683,35 @@ impl<'a, 'tcx> SpanDecoder for CacheDecoder<'a, 'tcx> { } } + // njn: gross + // copy&paste impl from rustc_metadata + #[inline] + fn decode_byte_symbol(&mut self) -> ByteSymbol { + let tag = self.read_u8(); + + match tag { + SYMBOL_STR => { + let s = self.read_byte_str(); + ByteSymbol::intern(s) + } + SYMBOL_OFFSET => { + // read str offset + let pos = self.read_usize(); + + // move to str offset and read + self.opaque.with_position(pos, |d| { + let s = d.read_byte_str(); + ByteSymbol::intern(s) + }) + } + SYMBOL_PREDEFINED => { + let symbol_index = self.read_u32(); + ByteSymbol::new(symbol_index) + } + _ => unreachable!(), + } + } + fn decode_crate_num(&mut self) -> CrateNum { let stable_id = StableCrateId::decode(self); let cnum = self.tcx.stable_crate_id_to_crate_num(stable_id); @@ -808,6 +839,7 @@ pub struct CacheEncoder<'a, 'tcx> { file_to_file_index: FxHashMap<*const SourceFile, SourceFileIndex>, hygiene_context: &'a HygieneEncodeContext, symbol_table: FxHashMap, + byte_symbol_table: FxHashMap, } impl<'a, 'tcx> CacheEncoder<'a, 'tcx> { @@ -913,6 +945,30 @@ impl<'a, 'tcx> SpanEncoder for CacheEncoder<'a, 'tcx> { } } + // copy&paste impl from rustc_metadata + fn encode_byte_symbol(&mut self, symbol: ByteSymbol) { + // if byte symbol predefined, emit tag and symbol index + if symbol.is_predefined() { + self.encoder.emit_u8(SYMBOL_PREDEFINED); + self.encoder.emit_u32(symbol.as_u32()); + } else { + // otherwise write it as byte string or as offset to it + match self.byte_symbol_table.entry(symbol) { + Entry::Vacant(o) => { + self.encoder.emit_u8(SYMBOL_STR); + let pos = self.encoder.position(); + o.insert(pos); + self.emit_byte_str(symbol.as_byte_str()); + } + Entry::Occupied(o) => { + let x = *o.get(); + self.emit_u8(SYMBOL_OFFSET); + self.emit_usize(x); + } + } + } + } + fn encode_crate_num(&mut self, crate_num: CrateNum) { self.tcx.stable_crate_id(crate_num).encode(self); } diff --git a/compiler/rustc_middle/src/thir.rs b/compiler/rustc_middle/src/thir.rs index b9a014d14c0d0..dd16fb0bd4b18 100644 --- a/compiler/rustc_middle/src/thir.rs +++ b/compiler/rustc_middle/src/thir.rs @@ -513,7 +513,7 @@ pub enum ExprKind<'tcx> { Closure(Box>), /// A literal. Literal { - lit: &'tcx hir::Lit, + lit: hir::Lit, neg: bool, }, /// For literals that don't correspond to anything in the HIR diff --git a/compiler/rustc_mir_build/src/builder/expr/as_constant.rs b/compiler/rustc_mir_build/src/builder/expr/as_constant.rs index eb8e98ec3644d..d0d0c21463f85 100644 --- a/compiler/rustc_mir_build/src/builder/expr/as_constant.rs +++ b/compiler/rustc_mir_build/src/builder/expr/as_constant.rs @@ -49,7 +49,7 @@ pub(crate) fn as_constant_inner<'tcx>( let Expr { ty, temp_lifetime: _, span, ref kind } = *expr; match *kind { ExprKind::Literal { lit, neg } => { - let const_ = lit_to_mir_constant(tcx, LitToConstInput { lit: &lit.node, ty, neg }); + let const_ = lit_to_mir_constant(tcx, LitToConstInput { lit: lit.node, ty, neg }); ConstOperand { span, user_ty: None, const_ } } @@ -128,34 +128,35 @@ fn lit_to_mir_constant<'tcx>(tcx: TyCtxt<'tcx>, lit_input: LitToConstInput<'tcx> (ast::LitKind::ByteStr(data, _), ty::Ref(_, inner_ty, _)) if matches!(inner_ty.kind(), ty::Slice(_)) => { - let allocation = Allocation::from_bytes_byte_aligned_immutable(data as &[u8], ()); + let allocation = Allocation::from_bytes_byte_aligned_immutable(data.as_byte_str(), ()); let allocation = tcx.mk_const_alloc(allocation); ConstValue::Slice { data: allocation, meta: allocation.inner().size().bytes() } } - (ast::LitKind::ByteStr(data, _), ty::Ref(_, inner_ty, _)) if inner_ty.is_array() => { - let id = tcx.allocate_bytes_dedup(data, CTFE_ALLOC_SALT); + (ast::LitKind::ByteStr(byte_sym, _), ty::Ref(_, inner_ty, _)) if inner_ty.is_array() => { + let id = tcx.allocate_bytes_dedup(byte_sym.as_byte_str(), CTFE_ALLOC_SALT); ConstValue::Scalar(Scalar::from_pointer(id.into(), &tcx)) } - (ast::LitKind::CStr(data, _), ty::Ref(_, inner_ty, _)) if matches!(inner_ty.kind(), ty::Adt(def, _) if tcx.is_lang_item(def.did(), LangItem::CStr)) => + (ast::LitKind::CStr(byte_sym, _), ty::Ref(_, inner_ty, _)) if matches!(inner_ty.kind(), ty::Adt(def, _) if tcx.is_lang_item(def.did(), LangItem::CStr)) => { - let allocation = Allocation::from_bytes_byte_aligned_immutable(data as &[u8], ()); + let allocation = + Allocation::from_bytes_byte_aligned_immutable(byte_sym.as_byte_str(), ()); let allocation = tcx.mk_const_alloc(allocation); ConstValue::Slice { data: allocation, meta: allocation.inner().size().bytes() } } (ast::LitKind::Byte(n), ty::Uint(ty::UintTy::U8)) => { - ConstValue::Scalar(Scalar::from_uint(*n, Size::from_bytes(1))) + ConstValue::Scalar(Scalar::from_uint(n, Size::from_bytes(1))) } (ast::LitKind::Int(n, _), ty::Uint(_)) if !neg => trunc(n.get()), (ast::LitKind::Int(n, _), ty::Int(_)) => { trunc(if neg { (n.get() as i128).overflowing_neg().0 as u128 } else { n.get() }) } (ast::LitKind::Float(n, _), ty::Float(fty)) => { - parse_float_into_constval(*n, *fty, neg).unwrap() + parse_float_into_constval(n, *fty, neg).unwrap() } - (ast::LitKind::Bool(b), ty::Bool) => ConstValue::Scalar(Scalar::from_bool(*b)), - (ast::LitKind::Char(c), ty::Char) => ConstValue::Scalar(Scalar::from_char(*c)), + (ast::LitKind::Bool(b), ty::Bool) => ConstValue::Scalar(Scalar::from_bool(b)), + (ast::LitKind::Char(c), ty::Char) => ConstValue::Scalar(Scalar::from_char(c)), (ast::LitKind::Err(guar), _) => { - return Const::Ty(Ty::new_error(tcx, *guar), ty::Const::new_error(tcx, *guar)); + return Const::Ty(Ty::new_error(tcx, guar), ty::Const::new_error(tcx, guar)); } _ => bug!("invalid lit/ty combination in `lit_to_mir_constant`: {lit:?}: {ty:?}"), }; diff --git a/compiler/rustc_mir_build/src/thir/constant.rs b/compiler/rustc_mir_build/src/thir/constant.rs index b4fa55e1c1fdb..8e218a380e9ea 100644 --- a/compiler/rustc_mir_build/src/thir/constant.rs +++ b/compiler/rustc_mir_build/src/thir/constant.rs @@ -43,27 +43,23 @@ pub(crate) fn lit_to_const<'tcx>( let str_bytes = s.as_str().as_bytes(); ty::ValTree::from_raw_bytes(tcx, str_bytes) } - (ast::LitKind::ByteStr(data, _), ty::Ref(_, inner_ty, _)) + (ast::LitKind::ByteStr(byte_sym, _), ty::Ref(_, inner_ty, _)) if matches!(inner_ty.kind(), ty::Slice(_) | ty::Array(..)) => { - let bytes = data as &[u8]; - ty::ValTree::from_raw_bytes(tcx, bytes) + ty::ValTree::from_raw_bytes(tcx, byte_sym.as_byte_str()) } - (ast::LitKind::ByteStr(data, _), ty::Slice(_) | ty::Array(..)) + (ast::LitKind::ByteStr(byte_sym, _), ty::Slice(_) | ty::Array(..)) if tcx.features().deref_patterns() => { // Byte string literal patterns may have type `[u8]` or `[u8; N]` if `deref_patterns` is // enabled, in order to allow, e.g., `deref!(b"..."): Vec`. - let bytes = data as &[u8]; - ty::ValTree::from_raw_bytes(tcx, bytes) + ty::ValTree::from_raw_bytes(tcx, byte_sym.as_byte_str()) } (ast::LitKind::Byte(n), ty::Uint(ty::UintTy::U8)) => { - ty::ValTree::from_scalar_int(tcx, (*n).into()) + ty::ValTree::from_scalar_int(tcx, n.into()) } - (ast::LitKind::CStr(data, _), ty::Ref(_, inner_ty, _)) if matches!(inner_ty.kind(), ty::Adt(def, _) if tcx.is_lang_item(def.did(), LangItem::CStr)) => - { - let bytes = data as &[u8]; - ty::ValTree::from_raw_bytes(tcx, bytes) + (ast::LitKind::CStr(byte_sym, _), ty::Ref(_, inner_ty, _)) if matches!(inner_ty.kind(), ty::Adt(def, _) if tcx.is_lang_item(def.did(), LangItem::CStr)) => { + ty::ValTree::from_raw_bytes(tcx, byte_sym.as_byte_str()) } (ast::LitKind::Int(n, _), ty::Uint(ui)) if !neg => { let scalar_int = trunc(n.get(), *ui); @@ -76,15 +72,15 @@ pub(crate) fn lit_to_const<'tcx>( ); ty::ValTree::from_scalar_int(tcx, scalar_int) } - (ast::LitKind::Bool(b), ty::Bool) => ty::ValTree::from_scalar_int(tcx, (*b).into()), + (ast::LitKind::Bool(b), ty::Bool) => ty::ValTree::from_scalar_int(tcx, b.into()), (ast::LitKind::Float(n, _), ty::Float(fty)) => { - let bits = parse_float_into_scalar(*n, *fty, neg).unwrap_or_else(|| { + let bits = parse_float_into_scalar(n, *fty, neg).unwrap_or_else(|| { tcx.dcx().bug(format!("couldn't parse float literal: {:?}", lit_input.lit)) }); ty::ValTree::from_scalar_int(tcx, bits) } - (ast::LitKind::Char(c), ty::Char) => ty::ValTree::from_scalar_int(tcx, (*c).into()), - (ast::LitKind::Err(guar), _) => return ty::Const::new_error(tcx, *guar), + (ast::LitKind::Char(c), ty::Char) => ty::ValTree::from_scalar_int(tcx, c.into()), + (ast::LitKind::Err(guar), _) => return ty::Const::new_error(tcx, guar), _ => return ty::Const::new_misc_error(tcx), }; diff --git a/compiler/rustc_mir_build/src/thir/pattern/mod.rs b/compiler/rustc_mir_build/src/thir/pattern/mod.rs index fcd106d78e253..e44a440b5c13c 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/mod.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/mod.rs @@ -680,7 +680,7 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> { Some(pat_ty) => pat_ty, None => self.typeck_results.node_type(expr.hir_id), }; - let lit_input = LitToConstInput { lit: &lit.node, ty: ct_ty, neg: *negated }; + let lit_input = LitToConstInput { lit: lit.node, ty: ct_ty, neg: *negated }; let constant = self.tcx.at(expr.span).lit_to_const(lit_input); self.const_to_pat(constant, ct_ty, expr.hir_id, lit.span).kind } diff --git a/compiler/rustc_serialize/src/serialize.rs b/compiler/rustc_serialize/src/serialize.rs index 1eefd76f92b49..ece110ec0726c 100644 --- a/compiler/rustc_serialize/src/serialize.rs +++ b/compiler/rustc_serialize/src/serialize.rs @@ -72,6 +72,13 @@ pub trait Encoder { self.emit_u8(STR_SENTINEL); } + #[inline] + fn emit_byte_str(&mut self, v: &[u8]) { + self.emit_usize(v.len()); + self.emit_raw_bytes(v); + self.emit_u8(STR_SENTINEL); + } + fn emit_raw_bytes(&mut self, s: &[u8]); } @@ -125,6 +132,14 @@ pub trait Decoder { unsafe { std::str::from_utf8_unchecked(&bytes[..len]) } } + #[inline] + fn read_byte_str(&mut self) -> &[u8] { + let len = self.read_usize(); + let bytes = self.read_raw_bytes(len + 1); + assert!(bytes[len] == STR_SENTINEL); + &bytes[..len] + } + fn read_raw_bytes(&mut self, len: usize) -> &[u8]; fn peek_byte(&self) -> u8; diff --git a/compiler/rustc_span/src/lib.rs b/compiler/rustc_span/src/lib.rs index 906462a0d229d..b263a6a8d21ff 100644 --- a/compiler/rustc_span/src/lib.rs +++ b/compiler/rustc_span/src/lib.rs @@ -66,7 +66,9 @@ mod span_encoding; pub use span_encoding::{DUMMY_SP, Span}; pub mod symbol; -pub use symbol::{Ident, MacroRulesNormalizedIdent, STDLIB_STABLE_CRATES, Symbol, kw, sym}; +pub use symbol::{ + ByteSymbol, Ident, MacroRulesNormalizedIdent, STDLIB_STABLE_CRATES, Symbol, kw, sym, +}; mod analyze_source_file; pub mod fatal_error; @@ -101,6 +103,7 @@ mod tests; /// session. pub struct SessionGlobals { symbol_interner: symbol::Interner, + byte_symbol_interner: symbol::ByteInterner, span_interner: Lock, /// Maps a macro argument token into use of the corresponding metavariable in the macro body. /// Collisions are possible and processed in `maybe_use_metavar_location` on best effort basis. @@ -121,6 +124,7 @@ impl SessionGlobals { ) -> SessionGlobals { SessionGlobals { symbol_interner: symbol::Interner::with_extra_symbols(extra_symbols), + byte_symbol_interner: symbol::ByteInterner::prefill(&[b""]), // njn: ? span_interner: Lock::new(span_encoding::SpanInterner::default()), metavar_spans: Default::default(), hygiene_data: Lock::new(hygiene::HygieneData::new(edition)), @@ -1185,6 +1189,7 @@ rustc_index::newtype_index! { pub trait SpanEncoder: Encoder { fn encode_span(&mut self, span: Span); fn encode_symbol(&mut self, symbol: Symbol); + fn encode_byte_symbol(&mut self, symbol: ByteSymbol); fn encode_expn_id(&mut self, expn_id: ExpnId); fn encode_syntax_context(&mut self, syntax_context: SyntaxContext); /// As a local identifier, a `CrateNum` is only meaningful within its context, e.g. within a tcx. @@ -1205,6 +1210,10 @@ impl SpanEncoder for FileEncoder { self.emit_str(symbol.as_str()); } + fn encode_byte_symbol(&mut self, symbol: ByteSymbol) { + self.emit_byte_str(symbol.as_byte_str()); + } + fn encode_expn_id(&mut self, _expn_id: ExpnId) { panic!("cannot encode `ExpnId` with `FileEncoder`"); } @@ -1239,6 +1248,12 @@ impl Encodable for Symbol { } } +impl Encodable for ByteSymbol { + fn encode(&self, s: &mut E) { + s.encode_byte_symbol(*self); + } +} + impl Encodable for ExpnId { fn encode(&self, s: &mut E) { s.encode_expn_id(*self) @@ -1280,6 +1295,7 @@ impl Encodable for AttrId { pub trait SpanDecoder: Decoder { fn decode_span(&mut self) -> Span; fn decode_symbol(&mut self) -> Symbol; + fn decode_byte_symbol(&mut self) -> ByteSymbol; fn decode_expn_id(&mut self) -> ExpnId; fn decode_syntax_context(&mut self) -> SyntaxContext; fn decode_crate_num(&mut self) -> CrateNum; @@ -1300,6 +1316,10 @@ impl SpanDecoder for MemDecoder<'_> { Symbol::intern(self.read_str()) } + fn decode_byte_symbol(&mut self) -> ByteSymbol { + ByteSymbol::intern(self.read_byte_str()) + } + fn decode_expn_id(&mut self) -> ExpnId { panic!("cannot decode `ExpnId` with `MemDecoder`"); } @@ -1337,6 +1357,12 @@ impl Decodable for Symbol { } } +impl Decodable for ByteSymbol { + fn decode(s: &mut D) -> ByteSymbol { + s.decode_byte_symbol() + } +} + impl Decodable for ExpnId { fn decode(s: &mut D) -> ExpnId { s.decode_expn_id() diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 970faf2997c5b..1c478550eac42 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -2850,3 +2850,217 @@ pub fn used_keywords(edition: impl Copy + FnOnce() -> Edition) -> Vec { }) .collect() } + +/// njn: update +/// njn: could move this to byte_symbol module +/// An interned string. +/// +/// Internally, a `Symbol` is implemented as an index, and all operations +/// (including hashing, equality, and ordering) operate on that index. The use +/// of `rustc_index::newtype_index!` means that `Option` only takes up 4 bytes, +/// because `rustc_index::newtype_index!` reserves the last 256 values for tagging purposes. +/// +/// Note that `Symbol` cannot directly be a `rustc_index::newtype_index!` because it +/// implements `fmt::Debug`, `Encodable`, and `Decodable` in special ways. +#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] +pub struct ByteSymbol(ByteSymbolIndex); + +rustc_index::newtype_index! { + #[orderable] + struct ByteSymbolIndex {} +} + +impl ByteSymbol { + pub const fn new(n: u32) -> Self { + ByteSymbol(ByteSymbolIndex::from_u32(n)) + } + + /// Maps a string to its interned representation. + #[rustc_diagnostic_item = "ByteSymbolIntern"] + // njn: rename `string` variables as `byte_str`? + pub fn intern(string: &[u8]) -> Self { + with_session_globals(|session_globals| session_globals.byte_symbol_interner.intern(string)) + } + + /// Access the underlying string. This is a slowish operation because it + /// requires locking the symbol interner. + /// + /// Note that the lifetime of the return value is a lie. It's not the same + /// as `&self`, but actually tied to the lifetime of the underlying + /// interner. Interners are long-lived, and there are very few of them, and + /// this function is typically used for short-lived things, so in practice + /// it works out ok. + /// njn: rename? + pub fn as_byte_str(&self) -> &[u8] { + with_session_globals(|session_globals| unsafe { + std::mem::transmute::<&[u8], &[u8]>(session_globals.byte_symbol_interner.get(*self)) + }) + } + + pub fn as_u32(self) -> u32 { + self.0.as_u32() + } + + // pub fn is_empty(self) -> bool { + // self == sym::empty + // } +} + +// njn: needed? +impl fmt::Debug for ByteSymbol { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt::Debug::fmt(self.as_byte_str(), f) + } +} + +// impl fmt::Display for Symbol { +// fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { +// fmt::Display::fmt(self.as_str(), f) +// } +// } + +impl HashStable for ByteSymbol { + #[inline] + fn hash_stable(&self, hcx: &mut CTX, hasher: &mut StableHasher) { + self.as_byte_str().hash_stable(hcx, hasher); + } +} + +// impl ToStableHashKey for Symbol { +// type KeyType = String; +// #[inline] +// fn to_stable_hash_key(&self, _: &CTX) -> String { +// self.as_str().to_string() +// } +// } + +// impl StableCompare for Symbol { +// const CAN_USE_UNSTABLE_SORT: bool = true; + +// fn stable_cmp(&self, other: &Self) -> std::cmp::Ordering { +// self.as_str().cmp(other.as_str()) +// } +// } + +pub(crate) struct ByteInterner(Lock); + +// njn: update comment +// The `&'static str`s in this type actually point into the arena. +// +// This type is private to prevent accidentally constructing more than one +// `Interner` on the same thread, which makes it easy to mix up `Symbol`s +// between `Interner`s. +// njn: parameterize? +struct ByteInternerInner { + arena: DroplessArena, + strings: FxIndexSet<&'static [u8]>, // njn: rename? +} + +impl ByteInterner { + // fn new(init: &[&'static str], extra: &[&'static str]) -> Self { + // let strings = FxIndexSet::from_iter(init.iter().copied().chain(extra.iter().copied())); + // assert_eq!( + // strings.len(), + // init.len() + extra.len(), + // "`init` or `extra` contain duplicate symbols", + // ); + // Interner(Lock::new(ByteInternerInner { arena: Default::default(), strings })) + // } + + pub(crate) fn prefill(init: &[&'static [u8]]) -> Self { + // njn: explain this + let strings = FxIndexSet::from_iter(init.iter().copied()); + assert_eq!(strings.len(), init.len(), "`init` contains duplicate symbols",); + ByteInterner(Lock::new(ByteInternerInner { arena: Default::default(), strings })) + } + + #[inline] + fn intern(&self, string: &[u8]) -> ByteSymbol { + let mut inner = self.0.lock(); + if let Some(idx) = inner.strings.get_index_of(string) { + return ByteSymbol::new(idx as u32); + } + + let string: &[u8] = inner.arena.alloc_slice(string); + + // SAFETY: we can extend the arena allocation to `'static` because we + // only access these while the arena is still alive. + let string: &'static [u8] = unsafe { &*(string as *const [u8]) }; + + // This second hash table lookup can be avoided by using `RawEntryMut`, + // but this code path isn't hot enough for it to be worth it. See + // #91445 for details. + let (idx, is_new) = inner.strings.insert_full(string); + debug_assert!(is_new); // due to the get_index_of check above + + ByteSymbol::new(idx as u32) + } + + /// Get the symbol as a string. + /// + /// [`ByteSymbol::as_byte_str()`] should be used in preference to this function. + fn get(&self, symbol: ByteSymbol) -> &[u8] { + self.0.lock().strings.get_index(symbol.0.as_usize()).unwrap() + } +} + +impl ByteSymbol { + // fn is_special(self) -> bool { + // self <= kw::Underscore + // } + + // fn is_used_keyword_always(self) -> bool { + // self >= kw::As && self <= kw::While + // } + + // fn is_unused_keyword_always(self) -> bool { + // self >= kw::Abstract && self <= kw::Yield + // } + + // fn is_used_keyword_conditional(self, edition: impl FnOnce() -> Edition) -> bool { + // (self >= kw::Async && self <= kw::Dyn) && edition() >= Edition::Edition2018 + // } + + // fn is_unused_keyword_conditional(self, edition: impl Copy + FnOnce() -> Edition) -> bool { + // self == kw::Gen && edition().at_least_rust_2024() + // || self == kw::Try && edition().at_least_rust_2018() + // } + + // pub fn is_reserved(self, edition: impl Copy + FnOnce() -> Edition) -> bool { + // self.is_special() + // || self.is_used_keyword_always() + // || self.is_unused_keyword_always() + // || self.is_used_keyword_conditional(edition) + // || self.is_unused_keyword_conditional(edition) + // } + + // pub fn is_weak(self) -> bool { + // self >= kw::Auto && self <= kw::Yeet + // } + + // /// A keyword or reserved identifier that can be used as a path segment. + // pub fn is_path_segment_keyword(self) -> bool { + // self == kw::Super + // || self == kw::SelfLower + // || self == kw::SelfUpper + // || self == kw::Crate + // || self == kw::PathRoot + // || self == kw::DollarCrate + // } + + // /// Returns `true` if the symbol is `true` or `false`. + // pub fn is_bool_lit(self) -> bool { + // self == kw::True || self == kw::False + // } + + // /// Returns `true` if this symbol can be a raw identifier. + // pub fn can_be_raw(self) -> bool { + // self != sym::empty && self != kw::Underscore && !self.is_path_segment_keyword() + // } + + /// njn: update comment + /// Was this symbol predefined in the compiler's `symbols!` macro + pub fn is_predefined(self) -> bool { + self.as_u32() == 0 // njn: do better! + } +} diff --git a/compiler/rustc_ty_utils/src/consts.rs b/compiler/rustc_ty_utils/src/consts.rs index b275cd382ab83..d21383b4f82fe 100644 --- a/compiler/rustc_ty_utils/src/consts.rs +++ b/compiler/rustc_ty_utils/src/consts.rs @@ -120,7 +120,7 @@ fn recurse_build<'tcx>( } &ExprKind::Literal { lit, neg } => { let sp = node.span; - tcx.at(sp).lit_to_const(LitToConstInput { lit: &lit.node, ty: node.ty, neg }) + tcx.at(sp).lit_to_const(LitToConstInput { lit: lit.node, ty: node.ty, neg }) } &ExprKind::NonHirLiteral { lit, user_ty: _ } => { let val = ty::ValTree::from_scalar_int(tcx, lit); diff --git a/src/tools/clippy/clippy_lints/src/approx_const.rs b/src/tools/clippy/clippy_lints/src/approx_const.rs index 852e48cbcaeec..5ed4c82634aa8 100644 --- a/src/tools/clippy/clippy_lints/src/approx_const.rs +++ b/src/tools/clippy/clippy_lints/src/approx_const.rs @@ -74,7 +74,7 @@ impl ApproxConstant { } impl LateLintPass<'_> for ApproxConstant { - fn check_lit(&mut self, cx: &LateContext<'_>, _hir_id: HirId, lit: &Lit, _negated: bool) { + fn check_lit(&mut self, cx: &LateContext<'_>, _hir_id: HirId, lit: Lit, _negated: bool) { match lit.node { LitKind::Float(s, LitFloatType::Suffixed(fty)) => match fty { FloatTy::F16 => self.check_known_consts(cx, lit.span, s, "f16"), diff --git a/src/tools/clippy/clippy_lints/src/bool_assert_comparison.rs b/src/tools/clippy/clippy_lints/src/bool_assert_comparison.rs index ae36bb76117d7..344d5c60914df 100644 --- a/src/tools/clippy/clippy_lints/src/bool_assert_comparison.rs +++ b/src/tools/clippy/clippy_lints/src/bool_assert_comparison.rs @@ -42,7 +42,7 @@ fn extract_bool_lit(e: &Expr<'_>) -> Option { }) = e.kind && !e.span.from_expansion() { - Some(*b) + Some(b) } else { None } diff --git a/src/tools/clippy/clippy_lints/src/casts/manual_dangling_ptr.rs b/src/tools/clippy/clippy_lints/src/casts/manual_dangling_ptr.rs index 61dfc0fc0425e..4d971028bd738 100644 --- a/src/tools/clippy/clippy_lints/src/casts/manual_dangling_ptr.rs +++ b/src/tools/clippy/clippy_lints/src/casts/manual_dangling_ptr.rs @@ -46,7 +46,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, from: &Expr<'_>, to: fn is_expr_const_aligned(cx: &LateContext<'_>, expr: &Expr<'_>, to: &Ty<'_>) -> bool { match expr.kind { ExprKind::Call(fun, _) => is_align_of_call(cx, fun, to), - ExprKind::Lit(lit) => is_literal_aligned(cx, lit, to), + ExprKind::Lit(lit) => is_literal_aligned(cx, &lit, to), _ => false, } } diff --git a/src/tools/clippy/clippy_lints/src/casts/unnecessary_cast.rs b/src/tools/clippy/clippy_lints/src/casts/unnecessary_cast.rs index 8e8c55cf38329..ca05ea60def6c 100644 --- a/src/tools/clippy/clippy_lints/src/casts/unnecessary_cast.rs +++ b/src/tools/clippy/clippy_lints/src/casts/unnecessary_cast.rs @@ -243,7 +243,7 @@ fn lint_unnecessary_cast( ); } -fn get_numeric_literal<'e>(expr: &'e Expr<'e>) -> Option<&'e Lit> { +fn get_numeric_literal<'e>(expr: &'e Expr<'e>) -> Option { match expr.kind { ExprKind::Lit(lit) => Some(lit), ExprKind::Unary(UnOp::Neg, e) => { diff --git a/src/tools/clippy/clippy_lints/src/default_numeric_fallback.rs b/src/tools/clippy/clippy_lints/src/default_numeric_fallback.rs index 784214c29af9f..1507f1ed30539 100644 --- a/src/tools/clippy/clippy_lints/src/default_numeric_fallback.rs +++ b/src/tools/clippy/clippy_lints/src/default_numeric_fallback.rs @@ -83,7 +83,7 @@ impl<'a, 'tcx> NumericFallbackVisitor<'a, 'tcx> { } /// Check whether a passed literal has potential to cause fallback or not. - fn check_lit(&self, lit: &Lit, lit_ty: Ty<'tcx>, emit_hir_id: HirId) { + fn check_lit(&self, lit: Lit, lit_ty: Ty<'tcx>, emit_hir_id: HirId) { if !lit.span.in_external_macro(self.cx.sess().source_map()) && matches!(self.ty_bounds.last(), Some(ExplicitTyBound(false))) && matches!( @@ -210,7 +210,7 @@ impl<'tcx> Visitor<'tcx> for NumericFallbackVisitor<'_, 'tcx> { ExprKind::Lit(lit) => { let ty = self.cx.typeck_results().expr_ty(expr); - self.check_lit(lit, ty, expr.hir_id); + self.check_lit(*lit, ty, expr.hir_id); return; }, diff --git a/src/tools/clippy/clippy_lints/src/large_include_file.rs b/src/tools/clippy/clippy_lints/src/large_include_file.rs index 621a2af1d322b..8707612fbdd0a 100644 --- a/src/tools/clippy/clippy_lints/src/large_include_file.rs +++ b/src/tools/clippy/clippy_lints/src/large_include_file.rs @@ -57,7 +57,7 @@ impl LateLintPass<'_> for LargeIncludeFile { if let ExprKind::Lit(lit) = &expr.kind && let len = match &lit.node { // include_bytes - LitKind::ByteStr(bstr, _) => bstr.len(), + LitKind::ByteStr(bstr, _) => bstr.as_byte_str().len(), // include_str LitKind::Str(sym, _) => sym.as_str().len(), _ => return, diff --git a/src/tools/clippy/clippy_lints/src/manual_ignore_case_cmp.rs b/src/tools/clippy/clippy_lints/src/manual_ignore_case_cmp.rs index 57c03fbb2ed2b..f7d9ec1fae8e4 100644 --- a/src/tools/clippy/clippy_lints/src/manual_ignore_case_cmp.rs +++ b/src/tools/clippy/clippy_lints/src/manual_ignore_case_cmp.rs @@ -41,12 +41,12 @@ declare_clippy_lint! { declare_lint_pass!(ManualIgnoreCaseCmp => [MANUAL_IGNORE_CASE_CMP]); -enum MatchType<'a, 'b> { +enum MatchType<'a> { ToAscii(bool, Ty<'a>), - Literal(&'b LitKind), + Literal(LitKind), } -fn get_ascii_type<'a, 'b>(cx: &LateContext<'a>, kind: rustc_hir::ExprKind<'b>) -> Option<(Span, MatchType<'a, 'b>)> { +fn get_ascii_type<'a>(cx: &LateContext<'a>, kind: rustc_hir::ExprKind<'_>) -> Option<(Span, MatchType<'a>)> { if let MethodCall(path, expr, _, _) = kind { let is_lower = match path.ident.name { sym::to_ascii_lowercase => true, @@ -63,7 +63,7 @@ fn get_ascii_type<'a, 'b>(cx: &LateContext<'a>, kind: rustc_hir::ExprKind<'b>) - return Some((expr.span, ToAscii(is_lower, ty_raw))); } } else if let Lit(expr) = kind { - return Some((expr.span, Literal(&expr.node))); + return Some((expr.span, Literal(expr.node))); } None } diff --git a/src/tools/clippy/clippy_lints/src/manual_strip.rs b/src/tools/clippy/clippy_lints/src/manual_strip.rs index 9e911e61f1968..6bf43a1c6d47c 100644 --- a/src/tools/clippy/clippy_lints/src/manual_strip.rs +++ b/src/tools/clippy/clippy_lints/src/manual_strip.rs @@ -184,7 +184,7 @@ fn eq_pattern_length<'tcx>(cx: &LateContext<'tcx>, pattern: &Expr<'_>, expr: &'t .. }) = expr.kind { - constant_length(cx, pattern).is_some_and(|length| *n == length) + constant_length(cx, pattern).is_some_and(|length| n == length) } else { len_arg(cx, expr).is_some_and(|arg| eq_expr_value(cx, pattern, arg)) } diff --git a/src/tools/clippy/clippy_lints/src/matches/match_like_matches.rs b/src/tools/clippy/clippy_lints/src/matches/match_like_matches.rs index f14b69d91ce4b..5816da5695eb6 100644 --- a/src/tools/clippy/clippy_lints/src/matches/match_like_matches.rs +++ b/src/tools/clippy/clippy_lints/src/matches/match_like_matches.rs @@ -159,7 +159,7 @@ fn find_bool_lit(ex: &ExprKind<'_>) -> Option { node: LitKind::Bool(b), .. }) = exp.kind { - Some(*b) + Some(b) } else { None } diff --git a/src/tools/clippy/clippy_lints/src/matches/match_same_arms.rs b/src/tools/clippy/clippy_lints/src/matches/match_same_arms.rs index dbb29ee776b18..b1a6b6e14c171 100644 --- a/src/tools/clippy/clippy_lints/src/matches/match_same_arms.rs +++ b/src/tools/clippy/clippy_lints/src/matches/match_same_arms.rs @@ -12,7 +12,7 @@ use rustc_hir::{Arm, Expr, HirId, HirIdMap, HirIdMapEntry, HirIdSet, Pat, PatExp use rustc_lint::builtin::NON_EXHAUSTIVE_OMITTED_PATTERNS; use rustc_lint::{LateContext, LintContext}; use rustc_middle::ty; -use rustc_span::{ErrorGuaranteed, Span, Symbol}; +use rustc_span::{ByteSymbol, ErrorGuaranteed, Span, Symbol}; use super::MATCH_SAME_ARMS; @@ -193,7 +193,7 @@ enum NormalizedPat<'a> { Or(&'a [Self]), Path(Option), LitStr(Symbol), - LitBytes(&'a [u8]), + LitBytes(ByteSymbol), LitInt(u128), LitBool(bool), Range(PatRange), @@ -332,7 +332,9 @@ impl<'a> NormalizedPat<'a> { // TODO: Handle negative integers. They're currently treated as a wild match. PatExprKind::Lit { lit, negated: false } => match lit.node { LitKind::Str(sym, _) => Self::LitStr(sym), - LitKind::ByteStr(ref bytes, _) | LitKind::CStr(ref bytes, _) => Self::LitBytes(bytes), + LitKind::ByteStr(bytes, _) | LitKind::CStr(bytes, _) => { + Self::LitBytes(bytes) + } LitKind::Byte(val) => Self::LitInt(val.into()), LitKind::Char(val) => Self::LitInt(val.into()), LitKind::Int(val, _) => Self::LitInt(val.get()), diff --git a/src/tools/clippy/clippy_lints/src/methods/open_options.rs b/src/tools/clippy/clippy_lints/src/methods/open_options.rs index bce314e64f053..6bce8b75e834a 100644 --- a/src/tools/clippy/clippy_lints/src/methods/open_options.rs +++ b/src/tools/clippy/clippy_lints/src/methods/open_options.rs @@ -76,7 +76,7 @@ fn get_open_options( .. } = span { - Argument::Set(*lit) + Argument::Set(lit) } else { // The function is called with a literal which is not a boolean literal. // This is theoretically possible, but not very likely. diff --git a/src/tools/clippy/clippy_lints/src/missing_asserts_for_indexing.rs b/src/tools/clippy/clippy_lints/src/missing_asserts_for_indexing.rs index c8e3462b24ef4..cf0c85990b150 100644 --- a/src/tools/clippy/clippy_lints/src/missing_asserts_for_indexing.rs +++ b/src/tools/clippy/clippy_lints/src/missing_asserts_for_indexing.rs @@ -104,7 +104,7 @@ fn len_comparison<'hir>( ) -> Option<(LengthComparison, usize, &'hir Expr<'hir>)> { macro_rules! int_lit_pat { ($id:ident) => { - ExprKind::Lit(&Spanned { + ExprKind::Lit(Spanned { node: LitKind::Int(Pu128($id), _), .. }) diff --git a/src/tools/clippy/clippy_lints/src/utils/author.rs b/src/tools/clippy/clippy_lints/src/utils/author.rs index 3a08531cf1c9c..ac92ab5a245cc 100644 --- a/src/tools/clippy/clippy_lints/src/utils/author.rs +++ b/src/tools/clippy/clippy_lints/src/utils/author.rs @@ -324,7 +324,7 @@ impl<'a, 'tcx> PrintVisitor<'a, 'tcx> { } } - fn lit(&self, lit: &Binding<&Lit>) { + fn lit(&self, lit: &Binding) { let kind = |kind| chain!(self, "let LitKind::{kind} = {lit}.node"); macro_rules! kind { ($($t:tt)*) => (kind(format_args!($($t)*))); diff --git a/src/tools/clippy/clippy_utils/src/consts.rs b/src/tools/clippy/clippy_utils/src/consts.rs index 1ec5d11384f57..45d53d120a250 100644 --- a/src/tools/clippy/clippy_utils/src/consts.rs +++ b/src/tools/clippy/clippy_utils/src/consts.rs @@ -4,8 +4,6 @@ //! executable MIR bodies, so we have to do this instead. #![allow(clippy::float_cmp)] -use std::sync::Arc; - use crate::source::{SpanRangeExt, walk_span_to_context}; use crate::{clip, is_direct_expn_of, sext, unsext}; @@ -38,7 +36,7 @@ pub enum Constant<'tcx> { /// A `String` (e.g., "abc"). Str(String), /// A binary string (e.g., `b"abc"`). - Binary(Arc<[u8]>), + Binary(Vec), /// A single `char` (e.g., `'a'`). Char(char), /// An integer's bit representation. @@ -306,7 +304,9 @@ pub fn lit_to_mir_constant<'tcx>(lit: &LitKind, ty: Option>) -> Constan match *lit { LitKind::Str(ref is, _) => Constant::Str(is.to_string()), LitKind::Byte(b) => Constant::Int(u128::from(b)), - LitKind::ByteStr(ref s, _) | LitKind::CStr(ref s, _) => Constant::Binary(Arc::clone(s)), + LitKind::ByteStr(ref s, _) | LitKind::CStr(ref s, _) => { + Constant::Binary(s.as_byte_str().to_vec()) + } LitKind::Char(c) => Constant::Char(c), LitKind::Int(n, _) => Constant::Int(n.get()), LitKind::Float(ref is, LitFloatType::Suffixed(fty)) => match fty { @@ -568,7 +568,9 @@ impl<'tcx> ConstEvalCtxt<'tcx> { } else { match &lit.node { LitKind::Str(is, _) => Some(is.is_empty()), - LitKind::ByteStr(s, _) | LitKind::CStr(s, _) => Some(s.is_empty()), + LitKind::ByteStr(s, _) | LitKind::CStr(s, _) => { + Some(s.as_byte_str().is_empty()) + } _ => None, } }