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:
commit
651e9cf327
559 changed files with 2330 additions and 761 deletions
|
|
@ -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",
|
||||
]
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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};
|
||||
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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 `;`
|
||||
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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`.
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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!(
|
||||
|
|
|
|||
|
|
@ -1049,6 +1049,7 @@ symbols! {
|
|||
from_u16,
|
||||
from_usize,
|
||||
from_yeet,
|
||||
frontmatter,
|
||||
fs_create_dir,
|
||||
fsub_algebraic,
|
||||
fsub_fast,
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -27,6 +27,7 @@ pub(crate) fn target() -> Target {
|
|||
abi: "abi64".into(),
|
||||
endian: Endian::Big,
|
||||
mcount: "_mcount".into(),
|
||||
llvm_abiname: "n64".into(),
|
||||
..base
|
||||
},
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
},
|
||||
|
|
|
|||
|
|
@ -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
|
||||
},
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
},
|
||||
|
|
|
|||
|
|
@ -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
|
||||
},
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
},
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
},
|
||||
|
|
|
|||
|
|
@ -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 = []
|
||||
|
|
|
|||
|
|
@ -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::*;
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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];
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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]
|
||||
|
|
|
|||
|
|
@ -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))
|
||||
}
|
||||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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};
|
||||
|
||||
|
|
|
|||
|
|
@ -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!(
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -20,7 +20,6 @@
|
|||
#[cfg(test)]
|
||||
mod tests;
|
||||
|
||||
pub mod process;
|
||||
pub mod wstr;
|
||||
pub mod wtf8;
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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")
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
------------------------
|
||||
|
||||
|
|
|
|||
|
|
@ -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).
|
||||
|
|
|
|||
|
|
@ -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).
|
||||
|
|
|
|||
25
src/doc/unstable-book/src/language-features/frontmatter.md
Normal file
25
src/doc/unstable-book/src/language-features/frontmatter.md
Normal 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
|
||||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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");
|
||||
|
|
|
|||
|
|
@ -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");
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
||||
|
||||
|
|
|
|||
|
|
@ -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");
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
| ^^^
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
53
src/tools/coverage-dump/src/covfun/tests.rs
Normal file
53
src/tools/coverage-dump/src/covfun/tests.rs
Normal 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));
|
||||
}
|
||||
}
|
||||
75
src/tools/coverage-dump/src/covmap.rs
Normal file
75
src/tools/coverage-dump/src/covmap.rs
Normal 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 })
|
||||
}
|
||||
85
src/tools/coverage-dump/src/llvm_utils.rs
Normal file
85
src/tools/coverage-dump/src/llvm_utils.rs
Normal 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))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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]
|
||||
|
|
@ -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(())
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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],
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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
|
|
@ -133,6 +133,7 @@ Meta =
|
|||
|
||||
SourceFile =
|
||||
'#shebang'?
|
||||
'#frontmatter'?
|
||||
Attr*
|
||||
Item*
|
||||
|
||||
|
|
|
|||
|
|
@ -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]) }
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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 {}
|
||||
|
|
|
|||
|
|
@ -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",
|
||||
|
|
|
|||
|
|
@ -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"]
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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
Loading…
Add table
Add a link
Reference in a new issue