Auto merge of #140695 - Zalathar:rollup-i32gzbo, r=Zalathar

Rollup of 12 pull requests

Successful merges:

 - #139550 (Fix `-Zremap-path-scope` rmeta handling)
 - #139764 (Consistent trait bounds for ExtractIf Debug impls)
 - #139773 (Implement `Iterator::last` for `vec::IntoIter`)
 - #140035 (Implement RFC 3503: frontmatters)
 - #140251 (coverage-dump: Resolve global file IDs to filenames)
 - #140393 (std: get rid of `sys_common::process`)
 - #140532 (Fix RustAnalyzer discovery of rustc's `stable_mir` crate)
 - #140598 (Steer docs to `utf8_chunks` and `Iterator::take`)
 - #140634 (Use more accurate ELF flags on MIPS)
 - #140673 (Clean rustdoc tests folder)
 - #140678 (Be a bit more relaxed about not yet constrained infer vars in closure upvar analysis)
 - #140687 (Update mdbook to 0.4.49)

r? `@ghost`
`@rustbot` modify labels: rollup
This commit is contained in:
bors 2025-05-06 06:37:30 +00:00
commit 651e9cf327
559 changed files with 2330 additions and 761 deletions

View file

@ -777,6 +777,7 @@ name = "coverage-dump"
version = "0.1.0"
dependencies = [
"anyhow",
"itertools",
"leb128",
"md-5",
"miniz_oxide 0.7.4",
@ -3604,13 +3605,13 @@ dependencies = [
"rustc_query_system",
"rustc_resolve",
"rustc_session",
"rustc_smir",
"rustc_span",
"rustc_target",
"rustc_trait_selection",
"rustc_ty_utils",
"serde_json",
"shlex",
"stable_mir",
"tracing",
"windows 0.59.0",
]

View file

@ -514,6 +514,7 @@ pub fn check_crate(krate: &ast::Crate, sess: &Session, features: &Features) {
gate_all!(contracts_internals, "contract internal machinery is for internal use only");
gate_all!(where_clause_attrs, "attributes in `where` clause are unstable");
gate_all!(super_let, "`super let` is experimental");
gate_all!(frontmatter, "frontmatters are experimental");
if !visitor.features.never_patterns() {
if let Some(spans) = spans.get(&sym::never_patterns) {

View file

@ -270,45 +270,61 @@ pub(super) fn elf_os_abi(sess: &Session) -> u8 {
pub(super) fn elf_e_flags(architecture: Architecture, sess: &Session) -> u32 {
match architecture {
Architecture::Mips => {
let arch = match sess.target.options.cpu.as_ref() {
"mips1" => elf::EF_MIPS_ARCH_1,
"mips2" => elf::EF_MIPS_ARCH_2,
Architecture::Mips | Architecture::Mips64 | Architecture::Mips64_N32 => {
// "N32" indicates an "ILP32" data model on a 64-bit MIPS CPU
// like SPARC's "v8+", x86_64's "x32", or the watchOS "arm64_32".
let is_32bit = architecture == Architecture::Mips;
let mut e_flags = match sess.target.options.cpu.as_ref() {
"mips1" if is_32bit => elf::EF_MIPS_ARCH_1,
"mips2" if is_32bit => elf::EF_MIPS_ARCH_2,
"mips3" => elf::EF_MIPS_ARCH_3,
"mips4" => elf::EF_MIPS_ARCH_4,
"mips5" => elf::EF_MIPS_ARCH_5,
s if s.contains("r6") => elf::EF_MIPS_ARCH_32R6,
_ => elf::EF_MIPS_ARCH_32R2,
"mips32r2" if is_32bit => elf::EF_MIPS_ARCH_32R2,
"mips32r6" if is_32bit => elf::EF_MIPS_ARCH_32R6,
"mips64r2" if !is_32bit => elf::EF_MIPS_ARCH_64R2,
"mips64r6" if !is_32bit => elf::EF_MIPS_ARCH_64R6,
s if s.starts_with("mips32") && !is_32bit => {
sess.dcx().fatal(format!("invalid CPU `{}` for 64-bit MIPS target", s))
}
s if s.starts_with("mips64") && is_32bit => {
sess.dcx().fatal(format!("invalid CPU `{}` for 32-bit MIPS target", s))
}
_ if is_32bit => elf::EF_MIPS_ARCH_32R2,
_ => elf::EF_MIPS_ARCH_64R2,
};
let mut e_flags = elf::EF_MIPS_CPIC | arch;
// If the ABI is explicitly given, use it or default to O32.
match sess.target.options.llvm_abiname.to_lowercase().as_str() {
"n32" => e_flags |= elf::EF_MIPS_ABI2,
"o32" => e_flags |= elf::EF_MIPS_ABI_O32,
_ => e_flags |= elf::EF_MIPS_ABI_O32,
// If the ABI is explicitly given, use it, or default to O32 on 32-bit MIPS,
// which is the only "true" 32-bit option that LLVM supports.
match sess.target.options.llvm_abiname.as_ref() {
"o32" if is_32bit => e_flags |= elf::EF_MIPS_ABI_O32,
"n32" if !is_32bit => e_flags |= elf::EF_MIPS_ABI2,
"n64" if !is_32bit => {}
"" if is_32bit => e_flags |= elf::EF_MIPS_ABI_O32,
"" => sess.dcx().fatal("LLVM ABI must be specifed for 64-bit MIPS targets"),
s if is_32bit => {
sess.dcx().fatal(format!("invalid LLVM ABI `{}` for 32-bit MIPS target", s))
}
s => sess.dcx().fatal(format!("invalid LLVM ABI `{}` for 64-bit MIPS target", s)),
};
if sess.target.options.relocation_model != RelocModel::Static {
e_flags |= elf::EF_MIPS_PIC;
// PIC means position-independent code. CPIC means "calls PIC".
// CPIC was mutually exclusive with PIC according to
// the SVR4 MIPS ABI https://refspecs.linuxfoundation.org/elf/mipsabi.pdf
// and should have only appeared on static objects with dynamically calls.
// At some point someone (GCC?) decided to set CPIC even for PIC.
// Nowadays various things expect both set on the same object file
// and may even error if you mix CPIC and non-CPIC object files,
// despite that being the entire point of the CPIC ABI extension!
// As we are in Rome, we do as the Romans do.
e_flags |= elf::EF_MIPS_PIC | elf::EF_MIPS_CPIC;
}
if sess.target.options.cpu.contains("r6") {
e_flags |= elf::EF_MIPS_NAN2008;
}
e_flags
}
Architecture::Mips64 => {
// copied from `mips64el-linux-gnuabi64-gcc foo.c -c`
let e_flags = elf::EF_MIPS_CPIC
| elf::EF_MIPS_PIC
| if sess.target.options.cpu.contains("r6") {
elf::EF_MIPS_ARCH_64R6 | elf::EF_MIPS_NAN2008
} else {
elf::EF_MIPS_ARCH_64R2
};
e_flags
}
Architecture::Riscv32 | Architecture::Riscv64 => {
// Source: https://github.com/riscv-non-isa/riscv-elf-psabi-doc/blob/079772828bd10933d34121117a222b4cc0ee2200/riscv-elf.adoc
let mut e_flags: u32 = 0x0;

View file

@ -44,13 +44,13 @@ rustc_privacy = { path = "../rustc_privacy" }
rustc_query_system = { path = "../rustc_query_system" }
rustc_resolve = { path = "../rustc_resolve" }
rustc_session = { path = "../rustc_session" }
rustc_smir = { path = "../rustc_smir" }
rustc_span = { path = "../rustc_span" }
rustc_target = { path = "../rustc_target" }
rustc_trait_selection = { path = "../rustc_trait_selection" }
rustc_ty_utils = { path = "../rustc_ty_utils" }
serde_json = "1.0.59"
shlex = "1.0"
stable_mir = { path = "../stable_mir", features = ["rustc_internal"] }
tracing = { version = "0.1.35" }
# tidy-alphabetical-end

View file

@ -10,8 +10,8 @@ use rustc_middle::ty::{self, TyCtxt};
use rustc_mir_build::thir::print::{thir_flat, thir_tree};
use rustc_session::Session;
use rustc_session::config::{OutFileName, PpHirMode, PpMode, PpSourceMode};
use rustc_smir::rustc_internal::pretty::write_smir_pretty;
use rustc_span::{FileName, Ident};
use stable_mir::rustc_internal::pretty::write_smir_pretty;
use tracing::debug;
use {rustc_ast as ast, rustc_hir_pretty as pprust_hir};

View file

@ -510,6 +510,8 @@ declare_features! (
(incomplete, fn_delegation, "1.76.0", Some(118212)),
/// Allows impls for the Freeze trait.
(internal, freeze_impls, "1.78.0", Some(121675)),
/// Frontmatter `---` blocks for use by external tools.
(unstable, frontmatter, "CURRENT_RUSTC_VERSION", Some(136889)),
/// Allows defining gen blocks and `gen fn`.
(unstable, gen_blocks, "1.75.0", Some(117078)),
/// Infer generic args for both consts and types.

View file

@ -158,7 +158,7 @@ pub trait TypeInformationCtxt<'tcx> {
fn resolve_vars_if_possible<T: TypeFoldable<TyCtxt<'tcx>>>(&self, t: T) -> T;
fn try_structurally_resolve_type(&self, span: Span, ty: Ty<'tcx>) -> Ty<'tcx>;
fn structurally_resolve_type(&self, span: Span, ty: Ty<'tcx>) -> Ty<'tcx>;
fn report_bug(&self, span: Span, msg: impl ToString) -> Self::Error;
@ -191,8 +191,8 @@ impl<'tcx> TypeInformationCtxt<'tcx> for &FnCtxt<'_, 'tcx> {
self.infcx.resolve_vars_if_possible(t)
}
fn try_structurally_resolve_type(&self, sp: Span, ty: Ty<'tcx>) -> Ty<'tcx> {
(**self).try_structurally_resolve_type(sp, ty)
fn structurally_resolve_type(&self, sp: Span, ty: Ty<'tcx>) -> Ty<'tcx> {
(**self).structurally_resolve_type(sp, ty)
}
fn report_bug(&self, span: Span, msg: impl ToString) -> Self::Error {
@ -236,7 +236,7 @@ impl<'tcx> TypeInformationCtxt<'tcx> for (&LateContext<'tcx>, LocalDefId) {
self.0.maybe_typeck_results().expect("expected typeck results")
}
fn try_structurally_resolve_type(&self, _span: Span, ty: Ty<'tcx>) -> Ty<'tcx> {
fn structurally_resolve_type(&self, _span: Span, ty: Ty<'tcx>) -> Ty<'tcx> {
// FIXME: Maybe need to normalize here.
ty
}
@ -776,7 +776,7 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx
// Select just those fields of the `with`
// expression that will actually be used
match self.cx.try_structurally_resolve_type(with_expr.span, with_place.place.ty()).kind() {
match self.cx.structurally_resolve_type(with_expr.span, with_place.place.ty()).kind() {
ty::Adt(adt, args) if adt.is_struct() => {
// Consume those fields of the with expression that are needed.
for (f_index, with_field) in adt.non_enum_variant().fields.iter_enumerated() {
@ -1176,7 +1176,7 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx
/// two operations: a dereference to reach the array data and then an index to
/// jump forward to the relevant item.
impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx, Cx, D> {
fn resolve_type_vars_or_bug(
fn expect_and_resolve_type(
&self,
id: HirId,
ty: Option<Ty<'tcx>>,
@ -1185,12 +1185,7 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx
Some(ty) => {
let ty = self.cx.resolve_vars_if_possible(ty);
self.cx.error_reported_in_ty(ty)?;
if ty.is_ty_var() {
debug!("resolve_type_vars_or_bug: infer var from {:?}", ty);
Err(self.cx.report_bug(self.cx.tcx().hir_span(id), "encountered type variable"))
} else {
Ok(ty)
}
Ok(ty)
}
None => {
// FIXME: We shouldn't be relying on the infcx being tainted.
@ -1201,15 +1196,15 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx
}
fn node_ty(&self, hir_id: HirId) -> Result<Ty<'tcx>, Cx::Error> {
self.resolve_type_vars_or_bug(hir_id, self.cx.typeck_results().node_type_opt(hir_id))
self.expect_and_resolve_type(hir_id, self.cx.typeck_results().node_type_opt(hir_id))
}
fn expr_ty(&self, expr: &hir::Expr<'_>) -> Result<Ty<'tcx>, Cx::Error> {
self.resolve_type_vars_or_bug(expr.hir_id, self.cx.typeck_results().expr_ty_opt(expr))
self.expect_and_resolve_type(expr.hir_id, self.cx.typeck_results().expr_ty_opt(expr))
}
fn expr_ty_adjusted(&self, expr: &hir::Expr<'_>) -> Result<Ty<'tcx>, Cx::Error> {
self.resolve_type_vars_or_bug(
self.expect_and_resolve_type(
expr.hir_id,
self.cx.typeck_results().expr_ty_adjusted_opt(expr),
)
@ -1264,10 +1259,7 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx
// a bind-by-ref means that the base_ty will be the type of the ident itself,
// but what we want here is the type of the underlying value being borrowed.
// So peel off one-level, turning the &T into T.
match self
.cx
.try_structurally_resolve_type(pat.span, base_ty)
.builtin_deref(false)
match self.cx.structurally_resolve_type(pat.span, base_ty).builtin_deref(false)
{
Some(ty) => Ok(ty),
None => {
@ -1513,10 +1505,7 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx
if node_ty != place_ty
&& self
.cx
.try_structurally_resolve_type(
self.cx.tcx().hir_span(base_place.hir_id),
place_ty,
)
.structurally_resolve_type(self.cx.tcx().hir_span(base_place.hir_id), place_ty)
.is_impl_trait()
{
projections.push(Projection { kind: ProjectionKind::OpaqueCast, ty: node_ty });
@ -1538,7 +1527,7 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx
let base_ty = self.expr_ty_adjusted(base)?;
let ty::Ref(region, _, mutbl) =
*self.cx.try_structurally_resolve_type(base.span, base_ty).kind()
*self.cx.structurally_resolve_type(base.span, base_ty).kind()
else {
span_bug!(expr.span, "cat_overloaded_place: base is not a reference");
};
@ -1556,7 +1545,7 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx
let base_curr_ty = base_place.place.ty();
let deref_ty = match self
.cx
.try_structurally_resolve_type(self.cx.tcx().hir_span(base_place.hir_id), base_curr_ty)
.structurally_resolve_type(self.cx.tcx().hir_span(base_place.hir_id), base_curr_ty)
.builtin_deref(true)
{
Some(ty) => ty,
@ -1584,7 +1573,7 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx
) -> Result<VariantIdx, Cx::Error> {
let res = self.cx.typeck_results().qpath_res(qpath, pat_hir_id);
let ty = self.cx.typeck_results().node_type(pat_hir_id);
let ty::Adt(adt_def, _) = self.cx.try_structurally_resolve_type(span, ty).kind() else {
let ty::Adt(adt_def, _) = self.cx.structurally_resolve_type(span, ty).kind() else {
return Err(self
.cx
.report_bug(span, "struct or tuple struct pattern not applied to an ADT"));
@ -1616,7 +1605,7 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx
span: Span,
) -> Result<usize, Cx::Error> {
let ty = self.cx.typeck_results().node_type(pat_hir_id);
match self.cx.try_structurally_resolve_type(span, ty).kind() {
match self.cx.structurally_resolve_type(span, ty).kind() {
ty::Adt(adt_def, _) => Ok(adt_def.variant(variant_index).fields.len()),
_ => {
self.cx
@ -1631,7 +1620,7 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx
/// Here `pat_hir_id` is the HirId of the pattern itself.
fn total_fields_in_tuple(&self, pat_hir_id: HirId, span: Span) -> Result<usize, Cx::Error> {
let ty = self.cx.typeck_results().node_type(pat_hir_id);
match self.cx.try_structurally_resolve_type(span, ty).kind() {
match self.cx.structurally_resolve_type(span, ty).kind() {
ty::Tuple(args) => Ok(args.len()),
_ => Err(self.cx.report_bug(span, "tuple pattern not applied to a tuple")),
}
@ -1820,7 +1809,7 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx
PatKind::Slice(before, ref slice, after) => {
let Some(element_ty) = self
.cx
.try_structurally_resolve_type(pat.span, place_with_id.place.ty())
.structurally_resolve_type(pat.span, place_with_id.place.ty())
.builtin_index()
else {
debug!("explicit index of non-indexable type {:?}", place_with_id);
@ -1890,7 +1879,7 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx
}
fn is_multivariant_adt(&self, ty: Ty<'tcx>, span: Span) -> bool {
if let ty::Adt(def, _) = self.cx.try_structurally_resolve_type(span, ty).kind() {
if let ty::Adt(def, _) = self.cx.structurally_resolve_type(span, ty).kind() {
// Note that if a non-exhaustive SingleVariant is defined in another crate, we need
// to assume that more cases will be added to the variant in the future. This mean
// that we should handle non-exhaustive SingleVariant the same way we would handle

View file

@ -1,5 +1,10 @@
use std::str::Chars;
pub enum FrontmatterAllowed {
Yes,
No,
}
/// Peekable iterator over a char sequence.
///
/// Next characters can be peeked via `first` method,
@ -8,6 +13,7 @@ pub struct Cursor<'a> {
len_remaining: usize,
/// Iterator over chars. Slightly faster than a &str.
chars: Chars<'a>,
pub(crate) frontmatter_allowed: FrontmatterAllowed,
#[cfg(debug_assertions)]
prev: char,
}
@ -15,10 +21,11 @@ pub struct Cursor<'a> {
pub(crate) const EOF_CHAR: char = '\0';
impl<'a> Cursor<'a> {
pub fn new(input: &'a str) -> Cursor<'a> {
pub fn new(input: &'a str, frontmatter_allowed: FrontmatterAllowed) -> Cursor<'a> {
Cursor {
len_remaining: input.len(),
chars: input.chars(),
frontmatter_allowed,
#[cfg(debug_assertions)]
prev: EOF_CHAR,
}
@ -95,6 +102,11 @@ impl<'a> Cursor<'a> {
Some(c)
}
/// Moves to a substring by a number of bytes.
pub(crate) fn bump_bytes(&mut self, n: usize) {
self.chars = self.as_str()[n..].chars();
}
/// Eats symbols while predicate returns true or until the end of file is reached.
pub(crate) fn eat_while(&mut self, mut predicate: impl FnMut(char) -> bool) {
// It was tried making optimized version of this for eg. line comments, but

View file

@ -35,8 +35,8 @@ pub use unicode_xid::UNICODE_VERSION as UNICODE_XID_VERSION;
use self::LiteralKind::*;
use self::TokenKind::*;
pub use crate::cursor::Cursor;
use crate::cursor::EOF_CHAR;
pub use crate::cursor::{Cursor, FrontmatterAllowed};
/// Parsed token.
/// It doesn't contain information about data that has been parsed,
@ -57,17 +57,27 @@ impl Token {
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum TokenKind {
/// A line comment, e.g. `// comment`.
LineComment { doc_style: Option<DocStyle> },
LineComment {
doc_style: Option<DocStyle>,
},
/// A block comment, e.g. `/* block comment */`.
///
/// Block comments can be recursive, so a sequence like `/* /* */`
/// will not be considered terminated and will result in a parsing error.
BlockComment { doc_style: Option<DocStyle>, terminated: bool },
BlockComment {
doc_style: Option<DocStyle>,
terminated: bool,
},
/// Any whitespace character sequence.
Whitespace,
Frontmatter {
has_invalid_preceding_whitespace: bool,
invalid_infostring: bool,
},
/// An identifier or keyword, e.g. `ident` or `continue`.
Ident,
@ -109,10 +119,15 @@ pub enum TokenKind {
/// this type will need to check for and reject that case.
///
/// See [LiteralKind] for more details.
Literal { kind: LiteralKind, suffix_start: u32 },
Literal {
kind: LiteralKind,
suffix_start: u32,
},
/// A lifetime, e.g. `'a`.
Lifetime { starts_with_number: bool },
Lifetime {
starts_with_number: bool,
},
/// `;`
Semi,
@ -280,7 +295,7 @@ pub fn strip_shebang(input: &str) -> Option<usize> {
#[inline]
pub fn validate_raw_str(input: &str, prefix_len: u32) -> Result<(), RawStrError> {
debug_assert!(!input.is_empty());
let mut cursor = Cursor::new(input);
let mut cursor = Cursor::new(input, FrontmatterAllowed::No);
// Move past the leading `r` or `br`.
for _ in 0..prefix_len {
cursor.bump().unwrap();
@ -290,7 +305,7 @@ pub fn validate_raw_str(input: &str, prefix_len: u32) -> Result<(), RawStrError>
/// Creates an iterator that produces tokens from the input string.
pub fn tokenize(input: &str) -> impl Iterator<Item = Token> {
let mut cursor = Cursor::new(input);
let mut cursor = Cursor::new(input, FrontmatterAllowed::No);
std::iter::from_fn(move || {
let token = cursor.advance_token();
if token.kind != TokenKind::Eof { Some(token) } else { None }
@ -361,7 +376,34 @@ impl Cursor<'_> {
Some(c) => c,
None => return Token::new(TokenKind::Eof, 0),
};
let token_kind = match first_char {
c if matches!(self.frontmatter_allowed, FrontmatterAllowed::Yes)
&& is_whitespace(c) =>
{
let mut last = first_char;
while is_whitespace(self.first()) {
let Some(c) = self.bump() else {
break;
};
last = c;
}
// invalid frontmatter opening as whitespace preceding it isn't newline.
// combine the whitespace and the frontmatter to a single token as we shall
// error later.
if last != '\n' && self.as_str().starts_with("---") {
self.bump();
self.frontmatter(true)
} else {
Whitespace
}
}
'-' if matches!(self.frontmatter_allowed, FrontmatterAllowed::Yes)
&& self.as_str().starts_with("--") =>
{
// happy path
self.frontmatter(false)
}
// Slash, comment or block comment.
'/' => match self.first() {
'/' => self.line_comment(),
@ -464,11 +506,110 @@ impl Cursor<'_> {
c if !c.is_ascii() && c.is_emoji_char() => self.invalid_ident(),
_ => Unknown,
};
if matches!(self.frontmatter_allowed, FrontmatterAllowed::Yes)
&& !matches!(token_kind, Whitespace)
{
// stop allowing frontmatters after first non-whitespace token
self.frontmatter_allowed = FrontmatterAllowed::No;
}
let res = Token::new(token_kind, self.pos_within_token());
self.reset_pos_within_token();
res
}
/// Given that one `-` was eaten, eat the rest of the frontmatter.
fn frontmatter(&mut self, has_invalid_preceding_whitespace: bool) -> TokenKind {
debug_assert_eq!('-', self.prev());
let pos = self.pos_within_token();
self.eat_while(|c| c == '-');
// one `-` is eaten by the caller.
let length_opening = self.pos_within_token() - pos + 1;
// must be ensured by the caller
debug_assert!(length_opening >= 3);
// whitespace between the opening and the infostring.
self.eat_while(|ch| ch != '\n' && is_whitespace(ch));
// copied from `eat_identifier`, but allows `.` in infostring to allow something like
// `---Cargo.toml` as a valid opener
if is_id_start(self.first()) {
self.bump();
self.eat_while(|c| is_id_continue(c) || c == '.');
}
self.eat_while(|ch| ch != '\n' && is_whitespace(ch));
let invalid_infostring = self.first() != '\n';
let mut s = self.as_str();
let mut found = false;
while let Some(closing) = s.find(&"-".repeat(length_opening as usize)) {
let preceding_chars_start = s[..closing].rfind("\n").map_or(0, |i| i + 1);
if s[preceding_chars_start..closing].chars().all(is_whitespace) {
// candidate found
self.bump_bytes(closing);
// in case like
// ---cargo
// --- blahblah
// or
// ---cargo
// ----
// combine those stuff into this frontmatter token such that it gets detected later.
self.eat_until(b'\n');
found = true;
break;
} else {
s = &s[closing + length_opening as usize..];
}
}
if !found {
// recovery strategy: a closing statement might have precending whitespace/newline
// but not have enough dashes to properly close. In this case, we eat until there,
// and report a mismatch in the parser.
let mut rest = self.as_str();
// We can look for a shorter closing (starting with four dashes but closing with three)
// and other indications that Rust has started and the infostring has ended.
let mut potential_closing = rest
.find("\n---")
// n.b. only in the case where there are dashes, we move the index to the line where
// the dashes start as we eat to include that line. For other cases those are Rust code
// and not included in the frontmatter.
.map(|x| x + 1)
.or_else(|| rest.find("\nuse "))
.or_else(|| rest.find("\n//!"))
.or_else(|| rest.find("\n#!["));
if potential_closing.is_none() {
// a less fortunate recovery if all else fails which finds any dashes preceded by whitespace
// on a standalone line. Might be wrong.
while let Some(closing) = rest.find("---") {
let preceding_chars_start = rest[..closing].rfind("\n").map_or(0, |i| i + 1);
if rest[preceding_chars_start..closing].chars().all(is_whitespace) {
// candidate found
potential_closing = Some(closing);
break;
} else {
rest = &rest[closing + 3..];
}
}
}
if let Some(potential_closing) = potential_closing {
// bump to the potential closing, and eat everything on that line.
self.bump_bytes(potential_closing);
self.eat_until(b'\n');
} else {
// eat everything. this will get reported as an unclosed frontmatter.
self.eat_while(|_| true);
}
}
Frontmatter { has_invalid_preceding_whitespace, invalid_infostring }
}
fn line_comment(&mut self) -> TokenKind {
debug_assert!(self.prev() == '/' && self.first() == '/');
self.bump();

View file

@ -4,7 +4,7 @@ use super::*;
fn check_raw_str(s: &str, expected: Result<u8, RawStrError>) {
let s = &format!("r{}", s);
let mut cursor = Cursor::new(s);
let mut cursor = Cursor::new(s, FrontmatterAllowed::No);
cursor.bump();
let res = cursor.raw_double_quoted_string(0);
assert_eq!(res, expected);

View file

@ -551,8 +551,6 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
match source_file.name {
FileName::Real(ref original_file_name) => {
// FIXME: This should probably to conditionally remapped under
// a RemapPathScopeComponents but which one?
let adapted_file_name = source_map
.path_mapping()
.to_embeddable_absolute_path(original_file_name.clone(), working_directory);

View file

@ -297,6 +297,19 @@ parse_forgot_paren = perhaps you forgot parentheses?
parse_found_expr_would_be_stmt = expected expression, found `{$token}`
.label = expected expression
parse_frontmatter_extra_characters_after_close = extra characters after frontmatter close are not allowed
parse_frontmatter_invalid_close_preceding_whitespace = invalid preceding whitespace for frontmatter close
.note = frontmatter close should not be preceded by whitespace
parse_frontmatter_invalid_infostring = invalid infostring for frontmatter
.note = frontmatter infostrings must be a single identifier immediately following the opening
parse_frontmatter_invalid_opening_preceding_whitespace = invalid preceding whitespace for frontmatter opening
.note = frontmatter opening should not be preceded by whitespace
parse_frontmatter_length_mismatch = frontmatter close does not match the opening
.label_opening = the opening here has {$len_opening} dashes...
.label_close = ...while the close has {$len_close} dashes
parse_frontmatter_unclosed = unclosed frontmatter
.note = frontmatter opening here was not closed
parse_function_body_equals_expr = function body cannot be `= expression;`
.suggestion = surround the expression with `{"{"}` and `{"}"}` instead of `=` and `;`

View file

@ -735,6 +735,61 @@ pub(crate) struct FoundExprWouldBeStmt {
pub suggestion: ExprParenthesesNeeded,
}
#[derive(Diagnostic)]
#[diag(parse_frontmatter_extra_characters_after_close)]
pub(crate) struct FrontmatterExtraCharactersAfterClose {
#[primary_span]
pub span: Span,
}
#[derive(Diagnostic)]
#[diag(parse_frontmatter_invalid_infostring)]
#[note]
pub(crate) struct FrontmatterInvalidInfostring {
#[primary_span]
pub span: Span,
}
#[derive(Diagnostic)]
#[diag(parse_frontmatter_invalid_opening_preceding_whitespace)]
pub(crate) struct FrontmatterInvalidOpeningPrecedingWhitespace {
#[primary_span]
pub span: Span,
#[note]
pub note_span: Span,
}
#[derive(Diagnostic)]
#[diag(parse_frontmatter_unclosed)]
pub(crate) struct FrontmatterUnclosed {
#[primary_span]
pub span: Span,
#[note]
pub note_span: Span,
}
#[derive(Diagnostic)]
#[diag(parse_frontmatter_invalid_close_preceding_whitespace)]
pub(crate) struct FrontmatterInvalidClosingPrecedingWhitespace {
#[primary_span]
pub span: Span,
#[note]
pub note_span: Span,
}
#[derive(Diagnostic)]
#[diag(parse_frontmatter_length_mismatch)]
pub(crate) struct FrontmatterLengthMismatch {
#[primary_span]
pub span: Span,
#[label(parse_label_opening)]
pub opening: Span,
#[label(parse_label_close)]
pub close: Span,
pub len_opening: usize,
pub len_close: usize,
}
#[derive(Diagnostic)]
#[diag(parse_leading_plus_not_supported)]
pub(crate) struct LeadingPlusNotSupported {

View file

@ -7,7 +7,9 @@ use rustc_ast::tokenstream::TokenStream;
use rustc_ast::util::unicode::contains_text_flow_control_chars;
use rustc_errors::codes::*;
use rustc_errors::{Applicability, Diag, DiagCtxtHandle, StashKey};
use rustc_lexer::{Base, Cursor, DocStyle, LiteralKind, RawStrError};
use rustc_lexer::{
Base, Cursor, DocStyle, FrontmatterAllowed, LiteralKind, RawStrError, is_whitespace,
};
use rustc_literal_escaper::{EscapeError, Mode, unescape_mixed, unescape_unicode};
use rustc_session::lint::BuiltinLintDiag;
use rustc_session::lint::builtin::{
@ -15,7 +17,7 @@ use rustc_session::lint::builtin::{
TEXT_DIRECTION_CODEPOINT_IN_COMMENT,
};
use rustc_session::parse::ParseSess;
use rustc_span::{BytePos, Pos, Span, Symbol};
use rustc_span::{BytePos, Pos, Span, Symbol, sym};
use tracing::debug;
use crate::errors;
@ -56,7 +58,7 @@ pub(crate) fn lex_token_trees<'psess, 'src>(
start_pos = start_pos + BytePos::from_usize(shebang_len);
}
let cursor = Cursor::new(src);
let cursor = Cursor::new(src, FrontmatterAllowed::Yes);
let mut lexer = Lexer {
psess,
start_pos,
@ -193,6 +195,11 @@ impl<'psess, 'src> Lexer<'psess, 'src> {
let content = self.str_from_to(content_start, content_end);
self.cook_doc_comment(content_start, content, CommentKind::Block, doc_style)
}
rustc_lexer::TokenKind::Frontmatter { has_invalid_preceding_whitespace, invalid_infostring } => {
self.validate_frontmatter(start, has_invalid_preceding_whitespace, invalid_infostring);
preceded_by_whitespace = true;
continue;
}
rustc_lexer::TokenKind::Whitespace => {
preceded_by_whitespace = true;
continue;
@ -256,7 +263,7 @@ impl<'psess, 'src> Lexer<'psess, 'src> {
// was consumed.
let lit_start = start + BytePos(prefix_len);
self.pos = lit_start;
self.cursor = Cursor::new(&str_before[prefix_len as usize..]);
self.cursor = Cursor::new(&str_before[prefix_len as usize..], FrontmatterAllowed::No);
self.report_unknown_prefix(start);
let prefix_span = self.mk_sp(start, lit_start);
return (Token::new(self.ident(start), prefix_span), preceded_by_whitespace);
@ -361,7 +368,7 @@ impl<'psess, 'src> Lexer<'psess, 'src> {
// Reset the state so we just lex the `'r`.
let lt_start = start + BytePos(2);
self.pos = lt_start;
self.cursor = Cursor::new(&str_before[2 as usize..]);
self.cursor = Cursor::new(&str_before[2 as usize..], FrontmatterAllowed::No);
let lifetime_name = self.str_from(start);
let ident = Symbol::intern(lifetime_name);
@ -474,6 +481,91 @@ impl<'psess, 'src> Lexer<'psess, 'src> {
}
}
fn validate_frontmatter(
&self,
start: BytePos,
has_invalid_preceding_whitespace: bool,
invalid_infostring: bool,
) {
let s = self.str_from(start);
let real_start = s.find("---").unwrap();
let frontmatter_opening_pos = BytePos(real_start as u32) + start;
let s_new = &s[real_start..];
let within = s_new.trim_start_matches('-');
let len_opening = s_new.len() - within.len();
let frontmatter_opening_end_pos = frontmatter_opening_pos + BytePos(len_opening as u32);
if has_invalid_preceding_whitespace {
let line_start =
BytePos(s[..real_start].rfind("\n").map_or(0, |i| i as u32 + 1)) + start;
let span = self.mk_sp(line_start, frontmatter_opening_end_pos);
let label_span = self.mk_sp(line_start, frontmatter_opening_pos);
self.dcx().emit_err(errors::FrontmatterInvalidOpeningPrecedingWhitespace {
span,
note_span: label_span,
});
}
if invalid_infostring {
let line_end = s[real_start..].find('\n').unwrap_or(s[real_start..].len());
let span = self.mk_sp(
frontmatter_opening_end_pos,
frontmatter_opening_pos + BytePos(line_end as u32),
);
self.dcx().emit_err(errors::FrontmatterInvalidInfostring { span });
}
let last_line_start = within.rfind('\n').map_or(0, |i| i + 1);
let last_line = &within[last_line_start..];
let last_line_trimmed = last_line.trim_start_matches(is_whitespace);
let last_line_start_pos = frontmatter_opening_end_pos + BytePos(last_line_start as u32);
let frontmatter_span = self.mk_sp(frontmatter_opening_pos, self.pos);
self.psess.gated_spans.gate(sym::frontmatter, frontmatter_span);
if !last_line_trimmed.starts_with("---") {
let label_span = self.mk_sp(frontmatter_opening_pos, frontmatter_opening_end_pos);
self.dcx().emit_err(errors::FrontmatterUnclosed {
span: frontmatter_span,
note_span: label_span,
});
return;
}
if last_line_trimmed.len() != last_line.len() {
let line_end = last_line_start_pos + BytePos(last_line.len() as u32);
let span = self.mk_sp(last_line_start_pos, line_end);
let whitespace_end =
last_line_start_pos + BytePos((last_line.len() - last_line_trimmed.len()) as u32);
let label_span = self.mk_sp(last_line_start_pos, whitespace_end);
self.dcx().emit_err(errors::FrontmatterInvalidClosingPrecedingWhitespace {
span,
note_span: label_span,
});
}
let rest = last_line_trimmed.trim_start_matches('-');
let len_close = last_line_trimmed.len() - rest.len();
if len_close != len_opening {
let span = self.mk_sp(frontmatter_opening_pos, self.pos);
let opening = self.mk_sp(frontmatter_opening_pos, frontmatter_opening_end_pos);
let last_line_close_pos = last_line_start_pos + BytePos(len_close as u32);
let close = self.mk_sp(last_line_start_pos, last_line_close_pos);
self.dcx().emit_err(errors::FrontmatterLengthMismatch {
span,
opening,
close,
len_opening,
len_close,
});
}
if !rest.trim_matches(is_whitespace).is_empty() {
let span = self.mk_sp(last_line_start_pos, self.pos);
self.dcx().emit_err(errors::FrontmatterExtraCharactersAfterClose { span });
}
}
fn cook_doc_comment(
&self,
content_start: BytePos,
@ -839,7 +931,7 @@ impl<'psess, 'src> Lexer<'psess, 'src> {
let space_pos = start + BytePos(1);
let space_span = self.mk_sp(space_pos, space_pos);
let mut cursor = Cursor::new(str_before);
let mut cursor = Cursor::new(str_before, FrontmatterAllowed::No);
let (is_string, span, unterminated) = match cursor.guarded_double_quoted_string() {
Some(rustc_lexer::GuardedStr { n_hashes, terminated, token_len }) => {
@ -905,7 +997,7 @@ impl<'psess, 'src> Lexer<'psess, 'src> {
// For backwards compatibility, roll back to after just the first `#`
// and return the `Pound` token.
self.pos = start + BytePos(1);
self.cursor = Cursor::new(&str_before[1..]);
self.cursor = Cursor::new(&str_before[1..], FrontmatterAllowed::No);
token::Pound
}
}

View file

@ -24,7 +24,8 @@ use rustc_macros::{Decodable, Encodable, HashStable_Generic};
use rustc_span::edition::{DEFAULT_EDITION, EDITION_NAME_LIST, Edition, LATEST_STABLE_EDITION};
use rustc_span::source_map::FilePathMapping;
use rustc_span::{
FileName, FileNameDisplayPreference, RealFileName, SourceFileHashAlgorithm, Symbol, sym,
FileName, FileNameDisplayPreference, FileNameEmbeddablePreference, RealFileName,
SourceFileHashAlgorithm, Symbol, sym,
};
use rustc_target::spec::{
FramePointer, LinkSelfContainedComponents, LinkerFeatures, SplitDebuginfo, Target, TargetTuple,
@ -1320,6 +1321,11 @@ fn file_path_mapping(
} else {
FileNameDisplayPreference::Local
},
if unstable_opts.remap_path_scope.is_all() {
FileNameEmbeddablePreference::RemappedOnly
} else {
FileNameEmbeddablePreference::LocalAndRemapped
},
)
}

View file

@ -224,7 +224,7 @@ pub fn with_metavar_spans<R>(f: impl FnOnce(&MetavarSpansMap) -> R) -> R {
// FIXME: We should use this enum or something like it to get rid of the
// use of magic `/rust/1.x/...` paths across the board.
#[derive(Debug, Eq, PartialEq, Clone, Ord, PartialOrd, Decodable)]
#[derive(Debug, Eq, PartialEq, Clone, Ord, PartialOrd, Decodable, Encodable)]
pub enum RealFileName {
LocalPath(PathBuf),
/// For remapped paths (namely paths into libstd that have been mapped
@ -250,28 +250,6 @@ impl Hash for RealFileName {
}
}
// This is functionally identical to #[derive(Encodable)], with the exception of
// an added assert statement
impl<S: Encoder> Encodable<S> for RealFileName {
fn encode(&self, encoder: &mut S) {
match *self {
RealFileName::LocalPath(ref local_path) => {
encoder.emit_u8(0);
local_path.encode(encoder);
}
RealFileName::Remapped { ref local_path, ref virtual_name } => {
encoder.emit_u8(1);
// For privacy and build reproducibility, we must not embed host-dependant path
// in artifacts if they have been remapped by --remap-path-prefix
assert!(local_path.is_none());
local_path.encode(encoder);
virtual_name.encode(encoder);
}
}
}
}
impl RealFileName {
/// Returns the path suitable for reading from the file system on the local host,
/// if this information exists.
@ -368,6 +346,16 @@ impl From<PathBuf> for FileName {
}
}
#[derive(Clone, Copy, Eq, PartialEq, Hash, Debug)]
pub enum FileNameEmbeddablePreference {
/// If a remapped path is available, only embed the `virtual_path` and omit the `local_path`.
///
/// Otherwise embed the local-path into the `virtual_path`.
RemappedOnly,
/// Embed the original path as well as its remapped `virtual_path` component if available.
LocalAndRemapped,
}
#[derive(Clone, Copy, Eq, PartialEq, Hash, Debug)]
pub enum FileNameDisplayPreference {
/// Display the path after the application of rewrite rules provided via `--remap-path-prefix`.

View file

@ -1108,18 +1108,28 @@ pub fn get_source_map() -> Option<Arc<SourceMap>> {
pub struct FilePathMapping {
mapping: Vec<(PathBuf, PathBuf)>,
filename_display_for_diagnostics: FileNameDisplayPreference,
filename_embeddable_preference: FileNameEmbeddablePreference,
}
impl FilePathMapping {
pub fn empty() -> FilePathMapping {
FilePathMapping::new(Vec::new(), FileNameDisplayPreference::Local)
FilePathMapping::new(
Vec::new(),
FileNameDisplayPreference::Local,
FileNameEmbeddablePreference::RemappedOnly,
)
}
pub fn new(
mapping: Vec<(PathBuf, PathBuf)>,
filename_display_for_diagnostics: FileNameDisplayPreference,
filename_embeddable_preference: FileNameEmbeddablePreference,
) -> FilePathMapping {
FilePathMapping { mapping, filename_display_for_diagnostics }
FilePathMapping {
mapping,
filename_display_for_diagnostics,
filename_embeddable_preference,
}
}
/// Applies any path prefix substitution as defined by the mapping.
@ -1217,11 +1227,13 @@ impl FilePathMapping {
) -> RealFileName {
match file_path {
// Anything that's already remapped we don't modify, except for erasing
// the `local_path` portion.
RealFileName::Remapped { local_path: _, virtual_name } => {
// the `local_path` portion (if desired).
RealFileName::Remapped { local_path, virtual_name } => {
RealFileName::Remapped {
// We do not want any local path to be exported into metadata
local_path: None,
local_path: match self.filename_embeddable_preference {
FileNameEmbeddablePreference::RemappedOnly => None,
FileNameEmbeddablePreference::LocalAndRemapped => local_path,
},
// We use the remapped name verbatim, even if it looks like a relative
// path. The assumption is that the user doesn't want us to further
// process paths that have gone through remapping.
@ -1231,12 +1243,18 @@ impl FilePathMapping {
RealFileName::LocalPath(unmapped_file_path) => {
// If no remapping has been applied yet, try to do so
let (new_path, was_remapped) = self.map_prefix(unmapped_file_path);
let (new_path, was_remapped) = self.map_prefix(&unmapped_file_path);
if was_remapped {
// It was remapped, so don't modify further
return RealFileName::Remapped {
local_path: None,
virtual_name: new_path.into_owned(),
// But still provide the local path if desired
local_path: match self.filename_embeddable_preference {
FileNameEmbeddablePreference::RemappedOnly => None,
FileNameEmbeddablePreference::LocalAndRemapped => {
Some(unmapped_file_path)
}
},
};
}
@ -1252,17 +1270,23 @@ impl FilePathMapping {
match working_directory {
RealFileName::LocalPath(unmapped_working_dir_abs) => {
let file_path_abs = unmapped_working_dir_abs.join(unmapped_file_path_rel);
let unmapped_file_path_abs =
unmapped_working_dir_abs.join(unmapped_file_path_rel);
// Although neither `working_directory` nor the file name were subject
// to path remapping, the concatenation between the two may be. Hence
// we need to do a remapping here.
let (file_path_abs, was_remapped) = self.map_prefix(file_path_abs);
let (file_path_abs, was_remapped) =
self.map_prefix(&unmapped_file_path_abs);
if was_remapped {
RealFileName::Remapped {
// Erase the actual path
local_path: None,
virtual_name: file_path_abs.into_owned(),
local_path: match self.filename_embeddable_preference {
FileNameEmbeddablePreference::RemappedOnly => None,
FileNameEmbeddablePreference::LocalAndRemapped => {
Some(unmapped_file_path_abs)
}
},
}
} else {
// No kind of remapping applied to this path, so
@ -1271,15 +1295,20 @@ impl FilePathMapping {
}
}
RealFileName::Remapped {
local_path: _,
local_path,
virtual_name: remapped_working_dir_abs,
} => {
// If working_directory has been remapped, then we emit
// Remapped variant as the expanded path won't be valid
RealFileName::Remapped {
local_path: None,
virtual_name: Path::new(remapped_working_dir_abs)
.join(unmapped_file_path_rel),
.join(&unmapped_file_path_rel),
local_path: match self.filename_embeddable_preference {
FileNameEmbeddablePreference::RemappedOnly => None,
FileNameEmbeddablePreference::LocalAndRemapped => local_path
.as_ref()
.map(|local_path| local_path.join(unmapped_file_path_rel)),
},
}
}
}
@ -1287,27 +1316,6 @@ impl FilePathMapping {
}
}
/// Expand a relative path to an absolute path **without** remapping taken into account.
///
/// The resulting `RealFileName` will have its `virtual_path` portion erased if
/// possible (i.e. if there's also a remapped path).
pub fn to_local_embeddable_absolute_path(
&self,
file_path: RealFileName,
working_directory: &RealFileName,
) -> RealFileName {
let file_path = file_path.local_path_if_available();
if file_path.is_absolute() {
// No remapping has applied to this path and it is absolute,
// so the working directory cannot influence it either, so
// we are done.
return RealFileName::LocalPath(file_path.to_path_buf());
}
debug_assert!(file_path.is_relative());
let working_directory = working_directory.local_path_if_available();
RealFileName::LocalPath(Path::new(working_directory).join(file_path))
}
/// Attempts to (heuristically) reverse a prefix mapping.
///
/// Returns [`Some`] if there is exactly one mapping where the "to" part is

View file

@ -305,6 +305,7 @@ fn path_prefix_remapping() {
let mapping = &FilePathMapping::new(
vec![(path("abc/def"), path("foo"))],
FileNameDisplayPreference::Remapped,
FileNameEmbeddablePreference::RemappedOnly,
);
assert_eq!(map_path_prefix(mapping, "abc/def/src/main.rs"), path_str("foo/src/main.rs"));
@ -316,6 +317,7 @@ fn path_prefix_remapping() {
let mapping = &FilePathMapping::new(
vec![(path("abc/def"), path("/foo"))],
FileNameDisplayPreference::Remapped,
FileNameEmbeddablePreference::RemappedOnly,
);
assert_eq!(map_path_prefix(mapping, "abc/def/src/main.rs"), path_str("/foo/src/main.rs"));
@ -327,6 +329,7 @@ fn path_prefix_remapping() {
let mapping = &FilePathMapping::new(
vec![(path("/abc/def"), path("foo"))],
FileNameDisplayPreference::Remapped,
FileNameEmbeddablePreference::RemappedOnly,
);
assert_eq!(map_path_prefix(mapping, "/abc/def/src/main.rs"), path_str("foo/src/main.rs"));
@ -338,6 +341,7 @@ fn path_prefix_remapping() {
let mapping = &FilePathMapping::new(
vec![(path("/abc/def"), path("/foo"))],
FileNameDisplayPreference::Remapped,
FileNameEmbeddablePreference::RemappedOnly,
);
assert_eq!(map_path_prefix(mapping, "/abc/def/src/main.rs"), path_str("/foo/src/main.rs"));
@ -351,6 +355,7 @@ fn path_prefix_remapping_expand_to_absolute() {
let mapping = &FilePathMapping::new(
vec![(path("/foo"), path("FOO")), (path("/bar"), path("BAR"))],
FileNameDisplayPreference::Remapped,
FileNameEmbeddablePreference::RemappedOnly,
);
let working_directory = path("/foo");
let working_directory = RealFileName::Remapped {
@ -448,6 +453,71 @@ fn path_prefix_remapping_expand_to_absolute() {
);
}
#[test]
fn path_prefix_remapping_expand_to_absolute_and_local() {
// "virtual" working directory is relative path
let mapping = &FilePathMapping::new(
vec![(path("/foo"), path("FOO")), (path("/bar"), path("BAR"))],
FileNameDisplayPreference::Remapped,
FileNameEmbeddablePreference::LocalAndRemapped,
);
let working_directory = path("/foo");
let working_directory = RealFileName::Remapped {
local_path: Some(working_directory.clone()),
virtual_name: mapping.map_prefix(working_directory).0.into_owned(),
};
assert_eq!(working_directory.remapped_path_if_available(), path("FOO"));
// Unmapped absolute path
assert_eq!(
mapping.to_embeddable_absolute_path(
RealFileName::LocalPath(path("/foo/src/main.rs")),
&working_directory
),
RealFileName::Remapped {
local_path: Some(path("/foo/src/main.rs")),
virtual_name: path("FOO/src/main.rs")
}
);
// Unmapped absolute path with unrelated working directory
assert_eq!(
mapping.to_embeddable_absolute_path(
RealFileName::LocalPath(path("/bar/src/main.rs")),
&working_directory
),
RealFileName::Remapped {
local_path: Some(path("/bar/src/main.rs")),
virtual_name: path("BAR/src/main.rs")
}
);
// Already remapped absolute path, with unrelated working directory
assert_eq!(
mapping.to_embeddable_absolute_path(
RealFileName::Remapped {
local_path: Some(path("/bar/src/main.rs")),
virtual_name: path("BAR/src/main.rs"),
},
&working_directory
),
RealFileName::Remapped {
local_path: Some(path("/bar/src/main.rs")),
virtual_name: path("BAR/src/main.rs")
}
);
// Already remapped relative path
assert_eq!(
mapping.to_embeddable_absolute_path(
RealFileName::Remapped { local_path: None, virtual_name: path("XYZ/src/main.rs") },
&working_directory
),
RealFileName::Remapped { local_path: None, virtual_name: path("XYZ/src/main.rs") }
);
}
#[test]
fn path_prefix_remapping_reverse() {
// Ignores options without alphanumeric chars.
@ -455,6 +525,7 @@ fn path_prefix_remapping_reverse() {
let mapping = &FilePathMapping::new(
vec![(path("abc"), path("/")), (path("def"), path("."))],
FileNameDisplayPreference::Remapped,
FileNameEmbeddablePreference::RemappedOnly,
);
assert_eq!(reverse_map_prefix(mapping, "/hello.rs"), None);
@ -466,6 +537,7 @@ fn path_prefix_remapping_reverse() {
let mapping = &FilePathMapping::new(
vec![(path("abc"), path("/redacted")), (path("def"), path("/redacted"))],
FileNameDisplayPreference::Remapped,
FileNameEmbeddablePreference::RemappedOnly,
);
assert_eq!(reverse_map_prefix(mapping, "/redacted/hello.rs"), None);
@ -476,6 +548,7 @@ fn path_prefix_remapping_reverse() {
let mapping = &FilePathMapping::new(
vec![(path("abc"), path("/redacted")), (path("def/ghi"), path("/fake/dir"))],
FileNameDisplayPreference::Remapped,
FileNameEmbeddablePreference::RemappedOnly,
);
assert_eq!(

View file

@ -1049,6 +1049,7 @@ symbols! {
from_u16,
from_usize,
from_yeet,
frontmatter,
fs_create_dir,
fsub_algebraic,
fsub_fast,

View file

@ -3567,7 +3567,19 @@ impl Target {
"x86" => (Architecture::I386, None),
"s390x" => (Architecture::S390x, None),
"mips" | "mips32r6" => (Architecture::Mips, None),
"mips64" | "mips64r6" => (Architecture::Mips64, None),
"mips64" | "mips64r6" => (
// While there are currently no builtin targets
// using the N32 ABI, it is possible to specify
// it using a custom target specification. N32
// is an ILP32 ABI like the Aarch64_Ilp32
// and X86_64_X32 cases above and below this one.
if self.options.llvm_abiname.as_ref() == "n32" {
Architecture::Mips64_N32
} else {
Architecture::Mips64
},
None,
),
"x86_64" => (
if self.pointer_width == 32 {
Architecture::X86_64_X32

View file

@ -27,6 +27,7 @@ pub(crate) fn target() -> Target {
abi: "abi64".into(),
endian: Endian::Big,
mcount: "_mcount".into(),
llvm_abiname: "n64".into(),
..base
},
}

View file

@ -22,6 +22,7 @@ pub(crate) fn target() -> Target {
features: "+mips64r2,+xgot".into(),
max_atomic_width: Some(64),
mcount: "_mcount".into(),
llvm_abiname: "n64".into(),
..base::linux_gnu::opts()
},

View file

@ -25,6 +25,7 @@ pub(crate) fn target() -> Target {
mcount: "_mcount".into(),
// FIXME(compiler-team#422): musl targets should be dynamically linked by default.
crt_static_default: true,
llvm_abiname: "n64".into(),
..base
},
}

View file

@ -19,6 +19,7 @@ pub(crate) fn target() -> Target {
features: "+mips64r2,+xgot".into(),
max_atomic_width: Some(64),
mcount: "_mcount".into(),
llvm_abiname: "n64".into(),
..base::linux_gnu::opts()
},

View file

@ -19,6 +19,11 @@ pub(crate) fn target() -> Target {
pointer_width: 64,
data_layout: "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128".into(),
arch: "mips64".into(),
options: TargetOptions { abi: "abi64".into(), mcount: "_mcount".into(), ..base },
options: TargetOptions {
abi: "abi64".into(),
mcount: "_mcount".into(),
llvm_abiname: "n64".into(),
..base
},
}
}

View file

@ -22,6 +22,7 @@ pub(crate) fn target() -> Target {
features: "+mips64r6".into(),
max_atomic_width: Some(64),
mcount: "_mcount".into(),
llvm_abiname: "n64".into(),
..base::linux_gnu::opts()
},

View file

@ -19,6 +19,7 @@ pub(crate) fn target() -> Target {
features: "+mips64r6".into(),
max_atomic_width: Some(64),
mcount: "_mcount".into(),
llvm_abiname: "n64".into(),
..base::linux_gnu::opts()
},

View file

@ -5,3 +5,9 @@ edition = "2024"
[dependencies]
rustc_smir = { path = "../rustc_smir" }
[features]
# Provides access to APIs that expose internals of the rust compiler.
# APIs enabled by this feature are unstable. They can be removed or modified
# at any point and they are not included in the crate's semantic versioning.
rustc_internal = []

View file

@ -4,4 +4,8 @@
//! This is a transitional measure as described in [PR #139319](https://github.com/rust-lang/rust/pull/139319).
//! Once the refactoring is complete, the `stable_mir` implementation will be moved back here.
/// Export the rustc_internal APIs. Note that this module has no stability
/// guarantees and it is not taken into account for semver.
#[cfg(feature = "rustc_internal")]
pub use rustc_smir::rustc_internal;
pub use rustc_smir::stable_mir::*;

View file

@ -1917,14 +1917,13 @@ pub struct ExtractIf<
V,
F,
#[unstable(feature = "allocator_api", issue = "32838")] A: Allocator + Clone = Global,
> where
F: 'a + FnMut(&K, &mut V) -> bool,
{
> {
pred: F,
inner: ExtractIfInner<'a, K, V>,
/// The BTreeMap will outlive this IntoIter so we don't care about drop order for `alloc`.
alloc: A,
}
/// Most of the implementation of ExtractIf are generic over the type
/// of the predicate, thus also serving for BTreeSet::ExtractIf.
pub(super) struct ExtractIfInner<'a, K, V> {
@ -1940,14 +1939,14 @@ pub(super) struct ExtractIfInner<'a, K, V> {
}
#[unstable(feature = "btree_extract_if", issue = "70530")]
impl<K, V, F> fmt::Debug for ExtractIf<'_, K, V, F>
impl<K, V, F, A> fmt::Debug for ExtractIf<'_, K, V, F, A>
where
K: fmt::Debug,
V: fmt::Debug,
F: FnMut(&K, &mut V) -> bool,
A: Allocator + Clone,
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_tuple("ExtractIf").field(&self.inner.peek()).finish()
f.debug_struct("ExtractIf").field("peek", &self.inner.peek()).finish_non_exhaustive()
}
}

View file

@ -1556,10 +1556,7 @@ pub struct ExtractIf<
T,
F,
#[unstable(feature = "allocator_api", issue = "32838")] A: Allocator + Clone = Global,
> where
T: 'a,
F: 'a + FnMut(&T) -> bool,
{
> {
pred: F,
inner: super::map::ExtractIfInner<'a, T, SetValZST>,
/// The BTreeMap will outlive this IntoIter so we don't care about drop order for `alloc`.
@ -1567,13 +1564,15 @@ pub struct ExtractIf<
}
#[unstable(feature = "btree_extract_if", issue = "70530")]
impl<T, F, A: Allocator + Clone> fmt::Debug for ExtractIf<'_, T, F, A>
impl<T, F, A> fmt::Debug for ExtractIf<'_, T, F, A>
where
T: fmt::Debug,
F: FnMut(&T) -> bool,
A: Allocator + Clone,
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_tuple("ExtractIf").field(&self.inner.peek().map(|(k, _)| k)).finish()
f.debug_struct("ExtractIf")
.field("peek", &self.inner.peek().map(|(k, _)| k))
.finish_non_exhaustive()
}
}

View file

@ -1976,9 +1976,14 @@ where
}
#[stable(feature = "extract_if", since = "1.87.0")]
impl<T: fmt::Debug, F> fmt::Debug for ExtractIf<'_, T, F> {
impl<T, F, A> fmt::Debug for ExtractIf<'_, T, F, A>
where
T: fmt::Debug,
A: Allocator,
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_tuple("ExtractIf").field(&self.list).finish()
let peek = self.it.map(|node| unsafe { &node.as_ref().element });
f.debug_struct("ExtractIf").field("peek", &peek).finish_non_exhaustive()
}
}

View file

@ -1,5 +1,5 @@
use core::ops::{Range, RangeBounds};
use core::{ptr, slice};
use core::{fmt, ptr, slice};
use super::Vec;
use crate::alloc::{Allocator, Global};
@ -16,7 +16,6 @@ use crate::alloc::{Allocator, Global};
/// let iter: std::vec::ExtractIf<'_, _, _> = v.extract_if(.., |x| *x % 2 == 0);
/// ```
#[stable(feature = "extract_if", since = "1.87.0")]
#[derive(Debug)]
#[must_use = "iterators are lazy and do nothing unless consumed"]
pub struct ExtractIf<
'a,
@ -108,3 +107,15 @@ impl<T, F, A: Allocator> Drop for ExtractIf<'_, T, F, A> {
}
}
}
#[stable(feature = "extract_if", since = "1.87.0")]
impl<T, F, A> fmt::Debug for ExtractIf<'_, T, F, A>
where
T: fmt::Debug,
A: Allocator,
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let peek = if self.idx < self.end { self.vec.get(self.idx) } else { None };
f.debug_struct("ExtractIf").field("peek", &peek).finish_non_exhaustive()
}
}

View file

@ -258,6 +258,11 @@ impl<T, A: Allocator> Iterator for IntoIter<T, A> {
self.len()
}
#[inline]
fn last(mut self) -> Option<T> {
self.next_back()
}
#[inline]
fn next_chunk<const N: usize>(&mut self) -> Result<[T; N], core::array::IntoIter<T, N>> {
let mut raw_ary = [const { MaybeUninit::uninit() }; N];

View file

@ -1358,6 +1358,7 @@ pub trait Iterator {
/// ```
///
/// [`by_ref`]: Iterator::by_ref
#[doc(alias = "limit")]
#[inline]
#[stable(feature = "rust1", since = "1.0.0")]
fn take(self, n: usize) -> Take<Self>

View file

@ -147,12 +147,14 @@ impl fmt::Debug for Debug<'_> {
/// An iterator used to decode a slice of mostly UTF-8 bytes to string slices
/// ([`&str`]) and byte slices ([`&[u8]`][byteslice]).
///
/// This struct is created by the [`utf8_chunks`] method on bytes slices.
/// If you want a simple conversion from UTF-8 byte slices to string slices,
/// [`from_utf8`] is easier to use.
///
/// See the [`Utf8Chunk`] type for documentation of the items yielded by this iterator.
///
/// [byteslice]: slice
/// [`utf8_chunks`]: slice::utf8_chunks
/// [`from_utf8`]: super::from_utf8
///
/// # Examples

View file

@ -683,7 +683,7 @@ impl<K, V, S> HashMap<K, V, S> {
/// ```
#[inline]
#[rustc_lint_query_instability]
#[stable(feature = "hash_extract_if", since = "1.87.0")]
#[stable(feature = "hash_extract_if", since = "CURRENT_RUSTC_VERSION")]
pub fn extract_if<F>(&mut self, pred: F) -> ExtractIf<'_, K, V, F>
where
F: FnMut(&K, &mut V) -> bool,
@ -1680,12 +1680,9 @@ impl<'a, K, V> Drain<'a, K, V> {
/// ]);
/// let iter = map.extract_if(|_k, v| *v % 2 == 0);
/// ```
#[stable(feature = "hash_extract_if", since = "1.87.0")]
#[stable(feature = "hash_extract_if", since = "CURRENT_RUSTC_VERSION")]
#[must_use = "iterators are lazy and do nothing unless consumed"]
pub struct ExtractIf<'a, K, V, F>
where
F: FnMut(&K, &mut V) -> bool,
{
pub struct ExtractIf<'a, K, V, F> {
base: base::ExtractIf<'a, K, V, F>,
}
@ -2297,7 +2294,7 @@ where
}
}
#[stable(feature = "hash_extract_if", since = "1.87.0")]
#[stable(feature = "hash_extract_if", since = "CURRENT_RUSTC_VERSION")]
impl<K, V, F> Iterator for ExtractIf<'_, K, V, F>
where
F: FnMut(&K, &mut V) -> bool,
@ -2314,13 +2311,14 @@ where
}
}
#[stable(feature = "hash_extract_if", since = "1.87.0")]
#[stable(feature = "hash_extract_if", since = "CURRENT_RUSTC_VERSION")]
impl<K, V, F> FusedIterator for ExtractIf<'_, K, V, F> where F: FnMut(&K, &mut V) -> bool {}
#[stable(feature = "hash_extract_if", since = "1.87.0")]
impl<'a, K, V, F> fmt::Debug for ExtractIf<'a, K, V, F>
#[stable(feature = "hash_extract_if", since = "CURRENT_RUSTC_VERSION")]
impl<K, V, F> fmt::Debug for ExtractIf<'_, K, V, F>
where
F: FnMut(&K, &mut V) -> bool,
K: fmt::Debug,
V: fmt::Debug,
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("ExtractIf").finish_non_exhaustive()

View file

@ -308,7 +308,7 @@ impl<T, S> HashSet<T, S> {
/// ```
#[inline]
#[rustc_lint_query_instability]
#[stable(feature = "hash_extract_if", since = "1.87.0")]
#[stable(feature = "hash_extract_if", since = "CURRENT_RUSTC_VERSION")]
pub fn extract_if<F>(&mut self, pred: F) -> ExtractIf<'_, T, F>
where
F: FnMut(&T) -> bool,
@ -1390,11 +1390,8 @@ pub struct Drain<'a, K: 'a> {
///
/// let mut extract_ifed = a.extract_if(|v| v % 2 == 0);
/// ```
#[stable(feature = "hash_extract_if", since = "1.87.0")]
pub struct ExtractIf<'a, K, F>
where
F: FnMut(&K) -> bool,
{
#[stable(feature = "hash_extract_if", since = "CURRENT_RUSTC_VERSION")]
pub struct ExtractIf<'a, K, F> {
base: base::ExtractIf<'a, K, F>,
}
@ -1673,7 +1670,7 @@ impl<K: fmt::Debug> fmt::Debug for Drain<'_, K> {
}
}
#[stable(feature = "hash_extract_if", since = "1.87.0")]
#[stable(feature = "hash_extract_if", since = "CURRENT_RUSTC_VERSION")]
impl<K, F> Iterator for ExtractIf<'_, K, F>
where
F: FnMut(&K) -> bool,
@ -1690,13 +1687,13 @@ where
}
}
#[stable(feature = "hash_extract_if", since = "1.87.0")]
#[stable(feature = "hash_extract_if", since = "CURRENT_RUSTC_VERSION")]
impl<K, F> FusedIterator for ExtractIf<'_, K, F> where F: FnMut(&K) -> bool {}
#[stable(feature = "hash_extract_if", since = "1.87.0")]
impl<'a, K, F> fmt::Debug for ExtractIf<'a, K, F>
#[stable(feature = "hash_extract_if", since = "CURRENT_RUSTC_VERSION")]
impl<K, F> fmt::Debug for ExtractIf<'_, K, F>
where
F: FnMut(&K) -> bool,
K: fmt::Debug,
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("ExtractIf").finish_non_exhaustive()

View file

@ -168,8 +168,6 @@ use crate::num::NonZero;
use crate::path::Path;
use crate::sys::pipe::{AnonPipe, read2};
use crate::sys::process as imp;
#[stable(feature = "command_access", since = "1.57.0")]
pub use crate::sys_common::process::CommandEnvs;
use crate::sys_common::{AsInner, AsInnerMut, FromInner, IntoInner};
use crate::{fmt, fs, str};
@ -1073,7 +1071,7 @@ impl Command {
/// ```
#[stable(feature = "process", since = "1.0.0")]
pub fn output(&mut self) -> io::Result<Output> {
let (status, stdout, stderr) = self.inner.output()?;
let (status, stdout, stderr) = imp::output(&mut self.inner)?;
Ok(Output { status: ExitStatus(status), stdout, stderr })
}
@ -1174,7 +1172,7 @@ impl Command {
/// ```
#[stable(feature = "command_access", since = "1.57.0")]
pub fn get_envs(&self) -> CommandEnvs<'_> {
self.inner.get_envs()
CommandEnvs { iter: self.inner.get_envs() }
}
/// Returns the working directory for the child process.
@ -1264,6 +1262,48 @@ impl<'a> ExactSizeIterator for CommandArgs<'a> {
}
}
/// An iterator over the command environment variables.
///
/// This struct is created by
/// [`Command::get_envs`][crate::process::Command::get_envs]. See its
/// documentation for more.
#[must_use = "iterators are lazy and do nothing unless consumed"]
#[stable(feature = "command_access", since = "1.57.0")]
pub struct CommandEnvs<'a> {
iter: imp::CommandEnvs<'a>,
}
#[stable(feature = "command_access", since = "1.57.0")]
impl<'a> Iterator for CommandEnvs<'a> {
type Item = (&'a OsStr, Option<&'a OsStr>);
fn next(&mut self) -> Option<Self::Item> {
self.iter.next()
}
fn size_hint(&self) -> (usize, Option<usize>) {
self.iter.size_hint()
}
}
#[stable(feature = "command_access", since = "1.57.0")]
impl<'a> ExactSizeIterator for CommandEnvs<'a> {
fn len(&self) -> usize {
self.iter.len()
}
fn is_empty(&self) -> bool {
self.iter.is_empty()
}
}
#[stable(feature = "command_access", since = "1.57.0")]
impl<'a> fmt::Debug for CommandEnvs<'a> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
self.iter.fmt(f)
}
}
/// The output of a finished process.
///
/// This is returned in a Result by either the [`output`] method of a

View file

@ -49,8 +49,8 @@ impl Iterator for Args {
}
#[inline]
fn last(mut self) -> Option<OsString> {
self.iter.next_back()
fn last(self) -> Option<OsString> {
self.iter.last()
}
#[inline]

View file

@ -1,13 +1,9 @@
#![allow(dead_code)]
#![unstable(feature = "process_internals", issue = "none")]
use crate::collections::BTreeMap;
use crate::ffi::{OsStr, OsString};
use crate::sys::pipe::read2;
use crate::sys::process::{EnvKey, ExitStatus, Process, StdioPipes};
use crate::{env, fmt, io};
use crate::sys::process::EnvKey;
use crate::{env, fmt};
// Stores a set of changes to an environment
/// Stores a set of changes to an environment
#[derive(Clone, Default)]
pub struct CommandEnv {
clear: bool,
@ -92,30 +88,23 @@ impl CommandEnv {
}
}
/// An iterator over the command environment variables.
///
/// This struct is created by
/// [`Command::get_envs`][crate::process::Command::get_envs]. See its
/// documentation for more.
#[must_use = "iterators are lazy and do nothing unless consumed"]
#[stable(feature = "command_access", since = "1.57.0")]
#[derive(Debug)]
pub struct CommandEnvs<'a> {
iter: crate::collections::btree_map::Iter<'a, EnvKey, Option<OsString>>,
}
#[stable(feature = "command_access", since = "1.57.0")]
impl<'a> Iterator for CommandEnvs<'a> {
type Item = (&'a OsStr, Option<&'a OsStr>);
fn next(&mut self) -> Option<Self::Item> {
self.iter.next().map(|(key, value)| (key.as_ref(), value.as_deref()))
}
fn size_hint(&self) -> (usize, Option<usize>) {
self.iter.size_hint()
}
}
#[stable(feature = "command_access", since = "1.57.0")]
impl<'a> ExactSizeIterator for CommandEnvs<'a> {
fn len(&self) -> usize {
self.iter.len()
@ -124,30 +113,3 @@ impl<'a> ExactSizeIterator for CommandEnvs<'a> {
self.iter.is_empty()
}
}
pub fn wait_with_output(
mut process: Process,
mut pipes: StdioPipes,
) -> io::Result<(ExitStatus, Vec<u8>, Vec<u8>)> {
drop(pipes.stdin.take());
let (mut stdout, mut stderr) = (Vec::new(), Vec::new());
match (pipes.stdout.take(), pipes.stderr.take()) {
(None, None) => {}
(Some(out), None) => {
let res = out.read_to_end(&mut stdout);
res.unwrap();
}
(None, Some(err)) => {
let res = err.read_to_end(&mut stderr);
res.unwrap();
}
(Some(out), Some(err)) => {
let res = read2(out, &mut stdout, err, &mut stderr);
res.unwrap();
}
}
let status = process.wait()?;
Ok((status, stdout, stderr))
}

View file

@ -14,6 +14,65 @@ cfg_if::cfg_if! {
}
}
// This module is shared by all platforms, but nearly all platforms except for
// the "normal" UNIX ones leave some of this code unused.
#[cfg_attr(not(target_os = "linux"), allow(dead_code))]
mod env;
pub use env::CommandEnvs;
pub use imp::{
Command, CommandArgs, EnvKey, ExitCode, ExitStatus, ExitStatusError, Process, Stdio, StdioPipes,
};
#[cfg(any(
all(
target_family = "unix",
not(any(
target_os = "espidf",
target_os = "horizon",
target_os = "vita",
target_os = "nuttx"
))
),
target_os = "windows",
))]
pub fn output(cmd: &mut Command) -> crate::io::Result<(ExitStatus, Vec<u8>, Vec<u8>)> {
use crate::sys::pipe::read2;
let (mut process, mut pipes) = cmd.spawn(Stdio::MakePipe, false)?;
drop(pipes.stdin.take());
let (mut stdout, mut stderr) = (Vec::new(), Vec::new());
match (pipes.stdout.take(), pipes.stderr.take()) {
(None, None) => {}
(Some(out), None) => {
let res = out.read_to_end(&mut stdout);
res.unwrap();
}
(None, Some(err)) => {
let res = err.read_to_end(&mut stderr);
res.unwrap();
}
(Some(out), Some(err)) => {
let res = read2(out, &mut stdout, err, &mut stderr);
res.unwrap();
}
}
let status = process.wait()?;
Ok((status, stdout, stderr))
}
#[cfg(not(any(
all(
target_family = "unix",
not(any(
target_os = "espidf",
target_os = "horizon",
target_os = "vita",
target_os = "nuttx"
))
),
target_os = "windows",
)))]
pub use imp::output;

View file

@ -1,5 +1,6 @@
use r_efi::protocols::{simple_text_input, simple_text_output};
use super::env::{CommandEnv, CommandEnvs};
use crate::collections::BTreeMap;
pub use crate::ffi::OsString as EnvKey;
use crate::ffi::{OsStr, OsString};
@ -10,7 +11,6 @@ use crate::sys::pal::helpers;
use crate::sys::pal::os::error_string;
use crate::sys::pipe::AnonPipe;
use crate::sys::unsupported;
use crate::sys_common::process::{CommandEnv, CommandEnvs};
use crate::{fmt, io};
////////////////////////////////////////////////////////////////////////////////
@ -139,72 +139,72 @@ impl Command {
Stdio::MakePipe => unsupported(),
}
}
}
pub fn output(&mut self) -> io::Result<(ExitStatus, Vec<u8>, Vec<u8>)> {
let mut cmd = uefi_command_internal::Image::load_image(&self.prog)?;
pub fn output(command: &mut Command) -> io::Result<(ExitStatus, Vec<u8>, Vec<u8>)> {
let mut cmd = uefi_command_internal::Image::load_image(&command.prog)?;
// UEFI adds the bin name by default
if !self.args.is_empty() {
let args = uefi_command_internal::create_args(&self.prog, &self.args);
cmd.set_args(args);
}
// Setup Stdout
let stdout = self.stdout.unwrap_or(Stdio::MakePipe);
let stdout = Self::create_pipe(stdout)?;
if let Some(con) = stdout {
cmd.stdout_init(con)
} else {
cmd.stdout_inherit()
};
// Setup Stderr
let stderr = self.stderr.unwrap_or(Stdio::MakePipe);
let stderr = Self::create_pipe(stderr)?;
if let Some(con) = stderr {
cmd.stderr_init(con)
} else {
cmd.stderr_inherit()
};
// Setup Stdin
let stdin = self.stdin.unwrap_or(Stdio::Null);
let stdin = Self::create_stdin(stdin)?;
if let Some(con) = stdin {
cmd.stdin_init(con)
} else {
cmd.stdin_inherit()
};
let env = env_changes(&self.env);
// Set any new vars
if let Some(e) = &env {
for (k, (_, v)) in e {
match v {
Some(v) => unsafe { crate::env::set_var(k, v) },
None => unsafe { crate::env::remove_var(k) },
}
}
}
let stat = cmd.start_image()?;
// Rollback any env changes
if let Some(e) = env {
for (k, (v, _)) in e {
match v {
Some(v) => unsafe { crate::env::set_var(k, v) },
None => unsafe { crate::env::remove_var(k) },
}
}
}
let stdout = cmd.stdout()?;
let stderr = cmd.stderr()?;
Ok((ExitStatus(stat), stdout, stderr))
// UEFI adds the bin name by default
if !command.args.is_empty() {
let args = uefi_command_internal::create_args(&command.prog, &command.args);
cmd.set_args(args);
}
// Setup Stdout
let stdout = command.stdout.unwrap_or(Stdio::MakePipe);
let stdout = Command::create_pipe(stdout)?;
if let Some(con) = stdout {
cmd.stdout_init(con)
} else {
cmd.stdout_inherit()
};
// Setup Stderr
let stderr = command.stderr.unwrap_or(Stdio::MakePipe);
let stderr = Command::create_pipe(stderr)?;
if let Some(con) = stderr {
cmd.stderr_init(con)
} else {
cmd.stderr_inherit()
};
// Setup Stdin
let stdin = command.stdin.unwrap_or(Stdio::Null);
let stdin = Command::create_stdin(stdin)?;
if let Some(con) = stdin {
cmd.stdin_init(con)
} else {
cmd.stdin_inherit()
};
let env = env_changes(&command.env);
// Set any new vars
if let Some(e) = &env {
for (k, (_, v)) in e {
match v {
Some(v) => unsafe { crate::env::set_var(k, v) },
None => unsafe { crate::env::remove_var(k) },
}
}
}
let stat = cmd.start_image()?;
// Rollback any env changes
if let Some(e) = env {
for (k, (v, _)) in e {
match v {
Some(v) => unsafe { crate::env::set_var(k, v) },
None => unsafe { crate::env::remove_var(k) },
}
}
}
let stdout = cmd.stdout()?;
let stderr = cmd.stderr()?;
Ok((ExitStatus(stat), stdout, stderr))
}
impl From<AnonPipe> for Stdio {

View file

@ -12,7 +12,7 @@ use crate::sys::fs::File;
#[cfg(not(target_os = "fuchsia"))]
use crate::sys::fs::OpenOptions;
use crate::sys::pipe::{self, AnonPipe};
use crate::sys_common::process::{CommandEnv, CommandEnvs};
use crate::sys::process::env::{CommandEnv, CommandEnvs};
use crate::sys_common::{FromInner, IntoInner};
use crate::{fmt, io, ptr};

View file

@ -31,11 +31,6 @@ impl Command {
Ok((Process { handle: Handle::new(process_handle) }, ours))
}
pub fn output(&mut self) -> io::Result<(ExitStatus, Vec<u8>, Vec<u8>)> {
let (proc, pipes) = self.spawn(Stdio::MakePipe, false)?;
crate::sys_common::process::wait_with_output(proc, pipes)
}
pub fn exec(&mut self, default: Stdio) -> io::Error {
if self.saw_nul() {
return io::const_error!(

View file

@ -162,11 +162,6 @@ impl Command {
}
}
pub fn output(&mut self) -> io::Result<(ExitStatus, Vec<u8>, Vec<u8>)> {
let (proc, pipes) = self.spawn(Stdio::MakePipe, false)?;
crate::sys_common::process::wait_with_output(proc, pipes)
}
// WatchOS and TVOS headers mark the `fork`/`exec*` functions with
// `__WATCHOS_PROHIBITED __TVOS_PROHIBITED`, and indicate that the
// `posix_spawn*` functions should be used instead. It isn't entirely clear

View file

@ -18,15 +18,15 @@ impl Command {
unsupported()
}
pub fn output(&mut self) -> io::Result<(ExitStatus, Vec<u8>, Vec<u8>)> {
unsupported()
}
pub fn exec(&mut self, _default: Stdio) -> io::Error {
unsupported_err()
}
}
pub fn output(_: &mut Command) -> io::Result<(ExitStatus, Vec<u8>, Vec<u8>)> {
unsupported()
}
////////////////////////////////////////////////////////////////////////////////
// Processes
////////////////////////////////////////////////////////////////////////////////

View file

@ -112,11 +112,6 @@ impl Command {
}
}
pub fn output(&mut self) -> io::Result<(ExitStatus, Vec<u8>, Vec<u8>)> {
let (proc, pipes) = self.spawn(Stdio::MakePipe, false)?;
crate::sys_common::process::wait_with_output(proc, pipes)
}
pub fn exec(&mut self, default: Stdio) -> io::Error {
let ret = Command::spawn(self, default, false);
match ret {

View file

@ -1,3 +1,4 @@
use super::env::{CommandEnv, CommandEnvs};
pub use crate::ffi::OsString as EnvKey;
use crate::ffi::{OsStr, OsString};
use crate::num::NonZero;
@ -5,7 +6,6 @@ use crate::path::Path;
use crate::sys::fs::File;
use crate::sys::pipe::AnonPipe;
use crate::sys::unsupported;
use crate::sys_common::process::{CommandEnv, CommandEnvs};
use crate::{fmt, io};
////////////////////////////////////////////////////////////////////////////////
@ -104,10 +104,10 @@ impl Command {
) -> io::Result<(Process, StdioPipes)> {
unsupported()
}
}
pub fn output(&mut self) -> io::Result<(ExitStatus, Vec<u8>, Vec<u8>)> {
unsupported()
}
pub fn output(_cmd: &mut Command) -> io::Result<(ExitStatus, Vec<u8>, Vec<u8>)> {
unsupported()
}
impl From<AnonPipe> for Stdio {

View file

@ -5,6 +5,7 @@ mod tests;
use core::ffi::c_void;
use super::env::{CommandEnv, CommandEnvs};
use crate::collections::BTreeMap;
use crate::env::consts::{EXE_EXTENSION, EXE_SUFFIX};
use crate::ffi::{OsStr, OsString};
@ -24,7 +25,6 @@ use crate::sys::pal::{ensure_no_nuls, fill_utf16_buf};
use crate::sys::pipe::{self, AnonPipe};
use crate::sys::{cvt, path, stdio};
use crate::sys_common::IntoInner;
use crate::sys_common::process::{CommandEnv, CommandEnvs};
use crate::{cmp, env, fmt, ptr};
////////////////////////////////////////////////////////////////////////////////
@ -389,11 +389,6 @@ impl Command {
))
}
}
pub fn output(&mut self) -> io::Result<(ExitStatus, Vec<u8>, Vec<u8>)> {
let (proc, pipes) = self.spawn(Stdio::MakePipe, false)?;
crate::sys_common::process::wait_with_output(proc, pipes)
}
}
impl fmt::Debug for Command {

View file

@ -20,7 +20,6 @@
#[cfg(test)]
mod tests;
pub mod process;
pub mod wstr;
pub mod wtf8;

View file

@ -527,3 +527,70 @@ tool_check_step!(Bootstrap { path: "src/bootstrap", default: false });
// `run-make-support` will be built as part of suitable run-make compiletest test steps, but support
// check to make it easier to work on.
tool_check_step!(RunMakeSupport { path: "src/tools/run-make-support", default: false });
/// Check step for the `coverage-dump` bootstrap tool. The coverage-dump tool
/// is used internally by coverage tests.
///
/// FIXME(Zalathar): This is temporarily separate from the other tool check
/// steps so that it can use the stage 0 compiler instead of `top_stage`,
/// without introducing conflicts with the stage 0 redesign (#119899).
///
/// After the stage 0 redesign lands, we can look into using the stage 0
/// compiler to check all bootstrap tools (#139170).
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub(crate) struct CoverageDump;
impl CoverageDump {
const PATH: &str = "src/tools/coverage-dump";
}
impl Step for CoverageDump {
type Output = ();
/// Most contributors won't care about coverage-dump, so don't make their
/// check builds slower unless they opt in and check it explicitly.
const DEFAULT: bool = false;
const ONLY_HOSTS: bool = true;
fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
run.path(Self::PATH)
}
fn make_run(run: RunConfig<'_>) {
run.builder.ensure(Self {});
}
fn run(self, builder: &Builder<'_>) -> Self::Output {
// Make sure we haven't forgotten any fields, if there are any.
let Self {} = self;
let display_name = "coverage-dump";
let host = builder.config.build;
let target = host;
let mode = Mode::ToolBootstrap;
let compiler = builder.compiler(0, host);
let cargo = prepare_tool_cargo(
builder,
compiler,
mode,
target,
builder.kind,
Self::PATH,
SourceType::InTree,
&[],
);
let stamp = BuildStamp::new(&builder.cargo_out(compiler, mode, target))
.with_prefix(&format!("{display_name}-check"));
let _guard = builder.msg_tool(
builder.kind,
mode,
display_name,
compiler.stage,
&compiler.host,
&target,
);
run_cargo(builder, cargo, builder.config.free_args.clone(), &stamp, vec![], true, false);
}
}

View file

@ -392,3 +392,31 @@ impl Step for CyclicStep {
builder.ensure(CyclicStep { n: self.n.saturating_sub(1) })
}
}
/// Step to manually run the coverage-dump tool (`./x run coverage-dump`).
///
/// The coverage-dump tool is an internal detail of coverage tests, so this run
/// step is only needed when testing coverage-dump manually.
#[derive(Debug, PartialOrd, Ord, Clone, Hash, PartialEq, Eq)]
pub struct CoverageDump;
impl Step for CoverageDump {
type Output = ();
const DEFAULT: bool = false;
const ONLY_HOSTS: bool = true;
fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
run.path("src/tools/coverage-dump")
}
fn make_run(run: RunConfig<'_>) {
run.builder.ensure(Self {});
}
fn run(self, builder: &Builder<'_>) {
let mut cmd = builder.tool_cmd(Tool::CoverageDump);
cmd.args(&builder.config.free_args);
cmd.run(builder);
}
}

View file

@ -54,6 +54,7 @@ impl Step for CrateBootstrap {
run.path("src/tools/jsondoclint")
.path("src/tools/suggest-tests")
.path("src/tools/replace-version-placeholder")
.path("src/tools/coverage-dump")
// We want `./x test tidy` to _run_ the tidy tool, not its tests.
// So we need a separate alias to test the tidy tool itself.
.alias("tidyselftest")

View file

@ -961,6 +961,7 @@ impl<'a> Builder<'a> {
check::RunMakeSupport,
check::Compiletest,
check::FeaturesStatusDump,
check::CoverageDump,
),
Kind::Test => describe!(
crate::core::build_steps::toolstate::ToolStateCheck,
@ -1114,6 +1115,7 @@ impl<'a> Builder<'a> {
run::UnicodeTableGenerator,
run::FeaturesStatusDump,
run::CyclicStep,
run::CoverageDump,
),
Kind::Setup => {
describe!(setup::Profile, setup::Hook, setup::Link, setup::Editor)

View file

@ -2,7 +2,7 @@
The tracking issue for this feature is: [#44874]
[#38788]: https://github.com/rust-lang/rust/issues/44874
[#44874]: https://github.com/rust-lang/rust/issues/44874
------------------------

View file

@ -6,4 +6,4 @@ The tracking issue for this feature is: [#116909]
---
Enable the `f128` type for IEEE 128-bit floating numbers (quad precision).
Enable the `f128` type for IEEE 128-bit floating numbers (quad precision).

View file

@ -6,4 +6,4 @@ The tracking issue for this feature is: [#116909]
---
Enable the `f16` type for IEEE 16-bit floating numbers (half precision).
Enable the `f16` type for IEEE 16-bit floating numbers (half precision).

View file

@ -0,0 +1,25 @@
# `frontmatter`
The tracking issue for this feature is: [#136889]
------
The `frontmatter` feature allows an extra metadata block at the top of files for consumption by
external tools. For example, it can be used by [`cargo-script`] files to specify dependencies.
```rust
#!/usr/bin/env -S cargo -Zscript
---
[dependencies]
libc = "0.2.172"
---
#![feature(frontmatter)]
# mod libc { pub type c_int = i32; }
fn main() {
let x: libc::c_int = 1i32;
}
```
[#136889]: https://github.com/rust-lang/rust/issues/136889
[`cargo-script`]: https://rust-lang.github.io/rfcs/3502-cargo-script.html

View file

@ -9,7 +9,7 @@ use std::collections::VecDeque;
use std::fmt::{Display, Write};
use rustc_data_structures::fx::FxIndexMap;
use rustc_lexer::{Cursor, LiteralKind, TokenKind};
use rustc_lexer::{Cursor, FrontmatterAllowed, LiteralKind, TokenKind};
use rustc_span::edition::Edition;
use rustc_span::symbol::Symbol;
use rustc_span::{BytePos, DUMMY_SP, Span};
@ -638,7 +638,8 @@ impl<'src> Classifier<'src> {
/// Takes as argument the source code to HTML-ify, the rust edition to use and the source code
/// file span which will be used later on by the `span_correspondence_map`.
fn new(src: &'src str, file_span: Span, decoration_info: Option<&DecorationInfo>) -> Self {
let tokens = PeekIter::new(TokenIter { src, cursor: Cursor::new(src) });
let tokens =
PeekIter::new(TokenIter { src, cursor: Cursor::new(src, FrontmatterAllowed::Yes) });
let decorations = decoration_info.map(Decorations::new);
Classifier {
tokens,
@ -884,6 +885,7 @@ impl<'src> Classifier<'src> {
| TokenKind::At
| TokenKind::Tilde
| TokenKind::Colon
| TokenKind::Frontmatter { .. }
| TokenKind::Unknown => return no_highlight(sink),
TokenKind::Question => Class::QuestionMark,

View file

@ -84,6 +84,19 @@ fn issue_14139() {
}
fn drop_order() {
struct DropDeIterator(std::vec::IntoIter<S>);
impl Iterator for DropDeIterator {
type Item = S;
fn next(&mut self) -> Option<Self::Item> {
self.0.next()
}
}
impl DoubleEndedIterator for DropDeIterator {
fn next_back(&mut self) -> Option<Self::Item> {
self.0.next_back()
}
}
struct S(&'static str);
impl std::ops::Drop for S {
fn drop(&mut self) {
@ -92,7 +105,7 @@ fn drop_order() {
}
let v = vec![S("one"), S("two"), S("three")];
let mut v = v.into_iter();
let mut v = DropDeIterator(v.into_iter());
println!("Last element is {}", v.next_back().unwrap().0);
//~^ ERROR: called `Iterator::last` on a `DoubleEndedIterator`
println!("Done");

View file

@ -84,6 +84,19 @@ fn issue_14139() {
}
fn drop_order() {
struct DropDeIterator(std::vec::IntoIter<S>);
impl Iterator for DropDeIterator {
type Item = S;
fn next(&mut self) -> Option<Self::Item> {
self.0.next()
}
}
impl DoubleEndedIterator for DropDeIterator {
fn next_back(&mut self) -> Option<Self::Item> {
self.0.next_back()
}
}
struct S(&'static str);
impl std::ops::Drop for S {
fn drop(&mut self) {
@ -92,7 +105,7 @@ fn drop_order() {
}
let v = vec![S("one"), S("two"), S("three")];
let v = v.into_iter();
let v = DropDeIterator(v.into_iter());
println!("Last element is {}", v.last().unwrap().0);
//~^ ERROR: called `Iterator::last` on a `DoubleEndedIterator`
println!("Done");

View file

@ -18,7 +18,7 @@ LL | let _ = DeIterator.last();
| help: try: `next_back()`
error: called `Iterator::last` on a `DoubleEndedIterator`; this will needlessly iterate the entire iterator
--> tests/ui/double_ended_iterator_last.rs:96:36
--> tests/ui/double_ended_iterator_last.rs:109:36
|
LL | println!("Last element is {}", v.last().unwrap().0);
| ^^^^^^^^
@ -26,7 +26,7 @@ LL | println!("Last element is {}", v.last().unwrap().0);
= note: this change will alter drop order which may be undesirable
help: try
|
LL ~ let mut v = v.into_iter();
LL ~ let mut v = DropDeIterator(v.into_iter());
LL ~ println!("Last element is {}", v.next_back().unwrap().0);
|

View file

@ -11,6 +11,19 @@ fn main() {
}
fn drop_order() {
struct DropDeIterator(std::vec::IntoIter<S>);
impl Iterator for DropDeIterator {
type Item = S;
fn next(&mut self) -> Option<Self::Item> {
self.0.next()
}
}
impl DoubleEndedIterator for DropDeIterator {
fn next_back(&mut self) -> Option<Self::Item> {
self.0.next_back()
}
}
struct S(&'static str);
impl std::ops::Drop for S {
fn drop(&mut self) {
@ -19,7 +32,7 @@ fn drop_order() {
}
let v = vec![S("one"), S("two"), S("three")];
let v = (v.into_iter(), 42);
let v = (DropDeIterator(v.into_iter()), 42);
println!("Last element is {}", v.0.last().unwrap().0);
//~^ ERROR: called `Iterator::last` on a `DoubleEndedIterator`
println!("Done");

View file

@ -1,5 +1,5 @@
error: called `Iterator::last` on a `DoubleEndedIterator`; this will needlessly iterate the entire iterator
--> tests/ui/double_ended_iterator_last_unfixable.rs:23:36
--> tests/ui/double_ended_iterator_last_unfixable.rs:36:36
|
LL | println!("Last element is {}", v.0.last().unwrap().0);
| ^^^^------
@ -8,7 +8,7 @@ LL | println!("Last element is {}", v.0.last().unwrap().0);
|
= note: this change will alter drop order which may be undesirable
note: this must be made mutable to use `.next_back()`
--> tests/ui/double_ended_iterator_last_unfixable.rs:23:36
--> tests/ui/double_ended_iterator_last_unfixable.rs:36:36
|
LL | println!("Last element is {}", v.0.last().unwrap().0);
| ^^^

View file

@ -7,6 +7,7 @@ edition = "2021"
[dependencies]
anyhow = "1.0.71"
itertools = "0.12"
leb128 = "0.2.5"
md5 = { package = "md-5" , version = "0.10.5" }
miniz_oxide = "0.7.1"

View file

@ -1,23 +1,33 @@
use std::collections::HashMap;
use std::fmt::{self, Debug, Write as _};
use std::sync::OnceLock;
use std::sync::LazyLock;
use anyhow::{Context, anyhow};
use anyhow::{Context, anyhow, bail, ensure};
use itertools::Itertools;
use regex::Regex;
use crate::parser::{Parser, unescape_llvm_string_contents};
use crate::covmap::FilenameTables;
use crate::llvm_utils::unescape_llvm_string_contents;
use crate::parser::Parser;
#[cfg(test)]
mod tests;
pub(crate) fn dump_covfun_mappings(
llvm_ir: &str,
filename_tables: &FilenameTables,
function_names: &HashMap<u64, String>,
) -> anyhow::Result<()> {
// Extract function coverage entries from the LLVM IR assembly, and associate
// each entry with its (demangled) name.
let mut covfun_entries = llvm_ir
.lines()
.filter_map(covfun_line_data)
.map(|line_data| (function_names.get(&line_data.name_hash).map(String::as_str), line_data))
.collect::<Vec<_>>();
.filter(|line| is_covfun_line(line))
.map(parse_covfun_line)
.map_ok(|line_data| {
(function_names.get(&line_data.name_hash).map(String::as_str), line_data)
})
.collect::<Result<Vec<_>, _>>()?;
covfun_entries.sort_by(|a, b| {
// Sort entries primarily by name, to help make the order consistent
// across platforms and relatively insensitive to changes.
@ -41,8 +51,12 @@ pub(crate) fn dump_covfun_mappings(
println!("Number of files: {num_files}");
for i in 0..num_files {
let global_file_id = parser.read_uleb128_u32()?;
println!("- file {i} => global file {global_file_id}");
let global_file_id = parser.read_uleb128_usize()?;
let &CovfunLineData { filenames_hash, .. } = line_data;
let Some(filename) = filename_tables.lookup(filenames_hash, global_file_id) else {
bail!("couldn't resolve global file: {filenames_hash}, {global_file_id}");
};
println!("- file {i} => {filename}");
}
let num_expressions = parser.read_uleb128_u32()?;
@ -107,36 +121,50 @@ pub(crate) fn dump_covfun_mappings(
Ok(())
}
#[derive(Debug, PartialEq, Eq)]
struct CovfunLineData {
name_hash: u64,
is_used: bool,
name_hash: u64,
filenames_hash: u64,
payload: Vec<u8>,
}
/// Checks a line of LLVM IR assembly to see if it contains an `__llvm_covfun`
/// entry, and if so extracts relevant data in a `CovfunLineData`.
fn covfun_line_data(line: &str) -> Option<CovfunLineData> {
let re = {
// We cheat a little bit and match variable names `@__covrec_[HASH]u`
// rather than the section name, because the section name is harder to
// extract and differs across Linux/Windows/macOS. We also extract the
// symbol name hash from the variable name rather than the data, since
// it's easier and both should match.
static RE: OnceLock<Regex> = OnceLock::new();
RE.get_or_init(|| {
Regex::new(
r#"^@__covrec_(?<name_hash>[0-9A-Z]+)(?<is_used>u)? = .*\[[0-9]+ x i8\] c"(?<payload>[^"]*)".*$"#,
)
.unwrap()
})
};
fn is_covfun_line(line: &str) -> bool {
line.starts_with("@__covrec_")
}
let captures = re.captures(line)?;
let name_hash = u64::from_str_radix(&captures["name_hash"], 16).unwrap();
/// Given a line of LLVM IR assembly that should contain an `__llvm_covfun`
/// entry, parses it to extract relevant data in a `CovfunLineData`.
fn parse_covfun_line(line: &str) -> anyhow::Result<CovfunLineData> {
ensure!(is_covfun_line(line));
// We cheat a little bit and match variable names `@__covrec_[HASH]u`
// rather than the section name, because the section name is harder to
// extract and differs across Linux/Windows/macOS.
const RE_STRING: &str = r#"(?x)^
@__covrec_[0-9A-Z]+(?<is_used>u)?
\ = \ # (trailing space)
.*
<\{
\ i64 \ (?<name_hash> -? [0-9]+),
\ i32 \ -? [0-9]+, # (length of payload; currently unused)
\ i64 \ -? [0-9]+, # (source hash; currently unused)
\ i64 \ (?<filenames_hash> -? [0-9]+),
\ \[ [0-9]+ \ x \ i8 \] \ c"(?<payload>[^"]*)"
\ # (trailing space)
}>
.*$
"#;
static RE: LazyLock<Regex> = LazyLock::new(|| Regex::new(RE_STRING).unwrap());
let captures =
RE.captures(line).with_context(|| format!("couldn't parse covfun line: {line:?}"))?;
let is_used = captures.name("is_used").is_some();
let name_hash = i64::from_str_radix(&captures["name_hash"], 10).unwrap() as u64;
let filenames_hash = i64::from_str_radix(&captures["filenames_hash"], 10).unwrap() as u64;
let payload = unescape_llvm_string_contents(&captures["payload"]);
Some(CovfunLineData { name_hash, is_used, payload })
Ok(CovfunLineData { is_used, name_hash, filenames_hash, payload })
}
// Extra parser methods only needed when parsing `covfun` payloads.

View file

@ -0,0 +1,53 @@
use super::{CovfunLineData, parse_covfun_line};
/// Integers in LLVM IR are not inherently signed/unsigned, and the text format tends
/// to emit them in signed form, so this helper function converts `i64` to `u64`.
fn as_u64(x: i64) -> u64 {
x as u64
}
#[test]
fn parse_covfun_line_data() {
struct Case {
line: &'static str,
expected: CovfunLineData,
}
let cases = &[
// Copied from `trivial.ll`:
Case {
line: r#"@__covrec_49A9BAAE5F896E81u = linkonce_odr hidden constant <{ i64, i32, i64, i64, [9 x i8] }> <{ i64 5307978893922758273, i32 9, i64 445092354169400020, i64 6343436898695299756, [9 x i8] c"\01\01\00\01\01\03\01\00\0D" }>, section "__LLVM_COV,__llvm_covfun", align 8"#,
expected: CovfunLineData {
is_used: true,
name_hash: as_u64(5307978893922758273),
filenames_hash: as_u64(6343436898695299756),
payload: b"\x01\x01\x00\x01\x01\x03\x01\x00\x0D".to_vec(),
},
},
// Copied from `on-off-sandwich.ll`:
Case {
line: r#"@__covrec_D0CE53C5E64F319Au = linkonce_odr hidden constant <{ i64, i32, i64, i64, [14 x i8] }> <{ i64 -3400688559180533350, i32 14, i64 7307957714577672185, i64 892196767019953100, [14 x i8] c"\01\01\00\02\01\10\05\02\10\01\07\05\00\06" }>, section "__LLVM_COV,__llvm_covfun", align 8"#,
expected: CovfunLineData {
is_used: true,
name_hash: as_u64(-3400688559180533350),
filenames_hash: as_u64(892196767019953100),
payload: b"\x01\x01\x00\x02\x01\x10\x05\x02\x10\x01\x07\x05\x00\x06".to_vec(),
},
},
// Copied from `no-core.ll`:
Case {
line: r#"@__covrec_F8016FC82D46106u = linkonce_odr hidden constant <{ i64, i32, i64, i64, [9 x i8] }> <{ i64 1116917981370409222, i32 9, i64 -8857254680411629915, i64 -3625186110715410276, [9 x i8] c"\01\01\00\01\01\0C\01\00\0D" }>, section "__LLVM_COV,__llvm_covfun", align 8"#,
expected: CovfunLineData {
is_used: true,
name_hash: as_u64(1116917981370409222),
filenames_hash: as_u64(-3625186110715410276),
payload: b"\x01\x01\x00\x01\x01\x0C\x01\x00\x0D".to_vec(),
},
},
];
for &Case { line, ref expected } in cases {
println!("- {line}");
let line_data = parse_covfun_line(line).map_err(|e| e.to_string());
assert_eq!(line_data.as_ref(), Ok(expected));
}
}

View file

@ -0,0 +1,75 @@
use std::collections::HashMap;
use std::sync::LazyLock;
use anyhow::{Context, ensure};
use regex::Regex;
use crate::llvm_utils::{truncated_md5, unescape_llvm_string_contents};
use crate::parser::Parser;
#[derive(Debug, Default)]
pub(crate) struct FilenameTables {
map: HashMap<u64, Vec<String>>,
}
impl FilenameTables {
pub(crate) fn lookup(&self, filenames_hash: u64, global_file_id: usize) -> Option<&str> {
let table = self.map.get(&filenames_hash)?;
let filename = table.get(global_file_id)?;
Some(filename)
}
}
struct CovmapLineData {
payload: Vec<u8>,
}
pub(crate) fn make_filename_tables(llvm_ir: &str) -> anyhow::Result<FilenameTables> {
let mut map = HashMap::default();
for line in llvm_ir.lines().filter(|line| is_covmap_line(line)) {
let CovmapLineData { payload } = parse_covmap_line(line)?;
let mut parser = Parser::new(&payload);
let n_filenames = parser.read_uleb128_usize()?;
let uncompressed_bytes = parser.read_chunk_to_uncompressed_bytes()?;
parser.ensure_empty()?;
let mut filenames_table = vec![];
let mut parser = Parser::new(&uncompressed_bytes);
for _ in 0..n_filenames {
let len = parser.read_uleb128_usize()?;
let bytes = parser.read_n_bytes(len)?;
let filename = str::from_utf8(bytes)?;
filenames_table.push(filename.to_owned());
}
let filenames_hash = truncated_md5(&payload);
map.insert(filenames_hash, filenames_table);
}
Ok(FilenameTables { map })
}
fn is_covmap_line(line: &str) -> bool {
line.starts_with("@__llvm_coverage_mapping ")
}
fn parse_covmap_line(line: &str) -> anyhow::Result<CovmapLineData> {
ensure!(is_covmap_line(line));
const RE_STRING: &str = r#"(?x)^
@__llvm_coverage_mapping \ =
.*
\[ [0-9]+ \ x \ i8 \] \ c"(?<payload>[^"]*)"
.*$
"#;
static RE: LazyLock<Regex> = LazyLock::new(|| Regex::new(RE_STRING).unwrap());
let captures =
RE.captures(line).with_context(|| format!("couldn't parse covmap line: {line:?}"))?;
let payload = unescape_llvm_string_contents(&captures["payload"]);
Ok(CovmapLineData { payload })
}

View file

@ -0,0 +1,85 @@
use std::borrow::Cow;
use std::sync::OnceLock;
use anyhow::{anyhow, ensure};
use regex::bytes;
use crate::parser::Parser;
#[cfg(test)]
mod tests;
/// Given the raw contents of a string literal in LLVM IR assembly, decodes any
/// backslash escapes and returns a vector containing the resulting byte string.
pub(crate) fn unescape_llvm_string_contents(contents: &str) -> Vec<u8> {
let escape_re = {
static RE: OnceLock<bytes::Regex> = OnceLock::new();
// LLVM IR supports two string escapes: `\\` and `\xx`.
RE.get_or_init(|| bytes::Regex::new(r"\\\\|\\([0-9A-Za-z]{2})").unwrap())
};
fn u8_from_hex_digits(digits: &[u8]) -> u8 {
// We know that the input contains exactly 2 hex digits, so these calls
// should never fail.
assert_eq!(digits.len(), 2);
let digits = std::str::from_utf8(digits).unwrap();
u8::from_str_radix(digits, 16).unwrap()
}
escape_re
.replace_all(contents.as_bytes(), |captures: &bytes::Captures<'_>| {
let byte = match captures.get(1) {
None => b'\\',
Some(hex_digits) => u8_from_hex_digits(hex_digits.as_bytes()),
};
[byte]
})
.into_owned()
}
/// LLVM's profiler/coverage metadata often uses an MD5 hash truncated to
/// 64 bits as a way to associate data stored in different tables/sections.
pub(crate) fn truncated_md5(bytes: &[u8]) -> u64 {
use md5::{Digest, Md5};
let mut hasher = Md5::new();
hasher.update(bytes);
let hash: [u8; 8] = hasher.finalize().as_slice()[..8].try_into().unwrap();
// The truncated hash is explicitly little-endian, regardless of host
// or target platform. (See `MD5Result::low` in LLVM's `MD5.h`.)
u64::from_le_bytes(hash)
}
impl<'a> Parser<'a> {
/// Reads a sequence of:
/// - Length of uncompressed data in bytes, as ULEB128
/// - Length of compressed data in bytes (or 0), as ULEB128
/// - The indicated number of compressed or uncompressed bytes
///
/// If the number of compressed bytes is 0, the subsequent bytes are
/// uncompressed. Otherwise, the subsequent bytes are compressed, and will
/// be decompressed.
///
/// Returns the uncompressed bytes that were read directly or decompressed.
pub(crate) fn read_chunk_to_uncompressed_bytes(&mut self) -> anyhow::Result<Cow<'a, [u8]>> {
let uncompressed_len = self.read_uleb128_usize()?;
let compressed_len = self.read_uleb128_usize()?;
if compressed_len == 0 {
// The bytes are uncompressed, so read them directly.
let uncompressed_bytes = self.read_n_bytes(uncompressed_len)?;
Ok(Cow::Borrowed(uncompressed_bytes))
} else {
// The bytes are compressed, so read and decompress them.
let compressed_bytes = self.read_n_bytes(compressed_len)?;
let uncompressed_bytes = miniz_oxide::inflate::decompress_to_vec_zlib_with_limit(
compressed_bytes,
uncompressed_len,
)
.map_err(|e| anyhow!("{e:?}"))?;
ensure!(uncompressed_bytes.len() == uncompressed_len);
Ok(Cow::Owned(uncompressed_bytes))
}
}
}

View file

@ -1,9 +1,5 @@
use super::unescape_llvm_string_contents;
// WARNING: These tests don't necessarily run in CI, and were mainly used to
// help track down problems when originally developing this tool.
// (The tool is still tested indirectly by snapshot tests that rely on it.)
// Tests for `unescape_llvm_string_contents`:
#[test]

View file

@ -1,4 +1,6 @@
mod covfun;
mod covmap;
mod llvm_utils;
mod parser;
mod prf_names;
@ -17,8 +19,9 @@ fn main() -> anyhow::Result<()> {
let llvm_ir_path = args.get(1).context("LLVM IR file not specified")?;
let llvm_ir = std::fs::read_to_string(llvm_ir_path).context("couldn't read LLVM IR file")?;
let filename_tables = covmap::make_filename_tables(&llvm_ir)?;
let function_names = crate::prf_names::make_function_names_table(&llvm_ir)?;
crate::covfun::dump_covfun_mappings(&llvm_ir, &function_names)?;
crate::covfun::dump_covfun_mappings(&llvm_ir, &filename_tables, &function_names)?;
Ok(())
}

View file

@ -1,38 +1,4 @@
#[cfg(test)]
mod tests;
use std::sync::OnceLock;
use anyhow::ensure;
use regex::bytes;
/// Given the raw contents of a string literal in LLVM IR assembly, decodes any
/// backslash escapes and returns a vector containing the resulting byte string.
pub(crate) fn unescape_llvm_string_contents(contents: &str) -> Vec<u8> {
let escape_re = {
static RE: OnceLock<bytes::Regex> = OnceLock::new();
// LLVM IR supports two string escapes: `\\` and `\xx`.
RE.get_or_init(|| bytes::Regex::new(r"\\\\|\\([0-9A-Za-z]{2})").unwrap())
};
fn u8_from_hex_digits(digits: &[u8]) -> u8 {
// We know that the input contains exactly 2 hex digits, so these calls
// should never fail.
assert_eq!(digits.len(), 2);
let digits = std::str::from_utf8(digits).unwrap();
u8::from_str_radix(digits, 16).unwrap()
}
escape_re
.replace_all(contents.as_bytes(), |captures: &bytes::Captures<'_>| {
let byte = match captures.get(1) {
None => b'\\',
Some(hex_digits) => u8_from_hex_digits(hex_digits.as_bytes()),
};
[byte]
})
.into_owned()
}
pub(crate) struct Parser<'a> {
rest: &'a [u8],

View file

@ -1,10 +1,10 @@
use std::collections::HashMap;
use std::sync::OnceLock;
use anyhow::{anyhow, ensure};
use regex::Regex;
use crate::parser::{Parser, unescape_llvm_string_contents};
use crate::llvm_utils::{truncated_md5, unescape_llvm_string_contents};
use crate::parser::Parser;
/// Scans through the contents of an LLVM IR assembly file to find `__llvm_prf_names`
/// entries, decodes them, and creates a table that maps name hash values to
@ -25,18 +25,6 @@ pub(crate) fn make_function_names_table(llvm_ir: &str) -> anyhow::Result<HashMap
Some(payload)
}
/// LLVM's profiler/coverage metadata often uses an MD5 hash truncated to
/// 64 bits as a way to associate data stored in different tables/sections.
fn truncated_md5(bytes: &[u8]) -> u64 {
use md5::{Digest, Md5};
let mut hasher = Md5::new();
hasher.update(bytes);
let hash: [u8; 8] = hasher.finalize().as_slice()[..8].try_into().unwrap();
// The truncated hash is explicitly little-endian, regardless of host
// or target platform. (See `MD5Result::low` in LLVM's `MD5.h`.)
u64::from_le_bytes(hash)
}
fn demangle_if_able(symbol_name_bytes: &[u8]) -> anyhow::Result<String> {
// In practice, raw symbol names should always be ASCII.
let symbol_name_str = std::str::from_utf8(symbol_name_bytes)?;
@ -54,26 +42,8 @@ pub(crate) fn make_function_names_table(llvm_ir: &str) -> anyhow::Result<HashMap
for payload in llvm_ir.lines().filter_map(prf_names_payload).map(unescape_llvm_string_contents)
{
let mut parser = Parser::new(&payload);
let uncompressed_len = parser.read_uleb128_usize()?;
let compressed_len = parser.read_uleb128_usize()?;
let uncompressed_bytes_vec;
let uncompressed_bytes: &[u8] = if compressed_len == 0 {
// The symbol name bytes are uncompressed, so read them directly.
parser.read_n_bytes(uncompressed_len)?
} else {
// The symbol name bytes are compressed, so read and decompress them.
let compressed_bytes = parser.read_n_bytes(compressed_len)?;
uncompressed_bytes_vec = miniz_oxide::inflate::decompress_to_vec_zlib_with_limit(
compressed_bytes,
uncompressed_len,
)
.map_err(|e| anyhow!("{e:?}"))?;
ensure!(uncompressed_bytes_vec.len() == uncompressed_len);
&uncompressed_bytes_vec
};
let uncompressed_bytes = parser.read_chunk_to_uncompressed_bytes()?;
parser.ensure_empty()?;
// Symbol names in the payload are separated by `0x01` bytes.
for raw_name in uncompressed_bytes.split(|&b| b == 0x01) {
@ -81,8 +51,6 @@ pub(crate) fn make_function_names_table(llvm_ir: &str) -> anyhow::Result<HashMap
let demangled = demangle_if_able(raw_name)?;
map.insert(hash, demangled);
}
parser.ensure_empty()?;
}
Ok(map)

View file

@ -179,6 +179,15 @@ impl<'a> Converter<'a> {
COMMENT
}
rustc_lexer::TokenKind::Frontmatter { has_invalid_preceding_whitespace, invalid_infostring } => {
if *has_invalid_preceding_whitespace {
err = "invalid preceding whitespace for frontmatter opening"
} else if *invalid_infostring {
err = "invalid infostring for frontmatter"
}
FRONTMATTER
}
rustc_lexer::TokenKind::Whitespace => WHITESPACE,
rustc_lexer::TokenKind::Ident if token_text == "_" => UNDERSCORE,

File diff suppressed because one or more lines are too long

View file

@ -133,6 +133,7 @@ Meta =
SourceFile =
'#shebang'?
'#frontmatter'?
Attr*
Item*

View file

@ -1524,6 +1524,10 @@ impl ast::HasAttrs for SourceFile {}
impl ast::HasDocComments for SourceFile {}
impl ast::HasModuleItem for SourceFile {}
impl SourceFile {
#[inline]
pub fn frontmatter_token(&self) -> Option<SyntaxToken> {
support::token(&self.syntax, T![frontmatter])
}
#[inline]
pub fn shebang_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![shebang]) }
}

View file

@ -670,6 +670,7 @@ fn generate_syntax_kinds(grammar: KindsSrc) -> String {
[ident] => { $crate::SyntaxKind::IDENT };
[string] => { $crate::SyntaxKind::STRING };
[shebang] => { $crate::SyntaxKind::SHEBANG };
[frontmatter] => { $crate::SyntaxKind::FRONTMATTER };
}
impl ::core::marker::Copy for SyntaxKind {}

View file

@ -938,9 +938,9 @@ dependencies = [
[[package]]
name = "mdbook"
version = "0.4.48"
version = "0.4.49"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8b6fbb4ac2d9fd7aa987c3510309ea3c80004a968d063c42f0d34fea070817c1"
checksum = "d1daacee059634081dee4250d2814763a365b92dfe14bfdef964bc27835209d4"
dependencies = [
"ammonia",
"anyhow",

View file

@ -15,6 +15,6 @@ mdbook-i18n-helpers = "0.3.3"
mdbook-spec = { path = "../../doc/reference/mdbook-spec" }
[dependencies.mdbook]
version = "0.4.48"
version = "0.4.49"
default-features = false
features = ["search"]

View file

@ -1,7 +1,7 @@
Function name: abort::main
Raw bytes (83): 0x[01, 01, 07, 05, 01, 05, 0b, 01, 09, 05, 13, 01, 0d, 05, 1b, 01, 11, 0d, 01, 0d, 01, 01, 1b, 05, 02, 0b, 00, 18, 02, 01, 0c, 00, 19, 09, 00, 1a, 02, 0a, 06, 02, 09, 00, 0a, 02, 02, 0c, 00, 19, 0d, 00, 1a, 00, 31, 0e, 00, 30, 00, 31, 02, 04, 0c, 00, 19, 11, 00, 1a, 00, 31, 16, 00, 30, 00, 31, 02, 01, 09, 00, 17, 01, 02, 05, 01, 02]
Number of files: 1
- file 0 => global file 1
- file 0 => $DIR/abort.rs
Number of expressions: 7
- expression 0 operands: lhs = Counter(1), rhs = Counter(0)
- expression 1 operands: lhs = Counter(1), rhs = Expression(2, Add)
@ -36,7 +36,7 @@ Highest counter ID seen: c4
Function name: abort::might_abort
Raw bytes (21): 0x[01, 01, 01, 01, 05, 03, 01, 03, 01, 01, 14, 05, 02, 09, 01, 0f, 02, 02, 0c, 03, 02]
Number of files: 1
- file 0 => global file 1
- file 0 => $DIR/abort.rs
Number of expressions: 1
- expression 0 operands: lhs = Counter(0), rhs = Counter(1)
Number of file 0 mappings: 3

View file

@ -1,7 +1,7 @@
Function name: assert_ne::main
Raw bytes (28): 0x[01, 01, 02, 01, 05, 01, 09, 04, 01, 08, 01, 03, 15, 05, 04, 0d, 00, 13, 02, 02, 0d, 00, 13, 06, 03, 05, 01, 02]
Number of files: 1
- file 0 => global file 1
- file 0 => $DIR/assert-ne.rs
Number of expressions: 2
- expression 0 operands: lhs = Counter(0), rhs = Counter(1)
- expression 1 operands: lhs = Counter(0), rhs = Counter(2)

View file

@ -1,7 +1,7 @@
Function name: assert::main
Raw bytes (61): 0x[01, 01, 06, 05, 01, 05, 17, 01, 09, 05, 13, 17, 0d, 01, 09, 09, 01, 09, 01, 01, 1b, 05, 02, 0b, 00, 18, 02, 01, 0c, 00, 1a, 09, 00, 1b, 02, 0a, 06, 02, 13, 00, 20, 0d, 00, 21, 02, 0a, 0e, 02, 09, 00, 0a, 02, 01, 09, 00, 17, 01, 02, 05, 01, 02]
Number of files: 1
- file 0 => global file 1
- file 0 => $DIR/assert.rs
Number of expressions: 6
- expression 0 operands: lhs = Counter(1), rhs = Counter(0)
- expression 1 operands: lhs = Counter(1), rhs = Expression(5, Add)
@ -28,7 +28,7 @@ Highest counter ID seen: c3
Function name: assert::might_fail_assert
Raw bytes (21): 0x[01, 01, 01, 01, 05, 03, 01, 04, 01, 02, 0f, 02, 02, 25, 00, 3d, 05, 01, 01, 00, 02]
Number of files: 1
- file 0 => global file 1
- file 0 => $DIR/assert.rs
Number of expressions: 1
- expression 0 operands: lhs = Counter(0), rhs = Counter(1)
Number of file 0 mappings: 3

View file

@ -1,7 +1,7 @@
Function name: assert_not::main
Raw bytes (29): 0x[01, 01, 00, 05, 01, 06, 01, 01, 11, 01, 02, 05, 00, 13, 01, 01, 05, 00, 13, 01, 01, 05, 00, 15, 01, 01, 01, 00, 02]
Number of files: 1
- file 0 => global file 1
- file 0 => $DIR/assert_not.rs
Number of expressions: 0
Number of file 0 mappings: 5
- Code(Counter(0)) at (prev + 6, 1) to (start + 1, 17)

View file

@ -1,7 +1,7 @@
Function name: async::c
Raw bytes (9): 0x[01, 01, 00, 01, 01, 0b, 01, 00, 19]
Number of files: 1
- file 0 => global file 1
- file 0 => $DIR/async.rs
Number of expressions: 0
Number of file 0 mappings: 1
- Code(Counter(0)) at (prev + 11, 1) to (start + 0, 25)
@ -10,7 +10,7 @@ Highest counter ID seen: c0
Function name: async::c::{closure#0}
Raw bytes (26): 0x[01, 01, 01, 01, 05, 04, 01, 0b, 19, 01, 0e, 05, 02, 09, 00, 0a, 02, 02, 09, 00, 0a, 01, 02, 01, 00, 02]
Number of files: 1
- file 0 => global file 1
- file 0 => $DIR/async.rs
Number of expressions: 1
- expression 0 operands: lhs = Counter(0), rhs = Counter(1)
Number of file 0 mappings: 4
@ -24,7 +24,7 @@ Highest counter ID seen: c1
Function name: async::d
Raw bytes (9): 0x[01, 01, 00, 01, 01, 13, 01, 00, 14]
Number of files: 1
- file 0 => global file 1
- file 0 => $DIR/async.rs
Number of expressions: 0
Number of file 0 mappings: 1
- Code(Counter(0)) at (prev + 19, 1) to (start + 0, 20)
@ -33,7 +33,7 @@ Highest counter ID seen: c0
Function name: async::d::{closure#0}
Raw bytes (9): 0x[01, 01, 00, 01, 01, 13, 14, 00, 19]
Number of files: 1
- file 0 => global file 1
- file 0 => $DIR/async.rs
Number of expressions: 0
Number of file 0 mappings: 1
- Code(Counter(0)) at (prev + 19, 20) to (start + 0, 25)
@ -42,7 +42,7 @@ Highest counter ID seen: c0
Function name: async::e (unused)
Raw bytes (9): 0x[01, 01, 00, 01, 00, 15, 01, 00, 14]
Number of files: 1
- file 0 => global file 1
- file 0 => $DIR/async.rs
Number of expressions: 0
Number of file 0 mappings: 1
- Code(Zero) at (prev + 21, 1) to (start + 0, 20)
@ -51,7 +51,7 @@ Highest counter ID seen: (none)
Function name: async::e::{closure#0} (unused)
Raw bytes (9): 0x[01, 01, 00, 01, 00, 15, 14, 00, 19]
Number of files: 1
- file 0 => global file 1
- file 0 => $DIR/async.rs
Number of expressions: 0
Number of file 0 mappings: 1
- Code(Zero) at (prev + 21, 20) to (start + 0, 25)
@ -60,7 +60,7 @@ Highest counter ID seen: (none)
Function name: async::f
Raw bytes (9): 0x[01, 01, 00, 01, 01, 17, 01, 00, 14]
Number of files: 1
- file 0 => global file 1
- file 0 => $DIR/async.rs
Number of expressions: 0
Number of file 0 mappings: 1
- Code(Counter(0)) at (prev + 23, 1) to (start + 0, 20)
@ -69,7 +69,7 @@ Highest counter ID seen: c0
Function name: async::f::{closure#0}
Raw bytes (9): 0x[01, 01, 00, 01, 01, 17, 14, 00, 19]
Number of files: 1
- file 0 => global file 1
- file 0 => $DIR/async.rs
Number of expressions: 0
Number of file 0 mappings: 1
- Code(Counter(0)) at (prev + 23, 20) to (start + 0, 25)
@ -78,7 +78,7 @@ Highest counter ID seen: c0
Function name: async::foo (unused)
Raw bytes (9): 0x[01, 01, 00, 01, 00, 19, 01, 00, 1e]
Number of files: 1
- file 0 => global file 1
- file 0 => $DIR/async.rs
Number of expressions: 0
Number of file 0 mappings: 1
- Code(Zero) at (prev + 25, 1) to (start + 0, 30)
@ -87,7 +87,7 @@ Highest counter ID seen: (none)
Function name: async::foo::{closure#0} (unused)
Raw bytes (9): 0x[01, 01, 00, 01, 00, 19, 1e, 00, 2d]
Number of files: 1
- file 0 => global file 1
- file 0 => $DIR/async.rs
Number of expressions: 0
Number of file 0 mappings: 1
- Code(Zero) at (prev + 25, 30) to (start + 0, 45)
@ -96,7 +96,7 @@ Highest counter ID seen: (none)
Function name: async::g
Raw bytes (9): 0x[01, 01, 00, 01, 01, 1b, 01, 00, 17]
Number of files: 1
- file 0 => global file 1
- file 0 => $DIR/async.rs
Number of expressions: 0
Number of file 0 mappings: 1
- Code(Counter(0)) at (prev + 27, 1) to (start + 0, 23)
@ -105,7 +105,7 @@ Highest counter ID seen: c0
Function name: async::g::{closure#0} (unused)
Raw bytes (59): 0x[01, 01, 00, 0b, 00, 1b, 17, 01, 0c, 00, 02, 09, 00, 0a, 00, 00, 0e, 00, 17, 00, 00, 1b, 00, 1c, 00, 00, 20, 00, 22, 00, 01, 09, 00, 0a, 00, 00, 0e, 00, 17, 00, 00, 1b, 00, 1c, 00, 00, 20, 00, 22, 00, 01, 0e, 00, 10, 00, 02, 01, 00, 02]
Number of files: 1
- file 0 => global file 1
- file 0 => $DIR/async.rs
Number of expressions: 0
Number of file 0 mappings: 11
- Code(Zero) at (prev + 27, 23) to (start + 1, 12)
@ -124,7 +124,7 @@ Highest counter ID seen: (none)
Function name: async::h
Raw bytes (9): 0x[01, 01, 00, 01, 01, 23, 01, 00, 16]
Number of files: 1
- file 0 => global file 1
- file 0 => $DIR/async.rs
Number of expressions: 0
Number of file 0 mappings: 1
- Code(Counter(0)) at (prev + 35, 1) to (start + 0, 22)
@ -133,7 +133,7 @@ Highest counter ID seen: c0
Function name: async::h::{closure#0} (unused)
Raw bytes (39): 0x[01, 01, 00, 07, 00, 23, 16, 03, 0c, 00, 04, 09, 00, 0a, 00, 00, 0e, 00, 19, 00, 00, 1a, 00, 1b, 00, 00, 20, 00, 22, 00, 01, 0e, 00, 10, 00, 02, 01, 00, 02]
Number of files: 1
- file 0 => global file 1
- file 0 => $DIR/async.rs
Number of expressions: 0
Number of file 0 mappings: 7
- Code(Zero) at (prev + 35, 22) to (start + 3, 12)
@ -148,7 +148,7 @@ Highest counter ID seen: (none)
Function name: async::i
Raw bytes (9): 0x[01, 01, 00, 01, 01, 2c, 01, 00, 13]
Number of files: 1
- file 0 => global file 1
- file 0 => $DIR/async.rs
Number of expressions: 0
Number of file 0 mappings: 1
- Code(Counter(0)) at (prev + 44, 1) to (start + 0, 19)
@ -157,7 +157,7 @@ Highest counter ID seen: c0
Function name: async::i::{closure#0}
Raw bytes (65): 0x[01, 01, 03, 05, 09, 11, 15, 0d, 11, 0b, 01, 2c, 13, 04, 0c, 09, 05, 09, 00, 0a, 01, 00, 0e, 00, 18, 05, 00, 1c, 00, 21, 09, 00, 27, 00, 30, 15, 01, 09, 00, 0a, 02, 00, 0e, 00, 17, 11, 00, 1b, 00, 20, 15, 00, 24, 00, 26, 06, 01, 0e, 00, 10, 0b, 02, 01, 00, 02]
Number of files: 1
- file 0 => global file 1
- file 0 => $DIR/async.rs
Number of expressions: 3
- expression 0 operands: lhs = Counter(1), rhs = Counter(2)
- expression 1 operands: lhs = Counter(4), rhs = Counter(5)
@ -182,7 +182,7 @@ Highest counter ID seen: c5
Function name: async::j
Raw bytes (60): 0x[01, 01, 03, 01, 05, 01, 0b, 05, 09, 0a, 01, 37, 01, 00, 0d, 01, 0b, 0b, 00, 0c, 05, 01, 09, 00, 0a, 01, 00, 0e, 00, 1b, 05, 00, 1f, 00, 27, 09, 01, 09, 00, 0a, 02, 00, 0e, 00, 1a, 09, 00, 1e, 00, 20, 06, 01, 0e, 00, 10, 01, 02, 01, 00, 02]
Number of files: 1
- file 0 => global file 1
- file 0 => $DIR/async.rs
Number of expressions: 3
- expression 0 operands: lhs = Counter(0), rhs = Counter(1)
- expression 1 operands: lhs = Counter(0), rhs = Expression(2, Add)
@ -205,7 +205,7 @@ Highest counter ID seen: c2
Function name: async::j::c
Raw bytes (26): 0x[01, 01, 01, 01, 05, 04, 01, 39, 05, 01, 12, 05, 02, 0d, 00, 0e, 02, 02, 0d, 00, 0e, 01, 02, 05, 00, 06]
Number of files: 1
- file 0 => global file 1
- file 0 => $DIR/async.rs
Number of expressions: 1
- expression 0 operands: lhs = Counter(0), rhs = Counter(1)
Number of file 0 mappings: 4
@ -219,7 +219,7 @@ Highest counter ID seen: c1
Function name: async::j::d
Raw bytes (9): 0x[01, 01, 00, 01, 01, 40, 05, 00, 17]
Number of files: 1
- file 0 => global file 1
- file 0 => $DIR/async.rs
Number of expressions: 0
Number of file 0 mappings: 1
- Code(Counter(0)) at (prev + 64, 5) to (start + 0, 23)
@ -228,7 +228,7 @@ Highest counter ID seen: c0
Function name: async::j::f
Raw bytes (9): 0x[01, 01, 00, 01, 01, 41, 05, 00, 17]
Number of files: 1
- file 0 => global file 1
- file 0 => $DIR/async.rs
Number of expressions: 0
Number of file 0 mappings: 1
- Code(Counter(0)) at (prev + 65, 5) to (start + 0, 23)
@ -237,7 +237,7 @@ Highest counter ID seen: c0
Function name: async::k (unused)
Raw bytes (29): 0x[01, 01, 00, 05, 00, 49, 01, 01, 0c, 00, 02, 0e, 00, 10, 00, 01, 0e, 00, 10, 00, 01, 0e, 00, 10, 00, 02, 01, 00, 02]
Number of files: 1
- file 0 => global file 1
- file 0 => $DIR/async.rs
Number of expressions: 0
Number of file 0 mappings: 5
- Code(Zero) at (prev + 73, 1) to (start + 1, 12)
@ -250,7 +250,7 @@ Highest counter ID seen: (none)
Function name: async::l
Raw bytes (33): 0x[01, 01, 02, 01, 07, 05, 09, 05, 01, 51, 01, 01, 0c, 02, 02, 0e, 00, 10, 09, 01, 0e, 00, 10, 05, 01, 0e, 00, 10, 01, 02, 01, 00, 02]
Number of files: 1
- file 0 => global file 1
- file 0 => $DIR/async.rs
Number of expressions: 2
- expression 0 operands: lhs = Counter(0), rhs = Expression(1, Add)
- expression 1 operands: lhs = Counter(1), rhs = Counter(2)
@ -266,7 +266,7 @@ Highest counter ID seen: c2
Function name: async::m
Raw bytes (9): 0x[01, 01, 00, 01, 01, 59, 01, 00, 19]
Number of files: 1
- file 0 => global file 1
- file 0 => $DIR/async.rs
Number of expressions: 0
Number of file 0 mappings: 1
- Code(Counter(0)) at (prev + 89, 1) to (start + 0, 25)
@ -275,7 +275,7 @@ Highest counter ID seen: c0
Function name: async::m::{closure#0} (unused)
Raw bytes (9): 0x[01, 01, 00, 01, 00, 59, 19, 00, 22]
Number of files: 1
- file 0 => global file 1
- file 0 => $DIR/async.rs
Number of expressions: 0
Number of file 0 mappings: 1
- Code(Zero) at (prev + 89, 25) to (start + 0, 34)
@ -284,7 +284,7 @@ Highest counter ID seen: (none)
Function name: async::main
Raw bytes (9): 0x[01, 01, 00, 01, 01, 5b, 01, 08, 02]
Number of files: 1
- file 0 => global file 1
- file 0 => $DIR/async.rs
Number of expressions: 0
Number of file 0 mappings: 1
- Code(Counter(0)) at (prev + 91, 1) to (start + 8, 2)

View file

@ -1,7 +1,7 @@
Function name: async2::async_func
Raw bytes (9): 0x[01, 01, 00, 01, 01, 0f, 01, 00, 17]
Number of files: 1
- file 0 => global file 1
- file 0 => $DIR/async2.rs
Number of expressions: 0
Number of file 0 mappings: 1
- Code(Counter(0)) at (prev + 15, 1) to (start + 0, 23)
@ -10,7 +10,7 @@ Highest counter ID seen: c0
Function name: async2::async_func::{closure#0}
Raw bytes (24): 0x[01, 01, 00, 04, 01, 0f, 17, 03, 09, 01, 03, 0a, 02, 06, 00, 02, 05, 00, 06, 01, 01, 01, 00, 02]
Number of files: 1
- file 0 => global file 1
- file 0 => $DIR/async2.rs
Number of expressions: 0
Number of file 0 mappings: 4
- Code(Counter(0)) at (prev + 15, 23) to (start + 3, 9)
@ -22,7 +22,7 @@ Highest counter ID seen: c0
Function name: async2::async_func_just_println
Raw bytes (9): 0x[01, 01, 00, 01, 01, 17, 01, 00, 24]
Number of files: 1
- file 0 => global file 1
- file 0 => $DIR/async2.rs
Number of expressions: 0
Number of file 0 mappings: 1
- Code(Counter(0)) at (prev + 23, 1) to (start + 0, 36)
@ -31,7 +31,7 @@ Highest counter ID seen: c0
Function name: async2::async_func_just_println::{closure#0}
Raw bytes (9): 0x[01, 01, 00, 01, 01, 17, 24, 02, 02]
Number of files: 1
- file 0 => global file 1
- file 0 => $DIR/async2.rs
Number of expressions: 0
Number of file 0 mappings: 1
- Code(Counter(0)) at (prev + 23, 36) to (start + 2, 2)
@ -40,7 +40,7 @@ Highest counter ID seen: c0
Function name: async2::main
Raw bytes (9): 0x[01, 01, 00, 01, 01, 1b, 01, 07, 02]
Number of files: 1
- file 0 => global file 1
- file 0 => $DIR/async2.rs
Number of expressions: 0
Number of file 0 mappings: 1
- Code(Counter(0)) at (prev + 27, 1) to (start + 7, 2)
@ -49,7 +49,7 @@ Highest counter ID seen: c0
Function name: async2::non_async_func
Raw bytes (24): 0x[01, 01, 00, 04, 01, 07, 01, 03, 09, 01, 03, 0a, 02, 06, 00, 02, 05, 00, 06, 01, 01, 01, 00, 02]
Number of files: 1
- file 0 => global file 1
- file 0 => $DIR/async2.rs
Number of expressions: 0
Number of file 0 mappings: 4
- Code(Counter(0)) at (prev + 7, 1) to (start + 3, 9)

View file

@ -1,7 +1,7 @@
Function name: async_block::main
Raw bytes (36): 0x[01, 01, 01, 05, 01, 06, 01, 07, 01, 00, 0b, 02, 01, 09, 00, 0a, 05, 00, 0e, 00, 13, 02, 01, 0d, 00, 13, 02, 07, 09, 00, 22, 01, 02, 01, 00, 02]
Number of files: 1
- file 0 => global file 1
- file 0 => $DIR/async_block.rs
Number of expressions: 1
- expression 0 operands: lhs = Counter(1), rhs = Counter(0)
Number of file 0 mappings: 6
@ -19,7 +19,7 @@ Highest counter ID seen: c1
Function name: async_block::main::{closure#0}
Raw bytes (26): 0x[01, 01, 01, 01, 05, 04, 01, 09, 1c, 01, 17, 05, 01, 18, 02, 0e, 02, 02, 14, 02, 0e, 01, 03, 09, 00, 0a]
Number of files: 1
- file 0 => global file 1
- file 0 => $DIR/async_block.rs
Number of expressions: 1
- expression 0 operands: lhs = Counter(0), rhs = Counter(1)
Number of file 0 mappings: 4

View file

@ -1,7 +1,7 @@
Function name: async_closure::call_once::<async_closure::main::{closure#0}>
Raw bytes (9): 0x[01, 01, 00, 01, 01, 06, 01, 00, 2b]
Number of files: 1
- file 0 => global file 1
- file 0 => $DIR/async_closure.rs
Number of expressions: 0
Number of file 0 mappings: 1
- Code(Counter(0)) at (prev + 6, 1) to (start + 0, 43)
@ -10,7 +10,7 @@ Highest counter ID seen: c0
Function name: async_closure::call_once::<async_closure::main::{closure#0}>::{closure#0}
Raw bytes (16): 0x[01, 01, 01, 05, 09, 02, 01, 06, 2b, 01, 0e, 02, 02, 01, 00, 02]
Number of files: 1
- file 0 => global file 1
- file 0 => $DIR/async_closure.rs
Number of expressions: 1
- expression 0 operands: lhs = Counter(1), rhs = Counter(2)
Number of file 0 mappings: 2
@ -22,7 +22,7 @@ Highest counter ID seen: c0
Function name: async_closure::main
Raw bytes (14): 0x[01, 01, 00, 02, 01, 0a, 01, 01, 16, 01, 02, 05, 02, 02]
Number of files: 1
- file 0 => global file 1
- file 0 => $DIR/async_closure.rs
Number of expressions: 0
Number of file 0 mappings: 2
- Code(Counter(0)) at (prev + 10, 1) to (start + 1, 22)
@ -32,7 +32,7 @@ Highest counter ID seen: c0
Function name: async_closure::main::{closure#0}
Raw bytes (14): 0x[01, 01, 00, 02, 01, 0b, 22, 00, 23, 01, 00, 23, 00, 24]
Number of files: 1
- file 0 => global file 1
- file 0 => $DIR/async_closure.rs
Number of expressions: 0
Number of file 0 mappings: 2
- Code(Counter(0)) at (prev + 11, 34) to (start + 0, 35)
@ -42,7 +42,7 @@ Highest counter ID seen: c0
Function name: async_closure::main::{closure#0}
Raw bytes (14): 0x[01, 01, 00, 02, 01, 0b, 22, 00, 23, 01, 00, 23, 00, 24]
Number of files: 1
- file 0 => global file 1
- file 0 => $DIR/async_closure.rs
Number of expressions: 0
Number of file 0 mappings: 2
- Code(Counter(0)) at (prev + 11, 34) to (start + 0, 35)
@ -52,7 +52,7 @@ Highest counter ID seen: c0
Function name: async_closure::main::{closure#0}::{closure#0}::<i16>
Raw bytes (9): 0x[01, 01, 00, 01, 01, 0b, 22, 00, 24]
Number of files: 1
- file 0 => global file 1
- file 0 => $DIR/async_closure.rs
Number of expressions: 0
Number of file 0 mappings: 1
- Code(Counter(0)) at (prev + 11, 34) to (start + 0, 36)

View file

@ -1,7 +1,7 @@
Function name: <impl::MyStruct>::off_on (unused)
Raw bytes (9): 0x[01, 01, 00, 01, 00, 0f, 05, 00, 13]
Number of files: 1
- file 0 => global file 1
- file 0 => $DIR/impl.rs
Number of expressions: 0
Number of file 0 mappings: 1
- Code(Zero) at (prev + 15, 5) to (start + 0, 19)
@ -10,7 +10,7 @@ Highest counter ID seen: (none)
Function name: <impl::MyStruct>::on_inherit (unused)
Raw bytes (9): 0x[01, 01, 00, 01, 00, 17, 05, 00, 17]
Number of files: 1
- file 0 => global file 1
- file 0 => $DIR/impl.rs
Number of expressions: 0
Number of file 0 mappings: 1
- Code(Zero) at (prev + 23, 5) to (start + 0, 23)
@ -19,7 +19,7 @@ Highest counter ID seen: (none)
Function name: <impl::MyStruct>::on_on (unused)
Raw bytes (9): 0x[01, 01, 00, 01, 00, 1a, 05, 00, 12]
Number of files: 1
- file 0 => global file 1
- file 0 => $DIR/impl.rs
Number of expressions: 0
Number of file 0 mappings: 1
- Code(Zero) at (prev + 26, 5) to (start + 0, 18)

View file

@ -1,7 +1,7 @@
Function name: module::off::on (unused)
Raw bytes (9): 0x[01, 01, 00, 01, 00, 0d, 05, 00, 0f]
Number of files: 1
- file 0 => global file 1
- file 0 => $DIR/module.rs
Number of expressions: 0
Number of file 0 mappings: 1
- Code(Zero) at (prev + 13, 5) to (start + 0, 15)
@ -10,7 +10,7 @@ Highest counter ID seen: (none)
Function name: module::on::inherit (unused)
Raw bytes (9): 0x[01, 01, 00, 01, 00, 15, 05, 00, 14]
Number of files: 1
- file 0 => global file 1
- file 0 => $DIR/module.rs
Number of expressions: 0
Number of file 0 mappings: 1
- Code(Zero) at (prev + 21, 5) to (start + 0, 20)
@ -19,7 +19,7 @@ Highest counter ID seen: (none)
Function name: module::on::on (unused)
Raw bytes (9): 0x[01, 01, 00, 01, 00, 18, 05, 00, 0f]
Number of files: 1
- file 0 => global file 1
- file 0 => $DIR/module.rs
Number of expressions: 0
Number of file 0 mappings: 1
- Code(Zero) at (prev + 24, 5) to (start + 0, 15)

View file

@ -1,7 +1,7 @@
Function name: nested::closure_expr
Raw bytes (14): 0x[01, 01, 00, 02, 01, 40, 01, 01, 0f, 01, 0b, 05, 01, 02]
Number of files: 1
- file 0 => global file 1
- file 0 => $DIR/nested.rs
Number of expressions: 0
Number of file 0 mappings: 2
- Code(Counter(0)) at (prev + 64, 1) to (start + 1, 15)
@ -11,7 +11,7 @@ Highest counter ID seen: c0
Function name: nested::closure_tail
Raw bytes (14): 0x[01, 01, 00, 02, 01, 4f, 01, 01, 0f, 01, 11, 05, 01, 02]
Number of files: 1
- file 0 => global file 1
- file 0 => $DIR/nested.rs
Number of expressions: 0
Number of file 0 mappings: 2
- Code(Counter(0)) at (prev + 79, 1) to (start + 1, 15)

View file

@ -1,7 +1,7 @@
Function name: off_on_sandwich::dense_a::dense_b
Raw bytes (14): 0x[01, 01, 00, 02, 01, 10, 05, 02, 10, 01, 07, 05, 00, 06]
Number of files: 1
- file 0 => global file 1
- file 0 => $DIR/off-on-sandwich.rs
Number of expressions: 0
Number of file 0 mappings: 2
- Code(Counter(0)) at (prev + 16, 5) to (start + 2, 16)
@ -11,7 +11,7 @@ Highest counter ID seen: c0
Function name: off_on_sandwich::sparse_a::sparse_b::sparse_c
Raw bytes (14): 0x[01, 01, 00, 02, 01, 22, 09, 02, 15, 01, 0b, 09, 00, 0a]
Number of files: 1
- file 0 => global file 1
- file 0 => $DIR/off-on-sandwich.rs
Number of expressions: 0
Number of file 0 mappings: 2
- Code(Counter(0)) at (prev + 34, 9) to (start + 2, 21)
@ -21,7 +21,7 @@ Highest counter ID seen: c0
Function name: off_on_sandwich::sparse_a::sparse_b::sparse_c::sparse_d
Raw bytes (14): 0x[01, 01, 00, 02, 01, 25, 0d, 02, 19, 01, 07, 0d, 00, 0e]
Number of files: 1
- file 0 => global file 1
- file 0 => $DIR/off-on-sandwich.rs
Number of expressions: 0
Number of file 0 mappings: 2
- Code(Counter(0)) at (prev + 37, 13) to (start + 2, 25)

View file

@ -1,7 +1,7 @@
Function name: <trait_impl_inherit::S as trait_impl_inherit::T>::f
Raw bytes (9): 0x[01, 01, 00, 01, 01, 11, 05, 02, 06]
Number of files: 1
- file 0 => global file 1
- file 0 => $DIR/trait-impl-inherit.rs
Number of expressions: 0
Number of file 0 mappings: 1
- Code(Counter(0)) at (prev + 17, 5) to (start + 2, 6)

View file

@ -1,7 +1,7 @@
Function name: await_ready::await_ready
Raw bytes (9): 0x[01, 01, 00, 01, 01, 0e, 01, 00, 1e]
Number of files: 1
- file 0 => global file 1
- file 0 => $DIR/await_ready.rs
Number of expressions: 0
Number of file 0 mappings: 1
- Code(Counter(0)) at (prev + 14, 1) to (start + 0, 30)
@ -10,7 +10,7 @@ Highest counter ID seen: c0
Function name: await_ready::await_ready::{closure#0}
Raw bytes (16): 0x[01, 01, 01, 05, 09, 02, 01, 0e, 1e, 03, 0f, 02, 04, 01, 00, 02]
Number of files: 1
- file 0 => global file 1
- file 0 => $DIR/await_ready.rs
Number of expressions: 1
- expression 0 operands: lhs = Counter(1), rhs = Counter(2)
Number of file 0 mappings: 2

View file

@ -1,7 +1,7 @@
Function name: bad_counter_ids::eq_bad
Raw bytes (14): 0x[01, 01, 00, 02, 01, 24, 01, 02, 0f, 00, 03, 01, 00, 02]
Number of files: 1
- file 0 => global file 1
- file 0 => $DIR/bad_counter_ids.rs
Number of expressions: 0
Number of file 0 mappings: 2
- Code(Counter(0)) at (prev + 36, 1) to (start + 2, 15)
@ -11,7 +11,7 @@ Highest counter ID seen: c0
Function name: bad_counter_ids::eq_bad_message
Raw bytes (19): 0x[01, 01, 00, 03, 01, 29, 01, 02, 0f, 01, 02, 20, 00, 2b, 00, 01, 01, 00, 02]
Number of files: 1
- file 0 => global file 1
- file 0 => $DIR/bad_counter_ids.rs
Number of expressions: 0
Number of file 0 mappings: 3
- Code(Counter(0)) at (prev + 41, 1) to (start + 2, 15)
@ -22,7 +22,7 @@ Highest counter ID seen: c0
Function name: bad_counter_ids::eq_good
Raw bytes (14): 0x[01, 01, 00, 02, 01, 10, 01, 02, 0f, 01, 03, 01, 00, 02]
Number of files: 1
- file 0 => global file 1
- file 0 => $DIR/bad_counter_ids.rs
Number of expressions: 0
Number of file 0 mappings: 2
- Code(Counter(0)) at (prev + 16, 1) to (start + 2, 15)
@ -32,7 +32,7 @@ Highest counter ID seen: c0
Function name: bad_counter_ids::eq_good_message
Raw bytes (19): 0x[01, 01, 00, 03, 01, 15, 01, 02, 0f, 00, 02, 20, 00, 2b, 01, 01, 01, 00, 02]
Number of files: 1
- file 0 => global file 1
- file 0 => $DIR/bad_counter_ids.rs
Number of expressions: 0
Number of file 0 mappings: 3
- Code(Counter(0)) at (prev + 21, 1) to (start + 2, 15)
@ -43,7 +43,7 @@ Highest counter ID seen: c0
Function name: bad_counter_ids::ne_bad
Raw bytes (14): 0x[01, 01, 00, 02, 01, 2e, 01, 02, 0f, 00, 03, 01, 00, 02]
Number of files: 1
- file 0 => global file 1
- file 0 => $DIR/bad_counter_ids.rs
Number of expressions: 0
Number of file 0 mappings: 2
- Code(Counter(0)) at (prev + 46, 1) to (start + 2, 15)
@ -53,7 +53,7 @@ Highest counter ID seen: c0
Function name: bad_counter_ids::ne_bad_message
Raw bytes (19): 0x[01, 01, 00, 03, 01, 33, 01, 02, 0f, 01, 02, 20, 00, 2b, 00, 01, 01, 00, 02]
Number of files: 1
- file 0 => global file 1
- file 0 => $DIR/bad_counter_ids.rs
Number of expressions: 0
Number of file 0 mappings: 3
- Code(Counter(0)) at (prev + 51, 1) to (start + 2, 15)
@ -64,7 +64,7 @@ Highest counter ID seen: c0
Function name: bad_counter_ids::ne_good
Raw bytes (14): 0x[01, 01, 00, 02, 01, 1a, 01, 02, 0f, 01, 03, 01, 00, 02]
Number of files: 1
- file 0 => global file 1
- file 0 => $DIR/bad_counter_ids.rs
Number of expressions: 0
Number of file 0 mappings: 2
- Code(Counter(0)) at (prev + 26, 1) to (start + 2, 15)
@ -74,7 +74,7 @@ Highest counter ID seen: c0
Function name: bad_counter_ids::ne_good_message
Raw bytes (19): 0x[01, 01, 00, 03, 01, 1f, 01, 02, 0f, 00, 02, 20, 00, 2b, 01, 01, 01, 00, 02]
Number of files: 1
- file 0 => global file 1
- file 0 => $DIR/bad_counter_ids.rs
Number of expressions: 0
Number of file 0 mappings: 3
- Code(Counter(0)) at (prev + 31, 1) to (start + 2, 15)

View file

@ -1,7 +1,7 @@
Function name: bench::my_bench
Raw bytes (9): 0x[01, 01, 00, 01, 01, 08, 01, 00, 27]
Number of files: 1
- file 0 => global file 1
- file 0 => $DIR/bench.rs
Number of expressions: 0
Number of file 0 mappings: 1
- Code(Counter(0)) at (prev + 8, 1) to (start + 0, 39)

View file

@ -1,7 +1,7 @@
Function name: generics::print_size::<()>
Raw bytes (33): 0x[01, 01, 01, 01, 05, 05, 01, 06, 01, 01, 24, 20, 05, 02, 01, 08, 00, 24, 05, 00, 25, 02, 06, 02, 02, 0c, 02, 06, 01, 03, 01, 00, 02]
Number of files: 1
- file 0 => global file 1
- file 0 => $DIR/generics.rs
Number of expressions: 1
- expression 0 operands: lhs = Counter(0), rhs = Counter(1)
Number of file 0 mappings: 5
@ -18,7 +18,7 @@ Highest counter ID seen: c1
Function name: generics::print_size::<u32>
Raw bytes (33): 0x[01, 01, 01, 01, 05, 05, 01, 06, 01, 01, 24, 20, 05, 02, 01, 08, 00, 24, 05, 00, 25, 02, 06, 02, 02, 0c, 02, 06, 01, 03, 01, 00, 02]
Number of files: 1
- file 0 => global file 1
- file 0 => $DIR/generics.rs
Number of expressions: 1
- expression 0 operands: lhs = Counter(0), rhs = Counter(1)
Number of file 0 mappings: 5
@ -35,7 +35,7 @@ Highest counter ID seen: c1
Function name: generics::print_size::<u64>
Raw bytes (33): 0x[01, 01, 01, 01, 05, 05, 01, 06, 01, 01, 24, 20, 05, 02, 01, 08, 00, 24, 05, 00, 25, 02, 06, 02, 02, 0c, 02, 06, 01, 03, 01, 00, 02]
Number of files: 1
- file 0 => global file 1
- file 0 => $DIR/generics.rs
Number of expressions: 1
- expression 0 operands: lhs = Counter(0), rhs = Counter(1)
Number of file 0 mappings: 5

View file

@ -1,7 +1,7 @@
Function name: guard::branch_match_guard
Raw bytes (89): 0x[01, 01, 08, 05, 0d, 09, 05, 05, 0f, 0d, 11, 17, 1b, 01, 05, 1f, 11, 09, 0d, 0d, 01, 0c, 01, 01, 0e, 02, 03, 0b, 00, 0c, 06, 01, 14, 02, 0a, 0d, 03, 0e, 00, 0f, 05, 00, 14, 00, 19, 20, 0d, 02, 00, 14, 00, 1e, 0d, 00, 1d, 02, 0a, 11, 03, 0e, 00, 0f, 02, 00, 14, 00, 19, 20, 11, 0a, 00, 14, 00, 1e, 11, 00, 1d, 02, 0a, 12, 03, 0e, 02, 0a, 01, 04, 01, 00, 02]
Number of files: 1
- file 0 => global file 1
- file 0 => $DIR/guard.rs
Number of expressions: 8
- expression 0 operands: lhs = Counter(1), rhs = Counter(3)
- expression 1 operands: lhs = Counter(2), rhs = Counter(1)

View file

@ -1,7 +1,7 @@
Function name: if_let::if_let
Raw bytes (43): 0x[01, 01, 01, 01, 05, 07, 01, 0c, 01, 01, 0e, 20, 02, 05, 03, 0c, 00, 13, 02, 00, 11, 00, 12, 01, 00, 16, 00, 1b, 02, 00, 1c, 02, 06, 05, 02, 0c, 02, 06, 01, 03, 05, 01, 02]
Number of files: 1
- file 0 => global file 1
- file 0 => $DIR/if-let.rs
Number of expressions: 1
- expression 0 operands: lhs = Counter(0), rhs = Counter(1)
Number of file 0 mappings: 7
@ -21,7 +21,7 @@ Highest counter ID seen: c1
Function name: if_let::if_let_chain
Raw bytes (74): 0x[01, 01, 08, 01, 05, 01, 1f, 05, 09, 01, 1f, 05, 09, 01, 1f, 05, 09, 05, 09, 0a, 01, 17, 01, 00, 33, 20, 02, 05, 01, 0c, 00, 13, 02, 00, 11, 00, 12, 01, 00, 16, 00, 17, 20, 16, 09, 01, 10, 00, 17, 16, 00, 15, 00, 16, 02, 00, 1a, 00, 1b, 16, 01, 05, 03, 06, 1f, 03, 0c, 02, 06, 01, 03, 05, 01, 02]
Number of files: 1
- file 0 => global file 1
- file 0 => $DIR/if-let.rs
Number of expressions: 8
- expression 0 operands: lhs = Counter(0), rhs = Counter(1)
- expression 1 operands: lhs = Counter(0), rhs = Expression(7, Add)

Some files were not shown because too many files have changed in this diff Show more