Merge from rustc
This commit is contained in:
commit
00cc1ece56
90 changed files with 2426 additions and 524 deletions
|
|
@ -4260,7 +4260,6 @@ dependencies = [
|
|||
"rustc_serialize",
|
||||
"rustc_type_ir",
|
||||
"rustc_type_ir_macros",
|
||||
"smallvec",
|
||||
"tracing",
|
||||
]
|
||||
|
||||
|
|
|
|||
|
|
@ -769,12 +769,9 @@ pub(crate) unsafe fn codegen(
|
|||
}
|
||||
}
|
||||
|
||||
// Two things to note:
|
||||
// - If object files are just LLVM bitcode we write bitcode, copy it to
|
||||
// the .o file, and delete the bitcode if it wasn't otherwise
|
||||
// requested.
|
||||
// - If we don't have the integrated assembler then we need to emit
|
||||
// asm from LLVM and use `gcc` to create the object file.
|
||||
// Note that if object files are just LLVM bitcode we write bitcode,
|
||||
// copy it to the .o file, and delete the bitcode if it wasn't
|
||||
// otherwise requested.
|
||||
|
||||
let bc_out = cgcx.output_filenames.temp_path(OutputType::Bitcode, module_name);
|
||||
let bc_summary_out =
|
||||
|
|
|
|||
|
|
@ -28,8 +28,8 @@ use std::io::{self, IsTerminal, Read, Write};
|
|||
use std::panic::{self, PanicHookInfo, catch_unwind};
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::process::{self, Command, Stdio};
|
||||
use std::sync::OnceLock;
|
||||
use std::sync::atomic::{AtomicBool, Ordering};
|
||||
use std::sync::{Arc, OnceLock};
|
||||
use std::time::{Instant, SystemTime};
|
||||
use std::{env, str};
|
||||
|
||||
|
|
@ -60,7 +60,6 @@ use rustc_session::lint::{Lint, LintId};
|
|||
use rustc_session::output::collect_crate_types;
|
||||
use rustc_session::{EarlyDiagCtxt, Session, config, filesearch};
|
||||
use rustc_span::FileName;
|
||||
use rustc_span::source_map::FileLoader;
|
||||
use rustc_target::json::ToJson;
|
||||
use rustc_target::spec::{Target, TargetTuple};
|
||||
use time::OffsetDateTime;
|
||||
|
|
@ -208,84 +207,7 @@ pub fn diagnostics_registry() -> Registry {
|
|||
}
|
||||
|
||||
/// This is the primary entry point for rustc.
|
||||
pub struct RunCompiler<'a> {
|
||||
at_args: &'a [String],
|
||||
callbacks: &'a mut (dyn Callbacks + Send),
|
||||
file_loader: Option<Box<dyn FileLoader + Send + Sync>>,
|
||||
make_codegen_backend:
|
||||
Option<Box<dyn FnOnce(&config::Options) -> Box<dyn CodegenBackend> + Send>>,
|
||||
using_internal_features: Arc<std::sync::atomic::AtomicBool>,
|
||||
}
|
||||
|
||||
impl<'a> RunCompiler<'a> {
|
||||
pub fn new(at_args: &'a [String], callbacks: &'a mut (dyn Callbacks + Send)) -> Self {
|
||||
Self {
|
||||
at_args,
|
||||
callbacks,
|
||||
file_loader: None,
|
||||
make_codegen_backend: None,
|
||||
using_internal_features: Arc::default(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Set a custom codegen backend.
|
||||
///
|
||||
/// Has no uses within this repository, but is used by bjorn3 for "the
|
||||
/// hotswapping branch of cg_clif" for "setting the codegen backend from a
|
||||
/// custom driver where the custom codegen backend has arbitrary data."
|
||||
/// (See #102759.)
|
||||
pub fn set_make_codegen_backend(
|
||||
&mut self,
|
||||
make_codegen_backend: Option<
|
||||
Box<dyn FnOnce(&config::Options) -> Box<dyn CodegenBackend> + Send>,
|
||||
>,
|
||||
) -> &mut Self {
|
||||
self.make_codegen_backend = make_codegen_backend;
|
||||
self
|
||||
}
|
||||
|
||||
/// Load files from sources other than the file system.
|
||||
///
|
||||
/// Has no uses within this repository, but may be used in the future by
|
||||
/// bjorn3 for "hooking rust-analyzer's VFS into rustc at some point for
|
||||
/// running rustc without having to save". (See #102759.)
|
||||
pub fn set_file_loader(
|
||||
&mut self,
|
||||
file_loader: Option<Box<dyn FileLoader + Send + Sync>>,
|
||||
) -> &mut Self {
|
||||
self.file_loader = file_loader;
|
||||
self
|
||||
}
|
||||
|
||||
/// Set the session-global flag that checks whether internal features have been used,
|
||||
/// suppressing the message about submitting an issue in ICEs when enabled.
|
||||
#[must_use]
|
||||
pub fn set_using_internal_features(mut self, using_internal_features: Arc<AtomicBool>) -> Self {
|
||||
self.using_internal_features = using_internal_features;
|
||||
self
|
||||
}
|
||||
|
||||
/// Parse args and run the compiler.
|
||||
pub fn run(self) {
|
||||
run_compiler(
|
||||
self.at_args,
|
||||
self.callbacks,
|
||||
self.file_loader,
|
||||
self.make_codegen_backend,
|
||||
self.using_internal_features,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
fn run_compiler(
|
||||
at_args: &[String],
|
||||
callbacks: &mut (dyn Callbacks + Send),
|
||||
file_loader: Option<Box<dyn FileLoader + Send + Sync>>,
|
||||
make_codegen_backend: Option<
|
||||
Box<dyn FnOnce(&config::Options) -> Box<dyn CodegenBackend> + Send>,
|
||||
>,
|
||||
using_internal_features: Arc<std::sync::atomic::AtomicBool>,
|
||||
) {
|
||||
pub fn run_compiler(at_args: &[String], callbacks: &mut (dyn Callbacks + Send)) {
|
||||
let mut default_early_dcx = EarlyDiagCtxt::new(ErrorOutputType::default());
|
||||
|
||||
// Throw away the first argument, the name of the binary.
|
||||
|
|
@ -322,16 +244,16 @@ fn run_compiler(
|
|||
output_file: ofile,
|
||||
output_dir: odir,
|
||||
ice_file,
|
||||
file_loader,
|
||||
file_loader: None,
|
||||
locale_resources: DEFAULT_LOCALE_RESOURCES.to_vec(),
|
||||
lint_caps: Default::default(),
|
||||
psess_created: None,
|
||||
hash_untracked_state: None,
|
||||
register_lints: None,
|
||||
override_queries: None,
|
||||
make_codegen_backend,
|
||||
make_codegen_backend: None,
|
||||
registry: diagnostics_registry(),
|
||||
using_internal_features,
|
||||
using_internal_features: &USING_INTERNAL_FEATURES,
|
||||
expanded_args: args,
|
||||
};
|
||||
|
||||
|
|
@ -1350,6 +1272,8 @@ fn ice_path_with_config(config: Option<&UnstableOptions>) -> &'static Option<Pat
|
|||
})
|
||||
}
|
||||
|
||||
pub static USING_INTERNAL_FEATURES: AtomicBool = AtomicBool::new(false);
|
||||
|
||||
/// Installs a panic hook that will print the ICE message on unexpected panics.
|
||||
///
|
||||
/// The hook is intended to be useable even by external tools. You can pass a custom
|
||||
|
|
@ -1360,15 +1284,8 @@ fn ice_path_with_config(config: Option<&UnstableOptions>) -> &'static Option<Pat
|
|||
/// If you have no extra info to report, pass the empty closure `|_| ()` as the argument to
|
||||
/// extra_info.
|
||||
///
|
||||
/// Returns a flag that can be set to disable the note for submitting a bug. This can be passed to
|
||||
/// [`RunCompiler::set_using_internal_features`] to let macro expansion set it when encountering
|
||||
/// internal features.
|
||||
///
|
||||
/// A custom rustc driver can skip calling this to set up a custom ICE hook.
|
||||
pub fn install_ice_hook(
|
||||
bug_report_url: &'static str,
|
||||
extra_info: fn(&DiagCtxt),
|
||||
) -> Arc<AtomicBool> {
|
||||
pub fn install_ice_hook(bug_report_url: &'static str, extra_info: fn(&DiagCtxt)) {
|
||||
// If the user has not explicitly overridden "RUST_BACKTRACE", then produce
|
||||
// full backtraces. When a compiler ICE happens, we want to gather
|
||||
// as much information as possible to present in the issue opened
|
||||
|
|
@ -1385,8 +1302,6 @@ pub fn install_ice_hook(
|
|||
}
|
||||
}
|
||||
|
||||
let using_internal_features = Arc::new(std::sync::atomic::AtomicBool::default());
|
||||
let using_internal_features_hook = Arc::clone(&using_internal_features);
|
||||
panic::update_hook(Box::new(
|
||||
move |default_hook: &(dyn Fn(&PanicHookInfo<'_>) + Send + Sync + 'static),
|
||||
info: &PanicHookInfo<'_>| {
|
||||
|
|
@ -1438,11 +1353,9 @@ pub fn install_ice_hook(
|
|||
}
|
||||
|
||||
// Print the ICE message
|
||||
report_ice(info, bug_report_url, extra_info, &using_internal_features_hook);
|
||||
report_ice(info, bug_report_url, extra_info, &USING_INTERNAL_FEATURES);
|
||||
},
|
||||
));
|
||||
|
||||
using_internal_features
|
||||
}
|
||||
|
||||
/// Prints the ICE message, including query stack, but without backtrace.
|
||||
|
|
@ -1583,13 +1496,11 @@ pub fn main() -> ! {
|
|||
init_rustc_env_logger(&early_dcx);
|
||||
signal_handler::install();
|
||||
let mut callbacks = TimePassesCallbacks::default();
|
||||
let using_internal_features = install_ice_hook(DEFAULT_BUG_REPORT_URL, |_| ());
|
||||
install_ice_hook(DEFAULT_BUG_REPORT_URL, |_| ());
|
||||
install_ctrlc_handler();
|
||||
|
||||
let exit_code = catch_with_exit_code(|| {
|
||||
RunCompiler::new(&args::raw_args(&early_dcx)?, &mut callbacks)
|
||||
.set_using_internal_features(using_internal_features)
|
||||
.run();
|
||||
run_compiler(&args::raw_args(&early_dcx)?, &mut callbacks);
|
||||
Ok(())
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -461,9 +461,17 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
|
|||
// to the target type), since that should be the least
|
||||
// confusing.
|
||||
let Some(InferOk { value: ty, mut obligations }) = found else {
|
||||
let err = first_error.expect("coerce_borrowed_pointer had no error");
|
||||
debug!("coerce_borrowed_pointer: failed with err = {:?}", err);
|
||||
return Err(err);
|
||||
if let Some(first_error) = first_error {
|
||||
debug!("coerce_borrowed_pointer: failed with err = {:?}", first_error);
|
||||
return Err(first_error);
|
||||
} else {
|
||||
// This may happen in the new trait solver since autoderef requires
|
||||
// the pointee to be structurally normalizable, or else it'll just bail.
|
||||
// So when we have a type like `&<not well formed>`, then we get no
|
||||
// autoderef steps (even though there should be at least one). That means
|
||||
// we get no type mismatches, since the loop above just exits early.
|
||||
return Err(TypeError::Mismatch);
|
||||
}
|
||||
};
|
||||
|
||||
if ty == a && mt_a.mutbl.is_not() && autoderef.step_count() == 1 {
|
||||
|
|
|
|||
|
|
@ -1,6 +1,5 @@
|
|||
use std::path::PathBuf;
|
||||
use std::result;
|
||||
use std::sync::Arc;
|
||||
|
||||
use rustc_ast::{LitKind, MetaItemKind, token};
|
||||
use rustc_codegen_ssa::traits::CodegenBackend;
|
||||
|
|
@ -309,6 +308,11 @@ pub struct Config {
|
|||
pub output_dir: Option<PathBuf>,
|
||||
pub output_file: Option<OutFileName>,
|
||||
pub ice_file: Option<PathBuf>,
|
||||
/// Load files from sources other than the file system.
|
||||
///
|
||||
/// Has no uses within this repository, but may be used in the future by
|
||||
/// bjorn3 for "hooking rust-analyzer's VFS into rustc at some point for
|
||||
/// running rustc without having to save". (See #102759.)
|
||||
pub file_loader: Option<Box<dyn FileLoader + Send + Sync>>,
|
||||
/// The list of fluent resources, used for lints declared with
|
||||
/// [`Diagnostic`](rustc_errors::Diagnostic) and [`LintDiagnostic`](rustc_errors::LintDiagnostic).
|
||||
|
|
@ -337,6 +341,11 @@ pub struct Config {
|
|||
pub override_queries: Option<fn(&Session, &mut Providers)>,
|
||||
|
||||
/// This is a callback from the driver that is called to create a codegen backend.
|
||||
///
|
||||
/// Has no uses within this repository, but is used by bjorn3 for "the
|
||||
/// hotswapping branch of cg_clif" for "setting the codegen backend from a
|
||||
/// custom driver where the custom codegen backend has arbitrary data."
|
||||
/// (See #102759.)
|
||||
pub make_codegen_backend:
|
||||
Option<Box<dyn FnOnce(&config::Options) -> Box<dyn CodegenBackend> + Send>>,
|
||||
|
||||
|
|
@ -346,8 +355,7 @@ pub struct Config {
|
|||
/// The inner atomic value is set to true when a feature marked as `internal` is
|
||||
/// enabled. Makes it so that "please report a bug" is hidden, as ICEs with
|
||||
/// internal features are wontfix, and they are usually the cause of the ICEs.
|
||||
/// None signifies that this is not tracked.
|
||||
pub using_internal_features: Arc<std::sync::atomic::AtomicBool>,
|
||||
pub using_internal_features: &'static std::sync::atomic::AtomicBool,
|
||||
|
||||
/// All commandline args used to invoke the compiler, with @file args fully expanded.
|
||||
/// This will only be used within debug info, e.g. in the pdb file on windows
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
use std::collections::{BTreeMap, BTreeSet};
|
||||
use std::num::NonZero;
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::sync::Arc;
|
||||
use std::sync::atomic::AtomicBool;
|
||||
|
||||
use rustc_data_structures::profiling::TimePassesFormat;
|
||||
use rustc_errors::emitter::HumanReadableErrorType;
|
||||
|
|
@ -62,6 +62,8 @@ where
|
|||
temps_dir,
|
||||
};
|
||||
|
||||
static USING_INTERNAL_FEATURES: AtomicBool = AtomicBool::new(false);
|
||||
|
||||
let sess = build_session(
|
||||
early_dcx,
|
||||
sessopts,
|
||||
|
|
@ -74,7 +76,7 @@ where
|
|||
sysroot,
|
||||
"",
|
||||
None,
|
||||
Arc::default(),
|
||||
&USING_INTERNAL_FEATURES,
|
||||
Default::default(),
|
||||
);
|
||||
let cfg = parse_cfg(sess.dcx(), matches.opt_strs("cfg"));
|
||||
|
|
|
|||
|
|
@ -972,6 +972,8 @@ lint_unused_result = unused result of type `{$ty}`
|
|||
|
||||
lint_use_let_underscore_ignore_suggestion = use `let _ = ...` to ignore the expression or result
|
||||
|
||||
lint_uses_power_alignment = repr(C) does not follow the power alignment rule. This may affect platform C ABI compatibility for this type
|
||||
|
||||
lint_variant_size_differences =
|
||||
enum variant is more than three times larger ({$largest} bytes) than the next largest
|
||||
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ use rustc_errors::{
|
|||
use rustc_hir::{self as hir, HirIdSet};
|
||||
use rustc_macros::LintDiagnostic;
|
||||
use rustc_middle::ty::TyCtxt;
|
||||
use rustc_session::lint::{FutureIncompatibilityReason, Level};
|
||||
use rustc_session::lint::{FutureIncompatibilityReason, LintId};
|
||||
use rustc_session::{declare_lint, impl_lint_pass};
|
||||
use rustc_span::Span;
|
||||
use rustc_span::edition::Edition;
|
||||
|
|
@ -245,12 +245,12 @@ impl_lint_pass!(
|
|||
|
||||
impl<'tcx> LateLintPass<'tcx> for IfLetRescope {
|
||||
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'tcx>) {
|
||||
if expr.span.edition().at_least_rust_2024() {
|
||||
return;
|
||||
}
|
||||
if let (Level::Allow, _) = cx.tcx.lint_level_at_node(IF_LET_RESCOPE, expr.hir_id) {
|
||||
if expr.span.edition().at_least_rust_2024()
|
||||
|| cx.tcx.lints_that_dont_need_to_run(()).contains(&LintId::of(IF_LET_RESCOPE))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if let hir::ExprKind::Loop(block, _label, hir::LoopSource::While, _span) = expr.kind
|
||||
&& let Some(value) = block.expr
|
||||
&& let hir::ExprKind::If(cond, _conseq, _alt) = value.kind
|
||||
|
|
@ -290,7 +290,6 @@ struct IfLetRescopeLint {
|
|||
rewrite: Option<IfLetRescopeRewrite>,
|
||||
}
|
||||
|
||||
// #[derive(Subdiagnostic)]
|
||||
struct IfLetRescopeRewrite {
|
||||
match_heads: Vec<SingleArmMatchBegin>,
|
||||
consequent_heads: Vec<ConsequentRewrite>,
|
||||
|
|
|
|||
|
|
@ -1694,6 +1694,10 @@ pub(crate) struct OverflowingLiteral<'a> {
|
|||
pub lit: String,
|
||||
}
|
||||
|
||||
#[derive(LintDiagnostic)]
|
||||
#[diag(lint_uses_power_alignment)]
|
||||
pub(crate) struct UsesPowerAlignment;
|
||||
|
||||
#[derive(LintDiagnostic)]
|
||||
#[diag(lint_unused_comparisons)]
|
||||
pub(crate) struct UnusedComparisons;
|
||||
|
|
|
|||
|
|
@ -1,14 +1,15 @@
|
|||
use std::iter;
|
||||
use std::ops::ControlFlow;
|
||||
|
||||
use rustc_abi::{BackendRepr, ExternAbi, TagEncoding, Variants, WrappingRange};
|
||||
use rustc_abi::{BackendRepr, ExternAbi, TagEncoding, VariantIdx, Variants, WrappingRange};
|
||||
use rustc_data_structures::fx::FxHashSet;
|
||||
use rustc_errors::DiagMessage;
|
||||
use rustc_hir::{Expr, ExprKind, LangItem};
|
||||
use rustc_middle::bug;
|
||||
use rustc_middle::ty::layout::{LayoutOf, SizeSkeleton};
|
||||
use rustc_middle::ty::{
|
||||
self, AdtKind, GenericArgsRef, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, TypeVisitableExt,
|
||||
self, Adt, AdtKind, GenericArgsRef, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable,
|
||||
TypeVisitableExt,
|
||||
};
|
||||
use rustc_session::{declare_lint, declare_lint_pass, impl_lint_pass};
|
||||
use rustc_span::def_id::LocalDefId;
|
||||
|
|
@ -23,7 +24,7 @@ use crate::lints::{
|
|||
AmbiguousWidePointerComparisonsAddrSuggestion, AtomicOrderingFence, AtomicOrderingLoad,
|
||||
AtomicOrderingStore, ImproperCTypes, InvalidAtomicOrderingDiag, InvalidNanComparisons,
|
||||
InvalidNanComparisonsSuggestion, UnpredictableFunctionPointerComparisons,
|
||||
UnpredictableFunctionPointerComparisonsSuggestion, UnusedComparisons,
|
||||
UnpredictableFunctionPointerComparisonsSuggestion, UnusedComparisons, UsesPowerAlignment,
|
||||
VariantSizeDifferencesDiag,
|
||||
};
|
||||
use crate::{LateContext, LateLintPass, LintContext, fluent_generated as fluent};
|
||||
|
|
@ -727,7 +728,60 @@ declare_lint! {
|
|||
"proper use of libc types in foreign item definitions"
|
||||
}
|
||||
|
||||
declare_lint_pass!(ImproperCTypesDefinitions => [IMPROPER_CTYPES_DEFINITIONS]);
|
||||
declare_lint! {
|
||||
/// The `uses_power_alignment` lint detects specific `repr(C)`
|
||||
/// aggregates on AIX.
|
||||
/// In its platform C ABI, AIX uses the "power" (as in PowerPC) alignment
|
||||
/// rule (detailed in https://www.ibm.com/docs/en/xl-c-and-cpp-aix/16.1?topic=data-using-alignment-modes#alignment),
|
||||
/// which can also be set for XLC by `#pragma align(power)` or
|
||||
/// `-qalign=power`. Aggregates with a floating-point type as the
|
||||
/// recursively first field (as in "at offset 0") modify the layout of
|
||||
/// *subsequent* fields of the associated structs to use an alignment value
|
||||
/// where the floating-point type is aligned on a 4-byte boundary.
|
||||
///
|
||||
/// The power alignment rule for structs needed for C compatibility is
|
||||
/// unimplementable within `repr(C)` in the compiler without building in
|
||||
/// handling of references to packed fields and infectious nested layouts,
|
||||
/// so a warning is produced in these situations.
|
||||
///
|
||||
/// ### Example
|
||||
///
|
||||
/// ```rust,ignore (fails on non-powerpc64-ibm-aix)
|
||||
/// #[repr(C)]
|
||||
/// pub struct Floats {
|
||||
/// a: f64,
|
||||
/// b: u8,
|
||||
/// c: f64,
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// This will produce:
|
||||
///
|
||||
/// ```text
|
||||
/// warning: repr(C) does not follow the power alignment rule. This may affect platform C ABI compatibility for this type
|
||||
/// --> <source>:5:3
|
||||
/// |
|
||||
/// 5 | c: f64,
|
||||
/// | ^^^^^^
|
||||
/// |
|
||||
/// = note: `#[warn(uses_power_alignment)]` on by default
|
||||
/// ```
|
||||
///
|
||||
/// ### Explanation
|
||||
///
|
||||
/// The power alignment rule specifies that the above struct has the
|
||||
/// following alignment:
|
||||
/// - offset_of!(Floats, a) == 0
|
||||
/// - offset_of!(Floats, b) == 8
|
||||
/// - offset_of!(Floats, c) == 12
|
||||
/// However, rust currently aligns `c` at offset_of!(Floats, c) == 16.
|
||||
/// Thus, a warning should be produced for the above struct in this case.
|
||||
USES_POWER_ALIGNMENT,
|
||||
Warn,
|
||||
"Structs do not follow the power alignment rule under repr(C)"
|
||||
}
|
||||
|
||||
declare_lint_pass!(ImproperCTypesDefinitions => [IMPROPER_CTYPES_DEFINITIONS, USES_POWER_ALIGNMENT]);
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
pub(crate) enum CItemKind {
|
||||
|
|
@ -1539,6 +1593,71 @@ impl ImproperCTypesDefinitions {
|
|||
vis.check_type_for_ffi_and_report_errors(span, fn_ptr_ty, true, false);
|
||||
}
|
||||
}
|
||||
|
||||
fn check_arg_for_power_alignment<'tcx>(
|
||||
&mut self,
|
||||
cx: &LateContext<'tcx>,
|
||||
ty: Ty<'tcx>,
|
||||
) -> bool {
|
||||
// Structs (under repr(C)) follow the power alignment rule if:
|
||||
// - the first field of the struct is a floating-point type that
|
||||
// is greater than 4-bytes, or
|
||||
// - the first field of the struct is an aggregate whose
|
||||
// recursively first field is a floating-point type greater than
|
||||
// 4 bytes.
|
||||
if cx.tcx.sess.target.os != "aix" {
|
||||
return false;
|
||||
}
|
||||
if ty.is_floating_point() && ty.primitive_size(cx.tcx).bytes() > 4 {
|
||||
return true;
|
||||
} else if let Adt(adt_def, _) = ty.kind()
|
||||
&& adt_def.is_struct()
|
||||
{
|
||||
let struct_variant = adt_def.variant(VariantIdx::ZERO);
|
||||
// Within a nested struct, all fields are examined to correctly
|
||||
// report if any fields after the nested struct within the
|
||||
// original struct are misaligned.
|
||||
for struct_field in &struct_variant.fields {
|
||||
let field_ty = cx.tcx.type_of(struct_field.did).instantiate_identity();
|
||||
if self.check_arg_for_power_alignment(cx, field_ty) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
fn check_struct_for_power_alignment<'tcx>(
|
||||
&mut self,
|
||||
cx: &LateContext<'tcx>,
|
||||
item: &'tcx hir::Item<'tcx>,
|
||||
) {
|
||||
let adt_def = cx.tcx.adt_def(item.owner_id.to_def_id());
|
||||
if adt_def.repr().c()
|
||||
&& !adt_def.repr().packed()
|
||||
&& cx.tcx.sess.target.os == "aix"
|
||||
&& !adt_def.all_fields().next().is_none()
|
||||
{
|
||||
let struct_variant_data = item.expect_struct().0;
|
||||
for (index, ..) in struct_variant_data.fields().iter().enumerate() {
|
||||
// Struct fields (after the first field) are checked for the
|
||||
// power alignment rule, as fields after the first are likely
|
||||
// to be the fields that are misaligned.
|
||||
if index != 0 {
|
||||
let first_field_def = struct_variant_data.fields()[index];
|
||||
let def_id = first_field_def.def_id;
|
||||
let ty = cx.tcx.type_of(def_id).instantiate_identity();
|
||||
if self.check_arg_for_power_alignment(cx, ty) {
|
||||
cx.emit_span_lint(
|
||||
USES_POWER_ALIGNMENT,
|
||||
first_field_def.span,
|
||||
UsesPowerAlignment,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// `ImproperCTypesDefinitions` checks items outside of foreign items (e.g. stuff that isn't in
|
||||
|
|
@ -1562,8 +1681,13 @@ impl<'tcx> LateLintPass<'tcx> for ImproperCTypesDefinitions {
|
|||
}
|
||||
// See `check_fn`..
|
||||
hir::ItemKind::Fn { .. } => {}
|
||||
// Structs are checked based on if they follow the power alignment
|
||||
// rule (under repr(C)).
|
||||
hir::ItemKind::Struct(..) => {
|
||||
self.check_struct_for_power_alignment(cx, item);
|
||||
}
|
||||
// See `check_field_def`..
|
||||
hir::ItemKind::Union(..) | hir::ItemKind::Struct(..) | hir::ItemKind::Enum(..) => {}
|
||||
hir::ItemKind::Union(..) | hir::ItemKind::Enum(..) => {}
|
||||
// Doesn't define something that can contain a external type to be checked.
|
||||
hir::ItemKind::Impl(..)
|
||||
| hir::ItemKind::TraitAlias(..)
|
||||
|
|
|
|||
47
compiler/rustc_middle/src/query/arena_cached.rs
Normal file
47
compiler/rustc_middle/src/query/arena_cached.rs
Normal file
|
|
@ -0,0 +1,47 @@
|
|||
/// Helper trait that allows `arena_cache` queries to return `Option<&T>`
|
||||
/// instead of `&Option<T>`, and avoid allocating `None` in the arena.
|
||||
///
|
||||
/// An arena-cached query must be declared to return a type that implements
|
||||
/// this trait, i.e. either `&'tcx T` or `Option<&'tcx T>`. This trait then
|
||||
/// determines the types returned by the provider and stored in the arena,
|
||||
/// and provides a function to bridge between the three types.
|
||||
pub trait ArenaCached<'tcx>: Sized {
|
||||
/// Type that is returned by the query provider.
|
||||
type Provided;
|
||||
/// Type that is stored in the arena.
|
||||
type Allocated: 'tcx;
|
||||
|
||||
/// Takes a provided value, and allocates it in the arena (if appropriate)
|
||||
/// with the help of the given `arena_alloc` closure.
|
||||
fn alloc_in_arena(
|
||||
arena_alloc: impl Fn(Self::Allocated) -> &'tcx Self::Allocated,
|
||||
value: Self::Provided,
|
||||
) -> Self;
|
||||
}
|
||||
|
||||
impl<'tcx, T> ArenaCached<'tcx> for &'tcx T {
|
||||
type Provided = T;
|
||||
type Allocated = T;
|
||||
|
||||
fn alloc_in_arena(
|
||||
arena_alloc: impl Fn(Self::Allocated) -> &'tcx Self::Allocated,
|
||||
value: Self::Provided,
|
||||
) -> Self {
|
||||
// Just allocate in the arena normally.
|
||||
arena_alloc(value)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx, T> ArenaCached<'tcx> for Option<&'tcx T> {
|
||||
type Provided = Option<T>;
|
||||
/// The provide value is `Option<T>`, but we only store `T` in the arena.
|
||||
type Allocated = T;
|
||||
|
||||
fn alloc_in_arena(
|
||||
arena_alloc: impl Fn(Self::Allocated) -> &'tcx Self::Allocated,
|
||||
value: Self::Provided,
|
||||
) -> Self {
|
||||
// Don't store None in the arena, and wrap the allocated reference in Some.
|
||||
value.map(arena_alloc)
|
||||
}
|
||||
}
|
||||
|
|
@ -7,7 +7,6 @@
|
|||
#![allow(unused_parens)]
|
||||
|
||||
use std::mem;
|
||||
use std::ops::Deref;
|
||||
use std::path::PathBuf;
|
||||
use std::sync::Arc;
|
||||
|
||||
|
|
@ -85,6 +84,7 @@ use crate::ty::{
|
|||
};
|
||||
use crate::{dep_graph, mir, thir};
|
||||
|
||||
mod arena_cached;
|
||||
pub mod erase;
|
||||
mod keys;
|
||||
pub use keys::{AsLocalKey, Key, LocalCrate};
|
||||
|
|
@ -586,7 +586,7 @@ rustc_queries! {
|
|||
separate_provide_extern
|
||||
}
|
||||
|
||||
query mir_coroutine_witnesses(key: DefId) -> &'tcx Option<mir::CoroutineLayout<'tcx>> {
|
||||
query mir_coroutine_witnesses(key: DefId) -> Option<&'tcx mir::CoroutineLayout<'tcx>> {
|
||||
arena_cache
|
||||
desc { |tcx| "coroutine witness types for `{}`", tcx.def_path_str(key) }
|
||||
cache_on_disk_if { key.is_local() }
|
||||
|
|
@ -2415,7 +2415,7 @@ rustc_queries! {
|
|||
/// because the `ty::Ty`-based wfcheck is always run.
|
||||
query diagnostic_hir_wf_check(
|
||||
key: (ty::Predicate<'tcx>, WellFormedLoc)
|
||||
) -> &'tcx Option<ObligationCause<'tcx>> {
|
||||
) -> Option<&'tcx ObligationCause<'tcx>> {
|
||||
arena_cache
|
||||
eval_always
|
||||
no_hash
|
||||
|
|
|
|||
|
|
@ -289,10 +289,10 @@ macro_rules! define_callbacks {
|
|||
|
||||
/// This type alias specifies the type returned from query providers and the type
|
||||
/// used for decoding. For regular queries this is the declared returned type `V`,
|
||||
/// but `arena_cache` will use `<V as Deref>::Target` instead.
|
||||
/// but `arena_cache` will use `<V as ArenaCached>::Provided` instead.
|
||||
pub type ProvidedValue<'tcx> = query_if_arena!(
|
||||
[$($modifiers)*]
|
||||
(<$V as Deref>::Target)
|
||||
(<$V as $crate::query::arena_cached::ArenaCached<'tcx>>::Provided)
|
||||
($V)
|
||||
);
|
||||
|
||||
|
|
@ -307,10 +307,18 @@ macro_rules! define_callbacks {
|
|||
) -> Erase<Value<'tcx>> {
|
||||
erase(query_if_arena!([$($modifiers)*]
|
||||
{
|
||||
if mem::needs_drop::<ProvidedValue<'tcx>>() {
|
||||
&*_tcx.query_system.arenas.$name.alloc(value)
|
||||
use $crate::query::arena_cached::ArenaCached;
|
||||
|
||||
if mem::needs_drop::<<$V as ArenaCached<'tcx>>::Allocated>() {
|
||||
<$V as ArenaCached>::alloc_in_arena(
|
||||
|v| _tcx.query_system.arenas.$name.alloc(v),
|
||||
value,
|
||||
)
|
||||
} else {
|
||||
&*_tcx.arena.dropless.alloc(value)
|
||||
<$V as ArenaCached>::alloc_in_arena(
|
||||
|v| _tcx.arena.dropless.alloc(v),
|
||||
value,
|
||||
)
|
||||
}
|
||||
}
|
||||
(value)
|
||||
|
|
@ -354,7 +362,7 @@ macro_rules! define_callbacks {
|
|||
|
||||
pub struct QueryArenas<'tcx> {
|
||||
$($(#[$attr])* pub $name: query_if_arena!([$($modifiers)*]
|
||||
(TypedArena<<$V as Deref>::Target>)
|
||||
(TypedArena<<$V as $crate::query::arena_cached::ArenaCached<'tcx>>::Allocated>)
|
||||
()
|
||||
),)*
|
||||
}
|
||||
|
|
|
|||
|
|
@ -13,7 +13,6 @@ rustc_macros = { path = "../rustc_macros", optional = true }
|
|||
rustc_serialize = { path = "../rustc_serialize", optional = true }
|
||||
rustc_type_ir = { path = "../rustc_type_ir", default-features = false }
|
||||
rustc_type_ir_macros = { path = "../rustc_type_ir_macros" }
|
||||
smallvec = "1.8.1"
|
||||
tracing = "0.1"
|
||||
# tidy-alphabetical-end
|
||||
|
||||
|
|
|
|||
|
|
@ -8,7 +8,6 @@ use rustc_type_ir::lang_items::TraitSolverLangItem;
|
|||
use rustc_type_ir::solve::CanonicalResponse;
|
||||
use rustc_type_ir::visit::TypeVisitableExt as _;
|
||||
use rustc_type_ir::{self as ty, Interner, TraitPredicate, TypingMode, Upcast as _, elaborate};
|
||||
use smallvec::SmallVec;
|
||||
use tracing::{instrument, trace};
|
||||
|
||||
use crate::delegate::SolverDelegate;
|
||||
|
|
@ -1199,33 +1198,42 @@ where
|
|||
// nested requirements, over all others. This is a fix for #53123 and
|
||||
// prevents where-bounds from accidentally extending the lifetime of a
|
||||
// variable.
|
||||
if candidates
|
||||
.iter()
|
||||
.any(|c| matches!(c.source, CandidateSource::BuiltinImpl(BuiltinImplSource::Trivial)))
|
||||
{
|
||||
let trivial_builtin_impls: SmallVec<[_; 1]> = candidates
|
||||
.iter()
|
||||
.filter(|c| {
|
||||
matches!(c.source, CandidateSource::BuiltinImpl(BuiltinImplSource::Trivial))
|
||||
})
|
||||
.map(|c| c.result)
|
||||
.collect();
|
||||
let mut trivial_builtin_impls = candidates.iter().filter(|c| {
|
||||
matches!(c.source, CandidateSource::BuiltinImpl(BuiltinImplSource::Trivial))
|
||||
});
|
||||
if let Some(candidate) = trivial_builtin_impls.next() {
|
||||
// There should only ever be a single trivial builtin candidate
|
||||
// as they would otherwise overlap.
|
||||
assert_eq!(trivial_builtin_impls.len(), 1);
|
||||
return if let Some(response) = self.try_merge_responses(&trivial_builtin_impls) {
|
||||
Ok((response, Some(TraitGoalProvenVia::Misc)))
|
||||
} else {
|
||||
Ok((self.bail_with_ambiguity(&trivial_builtin_impls), None))
|
||||
};
|
||||
assert!(trivial_builtin_impls.next().is_none());
|
||||
return Ok((candidate.result, Some(TraitGoalProvenVia::Misc)));
|
||||
}
|
||||
|
||||
// If there are non-global where-bounds, prefer where-bounds
|
||||
// (including global ones) over everything else.
|
||||
let has_non_global_where_bounds = candidates.iter().any(|c| match c.source {
|
||||
CandidateSource::ParamEnv(idx) => {
|
||||
let where_bound = goal.param_env.caller_bounds().get(idx);
|
||||
where_bound.has_bound_vars() || !where_bound.is_global()
|
||||
let where_bound = goal.param_env.caller_bounds().get(idx).unwrap();
|
||||
let ty::ClauseKind::Trait(trait_pred) = where_bound.kind().skip_binder() else {
|
||||
unreachable!("expected trait-bound: {where_bound:?}");
|
||||
};
|
||||
|
||||
if trait_pred.has_bound_vars() || !trait_pred.is_global() {
|
||||
return true;
|
||||
}
|
||||
|
||||
// We don't consider a trait-bound global if it has a projection bound.
|
||||
//
|
||||
// See ui/traits/next-solver/normalization-shadowing/global-trait-with-project.rs
|
||||
// for an example where this is necessary.
|
||||
for p in goal.param_env.caller_bounds().iter() {
|
||||
if let ty::ClauseKind::Projection(proj) = p.kind().skip_binder() {
|
||||
if proj.projection_term.trait_ref(self.cx()) == trait_pred.trait_ref {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
false
|
||||
}
|
||||
_ => false,
|
||||
});
|
||||
|
|
|
|||
|
|
@ -514,13 +514,7 @@ impl<'a> Parser<'a> {
|
|||
|
||||
/// Consumes all whitespace characters until the first non-whitespace character
|
||||
fn ws(&mut self) {
|
||||
while let Some(&(_, c)) = self.cur.peek() {
|
||||
if c.is_whitespace() {
|
||||
self.cur.next();
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
while let Some(_) = self.cur.next_if(|&(_, c)| c.is_whitespace()) {}
|
||||
}
|
||||
|
||||
/// Parses all of a string which is to be considered a "raw literal" in a
|
||||
|
|
@ -545,7 +539,7 @@ impl<'a> Parser<'a> {
|
|||
}
|
||||
}
|
||||
}
|
||||
&self.input[start..self.input.len()]
|
||||
&self.input[start..]
|
||||
}
|
||||
|
||||
/// Parses an `Argument` structure, or what's contained within braces inside the format string.
|
||||
|
|
|
|||
|
|
@ -189,7 +189,7 @@ pub struct Session {
|
|||
/// enabled. Makes it so that "please report a bug" is hidden, as ICEs with
|
||||
/// internal features are wontfix, and they are usually the cause of the ICEs.
|
||||
/// None signifies that this is not tracked.
|
||||
pub using_internal_features: Arc<AtomicBool>,
|
||||
pub using_internal_features: &'static AtomicBool,
|
||||
|
||||
/// All commandline args used to invoke the compiler, with @file args fully expanded.
|
||||
/// This will only be used within debug info, e.g. in the pdb file on windows
|
||||
|
|
@ -966,7 +966,7 @@ pub fn build_session(
|
|||
sysroot: PathBuf,
|
||||
cfg_version: &'static str,
|
||||
ice_file: Option<PathBuf>,
|
||||
using_internal_features: Arc<AtomicBool>,
|
||||
using_internal_features: &'static AtomicBool,
|
||||
expanded_args: Vec<String>,
|
||||
) -> Session {
|
||||
// FIXME: This is not general enough to make the warning lint completely override
|
||||
|
|
|
|||
|
|
@ -316,7 +316,7 @@ macro_rules! optional {
|
|||
#[doc(hidden)]
|
||||
macro_rules! run_driver {
|
||||
($args:expr, $callback:expr $(, $with_tcx:ident)?) => {{
|
||||
use rustc_driver::{Callbacks, Compilation, RunCompiler};
|
||||
use rustc_driver::{Callbacks, Compilation, run_compiler};
|
||||
use rustc_middle::ty::TyCtxt;
|
||||
use rustc_interface::interface;
|
||||
use stable_mir::CompilerError;
|
||||
|
|
@ -347,7 +347,7 @@ macro_rules! run_driver {
|
|||
/// Runs the compiler against given target and tests it with `test_function`
|
||||
pub fn run(&mut self) -> Result<C, CompilerError<B>> {
|
||||
let compiler_result = rustc_driver::catch_fatal_errors(|| -> interface::Result::<()> {
|
||||
RunCompiler::new(&self.args.clone(), self).run();
|
||||
run_compiler(&self.args.clone(), self);
|
||||
Ok(())
|
||||
});
|
||||
match (compiler_result, self.result.take()) {
|
||||
|
|
|
|||
|
|
@ -97,9 +97,9 @@ pub(crate) fn opts() -> TargetOptions {
|
|||
emit_debug_gdb_scripts: false,
|
||||
requires_uwtable: true,
|
||||
eh_frame_header: false,
|
||||
debuginfo_kind: DebuginfoKind::Dwarf,
|
||||
// FIXME(davidtwco): Support Split DWARF on Windows GNU - may require LLVM changes to
|
||||
// output DWO, despite using DWARF, doesn't use ELF..
|
||||
debuginfo_kind: DebuginfoKind::Pdb,
|
||||
supported_split_debuginfo: Cow::Borrowed(&[SplitDebuginfo::Off]),
|
||||
..Default::default()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -44,9 +44,9 @@ pub(crate) fn opts() -> TargetOptions {
|
|||
has_thread_local: true,
|
||||
crt_static_allows_dylibs: true,
|
||||
crt_static_respected: true,
|
||||
debuginfo_kind: DebuginfoKind::Dwarf,
|
||||
// FIXME(davidtwco): Support Split DWARF on Windows GNU - may require LLVM changes to
|
||||
// output DWO, despite using DWARF, doesn't use ELF..
|
||||
debuginfo_kind: DebuginfoKind::Pdb,
|
||||
supported_split_debuginfo: Cow::Borrowed(&[SplitDebuginfo::Off]),
|
||||
..Default::default()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -167,6 +167,18 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
|
|||
exp_span, exp_found.expected, exp_found.found,
|
||||
);
|
||||
|
||||
match self.tcx.coroutine_kind(cause.body_id) {
|
||||
Some(hir::CoroutineKind::Desugared(
|
||||
hir::CoroutineDesugaring::Async | hir::CoroutineDesugaring::AsyncGen,
|
||||
_,
|
||||
)) => (),
|
||||
None
|
||||
| Some(
|
||||
hir::CoroutineKind::Coroutine(_)
|
||||
| hir::CoroutineKind::Desugared(hir::CoroutineDesugaring::Gen, _),
|
||||
) => return,
|
||||
}
|
||||
|
||||
if let ObligationCauseCode::CompareImplItem { .. } = cause.code() {
|
||||
return;
|
||||
}
|
||||
|
|
|
|||
702
library/alloc/src/bstr.rs
Normal file
702
library/alloc/src/bstr.rs
Normal file
|
|
@ -0,0 +1,702 @@
|
|||
//! The `ByteStr` and `ByteString` types and trait implementations.
|
||||
|
||||
// This could be more fine-grained.
|
||||
#![cfg(not(no_global_oom_handling))]
|
||||
|
||||
use core::borrow::{Borrow, BorrowMut};
|
||||
#[unstable(feature = "bstr", issue = "134915")]
|
||||
pub use core::bstr::ByteStr;
|
||||
use core::bstr::{impl_partial_eq, impl_partial_eq_n, impl_partial_eq_ord};
|
||||
use core::cmp::Ordering;
|
||||
use core::ops::{
|
||||
Deref, DerefMut, DerefPure, Index, IndexMut, Range, RangeFrom, RangeFull, RangeInclusive,
|
||||
RangeTo, RangeToInclusive,
|
||||
};
|
||||
#[cfg(not(test))] // https://github.com/rust-lang/rust/issues/135100
|
||||
use core::str::FromStr;
|
||||
use core::{fmt, hash};
|
||||
|
||||
#[cfg(not(test))] // https://github.com/rust-lang/rust/issues/135100
|
||||
use crate::borrow::{Cow, ToOwned};
|
||||
#[cfg(not(test))] // https://github.com/rust-lang/rust/issues/135100
|
||||
use crate::boxed::Box;
|
||||
#[cfg(not(no_rc))]
|
||||
use crate::rc::Rc;
|
||||
use crate::string::String;
|
||||
#[cfg(all(not(no_rc), not(no_sync), target_has_atomic = "ptr"))]
|
||||
use crate::sync::Arc;
|
||||
use crate::vec::Vec;
|
||||
|
||||
/// A wrapper for `Vec<u8>` representing a human-readable string that's conventionally, but not
|
||||
/// always, UTF-8.
|
||||
///
|
||||
/// Unlike `String`, this type permits non-UTF-8 contents, making it suitable for user input,
|
||||
/// non-native filenames (as `Path` only supports native filenames), and other applications that
|
||||
/// need to round-trip whatever data the user provides.
|
||||
///
|
||||
/// A `ByteString` owns its contents and can grow and shrink, like a `Vec` or `String`. For a
|
||||
/// borrowed byte string, see [`ByteStr`](../../std/bstr/struct.ByteStr.html).
|
||||
///
|
||||
/// `ByteString` implements `Deref` to `&Vec<u8>`, so all methods available on `&Vec<u8>` are
|
||||
/// available on `ByteString`. Similarly, `ByteString` implements `DerefMut` to `&mut Vec<u8>`,
|
||||
/// so you can modify a `ByteString` using any method available on `&mut Vec<u8>`.
|
||||
///
|
||||
/// The `Debug` and `Display` implementations for `ByteString` are the same as those for `ByteStr`,
|
||||
/// showing invalid UTF-8 as hex escapes or the Unicode replacement character, respectively.
|
||||
#[unstable(feature = "bstr", issue = "134915")]
|
||||
#[repr(transparent)]
|
||||
#[derive(Clone)]
|
||||
#[doc(alias = "BString")]
|
||||
pub struct ByteString(pub Vec<u8>);
|
||||
|
||||
impl ByteString {
|
||||
#[inline]
|
||||
pub(crate) fn as_bytes(&self) -> &[u8] {
|
||||
&self.0
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub(crate) fn as_bytestr(&self) -> &ByteStr {
|
||||
ByteStr::new(&self.0)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub(crate) fn as_mut_bytestr(&mut self) -> &mut ByteStr {
|
||||
ByteStr::from_bytes_mut(&mut self.0)
|
||||
}
|
||||
}
|
||||
|
||||
#[unstable(feature = "bstr", issue = "134915")]
|
||||
impl Deref for ByteString {
|
||||
type Target = Vec<u8>;
|
||||
|
||||
#[inline]
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&self.0
|
||||
}
|
||||
}
|
||||
|
||||
#[unstable(feature = "bstr", issue = "134915")]
|
||||
impl DerefMut for ByteString {
|
||||
#[inline]
|
||||
fn deref_mut(&mut self) -> &mut Self::Target {
|
||||
&mut self.0
|
||||
}
|
||||
}
|
||||
|
||||
#[unstable(feature = "deref_pure_trait", issue = "87121")]
|
||||
unsafe impl DerefPure for ByteString {}
|
||||
|
||||
#[unstable(feature = "bstr", issue = "134915")]
|
||||
impl fmt::Debug for ByteString {
|
||||
#[inline]
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
fmt::Debug::fmt(self.as_bytestr(), f)
|
||||
}
|
||||
}
|
||||
|
||||
#[unstable(feature = "bstr", issue = "134915")]
|
||||
impl fmt::Display for ByteString {
|
||||
#[inline]
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
fmt::Display::fmt(self.as_bytestr(), f)
|
||||
}
|
||||
}
|
||||
|
||||
#[unstable(feature = "bstr", issue = "134915")]
|
||||
impl AsRef<[u8]> for ByteString {
|
||||
#[inline]
|
||||
fn as_ref(&self) -> &[u8] {
|
||||
&self.0
|
||||
}
|
||||
}
|
||||
|
||||
#[unstable(feature = "bstr", issue = "134915")]
|
||||
impl AsRef<ByteStr> for ByteString {
|
||||
#[inline]
|
||||
fn as_ref(&self) -> &ByteStr {
|
||||
self.as_bytestr()
|
||||
}
|
||||
}
|
||||
|
||||
#[unstable(feature = "bstr", issue = "134915")]
|
||||
impl AsMut<[u8]> for ByteString {
|
||||
#[inline]
|
||||
fn as_mut(&mut self) -> &mut [u8] {
|
||||
&mut self.0
|
||||
}
|
||||
}
|
||||
|
||||
#[unstable(feature = "bstr", issue = "134915")]
|
||||
impl AsMut<ByteStr> for ByteString {
|
||||
#[inline]
|
||||
fn as_mut(&mut self) -> &mut ByteStr {
|
||||
self.as_mut_bytestr()
|
||||
}
|
||||
}
|
||||
|
||||
#[unstable(feature = "bstr", issue = "134915")]
|
||||
impl Borrow<[u8]> for ByteString {
|
||||
#[inline]
|
||||
fn borrow(&self) -> &[u8] {
|
||||
&self.0
|
||||
}
|
||||
}
|
||||
|
||||
#[unstable(feature = "bstr", issue = "134915")]
|
||||
impl Borrow<ByteStr> for ByteString {
|
||||
#[inline]
|
||||
fn borrow(&self) -> &ByteStr {
|
||||
self.as_bytestr()
|
||||
}
|
||||
}
|
||||
|
||||
// `impl Borrow<ByteStr> for Vec<u8>` omitted to avoid inference failures
|
||||
// `impl Borrow<ByteStr> for String` omitted to avoid inference failures
|
||||
|
||||
#[unstable(feature = "bstr", issue = "134915")]
|
||||
impl BorrowMut<[u8]> for ByteString {
|
||||
#[inline]
|
||||
fn borrow_mut(&mut self) -> &mut [u8] {
|
||||
&mut self.0
|
||||
}
|
||||
}
|
||||
|
||||
#[unstable(feature = "bstr", issue = "134915")]
|
||||
impl BorrowMut<ByteStr> for ByteString {
|
||||
#[inline]
|
||||
fn borrow_mut(&mut self) -> &mut ByteStr {
|
||||
self.as_mut_bytestr()
|
||||
}
|
||||
}
|
||||
|
||||
// `impl BorrowMut<ByteStr> for Vec<u8>` omitted to avoid inference failures
|
||||
|
||||
#[unstable(feature = "bstr", issue = "134915")]
|
||||
impl Default for ByteString {
|
||||
fn default() -> Self {
|
||||
ByteString(Vec::new())
|
||||
}
|
||||
}
|
||||
|
||||
// Omitted due to inference failures
|
||||
//
|
||||
// #[cfg(not(test))] // https://github.com/rust-lang/rust/issues/135100
|
||||
// #[unstable(feature = "bstr", issue = "134915")]
|
||||
// impl<'a, const N: usize> From<&'a [u8; N]> for ByteString {
|
||||
// #[inline]
|
||||
// fn from(s: &'a [u8; N]) -> Self {
|
||||
// ByteString(s.as_slice().to_vec())
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// #[cfg(not(test))] // https://github.com/rust-lang/rust/issues/135100
|
||||
// #[unstable(feature = "bstr", issue = "134915")]
|
||||
// impl<const N: usize> From<[u8; N]> for ByteString {
|
||||
// #[inline]
|
||||
// fn from(s: [u8; N]) -> Self {
|
||||
// ByteString(s.as_slice().to_vec())
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// #[cfg(not(test))] // https://github.com/rust-lang/rust/issues/135100
|
||||
// #[unstable(feature = "bstr", issue = "134915")]
|
||||
// impl<'a> From<&'a [u8]> for ByteString {
|
||||
// #[inline]
|
||||
// fn from(s: &'a [u8]) -> Self {
|
||||
// ByteString(s.to_vec())
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// #[unstable(feature = "bstr", issue = "134915")]
|
||||
// impl From<Vec<u8>> for ByteString {
|
||||
// #[inline]
|
||||
// fn from(s: Vec<u8>) -> Self {
|
||||
// ByteString(s)
|
||||
// }
|
||||
// }
|
||||
|
||||
#[unstable(feature = "bstr", issue = "134915")]
|
||||
impl From<ByteString> for Vec<u8> {
|
||||
#[inline]
|
||||
fn from(s: ByteString) -> Self {
|
||||
s.0
|
||||
}
|
||||
}
|
||||
|
||||
// Omitted due to inference failures
|
||||
//
|
||||
// #[cfg(not(test))] // https://github.com/rust-lang/rust/issues/135100
|
||||
// #[unstable(feature = "bstr", issue = "134915")]
|
||||
// impl<'a> From<&'a str> for ByteString {
|
||||
// #[inline]
|
||||
// fn from(s: &'a str) -> Self {
|
||||
// ByteString(s.as_bytes().to_vec())
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// #[unstable(feature = "bstr", issue = "134915")]
|
||||
// impl From<String> for ByteString {
|
||||
// #[inline]
|
||||
// fn from(s: String) -> Self {
|
||||
// ByteString(s.into_bytes())
|
||||
// }
|
||||
// }
|
||||
|
||||
#[cfg(not(test))] // https://github.com/rust-lang/rust/issues/135100
|
||||
#[unstable(feature = "bstr", issue = "134915")]
|
||||
impl<'a> From<&'a ByteStr> for ByteString {
|
||||
#[inline]
|
||||
fn from(s: &'a ByteStr) -> Self {
|
||||
ByteString(s.0.to_vec())
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(test))] // https://github.com/rust-lang/rust/issues/135100
|
||||
#[unstable(feature = "bstr", issue = "134915")]
|
||||
impl<'a> From<ByteString> for Cow<'a, ByteStr> {
|
||||
#[inline]
|
||||
fn from(s: ByteString) -> Self {
|
||||
Cow::Owned(s)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(test))] // https://github.com/rust-lang/rust/issues/135100
|
||||
#[unstable(feature = "bstr", issue = "134915")]
|
||||
impl<'a> From<&'a ByteString> for Cow<'a, ByteStr> {
|
||||
#[inline]
|
||||
fn from(s: &'a ByteString) -> Self {
|
||||
Cow::Borrowed(s.as_bytestr())
|
||||
}
|
||||
}
|
||||
|
||||
#[unstable(feature = "bstr", issue = "134915")]
|
||||
impl FromIterator<char> for ByteString {
|
||||
#[inline]
|
||||
fn from_iter<T: IntoIterator<Item = char>>(iter: T) -> Self {
|
||||
ByteString(iter.into_iter().collect::<String>().into_bytes())
|
||||
}
|
||||
}
|
||||
|
||||
#[unstable(feature = "bstr", issue = "134915")]
|
||||
impl FromIterator<u8> for ByteString {
|
||||
#[inline]
|
||||
fn from_iter<T: IntoIterator<Item = u8>>(iter: T) -> Self {
|
||||
ByteString(iter.into_iter().collect())
|
||||
}
|
||||
}
|
||||
|
||||
#[unstable(feature = "bstr", issue = "134915")]
|
||||
impl<'a> FromIterator<&'a str> for ByteString {
|
||||
#[inline]
|
||||
fn from_iter<T: IntoIterator<Item = &'a str>>(iter: T) -> Self {
|
||||
ByteString(iter.into_iter().collect::<String>().into_bytes())
|
||||
}
|
||||
}
|
||||
|
||||
#[unstable(feature = "bstr", issue = "134915")]
|
||||
impl<'a> FromIterator<&'a [u8]> for ByteString {
|
||||
#[inline]
|
||||
fn from_iter<T: IntoIterator<Item = &'a [u8]>>(iter: T) -> Self {
|
||||
let mut buf = Vec::new();
|
||||
for b in iter {
|
||||
buf.extend_from_slice(b);
|
||||
}
|
||||
ByteString(buf)
|
||||
}
|
||||
}
|
||||
|
||||
#[unstable(feature = "bstr", issue = "134915")]
|
||||
impl<'a> FromIterator<&'a ByteStr> for ByteString {
|
||||
#[inline]
|
||||
fn from_iter<T: IntoIterator<Item = &'a ByteStr>>(iter: T) -> Self {
|
||||
let mut buf = Vec::new();
|
||||
for b in iter {
|
||||
buf.extend_from_slice(&b.0);
|
||||
}
|
||||
ByteString(buf)
|
||||
}
|
||||
}
|
||||
|
||||
#[unstable(feature = "bstr", issue = "134915")]
|
||||
impl FromIterator<ByteString> for ByteString {
|
||||
#[inline]
|
||||
fn from_iter<T: IntoIterator<Item = ByteString>>(iter: T) -> Self {
|
||||
let mut buf = Vec::new();
|
||||
for mut b in iter {
|
||||
buf.append(&mut b.0);
|
||||
}
|
||||
ByteString(buf)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(test))] // https://github.com/rust-lang/rust/issues/135100
|
||||
#[unstable(feature = "bstr", issue = "134915")]
|
||||
impl FromStr for ByteString {
|
||||
type Err = core::convert::Infallible;
|
||||
|
||||
#[inline]
|
||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||
Ok(ByteString(s.as_bytes().to_vec()))
|
||||
}
|
||||
}
|
||||
|
||||
#[unstable(feature = "bstr", issue = "134915")]
|
||||
impl Index<usize> for ByteString {
|
||||
type Output = u8;
|
||||
|
||||
#[inline]
|
||||
fn index(&self, idx: usize) -> &u8 {
|
||||
&self.0[idx]
|
||||
}
|
||||
}
|
||||
|
||||
#[unstable(feature = "bstr", issue = "134915")]
|
||||
impl Index<RangeFull> for ByteString {
|
||||
type Output = ByteStr;
|
||||
|
||||
#[inline]
|
||||
fn index(&self, _: RangeFull) -> &ByteStr {
|
||||
self.as_bytestr()
|
||||
}
|
||||
}
|
||||
|
||||
#[unstable(feature = "bstr", issue = "134915")]
|
||||
impl Index<Range<usize>> for ByteString {
|
||||
type Output = ByteStr;
|
||||
|
||||
#[inline]
|
||||
fn index(&self, r: Range<usize>) -> &ByteStr {
|
||||
ByteStr::from_bytes(&self.0[r])
|
||||
}
|
||||
}
|
||||
|
||||
#[unstable(feature = "bstr", issue = "134915")]
|
||||
impl Index<RangeInclusive<usize>> for ByteString {
|
||||
type Output = ByteStr;
|
||||
|
||||
#[inline]
|
||||
fn index(&self, r: RangeInclusive<usize>) -> &ByteStr {
|
||||
ByteStr::from_bytes(&self.0[r])
|
||||
}
|
||||
}
|
||||
|
||||
#[unstable(feature = "bstr", issue = "134915")]
|
||||
impl Index<RangeFrom<usize>> for ByteString {
|
||||
type Output = ByteStr;
|
||||
|
||||
#[inline]
|
||||
fn index(&self, r: RangeFrom<usize>) -> &ByteStr {
|
||||
ByteStr::from_bytes(&self.0[r])
|
||||
}
|
||||
}
|
||||
|
||||
#[unstable(feature = "bstr", issue = "134915")]
|
||||
impl Index<RangeTo<usize>> for ByteString {
|
||||
type Output = ByteStr;
|
||||
|
||||
#[inline]
|
||||
fn index(&self, r: RangeTo<usize>) -> &ByteStr {
|
||||
ByteStr::from_bytes(&self.0[r])
|
||||
}
|
||||
}
|
||||
|
||||
#[unstable(feature = "bstr", issue = "134915")]
|
||||
impl Index<RangeToInclusive<usize>> for ByteString {
|
||||
type Output = ByteStr;
|
||||
|
||||
#[inline]
|
||||
fn index(&self, r: RangeToInclusive<usize>) -> &ByteStr {
|
||||
ByteStr::from_bytes(&self.0[r])
|
||||
}
|
||||
}
|
||||
|
||||
#[unstable(feature = "bstr", issue = "134915")]
|
||||
impl IndexMut<usize> for ByteString {
|
||||
#[inline]
|
||||
fn index_mut(&mut self, idx: usize) -> &mut u8 {
|
||||
&mut self.0[idx]
|
||||
}
|
||||
}
|
||||
|
||||
#[unstable(feature = "bstr", issue = "134915")]
|
||||
impl IndexMut<RangeFull> for ByteString {
|
||||
#[inline]
|
||||
fn index_mut(&mut self, _: RangeFull) -> &mut ByteStr {
|
||||
self.as_mut_bytestr()
|
||||
}
|
||||
}
|
||||
|
||||
#[unstable(feature = "bstr", issue = "134915")]
|
||||
impl IndexMut<Range<usize>> for ByteString {
|
||||
#[inline]
|
||||
fn index_mut(&mut self, r: Range<usize>) -> &mut ByteStr {
|
||||
ByteStr::from_bytes_mut(&mut self.0[r])
|
||||
}
|
||||
}
|
||||
|
||||
#[unstable(feature = "bstr", issue = "134915")]
|
||||
impl IndexMut<RangeInclusive<usize>> for ByteString {
|
||||
#[inline]
|
||||
fn index_mut(&mut self, r: RangeInclusive<usize>) -> &mut ByteStr {
|
||||
ByteStr::from_bytes_mut(&mut self.0[r])
|
||||
}
|
||||
}
|
||||
|
||||
#[unstable(feature = "bstr", issue = "134915")]
|
||||
impl IndexMut<RangeFrom<usize>> for ByteString {
|
||||
#[inline]
|
||||
fn index_mut(&mut self, r: RangeFrom<usize>) -> &mut ByteStr {
|
||||
ByteStr::from_bytes_mut(&mut self.0[r])
|
||||
}
|
||||
}
|
||||
|
||||
#[unstable(feature = "bstr", issue = "134915")]
|
||||
impl IndexMut<RangeTo<usize>> for ByteString {
|
||||
#[inline]
|
||||
fn index_mut(&mut self, r: RangeTo<usize>) -> &mut ByteStr {
|
||||
ByteStr::from_bytes_mut(&mut self.0[r])
|
||||
}
|
||||
}
|
||||
|
||||
#[unstable(feature = "bstr", issue = "134915")]
|
||||
impl IndexMut<RangeToInclusive<usize>> for ByteString {
|
||||
#[inline]
|
||||
fn index_mut(&mut self, r: RangeToInclusive<usize>) -> &mut ByteStr {
|
||||
ByteStr::from_bytes_mut(&mut self.0[r])
|
||||
}
|
||||
}
|
||||
|
||||
#[unstable(feature = "bstr", issue = "134915")]
|
||||
impl hash::Hash for ByteString {
|
||||
#[inline]
|
||||
fn hash<H: hash::Hasher>(&self, state: &mut H) {
|
||||
self.0.hash(state);
|
||||
}
|
||||
}
|
||||
|
||||
#[unstable(feature = "bstr", issue = "134915")]
|
||||
impl Eq for ByteString {}
|
||||
|
||||
#[unstable(feature = "bstr", issue = "134915")]
|
||||
impl PartialEq for ByteString {
|
||||
#[inline]
|
||||
fn eq(&self, other: &ByteString) -> bool {
|
||||
self.0 == other.0
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! impl_partial_eq_ord_cow {
|
||||
($lhs:ty, $rhs:ty) => {
|
||||
#[cfg(not(test))] // https://github.com/rust-lang/rust/issues/135100
|
||||
#[allow(unused_lifetimes)]
|
||||
#[unstable(feature = "bstr", issue = "134915")]
|
||||
impl<'a> PartialEq<$rhs> for $lhs {
|
||||
#[inline]
|
||||
fn eq(&self, other: &$rhs) -> bool {
|
||||
let other: &[u8] = (&**other).as_ref();
|
||||
PartialEq::eq(self.as_bytes(), other)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(test))] // https://github.com/rust-lang/rust/issues/135100
|
||||
#[allow(unused_lifetimes)]
|
||||
#[unstable(feature = "bstr", issue = "134915")]
|
||||
impl<'a> PartialEq<$lhs> for $rhs {
|
||||
#[inline]
|
||||
fn eq(&self, other: &$lhs) -> bool {
|
||||
let this: &[u8] = (&**self).as_ref();
|
||||
PartialEq::eq(this, other.as_bytes())
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(test))] // https://github.com/rust-lang/rust/issues/135100
|
||||
#[allow(unused_lifetimes)]
|
||||
#[unstable(feature = "bstr", issue = "134915")]
|
||||
impl<'a> PartialOrd<$rhs> for $lhs {
|
||||
#[inline]
|
||||
fn partial_cmp(&self, other: &$rhs) -> Option<Ordering> {
|
||||
let other: &[u8] = (&**other).as_ref();
|
||||
PartialOrd::partial_cmp(self.as_bytes(), other)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(test))] // https://github.com/rust-lang/rust/issues/135100
|
||||
#[allow(unused_lifetimes)]
|
||||
#[unstable(feature = "bstr", issue = "134915")]
|
||||
impl<'a> PartialOrd<$lhs> for $rhs {
|
||||
#[inline]
|
||||
fn partial_cmp(&self, other: &$lhs) -> Option<Ordering> {
|
||||
let this: &[u8] = (&**self).as_ref();
|
||||
PartialOrd::partial_cmp(this, other.as_bytes())
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
// PartialOrd with `Vec<u8>` omitted to avoid inference failures
|
||||
impl_partial_eq!(ByteString, Vec<u8>);
|
||||
// PartialOrd with `[u8]` omitted to avoid inference failures
|
||||
impl_partial_eq!(ByteString, [u8]);
|
||||
// PartialOrd with `&[u8]` omitted to avoid inference failures
|
||||
impl_partial_eq!(ByteString, &[u8]);
|
||||
// PartialOrd with `String` omitted to avoid inference failures
|
||||
impl_partial_eq!(ByteString, String);
|
||||
// PartialOrd with `str` omitted to avoid inference failures
|
||||
impl_partial_eq!(ByteString, str);
|
||||
// PartialOrd with `&str` omitted to avoid inference failures
|
||||
impl_partial_eq!(ByteString, &str);
|
||||
impl_partial_eq_ord!(ByteString, ByteStr);
|
||||
impl_partial_eq_ord!(ByteString, &ByteStr);
|
||||
// PartialOrd with `[u8; N]` omitted to avoid inference failures
|
||||
impl_partial_eq_n!(ByteString, [u8; N]);
|
||||
// PartialOrd with `&[u8; N]` omitted to avoid inference failures
|
||||
impl_partial_eq_n!(ByteString, &[u8; N]);
|
||||
impl_partial_eq_ord_cow!(ByteString, Cow<'_, ByteStr>);
|
||||
impl_partial_eq_ord_cow!(ByteString, Cow<'_, str>);
|
||||
impl_partial_eq_ord_cow!(ByteString, Cow<'_, [u8]>);
|
||||
|
||||
#[unstable(feature = "bstr", issue = "134915")]
|
||||
impl Ord for ByteString {
|
||||
#[inline]
|
||||
fn cmp(&self, other: &ByteString) -> Ordering {
|
||||
Ord::cmp(&self.0, &other.0)
|
||||
}
|
||||
}
|
||||
|
||||
#[unstable(feature = "bstr", issue = "134915")]
|
||||
impl PartialOrd for ByteString {
|
||||
#[inline]
|
||||
fn partial_cmp(&self, other: &ByteString) -> Option<Ordering> {
|
||||
PartialOrd::partial_cmp(&self.0, &other.0)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(test))] // https://github.com/rust-lang/rust/issues/135100
|
||||
#[unstable(feature = "bstr", issue = "134915")]
|
||||
impl ToOwned for ByteStr {
|
||||
type Owned = ByteString;
|
||||
|
||||
#[inline]
|
||||
fn to_owned(&self) -> ByteString {
|
||||
ByteString(self.0.to_vec())
|
||||
}
|
||||
}
|
||||
|
||||
#[unstable(feature = "bstr", issue = "134915")]
|
||||
impl TryFrom<ByteString> for String {
|
||||
type Error = crate::string::FromUtf8Error;
|
||||
|
||||
#[inline]
|
||||
fn try_from(s: ByteString) -> Result<Self, Self::Error> {
|
||||
String::from_utf8(s.0)
|
||||
}
|
||||
}
|
||||
|
||||
#[unstable(feature = "bstr", issue = "134915")]
|
||||
impl<'a> TryFrom<&'a ByteString> for &'a str {
|
||||
type Error = crate::str::Utf8Error;
|
||||
|
||||
#[inline]
|
||||
fn try_from(s: &'a ByteString) -> Result<Self, Self::Error> {
|
||||
crate::str::from_utf8(s.0.as_slice())
|
||||
}
|
||||
}
|
||||
|
||||
// Additional impls for `ByteStr` that require types from `alloc`:
|
||||
|
||||
#[cfg(not(test))] // https://github.com/rust-lang/rust/issues/135100
|
||||
#[unstable(feature = "bstr", issue = "134915")]
|
||||
impl Clone for Box<ByteStr> {
|
||||
#[inline]
|
||||
fn clone(&self) -> Self {
|
||||
Self::from(Box::<[u8]>::from(&self.0))
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(test))] // https://github.com/rust-lang/rust/issues/135100
|
||||
#[unstable(feature = "bstr", issue = "134915")]
|
||||
impl<'a> From<&'a ByteStr> for Cow<'a, ByteStr> {
|
||||
#[inline]
|
||||
fn from(s: &'a ByteStr) -> Self {
|
||||
Cow::Borrowed(s)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(test))] // https://github.com/rust-lang/rust/issues/135100
|
||||
#[unstable(feature = "bstr", issue = "134915")]
|
||||
impl From<Box<[u8]>> for Box<ByteStr> {
|
||||
#[inline]
|
||||
fn from(s: Box<[u8]>) -> Box<ByteStr> {
|
||||
// SAFETY: `ByteStr` is a transparent wrapper around `[u8]`.
|
||||
unsafe { Box::from_raw(Box::into_raw(s) as _) }
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(test))] // https://github.com/rust-lang/rust/issues/135100
|
||||
#[unstable(feature = "bstr", issue = "134915")]
|
||||
impl From<Box<ByteStr>> for Box<[u8]> {
|
||||
#[inline]
|
||||
fn from(s: Box<ByteStr>) -> Box<[u8]> {
|
||||
// SAFETY: `ByteStr` is a transparent wrapper around `[u8]`.
|
||||
unsafe { Box::from_raw(Box::into_raw(s) as _) }
|
||||
}
|
||||
}
|
||||
|
||||
#[unstable(feature = "bstr", issue = "134915")]
|
||||
#[cfg(not(no_rc))]
|
||||
impl From<Rc<[u8]>> for Rc<ByteStr> {
|
||||
#[inline]
|
||||
fn from(s: Rc<[u8]>) -> Rc<ByteStr> {
|
||||
// SAFETY: `ByteStr` is a transparent wrapper around `[u8]`.
|
||||
unsafe { Rc::from_raw(Rc::into_raw(s) as _) }
|
||||
}
|
||||
}
|
||||
|
||||
#[unstable(feature = "bstr", issue = "134915")]
|
||||
#[cfg(not(no_rc))]
|
||||
impl From<Rc<ByteStr>> for Rc<[u8]> {
|
||||
#[inline]
|
||||
fn from(s: Rc<ByteStr>) -> Rc<[u8]> {
|
||||
// SAFETY: `ByteStr` is a transparent wrapper around `[u8]`.
|
||||
unsafe { Rc::from_raw(Rc::into_raw(s) as _) }
|
||||
}
|
||||
}
|
||||
|
||||
#[unstable(feature = "bstr", issue = "134915")]
|
||||
#[cfg(all(not(no_rc), not(no_sync), target_has_atomic = "ptr"))]
|
||||
impl From<Arc<[u8]>> for Arc<ByteStr> {
|
||||
#[inline]
|
||||
fn from(s: Arc<[u8]>) -> Arc<ByteStr> {
|
||||
// SAFETY: `ByteStr` is a transparent wrapper around `[u8]`.
|
||||
unsafe { Arc::from_raw(Arc::into_raw(s) as _) }
|
||||
}
|
||||
}
|
||||
|
||||
#[unstable(feature = "bstr", issue = "134915")]
|
||||
#[cfg(all(not(no_rc), not(no_sync), target_has_atomic = "ptr"))]
|
||||
impl From<Arc<ByteStr>> for Arc<[u8]> {
|
||||
#[inline]
|
||||
fn from(s: Arc<ByteStr>) -> Arc<[u8]> {
|
||||
// SAFETY: `ByteStr` is a transparent wrapper around `[u8]`.
|
||||
unsafe { Arc::from_raw(Arc::into_raw(s) as _) }
|
||||
}
|
||||
}
|
||||
|
||||
// PartialOrd with `Vec<u8>` omitted to avoid inference failures
|
||||
impl_partial_eq!(ByteStr, Vec<u8>);
|
||||
// PartialOrd with `String` omitted to avoid inference failures
|
||||
impl_partial_eq!(ByteStr, String);
|
||||
impl_partial_eq_ord_cow!(&'a ByteStr, Cow<'a, ByteStr>);
|
||||
impl_partial_eq_ord_cow!(&'a ByteStr, Cow<'a, str>);
|
||||
impl_partial_eq_ord_cow!(&'a ByteStr, Cow<'a, [u8]>);
|
||||
|
||||
#[unstable(feature = "bstr", issue = "134915")]
|
||||
impl<'a> TryFrom<&'a ByteStr> for String {
|
||||
type Error = core::str::Utf8Error;
|
||||
|
||||
#[inline]
|
||||
fn try_from(s: &'a ByteStr) -> Result<Self, Self::Error> {
|
||||
Ok(core::str::from_utf8(&s.0)?.into())
|
||||
}
|
||||
}
|
||||
|
|
@ -1442,20 +1442,20 @@ impl<T, A: Allocator + Clone> BTreeSet<T, A> {
|
|||
///
|
||||
/// let mut set = BTreeSet::from([1, 2, 3, 4]);
|
||||
///
|
||||
/// let mut cursor = unsafe { set.upper_bound_mut(Bound::Included(&3)) };
|
||||
/// let mut cursor = set.upper_bound_mut(Bound::Included(&3));
|
||||
/// assert_eq!(cursor.peek_prev(), Some(&3));
|
||||
/// assert_eq!(cursor.peek_next(), Some(&4));
|
||||
///
|
||||
/// let mut cursor = unsafe { set.upper_bound_mut(Bound::Excluded(&3)) };
|
||||
/// let mut cursor = set.upper_bound_mut(Bound::Excluded(&3));
|
||||
/// assert_eq!(cursor.peek_prev(), Some(&2));
|
||||
/// assert_eq!(cursor.peek_next(), Some(&3));
|
||||
///
|
||||
/// let mut cursor = unsafe { set.upper_bound_mut(Bound::Unbounded) };
|
||||
/// let mut cursor = set.upper_bound_mut(Bound::Unbounded);
|
||||
/// assert_eq!(cursor.peek_prev(), Some(&4));
|
||||
/// assert_eq!(cursor.peek_next(), None);
|
||||
/// ```
|
||||
#[unstable(feature = "btree_cursors", issue = "107540")]
|
||||
pub unsafe fn upper_bound_mut<Q: ?Sized>(&mut self, bound: Bound<&Q>) -> CursorMut<'_, T, A>
|
||||
pub fn upper_bound_mut<Q: ?Sized>(&mut self, bound: Bound<&Q>) -> CursorMut<'_, T, A>
|
||||
where
|
||||
T: Borrow<Q> + Ord,
|
||||
Q: Ord,
|
||||
|
|
|
|||
|
|
@ -102,6 +102,8 @@
|
|||
#![feature(async_fn_traits)]
|
||||
#![feature(async_iterator)]
|
||||
#![feature(box_uninit_write)]
|
||||
#![feature(bstr)]
|
||||
#![feature(bstr_internals)]
|
||||
#![feature(clone_to_uninit)]
|
||||
#![feature(coerce_unsized)]
|
||||
#![feature(const_eval_select)]
|
||||
|
|
@ -228,6 +230,8 @@ mod boxed {
|
|||
pub use std::boxed::Box;
|
||||
}
|
||||
pub mod borrow;
|
||||
#[unstable(feature = "bstr", issue = "134915")]
|
||||
pub mod bstr;
|
||||
pub mod collections;
|
||||
#[cfg(all(not(no_rc), not(no_sync), not(no_global_oom_handling)))]
|
||||
pub mod ffi;
|
||||
|
|
|
|||
581
library/core/src/bstr.rs
Normal file
581
library/core/src/bstr.rs
Normal file
|
|
@ -0,0 +1,581 @@
|
|||
//! The `ByteStr` type and trait implementations.
|
||||
|
||||
use crate::borrow::{Borrow, BorrowMut};
|
||||
use crate::cmp::Ordering;
|
||||
use crate::ops::{
|
||||
Deref, DerefMut, DerefPure, Index, IndexMut, Range, RangeFrom, RangeFull, RangeInclusive,
|
||||
RangeTo, RangeToInclusive,
|
||||
};
|
||||
use crate::{fmt, hash};
|
||||
|
||||
/// A wrapper for `&[u8]` representing a human-readable string that's conventionally, but not
|
||||
/// always, UTF-8.
|
||||
///
|
||||
/// Unlike `&str`, this type permits non-UTF-8 contents, making it suitable for user input,
|
||||
/// non-native filenames (as `Path` only supports native filenames), and other applications that
|
||||
/// need to round-trip whatever data the user provides.
|
||||
///
|
||||
/// For an owned, growable byte string buffer, use
|
||||
/// [`ByteString`](../../std/bstr/struct.ByteString.html).
|
||||
///
|
||||
/// `ByteStr` implements `Deref` to `[u8]`, so all methods available on `[u8]` are available on
|
||||
/// `ByteStr`.
|
||||
///
|
||||
/// # Representation
|
||||
///
|
||||
/// A `&ByteStr` has the same representation as a `&str`. That is, a `&ByteStr` is a wide pointer
|
||||
/// which includes a pointer to some bytes and a length.
|
||||
///
|
||||
/// # Trait implementations
|
||||
///
|
||||
/// The `ByteStr` type has a number of trait implementations, and in particular, defines equality
|
||||
/// and comparisons between `&ByteStr`, `&str`, and `&[u8]`, for convenience.
|
||||
///
|
||||
/// The `Debug` implementation for `ByteStr` shows its bytes as a normal string, with invalid UTF-8
|
||||
/// presented as hex escape sequences.
|
||||
///
|
||||
/// The `Display` implementation behaves as if the `ByteStr` were first lossily converted to a
|
||||
/// `str`, with invalid UTF-8 presented as the Unicode replacement character: <20>
|
||||
///
|
||||
#[unstable(feature = "bstr", issue = "134915")]
|
||||
#[repr(transparent)]
|
||||
#[doc(alias = "BStr")]
|
||||
pub struct ByteStr(pub [u8]);
|
||||
|
||||
impl ByteStr {
|
||||
/// Creates a `ByteStr` slice from anything that can be converted to a byte slice.
|
||||
///
|
||||
/// This is a zero-cost conversion.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// You can create a `ByteStr` from a byte array, a byte slice or a string slice:
|
||||
///
|
||||
/// ```
|
||||
/// # #![feature(bstr)]
|
||||
/// # use std::bstr::ByteStr;
|
||||
/// let a = ByteStr::new(b"abc");
|
||||
/// let b = ByteStr::new(&b"abc"[..]);
|
||||
/// let c = ByteStr::new("abc");
|
||||
///
|
||||
/// assert_eq!(a, b);
|
||||
/// assert_eq!(a, c);
|
||||
/// ```
|
||||
#[inline]
|
||||
#[unstable(feature = "bstr", issue = "134915")]
|
||||
pub fn new<B: ?Sized + AsRef<[u8]>>(bytes: &B) -> &Self {
|
||||
ByteStr::from_bytes(bytes.as_ref())
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
#[unstable(feature = "bstr_internals", issue = "none")]
|
||||
#[inline]
|
||||
pub fn from_bytes(slice: &[u8]) -> &Self {
|
||||
// SAFETY: `ByteStr` is a transparent wrapper around `[u8]`, so we can turn a reference to
|
||||
// the wrapped type into a reference to the wrapper type.
|
||||
unsafe { &*(slice as *const [u8] as *const Self) }
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
#[unstable(feature = "bstr_internals", issue = "none")]
|
||||
#[inline]
|
||||
pub fn from_bytes_mut(slice: &mut [u8]) -> &mut Self {
|
||||
// SAFETY: `ByteStr` is a transparent wrapper around `[u8]`, so we can turn a reference to
|
||||
// the wrapped type into a reference to the wrapper type.
|
||||
unsafe { &mut *(slice as *mut [u8] as *mut Self) }
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
#[unstable(feature = "bstr_internals", issue = "none")]
|
||||
#[inline]
|
||||
pub fn as_bytes(&self) -> &[u8] {
|
||||
&self.0
|
||||
}
|
||||
}
|
||||
|
||||
#[unstable(feature = "bstr", issue = "134915")]
|
||||
impl Deref for ByteStr {
|
||||
type Target = [u8];
|
||||
|
||||
#[inline]
|
||||
fn deref(&self) -> &[u8] {
|
||||
&self.0
|
||||
}
|
||||
}
|
||||
|
||||
#[unstable(feature = "bstr", issue = "134915")]
|
||||
impl DerefMut for ByteStr {
|
||||
#[inline]
|
||||
fn deref_mut(&mut self) -> &mut [u8] {
|
||||
&mut self.0
|
||||
}
|
||||
}
|
||||
|
||||
#[unstable(feature = "deref_pure_trait", issue = "87121")]
|
||||
unsafe impl DerefPure for ByteStr {}
|
||||
|
||||
#[unstable(feature = "bstr", issue = "134915")]
|
||||
impl fmt::Debug for ByteStr {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
write!(f, "\"")?;
|
||||
for chunk in self.utf8_chunks() {
|
||||
for c in chunk.valid().chars() {
|
||||
match c {
|
||||
'\0' => write!(f, "\\0")?,
|
||||
'\x01'..='\x7f' => write!(f, "{}", (c as u8).escape_ascii())?,
|
||||
_ => write!(f, "{}", c.escape_debug())?,
|
||||
}
|
||||
}
|
||||
write!(f, "{}", chunk.invalid().escape_ascii())?;
|
||||
}
|
||||
write!(f, "\"")?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[unstable(feature = "bstr", issue = "134915")]
|
||||
impl fmt::Display for ByteStr {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
fn fmt_nopad(this: &ByteStr, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
for chunk in this.utf8_chunks() {
|
||||
f.write_str(chunk.valid())?;
|
||||
if !chunk.invalid().is_empty() {
|
||||
f.write_str("\u{FFFD}")?;
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
let Some(align) = f.align() else {
|
||||
return fmt_nopad(self, f);
|
||||
};
|
||||
let nchars: usize = self
|
||||
.utf8_chunks()
|
||||
.map(|chunk| chunk.valid().len() + if chunk.invalid().is_empty() { 0 } else { 1 })
|
||||
.sum();
|
||||
let padding = f.width().unwrap_or(0).saturating_sub(nchars);
|
||||
let fill = f.fill();
|
||||
let (lpad, rpad) = match align {
|
||||
fmt::Alignment::Left => (0, padding),
|
||||
fmt::Alignment::Right => (padding, 0),
|
||||
fmt::Alignment::Center => {
|
||||
let half = padding / 2;
|
||||
(half, half + padding % 2)
|
||||
}
|
||||
};
|
||||
for _ in 0..lpad {
|
||||
write!(f, "{fill}")?;
|
||||
}
|
||||
fmt_nopad(self, f)?;
|
||||
for _ in 0..rpad {
|
||||
write!(f, "{fill}")?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[unstable(feature = "bstr", issue = "134915")]
|
||||
impl AsRef<[u8]> for ByteStr {
|
||||
#[inline]
|
||||
fn as_ref(&self) -> &[u8] {
|
||||
&self.0
|
||||
}
|
||||
}
|
||||
|
||||
#[unstable(feature = "bstr", issue = "134915")]
|
||||
impl AsRef<ByteStr> for ByteStr {
|
||||
#[inline]
|
||||
fn as_ref(&self) -> &ByteStr {
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
// `impl AsRef<ByteStr> for [u8]` omitted to avoid widespread inference failures
|
||||
|
||||
#[unstable(feature = "bstr", issue = "134915")]
|
||||
impl AsRef<ByteStr> for str {
|
||||
#[inline]
|
||||
fn as_ref(&self) -> &ByteStr {
|
||||
ByteStr::new(self)
|
||||
}
|
||||
}
|
||||
|
||||
#[unstable(feature = "bstr", issue = "134915")]
|
||||
impl AsMut<[u8]> for ByteStr {
|
||||
#[inline]
|
||||
fn as_mut(&mut self) -> &mut [u8] {
|
||||
&mut self.0
|
||||
}
|
||||
}
|
||||
|
||||
// `impl AsMut<ByteStr> for [u8]` omitted to avoid widespread inference failures
|
||||
|
||||
// `impl Borrow<ByteStr> for [u8]` omitted to avoid widespread inference failures
|
||||
|
||||
// `impl Borrow<ByteStr> for str` omitted to avoid widespread inference failures
|
||||
|
||||
#[unstable(feature = "bstr", issue = "134915")]
|
||||
impl Borrow<[u8]> for ByteStr {
|
||||
#[inline]
|
||||
fn borrow(&self) -> &[u8] {
|
||||
&self.0
|
||||
}
|
||||
}
|
||||
|
||||
// `impl BorrowMut<ByteStr> for [u8]` omitted to avoid widespread inference failures
|
||||
|
||||
#[unstable(feature = "bstr", issue = "134915")]
|
||||
impl BorrowMut<[u8]> for ByteStr {
|
||||
#[inline]
|
||||
fn borrow_mut(&mut self) -> &mut [u8] {
|
||||
&mut self.0
|
||||
}
|
||||
}
|
||||
|
||||
#[unstable(feature = "bstr", issue = "134915")]
|
||||
impl<'a> Default for &'a ByteStr {
|
||||
fn default() -> Self {
|
||||
ByteStr::from_bytes(b"")
|
||||
}
|
||||
}
|
||||
|
||||
#[unstable(feature = "bstr", issue = "134915")]
|
||||
impl<'a> Default for &'a mut ByteStr {
|
||||
fn default() -> Self {
|
||||
ByteStr::from_bytes_mut(&mut [])
|
||||
}
|
||||
}
|
||||
|
||||
// Omitted due to inference failures
|
||||
//
|
||||
// #[unstable(feature = "bstr", issue = "134915")]
|
||||
// impl<'a, const N: usize> From<&'a [u8; N]> for &'a ByteStr {
|
||||
// #[inline]
|
||||
// fn from(s: &'a [u8; N]) -> Self {
|
||||
// ByteStr::from_bytes(s)
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// #[unstable(feature = "bstr", issue = "134915")]
|
||||
// impl<'a> From<&'a [u8]> for &'a ByteStr {
|
||||
// #[inline]
|
||||
// fn from(s: &'a [u8]) -> Self {
|
||||
// ByteStr::from_bytes(s)
|
||||
// }
|
||||
// }
|
||||
|
||||
// Omitted due to slice-from-array-issue-113238:
|
||||
//
|
||||
// #[unstable(feature = "bstr", issue = "134915")]
|
||||
// impl<'a> From<&'a ByteStr> for &'a [u8] {
|
||||
// #[inline]
|
||||
// fn from(s: &'a ByteStr) -> Self {
|
||||
// &s.0
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// #[unstable(feature = "bstr", issue = "134915")]
|
||||
// impl<'a> From<&'a mut ByteStr> for &'a mut [u8] {
|
||||
// #[inline]
|
||||
// fn from(s: &'a mut ByteStr) -> Self {
|
||||
// &mut s.0
|
||||
// }
|
||||
// }
|
||||
|
||||
// Omitted due to inference failures
|
||||
//
|
||||
// #[unstable(feature = "bstr", issue = "134915")]
|
||||
// impl<'a> From<&'a str> for &'a ByteStr {
|
||||
// #[inline]
|
||||
// fn from(s: &'a str) -> Self {
|
||||
// ByteStr::from_bytes(s.as_bytes())
|
||||
// }
|
||||
// }
|
||||
|
||||
#[unstable(feature = "bstr", issue = "134915")]
|
||||
impl hash::Hash for ByteStr {
|
||||
#[inline]
|
||||
fn hash<H: hash::Hasher>(&self, state: &mut H) {
|
||||
self.0.hash(state);
|
||||
}
|
||||
}
|
||||
|
||||
#[unstable(feature = "bstr", issue = "134915")]
|
||||
impl Index<usize> for ByteStr {
|
||||
type Output = u8;
|
||||
|
||||
#[inline]
|
||||
fn index(&self, idx: usize) -> &u8 {
|
||||
&self.0[idx]
|
||||
}
|
||||
}
|
||||
|
||||
#[unstable(feature = "bstr", issue = "134915")]
|
||||
impl Index<RangeFull> for ByteStr {
|
||||
type Output = ByteStr;
|
||||
|
||||
#[inline]
|
||||
fn index(&self, _: RangeFull) -> &ByteStr {
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
#[unstable(feature = "bstr", issue = "134915")]
|
||||
impl Index<Range<usize>> for ByteStr {
|
||||
type Output = ByteStr;
|
||||
|
||||
#[inline]
|
||||
fn index(&self, r: Range<usize>) -> &ByteStr {
|
||||
ByteStr::from_bytes(&self.0[r])
|
||||
}
|
||||
}
|
||||
|
||||
#[unstable(feature = "bstr", issue = "134915")]
|
||||
impl Index<RangeInclusive<usize>> for ByteStr {
|
||||
type Output = ByteStr;
|
||||
|
||||
#[inline]
|
||||
fn index(&self, r: RangeInclusive<usize>) -> &ByteStr {
|
||||
ByteStr::from_bytes(&self.0[r])
|
||||
}
|
||||
}
|
||||
|
||||
#[unstable(feature = "bstr", issue = "134915")]
|
||||
impl Index<RangeFrom<usize>> for ByteStr {
|
||||
type Output = ByteStr;
|
||||
|
||||
#[inline]
|
||||
fn index(&self, r: RangeFrom<usize>) -> &ByteStr {
|
||||
ByteStr::from_bytes(&self.0[r])
|
||||
}
|
||||
}
|
||||
|
||||
#[unstable(feature = "bstr", issue = "134915")]
|
||||
impl Index<RangeTo<usize>> for ByteStr {
|
||||
type Output = ByteStr;
|
||||
|
||||
#[inline]
|
||||
fn index(&self, r: RangeTo<usize>) -> &ByteStr {
|
||||
ByteStr::from_bytes(&self.0[r])
|
||||
}
|
||||
}
|
||||
|
||||
#[unstable(feature = "bstr", issue = "134915")]
|
||||
impl Index<RangeToInclusive<usize>> for ByteStr {
|
||||
type Output = ByteStr;
|
||||
|
||||
#[inline]
|
||||
fn index(&self, r: RangeToInclusive<usize>) -> &ByteStr {
|
||||
ByteStr::from_bytes(&self.0[r])
|
||||
}
|
||||
}
|
||||
|
||||
#[unstable(feature = "bstr", issue = "134915")]
|
||||
impl IndexMut<usize> for ByteStr {
|
||||
#[inline]
|
||||
fn index_mut(&mut self, idx: usize) -> &mut u8 {
|
||||
&mut self.0[idx]
|
||||
}
|
||||
}
|
||||
|
||||
#[unstable(feature = "bstr", issue = "134915")]
|
||||
impl IndexMut<RangeFull> for ByteStr {
|
||||
#[inline]
|
||||
fn index_mut(&mut self, _: RangeFull) -> &mut ByteStr {
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
#[unstable(feature = "bstr", issue = "134915")]
|
||||
impl IndexMut<Range<usize>> for ByteStr {
|
||||
#[inline]
|
||||
fn index_mut(&mut self, r: Range<usize>) -> &mut ByteStr {
|
||||
ByteStr::from_bytes_mut(&mut self.0[r])
|
||||
}
|
||||
}
|
||||
|
||||
#[unstable(feature = "bstr", issue = "134915")]
|
||||
impl IndexMut<RangeInclusive<usize>> for ByteStr {
|
||||
#[inline]
|
||||
fn index_mut(&mut self, r: RangeInclusive<usize>) -> &mut ByteStr {
|
||||
ByteStr::from_bytes_mut(&mut self.0[r])
|
||||
}
|
||||
}
|
||||
|
||||
#[unstable(feature = "bstr", issue = "134915")]
|
||||
impl IndexMut<RangeFrom<usize>> for ByteStr {
|
||||
#[inline]
|
||||
fn index_mut(&mut self, r: RangeFrom<usize>) -> &mut ByteStr {
|
||||
ByteStr::from_bytes_mut(&mut self.0[r])
|
||||
}
|
||||
}
|
||||
|
||||
#[unstable(feature = "bstr", issue = "134915")]
|
||||
impl IndexMut<RangeTo<usize>> for ByteStr {
|
||||
#[inline]
|
||||
fn index_mut(&mut self, r: RangeTo<usize>) -> &mut ByteStr {
|
||||
ByteStr::from_bytes_mut(&mut self.0[r])
|
||||
}
|
||||
}
|
||||
|
||||
#[unstable(feature = "bstr", issue = "134915")]
|
||||
impl IndexMut<RangeToInclusive<usize>> for ByteStr {
|
||||
#[inline]
|
||||
fn index_mut(&mut self, r: RangeToInclusive<usize>) -> &mut ByteStr {
|
||||
ByteStr::from_bytes_mut(&mut self.0[r])
|
||||
}
|
||||
}
|
||||
|
||||
#[unstable(feature = "bstr", issue = "134915")]
|
||||
impl Eq for ByteStr {}
|
||||
|
||||
#[unstable(feature = "bstr", issue = "134915")]
|
||||
impl PartialEq<ByteStr> for ByteStr {
|
||||
#[inline]
|
||||
fn eq(&self, other: &ByteStr) -> bool {
|
||||
&self.0 == &other.0
|
||||
}
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
#[macro_export]
|
||||
#[unstable(feature = "bstr_internals", issue = "none")]
|
||||
macro_rules! impl_partial_eq {
|
||||
($lhs:ty, $rhs:ty) => {
|
||||
#[allow(unused_lifetimes)]
|
||||
impl<'a> PartialEq<$rhs> for $lhs {
|
||||
#[inline]
|
||||
fn eq(&self, other: &$rhs) -> bool {
|
||||
let other: &[u8] = other.as_ref();
|
||||
PartialEq::eq(self.as_bytes(), other)
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(unused_lifetimes)]
|
||||
impl<'a> PartialEq<$lhs> for $rhs {
|
||||
#[inline]
|
||||
fn eq(&self, other: &$lhs) -> bool {
|
||||
let this: &[u8] = self.as_ref();
|
||||
PartialEq::eq(this, other.as_bytes())
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
#[unstable(feature = "bstr_internals", issue = "none")]
|
||||
pub use impl_partial_eq;
|
||||
|
||||
#[doc(hidden)]
|
||||
#[macro_export]
|
||||
#[unstable(feature = "bstr_internals", issue = "none")]
|
||||
macro_rules! impl_partial_eq_ord {
|
||||
($lhs:ty, $rhs:ty) => {
|
||||
$crate::bstr::impl_partial_eq!($lhs, $rhs);
|
||||
|
||||
#[allow(unused_lifetimes)]
|
||||
#[unstable(feature = "bstr", issue = "134915")]
|
||||
impl<'a> PartialOrd<$rhs> for $lhs {
|
||||
#[inline]
|
||||
fn partial_cmp(&self, other: &$rhs) -> Option<Ordering> {
|
||||
let other: &[u8] = other.as_ref();
|
||||
PartialOrd::partial_cmp(self.as_bytes(), other)
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(unused_lifetimes)]
|
||||
#[unstable(feature = "bstr", issue = "134915")]
|
||||
impl<'a> PartialOrd<$lhs> for $rhs {
|
||||
#[inline]
|
||||
fn partial_cmp(&self, other: &$lhs) -> Option<Ordering> {
|
||||
let this: &[u8] = self.as_ref();
|
||||
PartialOrd::partial_cmp(this, other.as_bytes())
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
#[unstable(feature = "bstr_internals", issue = "none")]
|
||||
pub use impl_partial_eq_ord;
|
||||
|
||||
#[doc(hidden)]
|
||||
#[macro_export]
|
||||
#[unstable(feature = "bstr_internals", issue = "none")]
|
||||
macro_rules! impl_partial_eq_n {
|
||||
($lhs:ty, $rhs:ty) => {
|
||||
#[allow(unused_lifetimes)]
|
||||
#[unstable(feature = "bstr", issue = "134915")]
|
||||
impl<const N: usize> PartialEq<$rhs> for $lhs {
|
||||
#[inline]
|
||||
fn eq(&self, other: &$rhs) -> bool {
|
||||
let other: &[u8] = other.as_ref();
|
||||
PartialEq::eq(self.as_bytes(), other)
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(unused_lifetimes)]
|
||||
#[unstable(feature = "bstr", issue = "134915")]
|
||||
impl<const N: usize> PartialEq<$lhs> for $rhs {
|
||||
#[inline]
|
||||
fn eq(&self, other: &$lhs) -> bool {
|
||||
let this: &[u8] = self.as_ref();
|
||||
PartialEq::eq(this, other.as_bytes())
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
#[unstable(feature = "bstr_internals", issue = "none")]
|
||||
pub use impl_partial_eq_n;
|
||||
|
||||
// PartialOrd with `[u8]` omitted to avoid inference failures
|
||||
impl_partial_eq!(ByteStr, [u8]);
|
||||
// PartialOrd with `&[u8]` omitted to avoid inference failures
|
||||
impl_partial_eq!(ByteStr, &[u8]);
|
||||
// PartialOrd with `str` omitted to avoid inference failures
|
||||
impl_partial_eq!(ByteStr, str);
|
||||
// PartialOrd with `&str` omitted to avoid inference failures
|
||||
impl_partial_eq!(ByteStr, &str);
|
||||
// PartialOrd with `[u8; N]` omitted to avoid inference failures
|
||||
impl_partial_eq_n!(ByteStr, [u8; N]);
|
||||
// PartialOrd with `[u8; N]` omitted to avoid inference failures
|
||||
impl_partial_eq_n!(ByteStr, &[u8; N]);
|
||||
|
||||
#[unstable(feature = "bstr", issue = "134915")]
|
||||
impl Ord for ByteStr {
|
||||
#[inline]
|
||||
fn cmp(&self, other: &ByteStr) -> Ordering {
|
||||
Ord::cmp(&self.0, &other.0)
|
||||
}
|
||||
}
|
||||
|
||||
#[unstable(feature = "bstr", issue = "134915")]
|
||||
impl PartialOrd for ByteStr {
|
||||
#[inline]
|
||||
fn partial_cmp(&self, other: &ByteStr) -> Option<Ordering> {
|
||||
PartialOrd::partial_cmp(&self.0, &other.0)
|
||||
}
|
||||
}
|
||||
|
||||
#[unstable(feature = "bstr", issue = "134915")]
|
||||
impl<'a> TryFrom<&'a ByteStr> for &'a str {
|
||||
type Error = crate::str::Utf8Error;
|
||||
|
||||
#[inline]
|
||||
fn try_from(s: &'a ByteStr) -> Result<Self, Self::Error> {
|
||||
crate::str::from_utf8(&s.0)
|
||||
}
|
||||
}
|
||||
|
||||
#[unstable(feature = "bstr", issue = "134915")]
|
||||
impl<'a> TryFrom<&'a mut ByteStr> for &'a mut str {
|
||||
type Error = crate::str::Utf8Error;
|
||||
|
||||
#[inline]
|
||||
fn try_from(s: &'a mut ByteStr) -> Result<Self, Self::Error> {
|
||||
crate::str::from_utf8_mut(&mut s.0)
|
||||
}
|
||||
}
|
||||
|
|
@ -311,6 +311,16 @@ unsafe impl CloneToUninit for crate::ffi::CStr {
|
|||
}
|
||||
}
|
||||
|
||||
#[unstable(feature = "bstr", issue = "134915")]
|
||||
unsafe impl CloneToUninit for crate::bstr::ByteStr {
|
||||
#[inline]
|
||||
#[cfg_attr(debug_assertions, track_caller)]
|
||||
unsafe fn clone_to_uninit(&self, dst: *mut u8) {
|
||||
// SAFETY: ByteStr is a `#[repr(transparent)]` wrapper around `[u8]`
|
||||
unsafe { self.as_bytes().clone_to_uninit(dst) }
|
||||
}
|
||||
}
|
||||
|
||||
/// Implementations of `Clone` for primitive types.
|
||||
///
|
||||
/// Implementations that cannot be described in Rust
|
||||
|
|
|
|||
|
|
@ -288,7 +288,7 @@ pub enum DebugAsHex {
|
|||
///
|
||||
/// `FormattingOptions` is a [`Formatter`] without an attached [`Write`] trait.
|
||||
/// It is mainly used to construct `Formatter` instances.
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq, Default)]
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
|
||||
#[unstable(feature = "formatting_options", issue = "118117")]
|
||||
pub struct FormattingOptions {
|
||||
flags: u32,
|
||||
|
|
@ -508,6 +508,15 @@ impl FormattingOptions {
|
|||
}
|
||||
}
|
||||
|
||||
#[unstable(feature = "formatting_options", issue = "118117")]
|
||||
impl Default for FormattingOptions {
|
||||
/// Same as [`FormattingOptions::new()`].
|
||||
fn default() -> Self {
|
||||
// The `#[derive(Default)]` implementation would set `fill` to `\0` instead of space.
|
||||
Self::new()
|
||||
}
|
||||
}
|
||||
|
||||
/// Configuration for formatting.
|
||||
///
|
||||
/// A `Formatter` represents various options related to formatting. Users do not
|
||||
|
|
|
|||
|
|
@ -111,6 +111,8 @@
|
|||
#![feature(array_ptr_get)]
|
||||
#![feature(asm_experimental_arch)]
|
||||
#![feature(bigint_helper_methods)]
|
||||
#![feature(bstr)]
|
||||
#![feature(bstr_internals)]
|
||||
#![feature(const_carrying_mul_add)]
|
||||
#![feature(const_eval_select)]
|
||||
#![feature(core_intrinsics)]
|
||||
|
|
@ -336,6 +338,8 @@ pub mod ascii;
|
|||
pub mod asserting;
|
||||
#[unstable(feature = "async_iterator", issue = "79024")]
|
||||
pub mod async_iter;
|
||||
#[unstable(feature = "bstr", issue = "134915")]
|
||||
pub mod bstr;
|
||||
pub mod cell;
|
||||
pub mod char;
|
||||
pub mod ffi;
|
||||
|
|
|
|||
54
library/core/tests/bstr.rs
Normal file
54
library/core/tests/bstr.rs
Normal file
|
|
@ -0,0 +1,54 @@
|
|||
#![feature(bstr)]
|
||||
|
||||
use core::ByteStr;
|
||||
|
||||
#[test]
|
||||
fn test_debug() {
|
||||
assert_eq!(
|
||||
r#""\0\x01\x02\x03\x04\x05\x06\x07\x08\t\n\x11\x12\r\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f \x7f\x80\x81\xfe\xff""#,
|
||||
format!("{:?}", ByteStr::new(b"\0\x01\x02\x03\x04\x05\x06\x07\x08\t\n\x11\x12\r\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f \x7f\x80\x81\xfe\xff")),
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_display() {
|
||||
let b1 = ByteStr::new("abc");
|
||||
let b2 = ByteStr::new(b"\xf0\x28\x8c\xbc");
|
||||
|
||||
assert_eq!(&format!("{b1}"), "abc");
|
||||
assert_eq!(&format!("{b2}"), "<EFBFBD>(<28><>");
|
||||
|
||||
assert_eq!(&format!("{b1:<7}!"), "abc !");
|
||||
assert_eq!(&format!("{b1:>7}!"), " abc!");
|
||||
assert_eq!(&format!("{b1:^7}!"), " abc !");
|
||||
assert_eq!(&format!("{b1:^6}!"), " abc !");
|
||||
assert_eq!(&format!("{b1:-<7}!"), "abc----!");
|
||||
assert_eq!(&format!("{b1:->7}!"), "----abc!");
|
||||
assert_eq!(&format!("{b1:-^7}!"), "--abc--!");
|
||||
assert_eq!(&format!("{b1:-^6}!"), "-abc--!");
|
||||
|
||||
assert_eq!(&format!("{b2:<7}!"), "<EFBFBD>(<28><> !");
|
||||
assert_eq!(&format!("{b2:>7}!"), " <20>(<28><>!");
|
||||
assert_eq!(&format!("{b2:^7}!"), " <20>(<28><> !");
|
||||
assert_eq!(&format!("{b2:^6}!"), " <20>(<28><> !");
|
||||
assert_eq!(&format!("{b2:-<7}!"), "<EFBFBD>(<28><>---!");
|
||||
assert_eq!(&format!("{b2:->7}!"), "---<2D>(<28><>!");
|
||||
assert_eq!(&format!("{b2:-^7}!"), "-<2D>(<28><>--!");
|
||||
assert_eq!(&format!("{b2:-^6}!"), "-<2D>(<28><>-!");
|
||||
|
||||
assert_eq!(&format!("{b1:<2}!"), "abc!");
|
||||
assert_eq!(&format!("{b1:>2}!"), "abc!");
|
||||
assert_eq!(&format!("{b1:^2}!"), "abc!");
|
||||
assert_eq!(&format!("{b1:-<2}!"), "abc!");
|
||||
assert_eq!(&format!("{b1:->2}!"), "abc!");
|
||||
assert_eq!(&format!("{b1:-^2}!"), "abc!");
|
||||
|
||||
assert_eq!(&format!("{b2:<3}!"), "<EFBFBD>(<28><>!");
|
||||
assert_eq!(&format!("{b2:>3}!"), "<EFBFBD>(<28><>!");
|
||||
assert_eq!(&format!("{b2:^3}!"), "<EFBFBD>(<28><>!");
|
||||
assert_eq!(&format!("{b2:^2}!"), "<EFBFBD>(<28><>!");
|
||||
assert_eq!(&format!("{b2:-<3}!"), "<EFBFBD>(<28><>!");
|
||||
assert_eq!(&format!("{b2:->3}!"), "<EFBFBD>(<28><>!");
|
||||
assert_eq!(&format!("{b2:-^3}!"), "<EFBFBD>(<28><>!");
|
||||
assert_eq!(&format!("{b2:-^2}!"), "<EFBFBD>(<28><>!");
|
||||
}
|
||||
|
|
@ -51,6 +51,12 @@ fn test_maybe_uninit_short() {
|
|||
assert_eq!(format!("{x:?}"), "MaybeUninit<u32>");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn formatting_options_ctor() {
|
||||
use core::fmt::FormattingOptions;
|
||||
assert_eq!(FormattingOptions::new(), FormattingOptions::default());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn formatting_options_flags() {
|
||||
use core::fmt::*;
|
||||
|
|
|
|||
4
library/std/src/bstr.rs
Normal file
4
library/std/src/bstr.rs
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
//! The `ByteStr` and `ByteString` types and trait implementations.
|
||||
|
||||
#[unstable(feature = "bstr", issue = "134915")]
|
||||
pub use alloc::bstr::{ByteStr, ByteString};
|
||||
|
|
@ -320,6 +320,8 @@
|
|||
// Library features (core):
|
||||
// tidy-alphabetical-start
|
||||
#![feature(array_chunks)]
|
||||
#![feature(bstr)]
|
||||
#![feature(bstr_internals)]
|
||||
#![feature(c_str_module)]
|
||||
#![feature(char_internals)]
|
||||
#![feature(clone_to_uninit)]
|
||||
|
|
@ -581,6 +583,8 @@ pub mod f64;
|
|||
pub mod thread;
|
||||
pub mod ascii;
|
||||
pub mod backtrace;
|
||||
#[unstable(feature = "bstr", issue = "134915")]
|
||||
pub mod bstr;
|
||||
pub mod collections;
|
||||
pub mod env;
|
||||
pub mod error;
|
||||
|
|
|
|||
|
|
@ -1338,7 +1338,7 @@ impl Step for CrtBeginEnd {
|
|||
.file(crtbegin_src)
|
||||
.file(crtend_src);
|
||||
|
||||
// Those flags are defined in src/llvm-project/compiler-rt/lib/crt/CMakeLists.txt
|
||||
// Those flags are defined in src/llvm-project/compiler-rt/lib/builtins/CMakeLists.txt
|
||||
// Currently only consumer of those objects is musl, which use .init_array/.fini_array
|
||||
// instead of .ctors/.dtors
|
||||
cfg.flag("-std=c11")
|
||||
|
|
|
|||
|
|
@ -87,7 +87,7 @@ impl Step for CrateBootstrap {
|
|||
&[],
|
||||
);
|
||||
let crate_name = path.rsplit_once('/').unwrap().1;
|
||||
run_cargo_test(cargo, &[], &[], crate_name, crate_name, compiler, bootstrap_host, builder);
|
||||
run_cargo_test(cargo, &[], &[], crate_name, crate_name, bootstrap_host, builder);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -143,7 +143,6 @@ You can skip linkcheck with --skip src/tools/linkchecker"
|
|||
&[],
|
||||
"linkchecker",
|
||||
"linkchecker self tests",
|
||||
compiler,
|
||||
bootstrap_host,
|
||||
builder,
|
||||
);
|
||||
|
|
@ -312,7 +311,7 @@ impl Step for Cargo {
|
|||
);
|
||||
|
||||
// NOTE: can't use `run_cargo_test` because we need to overwrite `PATH`
|
||||
let mut cargo = prepare_cargo_test(cargo, &[], &[], "cargo", compiler, self.host, builder);
|
||||
let mut cargo = prepare_cargo_test(cargo, &[], &[], "cargo", self.host, builder);
|
||||
|
||||
// Don't run cross-compile tests, we may not have cross-compiled libstd libs
|
||||
// available.
|
||||
|
|
@ -397,7 +396,7 @@ impl Step for RustAnalyzer {
|
|||
cargo.env("SKIP_SLOW_TESTS", "1");
|
||||
|
||||
cargo.add_rustc_lib_path(builder);
|
||||
run_cargo_test(cargo, &[], &[], "rust-analyzer", "rust-analyzer", compiler, host, builder);
|
||||
run_cargo_test(cargo, &[], &[], "rust-analyzer", "rust-analyzer", host, builder);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -445,7 +444,7 @@ impl Step for Rustfmt {
|
|||
|
||||
cargo.add_rustc_lib_path(builder);
|
||||
|
||||
run_cargo_test(cargo, &[], &[], "rustfmt", "rustfmt", compiler, host, builder);
|
||||
run_cargo_test(cargo, &[], &[], "rustfmt", "rustfmt", host, builder);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -565,7 +564,7 @@ impl Step for Miri {
|
|||
|
||||
// We can NOT use `run_cargo_test` since Miri's integration tests do not use the usual test
|
||||
// harness and therefore do not understand the flags added by `add_flags_and_try_run_test`.
|
||||
let mut cargo = prepare_cargo_test(cargo, &[], &[], "miri", host_compiler, host, builder);
|
||||
let mut cargo = prepare_cargo_test(cargo, &[], &[], "miri", host, builder);
|
||||
|
||||
// miri tests need to know about the stage sysroot
|
||||
cargo.env("MIRI_SYSROOT", &miri_sysroot);
|
||||
|
|
@ -713,16 +712,7 @@ impl Step for CompiletestTest {
|
|||
&[],
|
||||
);
|
||||
cargo.allow_features("test");
|
||||
run_cargo_test(
|
||||
cargo,
|
||||
&[],
|
||||
&[],
|
||||
"compiletest",
|
||||
"compiletest self test",
|
||||
compiler,
|
||||
host,
|
||||
builder,
|
||||
);
|
||||
run_cargo_test(cargo, &[], &[], "compiletest", "compiletest self test", host, builder);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -769,7 +759,7 @@ impl Step for Clippy {
|
|||
cargo.env("HOST_LIBS", host_libs);
|
||||
|
||||
cargo.add_rustc_lib_path(builder);
|
||||
let cargo = prepare_cargo_test(cargo, &[], &[], "clippy", compiler, host, builder);
|
||||
let cargo = prepare_cargo_test(cargo, &[], &[], "clippy", host, builder);
|
||||
|
||||
let _guard = builder.msg_sysroot_tool(Kind::Test, compiler.stage, "clippy", host, host);
|
||||
|
||||
|
|
@ -1294,7 +1284,6 @@ impl Step for CrateRunMakeSupport {
|
|||
&[],
|
||||
"run-make-support",
|
||||
"run-make-support self test",
|
||||
compiler,
|
||||
host,
|
||||
builder,
|
||||
);
|
||||
|
|
@ -1334,16 +1323,7 @@ impl Step for CrateBuildHelper {
|
|||
&[],
|
||||
);
|
||||
cargo.allow_features("test");
|
||||
run_cargo_test(
|
||||
cargo,
|
||||
&[],
|
||||
&[],
|
||||
"build_helper",
|
||||
"build_helper self test",
|
||||
compiler,
|
||||
host,
|
||||
builder,
|
||||
);
|
||||
run_cargo_test(cargo, &[], &[], "build_helper", "build_helper self test", host, builder);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -2540,19 +2520,17 @@ impl Step for CrateLibrustc {
|
|||
/// Given a `cargo test` subcommand, add the appropriate flags and run it.
|
||||
///
|
||||
/// Returns whether the test succeeded.
|
||||
#[allow(clippy::too_many_arguments)] // FIXME: reduce the number of args and remove this.
|
||||
fn run_cargo_test<'a>(
|
||||
cargo: impl Into<BootstrapCommand>,
|
||||
cargo: builder::Cargo,
|
||||
libtest_args: &[&str],
|
||||
crates: &[String],
|
||||
primary_crate: &str,
|
||||
description: impl Into<Option<&'a str>>,
|
||||
compiler: Compiler,
|
||||
target: TargetSelection,
|
||||
builder: &Builder<'_>,
|
||||
) -> bool {
|
||||
let mut cargo =
|
||||
prepare_cargo_test(cargo, libtest_args, crates, primary_crate, compiler, target, builder);
|
||||
let compiler = cargo.compiler();
|
||||
let mut cargo = prepare_cargo_test(cargo, libtest_args, crates, primary_crate, target, builder);
|
||||
let _time = helpers::timeit(builder);
|
||||
let _group = description.into().and_then(|what| {
|
||||
builder.msg_sysroot_tool(Kind::Test, compiler.stage, what, compiler.host, target)
|
||||
|
|
@ -2573,15 +2551,15 @@ fn run_cargo_test<'a>(
|
|||
|
||||
/// Given a `cargo test` subcommand, pass it the appropriate test flags given a `builder`.
|
||||
fn prepare_cargo_test(
|
||||
cargo: impl Into<BootstrapCommand>,
|
||||
cargo: builder::Cargo,
|
||||
libtest_args: &[&str],
|
||||
crates: &[String],
|
||||
primary_crate: &str,
|
||||
compiler: Compiler,
|
||||
target: TargetSelection,
|
||||
builder: &Builder<'_>,
|
||||
) -> BootstrapCommand {
|
||||
let mut cargo = cargo.into();
|
||||
let compiler = cargo.compiler();
|
||||
let mut cargo: BootstrapCommand = cargo.into();
|
||||
|
||||
// Propagate `--bless` if it has not already been set/unset
|
||||
// Any tools that want to use this should bless if `RUSTC_BLESS` is set to
|
||||
|
|
@ -2793,7 +2771,6 @@ impl Step for Crate {
|
|||
&self.crates,
|
||||
&self.crates[0],
|
||||
&*crate_description(&self.crates),
|
||||
compiler,
|
||||
target,
|
||||
builder,
|
||||
);
|
||||
|
|
@ -2895,7 +2872,6 @@ impl Step for CrateRustdoc {
|
|||
&["rustdoc:0.0.0".to_string()],
|
||||
"rustdoc",
|
||||
"rustdoc",
|
||||
compiler,
|
||||
target,
|
||||
builder,
|
||||
);
|
||||
|
|
@ -2956,7 +2932,6 @@ impl Step for CrateRustdocJsonTypes {
|
|||
&["rustdoc-json-types".to_string()],
|
||||
"rustdoc-json-types",
|
||||
"rustdoc-json-types",
|
||||
compiler,
|
||||
target,
|
||||
builder,
|
||||
);
|
||||
|
|
@ -3113,23 +3088,25 @@ impl Step for Bootstrap {
|
|||
// Use `python -m unittest` manually if you want to pass arguments.
|
||||
check_bootstrap.delay_failure().run(builder);
|
||||
|
||||
let mut cmd = command(&builder.initial_cargo);
|
||||
cmd.arg("test")
|
||||
.current_dir(builder.src.join("src/bootstrap"))
|
||||
.env("RUSTFLAGS", "--cfg test -Cdebuginfo=2")
|
||||
let mut cargo = tool::prepare_tool_cargo(
|
||||
builder,
|
||||
compiler,
|
||||
Mode::ToolBootstrap,
|
||||
host,
|
||||
Kind::Test,
|
||||
"src/bootstrap",
|
||||
SourceType::InTree,
|
||||
&[],
|
||||
);
|
||||
|
||||
cargo
|
||||
.rustflag("-Cdebuginfo=2")
|
||||
.env("CARGO_TARGET_DIR", builder.out.join("bootstrap"))
|
||||
.env("RUSTC_BOOTSTRAP", "1")
|
||||
.env("RUSTDOC", builder.rustdoc(compiler))
|
||||
.env("RUSTC", &builder.initial_rustc);
|
||||
if let Some(flags) = option_env!("RUSTFLAGS") {
|
||||
// Use the same rustc flags for testing as for "normal" compilation,
|
||||
// so that Cargo doesn’t recompile the entire dependency graph every time:
|
||||
// https://github.com/rust-lang/rust/issues/49215
|
||||
cmd.env("RUSTFLAGS", flags);
|
||||
}
|
||||
.env("RUSTC_BOOTSTRAP", "1");
|
||||
|
||||
// bootstrap tests are racy on directory creation so just run them one at a time.
|
||||
// Since there's not many this shouldn't be a problem.
|
||||
run_cargo_test(cmd, &["--test-threads=1"], &[], "bootstrap", None, compiler, host, builder);
|
||||
run_cargo_test(cargo, &["--test-threads=1"], &[], "bootstrap", None, host, builder);
|
||||
}
|
||||
|
||||
fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
|
||||
|
|
@ -3254,7 +3231,7 @@ impl Step for RustInstaller {
|
|||
bootstrap_host,
|
||||
bootstrap_host,
|
||||
);
|
||||
run_cargo_test(cargo, &[], &[], "installer", None, compiler, bootstrap_host, builder);
|
||||
run_cargo_test(cargo, &[], &[], "installer", None, bootstrap_host, builder);
|
||||
|
||||
// We currently don't support running the test.sh script outside linux(?) environments.
|
||||
// Eventually this should likely migrate to #[test]s in rust-installer proper rather than a
|
||||
|
|
@ -3639,16 +3616,7 @@ impl Step for TestFloatParse {
|
|||
&[],
|
||||
);
|
||||
|
||||
run_cargo_test(
|
||||
cargo_test,
|
||||
&[],
|
||||
&[],
|
||||
crate_name,
|
||||
crate_name,
|
||||
compiler,
|
||||
bootstrap_host,
|
||||
builder,
|
||||
);
|
||||
run_cargo_test(cargo_test, &[], &[], crate_name, crate_name, bootstrap_host, builder);
|
||||
|
||||
// Run the actual parse tests.
|
||||
let mut cargo_run = tool::prepare_tool_cargo(
|
||||
|
|
|
|||
|
|
@ -121,6 +121,10 @@ impl Cargo {
|
|||
cargo
|
||||
}
|
||||
|
||||
pub fn compiler(&self) -> Compiler {
|
||||
self.compiler
|
||||
}
|
||||
|
||||
pub fn into_cmd(self) -> BootstrapCommand {
|
||||
self.into()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -92,7 +92,7 @@ fn detect_src_and_out() {
|
|||
// `{build-dir}/bootstrap/debug/deps/bootstrap-c7ee91d5661e2804`
|
||||
// `{build-dir}` can be anywhere, not just in the rust project directory.
|
||||
let dep = Path::new(args.first().unwrap());
|
||||
let expected_out = dep.ancestors().nth(4).unwrap();
|
||||
let expected_out = dep.ancestors().nth(5).unwrap();
|
||||
|
||||
assert_eq!(&cfg.out, expected_out);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -48,6 +48,8 @@ runners:
|
|||
<<: *base-job
|
||||
|
||||
- &job-aarch64-linux
|
||||
# Free some disk space to avoid running out of space during the build.
|
||||
free_disk: true
|
||||
os: ubuntu-22.04-arm
|
||||
|
||||
envs:
|
||||
|
|
|
|||
|
|
@ -18,8 +18,8 @@ use std::path::Path;
|
|||
|
||||
use rustc_ast_pretty::pprust::item_to_string;
|
||||
use rustc_data_structures::sync::Lrc;
|
||||
use rustc_driver::{Compilation, RunCompiler};
|
||||
use rustc_interface::interface::Compiler;
|
||||
use rustc_driver::{Compilation, run_compiler};
|
||||
use rustc_interface::interface::{Compiler, Config};
|
||||
use rustc_middle::ty::TyCtxt;
|
||||
|
||||
struct MyFileLoader;
|
||||
|
|
@ -51,6 +51,10 @@ fn main() {
|
|||
struct MyCallbacks;
|
||||
|
||||
impl rustc_driver::Callbacks for MyCallbacks {
|
||||
fn config(&mut self, config: &mut Config) {
|
||||
config.file_loader = Some(Box::new(MyFileLoader));
|
||||
}
|
||||
|
||||
fn after_crate_root_parsing(
|
||||
&mut self,
|
||||
_compiler: &Compiler,
|
||||
|
|
@ -83,10 +87,5 @@ impl rustc_driver::Callbacks for MyCallbacks {
|
|||
}
|
||||
|
||||
fn main() {
|
||||
match RunCompiler::new(&["main.rs".to_string()], &mut MyCallbacks) {
|
||||
mut compiler => {
|
||||
compiler.set_file_loader(Some(Box::new(MyFileLoader)));
|
||||
compiler.run();
|
||||
}
|
||||
}
|
||||
run_compiler(&["main.rs".to_string()], &mut MyCallbacks);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -18,8 +18,8 @@ use std::path::Path;
|
|||
|
||||
use rustc_ast_pretty::pprust::item_to_string;
|
||||
use rustc_data_structures::sync::Lrc;
|
||||
use rustc_driver::{Compilation, RunCompiler};
|
||||
use rustc_interface::interface::Compiler;
|
||||
use rustc_driver::{Compilation, run_compiler};
|
||||
use rustc_interface::interface::{Compiler, Config};
|
||||
use rustc_middle::ty::TyCtxt;
|
||||
|
||||
struct MyFileLoader;
|
||||
|
|
@ -51,6 +51,10 @@ fn main() {
|
|||
struct MyCallbacks;
|
||||
|
||||
impl rustc_driver::Callbacks for MyCallbacks {
|
||||
fn config(&mut self, config: &mut Config) {
|
||||
config.file_loader = Some(Box::new(MyFileLoader));
|
||||
}
|
||||
|
||||
fn after_crate_root_parsing(
|
||||
&mut self,
|
||||
_compiler: &Compiler,
|
||||
|
|
@ -90,10 +94,5 @@ impl rustc_driver::Callbacks for MyCallbacks {
|
|||
}
|
||||
|
||||
fn main() {
|
||||
match RunCompiler::new(&["main.rs".to_string()], &mut MyCallbacks) {
|
||||
mut compiler => {
|
||||
compiler.set_file_loader(Some(Box::new(MyFileLoader)));
|
||||
compiler.run();
|
||||
}
|
||||
}
|
||||
run_compiler(&["main.rs".to_string()], &mut MyCallbacks);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ The [`rustc_driver`] is essentially `rustc`'s `main` function.
|
|||
It acts as the glue for running the various phases of the compiler in the correct order,
|
||||
using the interface defined in the [`rustc_interface`] crate. Where possible, using [`rustc_driver`] rather than [`rustc_interface`] is recommended.
|
||||
|
||||
The main entry point of [`rustc_driver`] is [`rustc_driver::RunCompiler`][rd_rc].
|
||||
The main entry point of [`rustc_driver`] is [`rustc_driver::run_compiler`][rd_rc].
|
||||
This builder accepts the same command-line args as rustc as well as an implementation of [`Callbacks`][cb] and a couple of other optional options.
|
||||
[`Callbacks`][cb] is a `trait` that allows for custom compiler configuration,
|
||||
as well as allowing custom code to run after different phases of the compilation.
|
||||
|
|
@ -40,7 +40,7 @@ specifically [`rustc_driver_impl::run_compiler`][rdi_rc]
|
|||
[cb]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_driver/trait.Callbacks.html
|
||||
[example]: https://github.com/rust-lang/rustc-dev-guide/blob/master/examples/rustc-interface-example.rs
|
||||
[i_rc]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_interface/interface/fn.run_compiler.html
|
||||
[rd_rc]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_driver/struct.RunCompiler.html
|
||||
[rd_rc]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_driver/fn.run_compiler.html
|
||||
[rdi_rc]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_driver_impl/fn.run_compiler.html
|
||||
[stupid-stats]: https://github.com/nrc/stupid-stats
|
||||
[`nightly-rustc`]: https://doc.rust-lang.org/nightly/nightly-rustc/
|
||||
|
|
|
|||
|
|
@ -389,6 +389,49 @@ fn write_with_opt_paren<T: fmt::Display>(
|
|||
Ok(())
|
||||
}
|
||||
|
||||
impl Display<'_> {
|
||||
fn display_sub_cfgs(
|
||||
&self,
|
||||
fmt: &mut fmt::Formatter<'_>,
|
||||
sub_cfgs: &[Cfg],
|
||||
separator: &str,
|
||||
) -> fmt::Result {
|
||||
let short_longhand = self.1.is_long() && {
|
||||
let all_crate_features =
|
||||
sub_cfgs.iter().all(|sub_cfg| matches!(sub_cfg, Cfg::Cfg(sym::feature, Some(_))));
|
||||
let all_target_features = sub_cfgs
|
||||
.iter()
|
||||
.all(|sub_cfg| matches!(sub_cfg, Cfg::Cfg(sym::target_feature, Some(_))));
|
||||
|
||||
if all_crate_features {
|
||||
fmt.write_str("crate features ")?;
|
||||
true
|
||||
} else if all_target_features {
|
||||
fmt.write_str("target features ")?;
|
||||
true
|
||||
} else {
|
||||
false
|
||||
}
|
||||
};
|
||||
|
||||
for (i, sub_cfg) in sub_cfgs.iter().enumerate() {
|
||||
if i != 0 {
|
||||
fmt.write_str(separator)?;
|
||||
}
|
||||
if let (true, Cfg::Cfg(_, Some(feat))) = (short_longhand, sub_cfg) {
|
||||
if self.1.is_html() {
|
||||
write!(fmt, "<code>{feat}</code>")?;
|
||||
} else {
|
||||
write!(fmt, "`{feat}`")?;
|
||||
}
|
||||
} else {
|
||||
write_with_opt_paren(fmt, !sub_cfg.is_all(), Display(sub_cfg, self.1))?;
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for Display<'_> {
|
||||
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
match *self.0 {
|
||||
|
|
@ -408,79 +451,9 @@ impl fmt::Display for Display<'_> {
|
|||
|
||||
Cfg::Any(ref sub_cfgs) => {
|
||||
let separator = if sub_cfgs.iter().all(Cfg::is_simple) { " or " } else { ", or " };
|
||||
|
||||
let short_longhand = self.1.is_long() && {
|
||||
let all_crate_features = sub_cfgs
|
||||
.iter()
|
||||
.all(|sub_cfg| matches!(sub_cfg, Cfg::Cfg(sym::feature, Some(_))));
|
||||
let all_target_features = sub_cfgs
|
||||
.iter()
|
||||
.all(|sub_cfg| matches!(sub_cfg, Cfg::Cfg(sym::target_feature, Some(_))));
|
||||
|
||||
if all_crate_features {
|
||||
fmt.write_str("crate features ")?;
|
||||
true
|
||||
} else if all_target_features {
|
||||
fmt.write_str("target features ")?;
|
||||
true
|
||||
} else {
|
||||
false
|
||||
}
|
||||
};
|
||||
|
||||
for (i, sub_cfg) in sub_cfgs.iter().enumerate() {
|
||||
if i != 0 {
|
||||
fmt.write_str(separator)?;
|
||||
}
|
||||
if let (true, Cfg::Cfg(_, Some(feat))) = (short_longhand, sub_cfg) {
|
||||
if self.1.is_html() {
|
||||
write!(fmt, "<code>{feat}</code>")?;
|
||||
} else {
|
||||
write!(fmt, "`{feat}`")?;
|
||||
}
|
||||
} else {
|
||||
write_with_opt_paren(fmt, !sub_cfg.is_all(), Display(sub_cfg, self.1))?;
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
Cfg::All(ref sub_cfgs) => {
|
||||
let short_longhand = self.1.is_long() && {
|
||||
let all_crate_features = sub_cfgs
|
||||
.iter()
|
||||
.all(|sub_cfg| matches!(sub_cfg, Cfg::Cfg(sym::feature, Some(_))));
|
||||
let all_target_features = sub_cfgs
|
||||
.iter()
|
||||
.all(|sub_cfg| matches!(sub_cfg, Cfg::Cfg(sym::target_feature, Some(_))));
|
||||
|
||||
if all_crate_features {
|
||||
fmt.write_str("crate features ")?;
|
||||
true
|
||||
} else if all_target_features {
|
||||
fmt.write_str("target features ")?;
|
||||
true
|
||||
} else {
|
||||
false
|
||||
}
|
||||
};
|
||||
|
||||
for (i, sub_cfg) in sub_cfgs.iter().enumerate() {
|
||||
if i != 0 {
|
||||
fmt.write_str(" and ")?;
|
||||
}
|
||||
if let (true, Cfg::Cfg(_, Some(feat))) = (short_longhand, sub_cfg) {
|
||||
if self.1.is_html() {
|
||||
write!(fmt, "<code>{feat}</code>")?;
|
||||
} else {
|
||||
write!(fmt, "`{feat}`")?;
|
||||
}
|
||||
} else {
|
||||
write_with_opt_paren(fmt, !sub_cfg.is_simple(), Display(sub_cfg, self.1))?;
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
self.display_sub_cfgs(fmt, sub_cfgs, separator)
|
||||
}
|
||||
Cfg::All(ref sub_cfgs) => self.display_sub_cfgs(fmt, sub_cfgs, " and "),
|
||||
|
||||
Cfg::True => fmt.write_str("everywhere"),
|
||||
Cfg::False => fmt.write_str("nowhere"),
|
||||
|
|
|
|||
|
|
@ -1,10 +1,10 @@
|
|||
use std::sync::atomic::AtomicBool;
|
||||
use std::sync::{Arc, LazyLock};
|
||||
use std::sync::LazyLock;
|
||||
use std::{io, mem};
|
||||
|
||||
use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap};
|
||||
use rustc_data_structures::sync::Lrc;
|
||||
use rustc_data_structures::unord::UnordSet;
|
||||
use rustc_driver::USING_INTERNAL_FEATURES;
|
||||
use rustc_errors::TerminalUrl;
|
||||
use rustc_errors::codes::*;
|
||||
use rustc_errors::emitter::{
|
||||
|
|
@ -221,7 +221,6 @@ pub(crate) fn create_config(
|
|||
..
|
||||
}: RustdocOptions,
|
||||
RenderOptions { document_private, .. }: &RenderOptions,
|
||||
using_internal_features: Arc<AtomicBool>,
|
||||
) -> rustc_interface::Config {
|
||||
// Add the doc cfg into the doc build.
|
||||
cfgs.push("doc".to_string());
|
||||
|
|
@ -316,7 +315,7 @@ pub(crate) fn create_config(
|
|||
make_codegen_backend: None,
|
||||
registry: rustc_driver::diagnostics_registry(),
|
||||
ice_file: None,
|
||||
using_internal_features,
|
||||
using_internal_features: &USING_INTERNAL_FEATURES,
|
||||
expanded_args,
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -193,7 +193,7 @@ pub(crate) fn run(dcx: DiagCtxtHandle<'_>, input: Input, options: RustdocOptions
|
|||
make_codegen_backend: None,
|
||||
registry: rustc_driver::diagnostics_registry(),
|
||||
ice_file: None,
|
||||
using_internal_features: Arc::default(),
|
||||
using_internal_features: &rustc_driver::USING_INTERNAL_FEATURES,
|
||||
expanded_args: options.expanded_args.clone(),
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -150,8 +150,9 @@ pub(crate) fn comma_sep<T: Display>(
|
|||
items: impl Iterator<Item = T>,
|
||||
space_after_comma: bool,
|
||||
) -> impl Display {
|
||||
display_fn(move |f| {
|
||||
for (i, item) in items.enumerate() {
|
||||
let items = Cell::new(Some(items));
|
||||
fmt::from_fn(move |f| {
|
||||
for (i, item) in items.take().unwrap().enumerate() {
|
||||
if i != 0 {
|
||||
write!(f, ",{}", if space_after_comma { " " } else { "" })?;
|
||||
}
|
||||
|
|
@ -165,7 +166,7 @@ pub(crate) fn print_generic_bounds<'a, 'tcx: 'a>(
|
|||
bounds: &'a [clean::GenericBound],
|
||||
cx: &'a Context<'tcx>,
|
||||
) -> impl Display + 'a + Captures<'tcx> {
|
||||
display_fn(move |f| {
|
||||
fmt::from_fn(move |f| {
|
||||
let mut bounds_dup = FxHashSet::default();
|
||||
|
||||
for (i, bound) in bounds.iter().filter(|b| bounds_dup.insert(*b)).enumerate() {
|
||||
|
|
@ -183,7 +184,7 @@ impl clean::GenericParamDef {
|
|||
&'a self,
|
||||
cx: &'a Context<'tcx>,
|
||||
) -> impl Display + 'a + Captures<'tcx> {
|
||||
display_fn(move |f| match &self.kind {
|
||||
fmt::from_fn(move |f| match &self.kind {
|
||||
clean::GenericParamDefKind::Lifetime { outlives } => {
|
||||
write!(f, "{}", self.name)?;
|
||||
|
||||
|
|
@ -238,7 +239,7 @@ impl clean::Generics {
|
|||
&'a self,
|
||||
cx: &'a Context<'tcx>,
|
||||
) -> impl Display + 'a + Captures<'tcx> {
|
||||
display_fn(move |f| {
|
||||
fmt::from_fn(move |f| {
|
||||
let mut real_params = self.params.iter().filter(|p| !p.is_synthetic_param()).peekable();
|
||||
if real_params.peek().is_none() {
|
||||
return Ok(());
|
||||
|
|
@ -268,12 +269,12 @@ pub(crate) fn print_where_clause<'a, 'tcx: 'a>(
|
|||
indent: usize,
|
||||
ending: Ending,
|
||||
) -> impl Display + 'a + Captures<'tcx> {
|
||||
display_fn(move |f| {
|
||||
fmt::from_fn(move |f| {
|
||||
let mut where_predicates = gens
|
||||
.where_predicates
|
||||
.iter()
|
||||
.map(|pred| {
|
||||
display_fn(move |f| {
|
||||
fmt::from_fn(move |f| {
|
||||
if f.alternate() {
|
||||
f.write_str(" ")?;
|
||||
} else {
|
||||
|
|
@ -376,17 +377,15 @@ impl clean::Lifetime {
|
|||
impl clean::ConstantKind {
|
||||
pub(crate) fn print(&self, tcx: TyCtxt<'_>) -> impl Display + '_ {
|
||||
let expr = self.expr(tcx);
|
||||
display_fn(
|
||||
move |f| {
|
||||
if f.alternate() { f.write_str(&expr) } else { write!(f, "{}", Escape(&expr)) }
|
||||
},
|
||||
)
|
||||
fmt::from_fn(move |f| {
|
||||
if f.alternate() { f.write_str(&expr) } else { write!(f, "{}", Escape(&expr)) }
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl clean::PolyTrait {
|
||||
fn print<'a, 'tcx: 'a>(&'a self, cx: &'a Context<'tcx>) -> impl Display + 'a + Captures<'tcx> {
|
||||
display_fn(move |f| {
|
||||
fmt::from_fn(move |f| {
|
||||
print_higher_ranked_params_with_space(&self.generic_params, cx, "for").fmt(f)?;
|
||||
self.trait_.print(cx).fmt(f)
|
||||
})
|
||||
|
|
@ -398,7 +397,7 @@ impl clean::GenericBound {
|
|||
&'a self,
|
||||
cx: &'a Context<'tcx>,
|
||||
) -> impl Display + 'a + Captures<'tcx> {
|
||||
display_fn(move |f| match self {
|
||||
fmt::from_fn(move |f| match self {
|
||||
clean::GenericBound::Outlives(lt) => write!(f, "{}", lt.print()),
|
||||
clean::GenericBound::TraitBound(ty, modifiers) => {
|
||||
// `const` and `~const` trait bounds are experimental; don't render them.
|
||||
|
|
@ -430,7 +429,7 @@ impl clean::GenericBound {
|
|||
|
||||
impl clean::GenericArgs {
|
||||
fn print<'a, 'tcx: 'a>(&'a self, cx: &'a Context<'tcx>) -> impl Display + 'a + Captures<'tcx> {
|
||||
display_fn(move |f| {
|
||||
fmt::from_fn(move |f| {
|
||||
match self {
|
||||
clean::GenericArgs::AngleBracketed { args, constraints } => {
|
||||
if !args.is_empty() || !constraints.is_empty() {
|
||||
|
|
@ -950,7 +949,7 @@ fn tybounds<'a, 'tcx: 'a>(
|
|||
lt: &'a Option<clean::Lifetime>,
|
||||
cx: &'a Context<'tcx>,
|
||||
) -> impl Display + 'a + Captures<'tcx> {
|
||||
display_fn(move |f| {
|
||||
fmt::from_fn(move |f| {
|
||||
for (i, bound) in bounds.iter().enumerate() {
|
||||
if i > 0 {
|
||||
write!(f, " + ")?;
|
||||
|
|
@ -971,7 +970,7 @@ fn print_higher_ranked_params_with_space<'a, 'tcx: 'a>(
|
|||
cx: &'a Context<'tcx>,
|
||||
keyword: &'static str,
|
||||
) -> impl Display + 'a + Captures<'tcx> {
|
||||
display_fn(move |f| {
|
||||
fmt::from_fn(move |f| {
|
||||
if !params.is_empty() {
|
||||
f.write_str(keyword)?;
|
||||
f.write_str(if f.alternate() { "<" } else { "<" })?;
|
||||
|
|
@ -982,13 +981,13 @@ fn print_higher_ranked_params_with_space<'a, 'tcx: 'a>(
|
|||
})
|
||||
}
|
||||
|
||||
pub(crate) fn anchor<'a, 'cx: 'a>(
|
||||
pub(crate) fn anchor<'a: 'cx, 'cx>(
|
||||
did: DefId,
|
||||
text: Symbol,
|
||||
cx: &'cx Context<'_>,
|
||||
) -> impl Display + 'a {
|
||||
let parts = href(did, cx);
|
||||
display_fn(move |f| {
|
||||
cx: &'cx Context<'a>,
|
||||
) -> impl Display + Captures<'a> + 'cx {
|
||||
fmt::from_fn(move |f| {
|
||||
let parts = href(did, cx);
|
||||
if let Ok((url, short_ty, fqp)) = parts {
|
||||
write!(
|
||||
f,
|
||||
|
|
@ -1150,7 +1149,7 @@ fn fmt_type(
|
|||
}
|
||||
}
|
||||
clean::BorrowedRef { lifetime: ref l, mutability, type_: ref ty } => {
|
||||
let lt = display_fn(|f| match l {
|
||||
let lt = fmt::from_fn(|f| match l {
|
||||
Some(l) => write!(f, "{} ", l.print()),
|
||||
_ => Ok(()),
|
||||
});
|
||||
|
|
@ -1270,7 +1269,7 @@ impl clean::Type {
|
|||
&'a self,
|
||||
cx: &'a Context<'tcx>,
|
||||
) -> impl Display + 'b + Captures<'tcx> {
|
||||
display_fn(move |f| fmt_type(self, f, false, cx))
|
||||
fmt::from_fn(move |f| fmt_type(self, f, false, cx))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1279,7 +1278,7 @@ impl clean::Path {
|
|||
&'a self,
|
||||
cx: &'a Context<'tcx>,
|
||||
) -> impl Display + 'b + Captures<'tcx> {
|
||||
display_fn(move |f| resolved_path(f, self.def_id(), self, false, false, cx))
|
||||
fmt::from_fn(move |f| resolved_path(f, self.def_id(), self, false, false, cx))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1289,7 +1288,7 @@ impl clean::Impl {
|
|||
use_absolute: bool,
|
||||
cx: &'a Context<'tcx>,
|
||||
) -> impl Display + 'a + Captures<'tcx> {
|
||||
display_fn(move |f| {
|
||||
fmt::from_fn(move |f| {
|
||||
f.write_str("impl")?;
|
||||
self.generics.print(cx).fmt(f)?;
|
||||
f.write_str(" ")?;
|
||||
|
|
@ -1407,7 +1406,7 @@ impl clean::Arguments {
|
|||
&'a self,
|
||||
cx: &'a Context<'tcx>,
|
||||
) -> impl Display + 'a + Captures<'tcx> {
|
||||
display_fn(move |f| {
|
||||
fmt::from_fn(move |f| {
|
||||
for (i, input) in self.values.iter().enumerate() {
|
||||
write!(f, "{}: ", input.name)?;
|
||||
input.type_.print(cx).fmt(f)?;
|
||||
|
|
@ -1447,7 +1446,7 @@ impl clean::FnDecl {
|
|||
&'a self,
|
||||
cx: &'a Context<'tcx>,
|
||||
) -> impl Display + 'b + Captures<'tcx> {
|
||||
display_fn(move |f| {
|
||||
fmt::from_fn(move |f| {
|
||||
let ellipsis = if self.c_variadic { ", ..." } else { "" };
|
||||
if f.alternate() {
|
||||
write!(
|
||||
|
|
@ -1481,10 +1480,10 @@ impl clean::FnDecl {
|
|||
indent: usize,
|
||||
cx: &'a Context<'tcx>,
|
||||
) -> impl Display + 'a + Captures<'tcx> {
|
||||
display_fn(move |f| {
|
||||
fmt::from_fn(move |f| {
|
||||
// First, generate the text form of the declaration, with no line wrapping, and count the bytes.
|
||||
let mut counter = WriteCounter(0);
|
||||
write!(&mut counter, "{:#}", display_fn(|f| { self.inner_full_print(None, f, cx) }))
|
||||
write!(&mut counter, "{:#}", fmt::from_fn(|f| { self.inner_full_print(None, f, cx) }))
|
||||
.unwrap();
|
||||
// If the text form was over 80 characters wide, we will line-wrap our output.
|
||||
let line_wrapping_indent =
|
||||
|
|
@ -1566,7 +1565,7 @@ impl clean::FnDecl {
|
|||
&'a self,
|
||||
cx: &'a Context<'tcx>,
|
||||
) -> impl Display + 'a + Captures<'tcx> {
|
||||
display_fn(move |f| match &self.output {
|
||||
fmt::from_fn(move |f| match &self.output {
|
||||
clean::Tuple(tys) if tys.is_empty() => Ok(()),
|
||||
ty if f.alternate() => {
|
||||
write!(f, " -> {:#}", ty.print(cx))
|
||||
|
|
@ -1618,7 +1617,7 @@ pub(crate) fn visibility_print_with_space<'a, 'tcx: 'a>(
|
|||
};
|
||||
|
||||
let is_doc_hidden = item.is_doc_hidden();
|
||||
display_fn(move |f| {
|
||||
fmt::from_fn(move |f| {
|
||||
if is_doc_hidden {
|
||||
f.write_str("#[doc(hidden)] ")?;
|
||||
}
|
||||
|
|
@ -1692,7 +1691,7 @@ impl clean::Import {
|
|||
&'a self,
|
||||
cx: &'a Context<'tcx>,
|
||||
) -> impl Display + 'a + Captures<'tcx> {
|
||||
display_fn(move |f| match self.kind {
|
||||
fmt::from_fn(move |f| match self.kind {
|
||||
clean::ImportKind::Simple(name) => {
|
||||
if name == self.source.path.last() {
|
||||
write!(f, "use {};", self.source.print(cx))
|
||||
|
|
@ -1716,7 +1715,7 @@ impl clean::ImportSource {
|
|||
&'a self,
|
||||
cx: &'a Context<'tcx>,
|
||||
) -> impl Display + 'a + Captures<'tcx> {
|
||||
display_fn(move |f| match self.did {
|
||||
fmt::from_fn(move |f| match self.did {
|
||||
Some(did) => resolved_path(f, did, &self.path, true, false, cx),
|
||||
_ => {
|
||||
for seg in &self.path.segments[..self.path.segments.len() - 1] {
|
||||
|
|
@ -1744,7 +1743,7 @@ impl clean::AssocItemConstraint {
|
|||
&'a self,
|
||||
cx: &'a Context<'tcx>,
|
||||
) -> impl Display + 'a + Captures<'tcx> {
|
||||
display_fn(move |f| {
|
||||
fmt::from_fn(move |f| {
|
||||
f.write_str(self.assoc.name.as_str())?;
|
||||
self.assoc.args.print(cx).fmt(f)?;
|
||||
match self.kind {
|
||||
|
|
@ -1765,7 +1764,7 @@ impl clean::AssocItemConstraint {
|
|||
}
|
||||
|
||||
pub(crate) fn print_abi_with_space(abi: ExternAbi) -> impl Display {
|
||||
display_fn(move |f| {
|
||||
fmt::from_fn(move |f| {
|
||||
let quot = if f.alternate() { "\"" } else { """ };
|
||||
match abi {
|
||||
ExternAbi::Rust => Ok(()),
|
||||
|
|
@ -1783,7 +1782,7 @@ impl clean::GenericArg {
|
|||
&'a self,
|
||||
cx: &'a Context<'tcx>,
|
||||
) -> impl Display + 'a + Captures<'tcx> {
|
||||
display_fn(move |f| match self {
|
||||
fmt::from_fn(move |f| match self {
|
||||
clean::GenericArg::Lifetime(lt) => lt.print().fmt(f),
|
||||
clean::GenericArg::Type(ty) => ty.print(cx).fmt(f),
|
||||
clean::GenericArg::Const(ct) => ct.print(cx.tcx()).fmt(f),
|
||||
|
|
@ -1797,24 +1796,9 @@ impl clean::Term {
|
|||
&'a self,
|
||||
cx: &'a Context<'tcx>,
|
||||
) -> impl Display + 'a + Captures<'tcx> {
|
||||
display_fn(move |f| match self {
|
||||
fmt::from_fn(move |f| match self {
|
||||
clean::Term::Type(ty) => ty.print(cx).fmt(f),
|
||||
clean::Term::Constant(ct) => ct.print(cx.tcx()).fmt(f),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn display_fn(f: impl FnOnce(&mut fmt::Formatter<'_>) -> fmt::Result) -> impl Display {
|
||||
struct WithFormatter<F>(Cell<Option<F>>);
|
||||
|
||||
impl<F> Display for WithFormatter<F>
|
||||
where
|
||||
F: FnOnce(&mut fmt::Formatter<'_>) -> fmt::Result,
|
||||
{
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
(self.0.take()).unwrap()(f)
|
||||
}
|
||||
}
|
||||
|
||||
WithFormatter(Cell::new(Some(f)))
|
||||
}
|
||||
|
|
|
|||
|
|
@ -233,7 +233,7 @@ pub(super) fn write_code(
|
|||
out: &mut impl Write,
|
||||
src: &str,
|
||||
href_context: Option<HrefContext<'_, '_>>,
|
||||
decoration_info: Option<DecorationInfo>,
|
||||
decoration_info: Option<&DecorationInfo>,
|
||||
) {
|
||||
// This replace allows to fix how the code source with DOS backline characters is displayed.
|
||||
let src = src.replace("\r\n", "\n");
|
||||
|
|
@ -510,12 +510,12 @@ struct Decorations {
|
|||
}
|
||||
|
||||
impl Decorations {
|
||||
fn new(info: DecorationInfo) -> Self {
|
||||
fn new(info: &DecorationInfo) -> Self {
|
||||
// Extract tuples (start, end, kind) into separate sequences of (start, kind) and (end).
|
||||
let (mut starts, mut ends): (Vec<_>, Vec<_>) = info
|
||||
.0
|
||||
.into_iter()
|
||||
.flat_map(|(kind, ranges)| ranges.into_iter().map(move |(lo, hi)| ((lo, kind), hi)))
|
||||
.iter()
|
||||
.flat_map(|(&kind, ranges)| ranges.into_iter().map(move |&(lo, hi)| ((lo, kind), hi)))
|
||||
.unzip();
|
||||
|
||||
// Sort the sequences in document order.
|
||||
|
|
@ -542,7 +542,7 @@ struct Classifier<'src> {
|
|||
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: &str, file_span: Span, decoration_info: Option<DecorationInfo>) -> Classifier<'_> {
|
||||
fn new(src: &'src str, file_span: Span, decoration_info: Option<&DecorationInfo>) -> Self {
|
||||
let tokens = PeekIter::new(TokenIter { src, cursor: Cursor::new(src) });
|
||||
let decorations = decoration_info.map(Decorations::new);
|
||||
Classifier {
|
||||
|
|
|
|||
|
|
@ -78,7 +78,7 @@ let a = 4;";
|
|||
decorations.insert("example2", vec![(22, 32)]);
|
||||
|
||||
let mut html = Buffer::new();
|
||||
write_code(&mut html, src, None, Some(DecorationInfo(decorations)));
|
||||
write_code(&mut html, src, None, Some(&DecorationInfo(decorations)));
|
||||
expect_file!["fixtures/decorations.html"].assert_eq(&html.into_inner());
|
||||
});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -69,9 +69,9 @@ use crate::formats::cache::Cache;
|
|||
use crate::formats::item_type::ItemType;
|
||||
use crate::html::escape::Escape;
|
||||
use crate::html::format::{
|
||||
Buffer, Ending, HrefError, PrintWithSpace, display_fn, href, join_with_double_colon,
|
||||
print_abi_with_space, print_constness_with_space, print_default_space, print_generic_bounds,
|
||||
print_where_clause, visibility_print_with_space,
|
||||
Buffer, Ending, HrefError, PrintWithSpace, href, join_with_double_colon, print_abi_with_space,
|
||||
print_constness_with_space, print_default_space, print_generic_bounds, print_where_clause,
|
||||
visibility_print_with_space,
|
||||
};
|
||||
use crate::html::markdown::{
|
||||
HeadingOffset, IdMap, Markdown, MarkdownItemInfo, MarkdownSummaryLine,
|
||||
|
|
@ -82,13 +82,14 @@ use crate::scrape_examples::{CallData, CallLocation};
|
|||
use crate::{DOC_RUST_LANG_ORG_CHANNEL, try_none};
|
||||
|
||||
pub(crate) fn ensure_trailing_slash(v: &str) -> impl fmt::Display + '_ {
|
||||
crate::html::format::display_fn(move |f| {
|
||||
fmt::from_fn(move |f| {
|
||||
if !v.ends_with('/') && !v.is_empty() { write!(f, "{v}/") } else { f.write_str(v) }
|
||||
})
|
||||
}
|
||||
|
||||
/// Specifies whether rendering directly implemented trait items or ones from a certain Deref
|
||||
/// impl.
|
||||
#[derive(Copy, Clone)]
|
||||
pub(crate) enum AssocItemRender<'a> {
|
||||
All,
|
||||
DerefFor { trait_: &'a clean::Path, type_: &'a clean::Type, deref_mut_: bool },
|
||||
|
|
@ -309,9 +310,7 @@ impl ItemEntry {
|
|||
|
||||
impl ItemEntry {
|
||||
pub(crate) fn print(&self) -> impl fmt::Display + '_ {
|
||||
crate::html::format::display_fn(move |f| {
|
||||
write!(f, "<a href=\"{}\">{}</a>", self.url, Escape(&self.name))
|
||||
})
|
||||
fmt::from_fn(move |f| write!(f, "<a href=\"{}\">{}</a>", self.url, Escape(&self.name)))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -513,7 +512,7 @@ fn document<'a, 'cx: 'a>(
|
|||
info!("Documenting {name}");
|
||||
}
|
||||
|
||||
display_fn(move |f| {
|
||||
fmt::from_fn(move |f| {
|
||||
document_item_info(cx, item, parent).render_into(f).unwrap();
|
||||
if parent.is_none() {
|
||||
write!(f, "{}", document_full_collapsible(item, cx, heading_offset))
|
||||
|
|
@ -530,7 +529,7 @@ fn render_markdown<'a, 'cx: 'a>(
|
|||
links: Vec<RenderedLink>,
|
||||
heading_offset: HeadingOffset,
|
||||
) -> impl fmt::Display + 'a + Captures<'cx> {
|
||||
display_fn(move |f| {
|
||||
fmt::from_fn(move |f| {
|
||||
write!(
|
||||
f,
|
||||
"<div class=\"docblock\">{}</div>",
|
||||
|
|
@ -557,7 +556,7 @@ fn document_short<'a, 'cx: 'a>(
|
|||
parent: &'a clean::Item,
|
||||
show_def_docs: bool,
|
||||
) -> impl fmt::Display + 'a + Captures<'cx> {
|
||||
display_fn(move |f| {
|
||||
fmt::from_fn(move |f| {
|
||||
document_item_info(cx, item, Some(parent)).render_into(f).unwrap();
|
||||
if !show_def_docs {
|
||||
return Ok(());
|
||||
|
|
@ -605,7 +604,7 @@ fn document_full_inner<'a, 'cx: 'a>(
|
|||
is_collapsible: bool,
|
||||
heading_offset: HeadingOffset,
|
||||
) -> impl fmt::Display + 'a + Captures<'cx> {
|
||||
display_fn(move |f| {
|
||||
fmt::from_fn(move |f| {
|
||||
if let Some(s) = item.opt_doc_value() {
|
||||
debug!("Doc block: =====\n{s}\n=====");
|
||||
if is_collapsible {
|
||||
|
|
@ -1159,7 +1158,7 @@ fn render_attributes_in_pre<'a, 'tcx: 'a>(
|
|||
prefix: &'a str,
|
||||
cx: &'a Context<'tcx>,
|
||||
) -> impl fmt::Display + Captures<'a> + Captures<'tcx> {
|
||||
crate::html::format::display_fn(move |f| {
|
||||
fmt::from_fn(move |f| {
|
||||
for a in it.attributes(cx.tcx(), cx.cache(), false) {
|
||||
writeln!(f, "{prefix}{a}")?;
|
||||
}
|
||||
|
|
@ -1256,9 +1255,9 @@ fn render_assoc_items<'a, 'cx: 'a>(
|
|||
it: DefId,
|
||||
what: AssocItemRender<'a>,
|
||||
) -> impl fmt::Display + 'a + Captures<'cx> {
|
||||
let mut derefs = DefIdSet::default();
|
||||
derefs.insert(it);
|
||||
display_fn(move |f| {
|
||||
fmt::from_fn(move |f| {
|
||||
let mut derefs = DefIdSet::default();
|
||||
derefs.insert(it);
|
||||
render_assoc_items_inner(f, cx, containing_item, it, what, &mut derefs);
|
||||
Ok(())
|
||||
})
|
||||
|
|
@ -2577,7 +2576,7 @@ fn render_call_locations<W: fmt::Write>(mut w: W, cx: &Context<'_>, item: &clean
|
|||
file_span,
|
||||
cx,
|
||||
&cx.root_path(),
|
||||
highlight::DecorationInfo(decoration_info),
|
||||
&highlight::DecorationInfo(decoration_info),
|
||||
sources::SourceContext::Embedded(sources::ScrapedInfo {
|
||||
needs_expansion,
|
||||
offset: line_min,
|
||||
|
|
|
|||
|
|
@ -30,7 +30,7 @@ use crate::formats::Impl;
|
|||
use crate::formats::item_type::ItemType;
|
||||
use crate::html::escape::{Escape, EscapeBodyTextWithWbr};
|
||||
use crate::html::format::{
|
||||
Buffer, Ending, PrintWithSpace, display_fn, join_with_double_colon, print_abi_with_space,
|
||||
Buffer, Ending, PrintWithSpace, join_with_double_colon, print_abi_with_space,
|
||||
print_constness_with_space, print_where_clause, visibility_print_with_space,
|
||||
};
|
||||
use crate::html::markdown::{HeadingOffset, MarkdownSummaryLine};
|
||||
|
|
@ -92,7 +92,7 @@ macro_rules! item_template_methods {
|
|||
() => {};
|
||||
(document $($rest:tt)*) => {
|
||||
fn document<'b>(&'b self) -> impl fmt::Display + Captures<'a> + 'b + Captures<'cx> {
|
||||
display_fn(move |f| {
|
||||
fmt::from_fn(move |f| {
|
||||
let (item, cx) = self.item_and_cx();
|
||||
let v = document(cx, item, None, HeadingOffset::H2);
|
||||
write!(f, "{v}")
|
||||
|
|
@ -102,7 +102,7 @@ macro_rules! item_template_methods {
|
|||
};
|
||||
(document_type_layout $($rest:tt)*) => {
|
||||
fn document_type_layout<'b>(&'b self) -> impl fmt::Display + Captures<'a> + 'b + Captures<'cx> {
|
||||
display_fn(move |f| {
|
||||
fmt::from_fn(move |f| {
|
||||
let (item, cx) = self.item_and_cx();
|
||||
let def_id = item.item_id.expect_def_id();
|
||||
let v = document_type_layout(cx, def_id);
|
||||
|
|
@ -113,7 +113,7 @@ macro_rules! item_template_methods {
|
|||
};
|
||||
(render_attributes_in_pre $($rest:tt)*) => {
|
||||
fn render_attributes_in_pre<'b>(&'b self) -> impl fmt::Display + Captures<'a> + 'b + Captures<'cx> {
|
||||
display_fn(move |f| {
|
||||
fmt::from_fn(move |f| {
|
||||
let (item, cx) = self.item_and_cx();
|
||||
let v = render_attributes_in_pre(item, "", cx);
|
||||
write!(f, "{v}")
|
||||
|
|
@ -123,7 +123,7 @@ macro_rules! item_template_methods {
|
|||
};
|
||||
(render_assoc_items $($rest:tt)*) => {
|
||||
fn render_assoc_items<'b>(&'b self) -> impl fmt::Display + Captures<'a> + 'b + Captures<'cx> {
|
||||
display_fn(move |f| {
|
||||
fmt::from_fn(move |f| {
|
||||
let (item, cx) = self.item_and_cx();
|
||||
let def_id = item.item_id.expect_def_id();
|
||||
let v = render_assoc_items(cx, item, def_id, AssocItemRender::All);
|
||||
|
|
@ -520,13 +520,13 @@ fn extra_info_tags<'a, 'tcx: 'a>(
|
|||
parent: &'a clean::Item,
|
||||
import_def_id: Option<DefId>,
|
||||
) -> impl fmt::Display + 'a + Captures<'tcx> {
|
||||
display_fn(move |f| {
|
||||
fmt::from_fn(move |f| {
|
||||
fn tag_html<'a>(
|
||||
class: &'a str,
|
||||
title: &'a str,
|
||||
contents: &'a str,
|
||||
) -> impl fmt::Display + 'a {
|
||||
display_fn(move |f| {
|
||||
fmt::from_fn(move |f| {
|
||||
write!(
|
||||
f,
|
||||
r#"<wbr><span class="stab {class}" title="{title}">{contents}</span>"#,
|
||||
|
|
@ -1375,7 +1375,7 @@ fn item_union(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, s: &clean::Uni
|
|||
|
||||
impl<'a, 'cx: 'a> ItemUnion<'a, 'cx> {
|
||||
fn render_union<'b>(&'b self) -> impl fmt::Display + Captures<'a> + 'b + Captures<'cx> {
|
||||
display_fn(move |f| {
|
||||
fmt::from_fn(move |f| {
|
||||
let v = render_union(self.it, Some(&self.s.generics), &self.s.fields, self.cx);
|
||||
write!(f, "{v}")
|
||||
})
|
||||
|
|
@ -1385,7 +1385,7 @@ fn item_union(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, s: &clean::Uni
|
|||
&'b self,
|
||||
field: &'a clean::Item,
|
||||
) -> impl fmt::Display + Captures<'a> + 'b + Captures<'cx> {
|
||||
display_fn(move |f| {
|
||||
fmt::from_fn(move |f| {
|
||||
let v = document(self.cx, field, Some(self.it), HeadingOffset::H3);
|
||||
write!(f, "{v}")
|
||||
})
|
||||
|
|
@ -1399,7 +1399,7 @@ fn item_union(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, s: &clean::Uni
|
|||
&'b self,
|
||||
ty: &'a clean::Type,
|
||||
) -> impl fmt::Display + Captures<'a> + 'b + Captures<'cx> {
|
||||
display_fn(move |f| {
|
||||
fmt::from_fn(move |f| {
|
||||
let v = ty.print(self.cx);
|
||||
write!(f, "{v}")
|
||||
})
|
||||
|
|
@ -1426,7 +1426,7 @@ fn print_tuple_struct_fields<'a, 'cx: 'a>(
|
|||
cx: &'a Context<'cx>,
|
||||
s: &'a [clean::Item],
|
||||
) -> impl fmt::Display + 'a + Captures<'cx> {
|
||||
display_fn(|f| {
|
||||
fmt::from_fn(|f| {
|
||||
if !s.is_empty()
|
||||
&& s.iter().all(|field| {
|
||||
matches!(field.kind, clean::StrippedItem(box clean::StructFieldItem(..)))
|
||||
|
|
@ -2151,7 +2151,7 @@ fn render_union<'a, 'cx: 'a>(
|
|||
fields: &'a [clean::Item],
|
||||
cx: &'a Context<'cx>,
|
||||
) -> impl fmt::Display + 'a + Captures<'cx> {
|
||||
display_fn(move |mut f| {
|
||||
fmt::from_fn(move |mut f| {
|
||||
write!(f, "{}union {}", visibility_print_with_space(it, cx), it.name.unwrap(),)?;
|
||||
|
||||
let where_displayed = g
|
||||
|
|
@ -2331,7 +2331,7 @@ fn document_non_exhaustive_header(item: &clean::Item) -> &str {
|
|||
}
|
||||
|
||||
fn document_non_exhaustive(item: &clean::Item) -> impl fmt::Display + '_ {
|
||||
display_fn(|f| {
|
||||
fmt::from_fn(|f| {
|
||||
if item.is_non_exhaustive() {
|
||||
write!(
|
||||
f,
|
||||
|
|
|
|||
|
|
@ -100,18 +100,17 @@ impl<'a> Link<'a> {
|
|||
}
|
||||
|
||||
pub(crate) mod filters {
|
||||
use std::fmt::Display;
|
||||
use std::fmt::{self, Display};
|
||||
|
||||
use rinja::filters::Safe;
|
||||
|
||||
use crate::html::escape::EscapeBodyTextWithWbr;
|
||||
use crate::html::render::display_fn;
|
||||
pub(crate) fn wrapped<T>(v: T) -> rinja::Result<Safe<impl Display>>
|
||||
where
|
||||
T: Display,
|
||||
{
|
||||
let string = v.to_string();
|
||||
Ok(Safe(display_fn(move |f| EscapeBodyTextWithWbr(&string).fmt(f))))
|
||||
Ok(Safe(fmt::from_fn(move |f| EscapeBodyTextWithWbr(&string).fmt(f))))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -9,7 +9,6 @@ use rustc_middle::ty::layout::LayoutError;
|
|||
use rustc_middle::ty::{self};
|
||||
use rustc_span::symbol::Symbol;
|
||||
|
||||
use crate::html::format::display_fn;
|
||||
use crate::html::render::Context;
|
||||
|
||||
#[derive(Template)]
|
||||
|
|
@ -31,7 +30,7 @@ pub(crate) fn document_type_layout<'a, 'cx: 'a>(
|
|||
cx: &'a Context<'cx>,
|
||||
ty_def_id: DefId,
|
||||
) -> impl fmt::Display + 'a + Captures<'cx> {
|
||||
display_fn(move |f| {
|
||||
fmt::from_fn(move |f| {
|
||||
if !cx.shared.show_type_layout {
|
||||
return Ok(());
|
||||
}
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@ use crate::clean::utils::has_doc_flag;
|
|||
use crate::docfs::PathError;
|
||||
use crate::error::Error;
|
||||
use crate::html::render::Context;
|
||||
use crate::html::{format, highlight, layout};
|
||||
use crate::html::{highlight, layout};
|
||||
use crate::visit::DocVisitor;
|
||||
|
||||
pub(crate) fn render(cx: &mut Context<'_>, krate: &clean::Crate) -> Result<(), Error> {
|
||||
|
|
@ -249,7 +249,7 @@ impl SourceCollector<'_, '_> {
|
|||
file_span,
|
||||
self.cx,
|
||||
&root_path,
|
||||
highlight::DecorationInfo::default(),
|
||||
&highlight::DecorationInfo::default(),
|
||||
SourceContext::Standalone { file_path },
|
||||
)
|
||||
},
|
||||
|
|
@ -328,13 +328,13 @@ pub(crate) fn print_src(
|
|||
file_span: rustc_span::Span,
|
||||
context: &Context<'_>,
|
||||
root_path: &str,
|
||||
decoration_info: highlight::DecorationInfo,
|
||||
decoration_info: &highlight::DecorationInfo,
|
||||
source_context: SourceContext<'_>,
|
||||
) {
|
||||
let current_href = context
|
||||
.href_from_span(clean::Span::new(file_span), false)
|
||||
.expect("only local crates should have sources emitted");
|
||||
let code = format::display_fn(move |fmt| {
|
||||
let code = fmt::from_fn(move |fmt| {
|
||||
let current_href = context
|
||||
.href_from_span(clean::Span::new(file_span), false)
|
||||
.expect("only local crates should have sources emitted");
|
||||
highlight::write_code(
|
||||
fmt,
|
||||
s,
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@
|
|||
#![feature(rustc_private)]
|
||||
#![feature(assert_matches)]
|
||||
#![feature(box_patterns)]
|
||||
#![feature(debug_closure_helpers)]
|
||||
#![feature(file_buffered)]
|
||||
#![feature(if_let_guard)]
|
||||
#![feature(impl_trait_in_assoc_type)]
|
||||
|
|
@ -73,8 +74,6 @@ extern crate tikv_jemalloc_sys as jemalloc_sys;
|
|||
use std::env::{self, VarError};
|
||||
use std::io::{self, IsTerminal};
|
||||
use std::process;
|
||||
use std::sync::Arc;
|
||||
use std::sync::atomic::AtomicBool;
|
||||
|
||||
use rustc_errors::DiagCtxtHandle;
|
||||
use rustc_interface::interface;
|
||||
|
|
@ -158,7 +157,7 @@ pub fn main() {
|
|||
|
||||
let mut early_dcx = EarlyDiagCtxt::new(ErrorOutputType::default());
|
||||
|
||||
let using_internal_features = rustc_driver::install_ice_hook(
|
||||
rustc_driver::install_ice_hook(
|
||||
"https://github.com/rust-lang/rust/issues/new\
|
||||
?labels=C-bug%2C+I-ICE%2C+T-rustdoc&template=ice.md",
|
||||
|_| (),
|
||||
|
|
@ -179,7 +178,7 @@ pub fn main() {
|
|||
|
||||
let exit_code = rustc_driver::catch_with_exit_code(|| {
|
||||
let at_args = rustc_driver::args::raw_args(&early_dcx)?;
|
||||
main_args(&mut early_dcx, &at_args, using_internal_features);
|
||||
main_args(&mut early_dcx, &at_args);
|
||||
Ok(())
|
||||
});
|
||||
process::exit(exit_code);
|
||||
|
|
@ -768,11 +767,7 @@ fn run_merge_finalize(opt: config::RenderOptions) -> Result<(), error::Error> {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
fn main_args(
|
||||
early_dcx: &mut EarlyDiagCtxt,
|
||||
at_args: &[String],
|
||||
using_internal_features: Arc<AtomicBool>,
|
||||
) {
|
||||
fn main_args(early_dcx: &mut EarlyDiagCtxt, at_args: &[String]) {
|
||||
// Throw away the first argument, the name of the binary.
|
||||
// In case of at_args being empty, as might be the case by
|
||||
// passing empty argument array to execve under some platforms,
|
||||
|
|
@ -825,8 +820,7 @@ fn main_args(
|
|||
(false, Some(md_input)) => {
|
||||
let md_input = md_input.to_owned();
|
||||
let edition = options.edition;
|
||||
let config =
|
||||
core::create_config(input, options, &render_options, using_internal_features);
|
||||
let config = core::create_config(input, options, &render_options);
|
||||
|
||||
// `markdown::render` can invoke `doctest::make_test`, which
|
||||
// requires session globals and a thread pool, so we use
|
||||
|
|
@ -859,7 +853,7 @@ fn main_args(
|
|||
let scrape_examples_options = options.scrape_examples_options.clone();
|
||||
let bin_crate = options.bin_crate;
|
||||
|
||||
let config = core::create_config(input, options, &render_options, using_internal_features);
|
||||
let config = core::create_config(input, options, &render_options);
|
||||
|
||||
let registered_lints = config.register_lints.is_some();
|
||||
|
||||
|
|
|
|||
|
|
@ -1099,8 +1099,7 @@ pub struct Trait {
|
|||
pub is_auto: bool,
|
||||
/// Whether the trait is marked as `unsafe`.
|
||||
pub is_unsafe: bool,
|
||||
// FIXME(dyn_compat_renaming): Update the URL once the Reference is updated and hits stable.
|
||||
/// Whether the trait is [dyn compatible](https://doc.rust-lang.org/reference/items/traits.html#object-safety)[^1].
|
||||
/// Whether the trait is [dyn compatible](https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility)[^1].
|
||||
///
|
||||
/// [^1]: Formerly known as "object safe".
|
||||
pub is_dyn_compatible: bool,
|
||||
|
|
|
|||
|
|
@ -186,7 +186,7 @@ pub fn main() {
|
|||
|
||||
rustc_driver::init_rustc_env_logger(&early_dcx);
|
||||
|
||||
let using_internal_features = rustc_driver::install_ice_hook(BUG_REPORT_URL, |dcx| {
|
||||
rustc_driver::install_ice_hook(BUG_REPORT_URL, |dcx| {
|
||||
// FIXME: this macro calls unwrap internally but is called in a panicking context! It's not
|
||||
// as simple as moving the call from the hook to main, because `install_ice_hook` doesn't
|
||||
// accept a generic closure.
|
||||
|
|
@ -236,7 +236,7 @@ pub fn main() {
|
|||
let mut args: Vec<String> = orig_args.clone();
|
||||
pass_sysroot_env_if_given(&mut args, sys_root_env);
|
||||
|
||||
rustc_driver::RunCompiler::new(&args, &mut DefaultCallbacks).run();
|
||||
rustc_driver::run_compiler(&args, &mut DefaultCallbacks);
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
|
|
@ -295,13 +295,9 @@ pub fn main() {
|
|||
let clippy_enabled = !cap_lints_allow && relevant_package && !info_query;
|
||||
if clippy_enabled {
|
||||
args.extend(clippy_args);
|
||||
rustc_driver::RunCompiler::new(&args, &mut ClippyCallbacks { clippy_args_var })
|
||||
.set_using_internal_features(using_internal_features)
|
||||
.run();
|
||||
rustc_driver::run_compiler(&args, &mut ClippyCallbacks { clippy_args_var });
|
||||
} else {
|
||||
rustc_driver::RunCompiler::new(&args, &mut RustcCallbacks { clippy_args_var })
|
||||
.set_using_internal_features(using_internal_features)
|
||||
.run();
|
||||
rustc_driver::run_compiler(&args, &mut RustcCallbacks { clippy_args_var });
|
||||
}
|
||||
Ok(())
|
||||
}))
|
||||
|
|
|
|||
|
|
@ -50,6 +50,29 @@ const LINKCHECK_EXCEPTIONS: &[(&str, &[&str])] = &[
|
|||
("alloc/slice/trait.Concat.html", &["#method.concat"]),
|
||||
("alloc/slice/index.html", &["#method.concat", "#method.join"]),
|
||||
("alloc/vec/struct.Vec.html", &["#method.sort_by_key", "#method.sort_by_cached_key"]),
|
||||
("alloc/bstr/struct.ByteStr.html", &[
|
||||
"#method.to_ascii_uppercase",
|
||||
"#method.to_ascii_lowercase",
|
||||
"core/slice::sort_by_key",
|
||||
"core\\slice::sort_by_key",
|
||||
"#method.sort_by_cached_key",
|
||||
"#method.sort_by_key"
|
||||
]),
|
||||
("alloc/bstr/struct.ByteString.html", &[
|
||||
"#method.to_ascii_uppercase",
|
||||
"#method.to_ascii_lowercase",
|
||||
"core/slice::sort_by_key",
|
||||
"core\\slice::sort_by_key",
|
||||
"#method.sort_by_cached_key",
|
||||
"#method.sort_by_key"
|
||||
]),
|
||||
("core/bstr/struct.ByteStr.html", &[
|
||||
"#method.to_ascii_uppercase",
|
||||
"#method.to_ascii_lowercase",
|
||||
"core/bstr/slice::sort_by_key",
|
||||
"core\\bstr\\slice::sort_by_key",
|
||||
"#method.sort_by_cached_key"
|
||||
]),
|
||||
("core/primitive.str.html", &["#method.to_ascii_uppercase", "#method.to_ascii_lowercase"]),
|
||||
("core/primitive.slice.html", &["#method.to_ascii_uppercase", "#method.to_ascii_lowercase",
|
||||
"core/slice::sort_by_key", "core\\slice::sort_by_key",
|
||||
|
|
|
|||
|
|
@ -30,7 +30,7 @@ use std::ops::Range;
|
|||
use std::path::PathBuf;
|
||||
use std::str::FromStr;
|
||||
use std::sync::atomic::{AtomicI32, Ordering};
|
||||
use std::sync::{Arc, Once};
|
||||
use std::sync::Once;
|
||||
|
||||
use miri::{
|
||||
BacktraceStyle, BorrowTrackerMethod, MiriConfig, MiriEntryFnType, ProvenanceMode, RetagFields,
|
||||
|
|
@ -371,13 +371,10 @@ fn init_late_loggers(early_dcx: &EarlyDiagCtxt, tcx: TyCtxt<'_>) {
|
|||
fn run_compiler_and_exit(
|
||||
args: &[String],
|
||||
callbacks: &mut (dyn rustc_driver::Callbacks + Send),
|
||||
using_internal_features: Arc<std::sync::atomic::AtomicBool>,
|
||||
) -> ! {
|
||||
// Invoke compiler, and handle return code.
|
||||
let exit_code = rustc_driver::catch_with_exit_code(move || {
|
||||
rustc_driver::RunCompiler::new(args, callbacks)
|
||||
.set_using_internal_features(using_internal_features)
|
||||
.run();
|
||||
rustc_driver::run_compiler(args, callbacks);
|
||||
Ok(())
|
||||
});
|
||||
std::process::exit(exit_code)
|
||||
|
|
@ -468,8 +465,7 @@ fn main() {
|
|||
// If the environment asks us to actually be rustc, then do that.
|
||||
if let Some(crate_kind) = env::var_os("MIRI_BE_RUSTC") {
|
||||
// Earliest rustc setup.
|
||||
let using_internal_features =
|
||||
rustc_driver::install_ice_hook(rustc_driver::DEFAULT_BUG_REPORT_URL, |_| ());
|
||||
rustc_driver::install_ice_hook(rustc_driver::DEFAULT_BUG_REPORT_URL, |_| ());
|
||||
rustc_driver::init_rustc_env_logger(&early_dcx);
|
||||
|
||||
let target_crate = if crate_kind == "target" {
|
||||
|
|
@ -493,16 +489,11 @@ fn main() {
|
|||
}
|
||||
|
||||
// We cannot use `rustc_driver::main` as we want it to use `args` as the CLI arguments.
|
||||
run_compiler_and_exit(
|
||||
&args,
|
||||
&mut MiriBeRustCompilerCalls { target_crate },
|
||||
using_internal_features,
|
||||
)
|
||||
run_compiler_and_exit(&args, &mut MiriBeRustCompilerCalls { target_crate })
|
||||
}
|
||||
|
||||
// Add an ICE bug report hook.
|
||||
let using_internal_features =
|
||||
rustc_driver::install_ice_hook("https://github.com/rust-lang/miri/issues/new", |_| ());
|
||||
rustc_driver::install_ice_hook("https://github.com/rust-lang/miri/issues/new", |_| ());
|
||||
|
||||
// Init loggers the Miri way.
|
||||
init_early_loggers(&early_dcx);
|
||||
|
|
@ -736,9 +727,5 @@ fn main() {
|
|||
|
||||
debug!("rustc arguments: {:?}", rustc_args);
|
||||
debug!("crate arguments: {:?}", miri_config.args);
|
||||
run_compiler_and_exit(
|
||||
&rustc_args,
|
||||
&mut MiriCompilerCalls::new(miri_config, many_seeds),
|
||||
using_internal_features,
|
||||
)
|
||||
run_compiler_and_exit(&rustc_args, &mut MiriCompilerCalls::new(miri_config, many_seeds))
|
||||
}
|
||||
|
|
|
|||
|
|
@ -25,7 +25,7 @@ fn main() {
|
|||
let mut count = 1;
|
||||
let args = vec!["compiler-calls".to_string(), "foo.rs".to_string()];
|
||||
rustc_driver::catch_fatal_errors(|| -> interface::Result<()> {
|
||||
rustc_driver::RunCompiler::new(&args, &mut TestCalls { count: &mut count }).run();
|
||||
rustc_driver::run_compiler(&args, &mut TestCalls { count: &mut count });
|
||||
Ok(())
|
||||
})
|
||||
.ok();
|
||||
|
|
|
|||
|
|
@ -47,7 +47,7 @@ fn main() {
|
|||
rustc_args.push("-Zpolonius".to_owned());
|
||||
let mut callbacks = CompilerCalls::default();
|
||||
// Call the Rust compiler with our callbacks.
|
||||
rustc_driver::RunCompiler::new(&rustc_args, &mut callbacks).run();
|
||||
rustc_driver::run_compiler(&rustc_args, &mut callbacks);
|
||||
Ok(())
|
||||
});
|
||||
std::process::exit(exit_code);
|
||||
|
|
|
|||
|
|
@ -72,7 +72,7 @@ fn compile(code: String, output: PathBuf, sysroot: PathBuf, linker: Option<&Path
|
|||
override_queries: None,
|
||||
make_codegen_backend: None,
|
||||
registry: rustc_driver::diagnostics_registry(),
|
||||
using_internal_features: std::sync::Arc::default(),
|
||||
using_internal_features: &rustc_driver::USING_INTERNAL_FEATURES,
|
||||
expanded_args: Default::default(),
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -40,14 +40,14 @@ LL | type X = std::ops::Deref::Target;
|
|||
|
|
||||
help: use fully-qualified syntax
|
||||
|
|
||||
LL | type X = <ByteStr as Deref>::Target;
|
||||
| ~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
LL | type X = <ByteString as Deref>::Target;
|
||||
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
LL | type X = <CString as Deref>::Target;
|
||||
| ~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
LL | type X = <IoSlice<'_> as Deref>::Target;
|
||||
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
LL | type X = <IoSliceMut<'_> as Deref>::Target;
|
||||
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
LL | type X = <OsString as Deref>::Target;
|
||||
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
and N other candidates
|
||||
|
||||
error: aborting due to 5 previous errors
|
||||
|
|
|
|||
|
|
@ -30,7 +30,6 @@ LL | fun(one(), two());
|
|||
| | expected all arguments to be this future type because they need to match the type of this parameter
|
||||
| arguments to this function are incorrect
|
||||
|
|
||||
= help: consider `await`ing on both `Future`s
|
||||
= note: distinct uses of `impl Trait` result in different opaque types
|
||||
note: function defined here
|
||||
--> $DIR/coroutine-desc.rs:7:4
|
||||
|
|
|
|||
|
|
@ -6,20 +6,11 @@ LL | take_u32(x)
|
|||
| |
|
||||
| arguments to this function are incorrect
|
||||
|
|
||||
note: calling an async function returns a future
|
||||
--> $DIR/dont-suggest-missing-await.rs:14:18
|
||||
|
|
||||
LL | take_u32(x)
|
||||
| ^
|
||||
note: function defined here
|
||||
--> $DIR/dont-suggest-missing-await.rs:5:4
|
||||
|
|
||||
LL | fn take_u32(x: u32) {}
|
||||
| ^^^^^^^^ ------
|
||||
help: consider `await`ing on the `Future`
|
||||
|
|
||||
LL | take_u32(x.await)
|
||||
| ++++++
|
||||
|
||||
error: aborting due to 1 previous error
|
||||
|
||||
|
|
|
|||
|
|
@ -32,13 +32,13 @@ LL | [5; Self::HOST_SIZE] == [6; 0]
|
|||
= help: the following other types implement trait `PartialEq<Rhs>`:
|
||||
`&[T]` implements `PartialEq<Vec<U, A>>`
|
||||
`&[T]` implements `PartialEq<[U; N]>`
|
||||
`&[u8; N]` implements `PartialEq<ByteStr>`
|
||||
`&[u8; N]` implements `PartialEq<ByteString>`
|
||||
`&[u8]` implements `PartialEq<ByteStr>`
|
||||
`&[u8]` implements `PartialEq<ByteString>`
|
||||
`&mut [T]` implements `PartialEq<Vec<U, A>>`
|
||||
`&mut [T]` implements `PartialEq<[U; N]>`
|
||||
`[T; N]` implements `PartialEq<&[U]>`
|
||||
`[T; N]` implements `PartialEq<&mut [U]>`
|
||||
`[T; N]` implements `PartialEq<[U; N]>`
|
||||
`[T; N]` implements `PartialEq<[U]>`
|
||||
and 3 others
|
||||
and 11 others
|
||||
|
||||
error: aborting due to 4 previous errors
|
||||
|
||||
|
|
|
|||
29
tests/ui/debuginfo/windows_gnu_split_debuginfo_off.rs
Normal file
29
tests/ui/debuginfo/windows_gnu_split_debuginfo_off.rs
Normal file
|
|
@ -0,0 +1,29 @@
|
|||
//@ revisions: aarch64_gl i686_g i686_gl i686_uwp_g x86_64_g x86_64_gl x86_64_uwp_g
|
||||
//@ compile-flags: --crate-type cdylib -Csplit-debuginfo=off
|
||||
//@ check-pass
|
||||
|
||||
//@[aarch64_gl] compile-flags: --target aarch64-pc-windows-gnullvm
|
||||
//@[aarch64_gl] needs-llvm-components: aarch64
|
||||
|
||||
//@[i686_g] compile-flags: --target i686-pc-windows-gnu
|
||||
//@[i686_g] needs-llvm-components: x86
|
||||
|
||||
//@[i686_gl] compile-flags: --target i686-pc-windows-gnullvm
|
||||
//@[i686_gl] needs-llvm-components: x86
|
||||
|
||||
//@[i686_uwp_g] compile-flags: --target i686-uwp-windows-gnu
|
||||
//@[i686_uwp_g] needs-llvm-components: x86
|
||||
|
||||
//@[x86_64_g] compile-flags: --target x86_64-pc-windows-gnu
|
||||
//@[x86_64_g] needs-llvm-components: x86
|
||||
|
||||
//@[x86_64_gl] compile-flags: --target x86_64-pc-windows-gnullvm
|
||||
//@[x86_64_gl] needs-llvm-components: x86
|
||||
|
||||
//@[x86_64_uwp_g] compile-flags: --target x86_64-uwp-windows-gnu
|
||||
//@[x86_64_uwp_g] needs-llvm-components: x86
|
||||
|
||||
#![feature(no_core)]
|
||||
|
||||
#![no_core]
|
||||
#![no_std]
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
error: `-Csplit-debuginfo=packed` is unstable on this platform
|
||||
|
||||
error: aborting due to 1 previous error
|
||||
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
error: `-Csplit-debuginfo=packed` is unstable on this platform
|
||||
|
||||
error: aborting due to 1 previous error
|
||||
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
error: `-Csplit-debuginfo=packed` is unstable on this platform
|
||||
|
||||
error: aborting due to 1 previous error
|
||||
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
error: `-Csplit-debuginfo=packed` is unstable on this platform
|
||||
|
||||
error: aborting due to 1 previous error
|
||||
|
||||
29
tests/ui/debuginfo/windows_gnu_split_debuginfo_packed.rs
Normal file
29
tests/ui/debuginfo/windows_gnu_split_debuginfo_packed.rs
Normal file
|
|
@ -0,0 +1,29 @@
|
|||
//@ revisions: aarch64_gl i686_g i686_gl i686_uwp_g x86_64_g x86_64_gl x86_64_uwp_g
|
||||
//@ compile-flags: --crate-type cdylib -Csplit-debuginfo=packed
|
||||
//@ error-pattern: error: `-Csplit-debuginfo=packed` is unstable on this platform
|
||||
|
||||
//@[aarch64_gl] compile-flags: --target aarch64-pc-windows-gnullvm
|
||||
//@[aarch64_gl] needs-llvm-components: aarch64
|
||||
|
||||
//@[i686_g] compile-flags: --target i686-pc-windows-gnu
|
||||
//@[i686_g] needs-llvm-components: x86
|
||||
|
||||
//@[i686_gl] compile-flags: --target i686-pc-windows-gnullvm
|
||||
//@[i686_gl] needs-llvm-components: x86
|
||||
|
||||
//@[i686_uwp_g] compile-flags: --target i686-uwp-windows-gnu
|
||||
//@[i686_uwp_g] needs-llvm-components: x86
|
||||
|
||||
//@[x86_64_g] compile-flags: --target x86_64-pc-windows-gnu
|
||||
//@[x86_64_g] needs-llvm-components: x86
|
||||
|
||||
//@[x86_64_gl] compile-flags: --target x86_64-pc-windows-gnullvm
|
||||
//@[x86_64_gl] needs-llvm-components: x86
|
||||
|
||||
//@[x86_64_uwp_g] compile-flags: --target x86_64-uwp-windows-gnu
|
||||
//@[x86_64_uwp_g] needs-llvm-components: x86
|
||||
|
||||
#![feature(no_core)]
|
||||
|
||||
#![no_core]
|
||||
#![no_std]
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
error: `-Csplit-debuginfo=packed` is unstable on this platform
|
||||
|
||||
error: aborting due to 1 previous error
|
||||
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
error: `-Csplit-debuginfo=packed` is unstable on this platform
|
||||
|
||||
error: aborting due to 1 previous error
|
||||
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
error: `-Csplit-debuginfo=packed` is unstable on this platform
|
||||
|
||||
error: aborting due to 1 previous error
|
||||
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
error: `-Csplit-debuginfo=unpacked` is unstable on this platform
|
||||
|
||||
error: aborting due to 1 previous error
|
||||
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
error: `-Csplit-debuginfo=unpacked` is unstable on this platform
|
||||
|
||||
error: aborting due to 1 previous error
|
||||
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
error: `-Csplit-debuginfo=unpacked` is unstable on this platform
|
||||
|
||||
error: aborting due to 1 previous error
|
||||
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
error: `-Csplit-debuginfo=unpacked` is unstable on this platform
|
||||
|
||||
error: aborting due to 1 previous error
|
||||
|
||||
29
tests/ui/debuginfo/windows_gnu_split_debuginfo_unpacked.rs
Normal file
29
tests/ui/debuginfo/windows_gnu_split_debuginfo_unpacked.rs
Normal file
|
|
@ -0,0 +1,29 @@
|
|||
//@ revisions: aarch64_gl i686_g i686_gl i686_uwp_g x86_64_g x86_64_gl x86_64_uwp_g
|
||||
//@ compile-flags: --crate-type cdylib -Csplit-debuginfo=unpacked
|
||||
//@ error-pattern: error: `-Csplit-debuginfo=unpacked` is unstable on this platform
|
||||
|
||||
//@[aarch64_gl] compile-flags: --target aarch64-pc-windows-gnullvm
|
||||
//@[aarch64_gl] needs-llvm-components: aarch64
|
||||
|
||||
//@[i686_g] compile-flags: --target i686-pc-windows-gnu
|
||||
//@[i686_g] needs-llvm-components: x86
|
||||
|
||||
//@[i686_gl] compile-flags: --target i686-pc-windows-gnullvm
|
||||
//@[i686_gl] needs-llvm-components: x86
|
||||
|
||||
//@[i686_uwp_g] compile-flags: --target i686-uwp-windows-gnu
|
||||
//@[i686_uwp_g] needs-llvm-components: x86
|
||||
|
||||
//@[x86_64_g] compile-flags: --target x86_64-pc-windows-gnu
|
||||
//@[x86_64_g] needs-llvm-components: x86
|
||||
|
||||
//@[x86_64_gl] compile-flags: --target x86_64-pc-windows-gnullvm
|
||||
//@[x86_64_gl] needs-llvm-components: x86
|
||||
|
||||
//@[x86_64_uwp_g] compile-flags: --target x86_64-uwp-windows-gnu
|
||||
//@[x86_64_uwp_g] needs-llvm-components: x86
|
||||
|
||||
#![feature(no_core)]
|
||||
|
||||
#![no_core]
|
||||
#![no_std]
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
error: `-Csplit-debuginfo=unpacked` is unstable on this platform
|
||||
|
||||
error: aborting due to 1 previous error
|
||||
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
error: `-Csplit-debuginfo=unpacked` is unstable on this platform
|
||||
|
||||
error: aborting due to 1 previous error
|
||||
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
error: `-Csplit-debuginfo=unpacked` is unstable on this platform
|
||||
|
||||
error: aborting due to 1 previous error
|
||||
|
||||
|
|
@ -14,20 +14,11 @@ LL | convert_result(foo())
|
|||
| |
|
||||
| arguments to this function are incorrect
|
||||
|
|
||||
note: calling an async function returns a future
|
||||
--> $DIR/issue-102605.rs:13:20
|
||||
|
|
||||
LL | convert_result(foo())
|
||||
| ^^^^^
|
||||
note: function defined here
|
||||
--> $DIR/issue-102605.rs:7:4
|
||||
|
|
||||
LL | fn convert_result<T, E>(r: Result<T, E>) -> Option<T> {
|
||||
| ^^^^^^^^^^^^^^ ---------------
|
||||
help: consider `await`ing on the `Future`
|
||||
|
|
||||
LL | convert_result(foo().await)
|
||||
| ++++++
|
||||
help: try wrapping the expression in `Err`
|
||||
|
|
||||
LL | convert_result(Err(foo()))
|
||||
|
|
|
|||
|
|
@ -6,11 +6,14 @@ LL | if String::from("a") == "a".try_into().unwrap() {}
|
|||
| |
|
||||
| type must be known at this point
|
||||
|
|
||||
= note: multiple `impl`s satisfying `String: PartialEq<_>` found in the `alloc` crate:
|
||||
- impl PartialEq for String;
|
||||
- impl<'a, 'b> PartialEq<&'a str> for String;
|
||||
- impl<'a, 'b> PartialEq<Cow<'a, str>> for String;
|
||||
- impl<'a, 'b> PartialEq<str> for String;
|
||||
= note: cannot satisfy `String: PartialEq<_>`
|
||||
= help: the following types implement trait `PartialEq<Rhs>`:
|
||||
`String` implements `PartialEq<&str>`
|
||||
`String` implements `PartialEq<ByteStr>`
|
||||
`String` implements `PartialEq<ByteString>`
|
||||
`String` implements `PartialEq<Cow<'_, str>>`
|
||||
`String` implements `PartialEq<str>`
|
||||
`String` implements `PartialEq`
|
||||
help: try using a fully qualified path to specify the expected types
|
||||
|
|
||||
LL | if String::from("a") == <&str as TryInto<T>>::try_into("a").unwrap() {}
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@ LL | String::from("x".as_ref());
|
|||
| ^^^^^^
|
||||
|
|
||||
= note: multiple `impl`s satisfying `str: AsRef<_>` found in the following crates: `core`, `std`:
|
||||
- impl AsRef<ByteStr> for str;
|
||||
- impl AsRef<OsStr> for str;
|
||||
- impl AsRef<Path> for str;
|
||||
- impl AsRef<[u8]> for str;
|
||||
|
|
@ -41,6 +42,7 @@ LL | |x| String::from("x".as_ref());
|
|||
| ^^^^^^
|
||||
|
|
||||
= note: multiple `impl`s satisfying `str: AsRef<_>` found in the following crates: `core`, `std`:
|
||||
- impl AsRef<ByteStr> for str;
|
||||
- impl AsRef<OsStr> for str;
|
||||
- impl AsRef<Path> for str;
|
||||
- impl AsRef<[u8]> for str;
|
||||
|
|
@ -57,6 +59,7 @@ LL | let _ = "x".as_ref();
|
|||
| ^ ------ type must be known at this point
|
||||
|
|
||||
= note: multiple `impl`s satisfying `str: AsRef<_>` found in the following crates: `core`, `std`:
|
||||
- impl AsRef<ByteStr> for str;
|
||||
- impl AsRef<OsStr> for str;
|
||||
- impl AsRef<Path> for str;
|
||||
- impl AsRef<[u8]> for str;
|
||||
|
|
@ -83,6 +86,7 @@ LL | String::from("x".as_ref());
|
|||
| ^^^^^^
|
||||
|
|
||||
= note: multiple `impl`s satisfying `str: AsRef<_>` found in the following crates: `core`, `std`:
|
||||
- impl AsRef<ByteStr> for str;
|
||||
- impl AsRef<OsStr> for str;
|
||||
- impl AsRef<Path> for str;
|
||||
- impl AsRef<[u8]> for str;
|
||||
|
|
@ -109,6 +113,7 @@ LL | String::from("x".as_ref());
|
|||
| ^^^^^^
|
||||
|
|
||||
= note: multiple `impl`s satisfying `str: AsRef<_>` found in the following crates: `core`, `std`:
|
||||
- impl AsRef<ByteStr> for str;
|
||||
- impl AsRef<OsStr> for str;
|
||||
- impl AsRef<Path> for str;
|
||||
- impl AsRef<[u8]> for str;
|
||||
|
|
@ -135,6 +140,7 @@ LL | String::from("x".as_ref());
|
|||
| ^^^^^^
|
||||
|
|
||||
= note: multiple `impl`s satisfying `str: AsRef<_>` found in the following crates: `core`, `std`:
|
||||
- impl AsRef<ByteStr> for str;
|
||||
- impl AsRef<OsStr> for str;
|
||||
- impl AsRef<Path> for str;
|
||||
- impl AsRef<[u8]> for str;
|
||||
|
|
@ -161,6 +167,7 @@ LL | String::from("x".as_ref());
|
|||
| ^^^^^^
|
||||
|
|
||||
= note: multiple `impl`s satisfying `str: AsRef<_>` found in the following crates: `core`, `std`:
|
||||
- impl AsRef<ByteStr> for str;
|
||||
- impl AsRef<OsStr> for str;
|
||||
- impl AsRef<Path> for str;
|
||||
- impl AsRef<[u8]> for str;
|
||||
|
|
@ -187,6 +194,7 @@ LL | String::from("x".as_ref());
|
|||
| ^^^^^^
|
||||
|
|
||||
= note: multiple `impl`s satisfying `str: AsRef<_>` found in the following crates: `core`, `std`:
|
||||
- impl AsRef<ByteStr> for str;
|
||||
- impl AsRef<OsStr> for str;
|
||||
- impl AsRef<Path> for str;
|
||||
- impl AsRef<[u8]> for str;
|
||||
|
|
@ -213,6 +221,7 @@ LL | String::from("x".as_ref());
|
|||
| ^^^^^^
|
||||
|
|
||||
= note: multiple `impl`s satisfying `str: AsRef<_>` found in the following crates: `core`, `std`:
|
||||
- impl AsRef<ByteStr> for str;
|
||||
- impl AsRef<OsStr> for str;
|
||||
- impl AsRef<Path> for str;
|
||||
- impl AsRef<[u8]> for str;
|
||||
|
|
|
|||
152
tests/ui/layout/reprc-power-alignment.rs
Normal file
152
tests/ui/layout/reprc-power-alignment.rs
Normal file
|
|
@ -0,0 +1,152 @@
|
|||
//@ check-pass
|
||||
//@ compile-flags: --target powerpc64-ibm-aix
|
||||
//@ needs-llvm-components: powerpc
|
||||
//@ add-core-stubs
|
||||
#![feature(no_core)]
|
||||
#![no_core]
|
||||
#![no_std]
|
||||
|
||||
extern crate minicore;
|
||||
use minicore::*;
|
||||
|
||||
#[warn(uses_power_alignment)]
|
||||
|
||||
#[repr(C)]
|
||||
pub struct Floats {
|
||||
a: f64,
|
||||
b: u8,
|
||||
c: f64, //~ WARNING repr(C) does not follow the power alignment rule. This may affect platform C ABI compatibility for this type
|
||||
d: f32,
|
||||
}
|
||||
|
||||
pub struct Floats2 {
|
||||
a: f64,
|
||||
b: u32,
|
||||
c: f64,
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
pub struct Floats3 {
|
||||
a: f32,
|
||||
b: f32,
|
||||
c: i64,
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
pub struct Floats4 {
|
||||
a: u64,
|
||||
b: u32,
|
||||
c: f32,
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
pub struct Floats5 {
|
||||
a: f32,
|
||||
b: f64, //~ WARNING repr(C) does not follow the power alignment rule. This may affect platform C ABI compatibility for this type
|
||||
c: f32,
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
pub struct FloatAgg1 {
|
||||
x: Floats,
|
||||
y: f64, //~ WARNING repr(C) does not follow the power alignment rule. This may affect platform C ABI compatibility for this type
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
pub struct FloatAgg2 {
|
||||
x: i64,
|
||||
y: Floats, //~ WARNING repr(C) does not follow the power alignment rule. This may affect platform C ABI compatibility for this type
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
pub struct FloatAgg3 {
|
||||
x: FloatAgg1,
|
||||
// NOTE: the "power" alignment rule is infectious to nested struct fields.
|
||||
y: FloatAgg2, //~ WARNING repr(C) does not follow the power alignment rule. This may affect platform C ABI compatibility for this type
|
||||
z: FloatAgg2, //~ WARNING repr(C) does not follow the power alignment rule. This may affect platform C ABI compatibility for this type
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
pub struct FloatAgg4 {
|
||||
x: FloatAgg1,
|
||||
y: FloatAgg2, //~ WARNING repr(C) does not follow the power alignment rule. This may affect platform C ABI compatibility for this type
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
pub struct FloatAgg5 {
|
||||
x: FloatAgg1,
|
||||
y: FloatAgg2, //~ WARNING repr(C) does not follow the power alignment rule. This may affect platform C ABI compatibility for this type
|
||||
z: FloatAgg3, //~ WARNING repr(C) does not follow the power alignment rule. This may affect platform C ABI compatibility for this type
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
pub struct FloatAgg6 {
|
||||
x: i64,
|
||||
y: Floats, //~ WARNING repr(C) does not follow the power alignment rule. This may affect platform C ABI compatibility for this type
|
||||
z: u8,
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
pub struct FloatAgg7 {
|
||||
x: i64,
|
||||
y: Floats, //~ WARNING repr(C) does not follow the power alignment rule. This may affect platform C ABI compatibility for this type
|
||||
z: u8,
|
||||
zz: f32,
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
pub struct A {
|
||||
d: f64,
|
||||
}
|
||||
#[repr(C)]
|
||||
pub struct B {
|
||||
a: A,
|
||||
f: f32,
|
||||
d: f64, //~ WARNING repr(C) does not follow the power alignment rule. This may affect platform C ABI compatibility for this type
|
||||
}
|
||||
#[repr(C)]
|
||||
pub struct C {
|
||||
c: u8,
|
||||
b: B, //~ WARNING repr(C) does not follow the power alignment rule. This may affect platform C ABI compatibility for this type
|
||||
}
|
||||
#[repr(C)]
|
||||
pub struct D {
|
||||
x: f64,
|
||||
}
|
||||
#[repr(C)]
|
||||
pub struct E {
|
||||
x: i32,
|
||||
d: D, //~ WARNING repr(C) does not follow the power alignment rule. This may affect platform C ABI compatibility for this type
|
||||
}
|
||||
#[repr(C)]
|
||||
pub struct F {
|
||||
a: u8,
|
||||
b: f64, //~ WARNING repr(C) does not follow the power alignment rule. This may affect platform C ABI compatibility for this type
|
||||
}
|
||||
#[repr(C)]
|
||||
pub struct G {
|
||||
a: u8,
|
||||
b: u8,
|
||||
c: f64, //~ WARNING repr(C) does not follow the power alignment rule. This may affect platform C ABI compatibility for this type
|
||||
d: f32,
|
||||
e: f64, //~ WARNING repr(C) does not follow the power alignment rule. This may affect platform C ABI compatibility for this type
|
||||
}
|
||||
// Should not warn on #[repr(packed)].
|
||||
#[repr(packed)]
|
||||
pub struct H {
|
||||
a: u8,
|
||||
b: u8,
|
||||
c: f64,
|
||||
d: f32,
|
||||
e: f64,
|
||||
}
|
||||
#[repr(C, packed)]
|
||||
pub struct I {
|
||||
a: u8,
|
||||
b: u8,
|
||||
c: f64,
|
||||
d: f32,
|
||||
e: f64,
|
||||
}
|
||||
|
||||
fn main() { }
|
||||
112
tests/ui/layout/reprc-power-alignment.stderr
Normal file
112
tests/ui/layout/reprc-power-alignment.stderr
Normal file
|
|
@ -0,0 +1,112 @@
|
|||
warning: repr(C) does not follow the power alignment rule. This may affect platform C ABI compatibility for this type
|
||||
--> $DIR/reprc-power-alignment.rs:18:5
|
||||
|
|
||||
LL | c: f64,
|
||||
| ^^^^^^
|
||||
|
|
||||
note: the lint level is defined here
|
||||
--> $DIR/reprc-power-alignment.rs:12:8
|
||||
|
|
||||
LL | #[warn(uses_power_alignment)]
|
||||
| ^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
warning: repr(C) does not follow the power alignment rule. This may affect platform C ABI compatibility for this type
|
||||
--> $DIR/reprc-power-alignment.rs:45:5
|
||||
|
|
||||
LL | b: f64,
|
||||
| ^^^^^^
|
||||
|
|
||||
= note: `#[warn(uses_power_alignment)]` on by default
|
||||
|
||||
warning: repr(C) does not follow the power alignment rule. This may affect platform C ABI compatibility for this type
|
||||
--> $DIR/reprc-power-alignment.rs:52:5
|
||||
|
|
||||
LL | y: f64,
|
||||
| ^^^^^^
|
||||
|
||||
warning: repr(C) does not follow the power alignment rule. This may affect platform C ABI compatibility for this type
|
||||
--> $DIR/reprc-power-alignment.rs:58:5
|
||||
|
|
||||
LL | y: Floats,
|
||||
| ^^^^^^^^^
|
||||
|
||||
warning: repr(C) does not follow the power alignment rule. This may affect platform C ABI compatibility for this type
|
||||
--> $DIR/reprc-power-alignment.rs:65:5
|
||||
|
|
||||
LL | y: FloatAgg2,
|
||||
| ^^^^^^^^^^^^
|
||||
|
||||
warning: repr(C) does not follow the power alignment rule. This may affect platform C ABI compatibility for this type
|
||||
--> $DIR/reprc-power-alignment.rs:66:5
|
||||
|
|
||||
LL | z: FloatAgg2,
|
||||
| ^^^^^^^^^^^^
|
||||
|
||||
warning: repr(C) does not follow the power alignment rule. This may affect platform C ABI compatibility for this type
|
||||
--> $DIR/reprc-power-alignment.rs:72:5
|
||||
|
|
||||
LL | y: FloatAgg2,
|
||||
| ^^^^^^^^^^^^
|
||||
|
||||
warning: repr(C) does not follow the power alignment rule. This may affect platform C ABI compatibility for this type
|
||||
--> $DIR/reprc-power-alignment.rs:78:5
|
||||
|
|
||||
LL | y: FloatAgg2,
|
||||
| ^^^^^^^^^^^^
|
||||
|
||||
warning: repr(C) does not follow the power alignment rule. This may affect platform C ABI compatibility for this type
|
||||
--> $DIR/reprc-power-alignment.rs:79:5
|
||||
|
|
||||
LL | z: FloatAgg3,
|
||||
| ^^^^^^^^^^^^
|
||||
|
||||
warning: repr(C) does not follow the power alignment rule. This may affect platform C ABI compatibility for this type
|
||||
--> $DIR/reprc-power-alignment.rs:85:5
|
||||
|
|
||||
LL | y: Floats,
|
||||
| ^^^^^^^^^
|
||||
|
||||
warning: repr(C) does not follow the power alignment rule. This may affect platform C ABI compatibility for this type
|
||||
--> $DIR/reprc-power-alignment.rs:92:5
|
||||
|
|
||||
LL | y: Floats,
|
||||
| ^^^^^^^^^
|
||||
|
||||
warning: repr(C) does not follow the power alignment rule. This may affect platform C ABI compatibility for this type
|
||||
--> $DIR/reprc-power-alignment.rs:105:3
|
||||
|
|
||||
LL | d: f64,
|
||||
| ^^^^^^
|
||||
|
||||
warning: repr(C) does not follow the power alignment rule. This may affect platform C ABI compatibility for this type
|
||||
--> $DIR/reprc-power-alignment.rs:110:3
|
||||
|
|
||||
LL | b: B,
|
||||
| ^^^^
|
||||
|
||||
warning: repr(C) does not follow the power alignment rule. This may affect platform C ABI compatibility for this type
|
||||
--> $DIR/reprc-power-alignment.rs:119:3
|
||||
|
|
||||
LL | d: D,
|
||||
| ^^^^
|
||||
|
||||
warning: repr(C) does not follow the power alignment rule. This may affect platform C ABI compatibility for this type
|
||||
--> $DIR/reprc-power-alignment.rs:124:3
|
||||
|
|
||||
LL | b: f64,
|
||||
| ^^^^^^
|
||||
|
||||
warning: repr(C) does not follow the power alignment rule. This may affect platform C ABI compatibility for this type
|
||||
--> $DIR/reprc-power-alignment.rs:130:5
|
||||
|
|
||||
LL | c: f64,
|
||||
| ^^^^^^
|
||||
|
||||
warning: repr(C) does not follow the power alignment rule. This may affect platform C ABI compatibility for this type
|
||||
--> $DIR/reprc-power-alignment.rs:132:5
|
||||
|
|
||||
LL | e: f64,
|
||||
| ^^^^^^
|
||||
|
||||
warning: 17 warnings emitted
|
||||
|
||||
|
|
@ -248,6 +248,7 @@ mod sameish_members {
|
|||
|
||||
mod same_sized_members_clash {
|
||||
mod a {
|
||||
#[allow(uses_power_alignment)]
|
||||
#[repr(C)]
|
||||
struct Point3 {
|
||||
x: f32,
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
warning: `extern` block uses type `Option<TransparentNoNiche>`, which is not FFI-safe
|
||||
--> $DIR/clashing-extern-fn.rs:482:55
|
||||
--> $DIR/clashing-extern-fn.rs:483:55
|
||||
|
|
||||
LL | fn hidden_niche_transparent_no_niche() -> Option<TransparentNoNiche>;
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe
|
||||
|
|
@ -9,7 +9,7 @@ LL | fn hidden_niche_transparent_no_niche() -> Option<TransparentNoN
|
|||
= note: `#[warn(improper_ctypes)]` on by default
|
||||
|
||||
warning: `extern` block uses type `Option<UnsafeCell<NonZero<usize>>>`, which is not FFI-safe
|
||||
--> $DIR/clashing-extern-fn.rs:486:46
|
||||
--> $DIR/clashing-extern-fn.rs:487:46
|
||||
|
|
||||
LL | fn hidden_niche_unsafe_cell() -> Option<UnsafeCell<NonZero<usize>>>;
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe
|
||||
|
|
@ -151,7 +151,7 @@ LL | fn draw_point(p: Point);
|
|||
found `unsafe extern "C" fn(sameish_members::b::Point)`
|
||||
|
||||
warning: `origin` redeclared with a different signature
|
||||
--> $DIR/clashing-extern-fn.rs:269:13
|
||||
--> $DIR/clashing-extern-fn.rs:270:13
|
||||
|
|
||||
LL | fn origin() -> Point3;
|
||||
| ---------------------- `origin` previously declared here
|
||||
|
|
@ -163,7 +163,7 @@ LL | fn origin() -> Point3;
|
|||
found `unsafe extern "C" fn() -> same_sized_members_clash::b::Point3`
|
||||
|
||||
warning: `transparent_incorrect` redeclared with a different signature
|
||||
--> $DIR/clashing-extern-fn.rs:292:13
|
||||
--> $DIR/clashing-extern-fn.rs:293:13
|
||||
|
|
||||
LL | fn transparent_incorrect() -> T;
|
||||
| -------------------------------- `transparent_incorrect` previously declared here
|
||||
|
|
@ -175,7 +175,7 @@ LL | fn transparent_incorrect() -> isize;
|
|||
found `unsafe extern "C" fn() -> isize`
|
||||
|
||||
warning: `missing_return_type` redeclared with a different signature
|
||||
--> $DIR/clashing-extern-fn.rs:310:13
|
||||
--> $DIR/clashing-extern-fn.rs:311:13
|
||||
|
|
||||
LL | fn missing_return_type() -> usize;
|
||||
| ---------------------------------- `missing_return_type` previously declared here
|
||||
|
|
@ -187,7 +187,7 @@ LL | fn missing_return_type();
|
|||
found `unsafe extern "C" fn()`
|
||||
|
||||
warning: `non_zero_usize` redeclared with a different signature
|
||||
--> $DIR/clashing-extern-fn.rs:328:13
|
||||
--> $DIR/clashing-extern-fn.rs:329:13
|
||||
|
|
||||
LL | fn non_zero_usize() -> core::num::NonZero<usize>;
|
||||
| ------------------------------------------------- `non_zero_usize` previously declared here
|
||||
|
|
@ -199,7 +199,7 @@ LL | fn non_zero_usize() -> usize;
|
|||
found `unsafe extern "C" fn() -> usize`
|
||||
|
||||
warning: `non_null_ptr` redeclared with a different signature
|
||||
--> $DIR/clashing-extern-fn.rs:330:13
|
||||
--> $DIR/clashing-extern-fn.rs:331:13
|
||||
|
|
||||
LL | fn non_null_ptr() -> core::ptr::NonNull<usize>;
|
||||
| ----------------------------------------------- `non_null_ptr` previously declared here
|
||||
|
|
@ -211,7 +211,7 @@ LL | fn non_null_ptr() -> *const usize;
|
|||
found `unsafe extern "C" fn() -> *const usize`
|
||||
|
||||
warning: `option_non_zero_usize_incorrect` redeclared with a different signature
|
||||
--> $DIR/clashing-extern-fn.rs:424:13
|
||||
--> $DIR/clashing-extern-fn.rs:425:13
|
||||
|
|
||||
LL | fn option_non_zero_usize_incorrect() -> usize;
|
||||
| ---------------------------------------------- `option_non_zero_usize_incorrect` previously declared here
|
||||
|
|
@ -223,7 +223,7 @@ LL | fn option_non_zero_usize_incorrect() -> isize;
|
|||
found `unsafe extern "C" fn() -> isize`
|
||||
|
||||
warning: `option_non_null_ptr_incorrect` redeclared with a different signature
|
||||
--> $DIR/clashing-extern-fn.rs:426:13
|
||||
--> $DIR/clashing-extern-fn.rs:427:13
|
||||
|
|
||||
LL | fn option_non_null_ptr_incorrect() -> *const usize;
|
||||
| --------------------------------------------------- `option_non_null_ptr_incorrect` previously declared here
|
||||
|
|
@ -235,7 +235,7 @@ LL | fn option_non_null_ptr_incorrect() -> *const isize;
|
|||
found `unsafe extern "C" fn() -> *const isize`
|
||||
|
||||
warning: `hidden_niche_transparent_no_niche` redeclared with a different signature
|
||||
--> $DIR/clashing-extern-fn.rs:482:13
|
||||
--> $DIR/clashing-extern-fn.rs:483:13
|
||||
|
|
||||
LL | fn hidden_niche_transparent_no_niche() -> usize;
|
||||
| ------------------------------------------------ `hidden_niche_transparent_no_niche` previously declared here
|
||||
|
|
@ -247,7 +247,7 @@ LL | fn hidden_niche_transparent_no_niche() -> Option<TransparentNoN
|
|||
found `unsafe extern "C" fn() -> Option<TransparentNoNiche>`
|
||||
|
||||
warning: `hidden_niche_unsafe_cell` redeclared with a different signature
|
||||
--> $DIR/clashing-extern-fn.rs:486:13
|
||||
--> $DIR/clashing-extern-fn.rs:487:13
|
||||
|
|
||||
LL | fn hidden_niche_unsafe_cell() -> usize;
|
||||
| --------------------------------------- `hidden_niche_unsafe_cell` previously declared here
|
||||
|
|
|
|||
17
tests/ui/traits/next-solver/non-wf-in-coerce-pointers.rs
Normal file
17
tests/ui/traits/next-solver/non-wf-in-coerce-pointers.rs
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
//@ compile-flags: -Znext-solver
|
||||
|
||||
trait Wf {
|
||||
type Assoc;
|
||||
}
|
||||
|
||||
struct S {
|
||||
f: &'static <() as Wf>::Assoc,
|
||||
//~^ ERROR the trait bound `(): Wf` is not satisfied
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let x: S = todo!();
|
||||
let y: &() = x.f;
|
||||
//~^ ERROR mismatched types
|
||||
//~| ERROR the trait bound `(): Wf` is not satisfied
|
||||
}
|
||||
39
tests/ui/traits/next-solver/non-wf-in-coerce-pointers.stderr
Normal file
39
tests/ui/traits/next-solver/non-wf-in-coerce-pointers.stderr
Normal file
|
|
@ -0,0 +1,39 @@
|
|||
error[E0277]: the trait bound `(): Wf` is not satisfied
|
||||
--> $DIR/non-wf-in-coerce-pointers.rs:8:17
|
||||
|
|
||||
LL | f: &'static <() as Wf>::Assoc,
|
||||
| ^^^^^^^^^^^^^^^^^ the trait `Wf` is not implemented for `()`
|
||||
|
|
||||
help: this trait has no implementations, consider adding one
|
||||
--> $DIR/non-wf-in-coerce-pointers.rs:3:1
|
||||
|
|
||||
LL | trait Wf {
|
||||
| ^^^^^^^^
|
||||
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/non-wf-in-coerce-pointers.rs:14:18
|
||||
|
|
||||
LL | let y: &() = x.f;
|
||||
| --- ^^^ types differ
|
||||
| |
|
||||
| expected due to this
|
||||
|
|
||||
= note: expected reference `&()`
|
||||
found reference `&'static <() as Wf>::Assoc`
|
||||
|
||||
error[E0277]: the trait bound `(): Wf` is not satisfied
|
||||
--> $DIR/non-wf-in-coerce-pointers.rs:14:18
|
||||
|
|
||||
LL | let y: &() = x.f;
|
||||
| ^^^ the trait `Wf` is not implemented for `()`
|
||||
|
|
||||
help: this trait has no implementations, consider adding one
|
||||
--> $DIR/non-wf-in-coerce-pointers.rs:3:1
|
||||
|
|
||||
LL | trait Wf {
|
||||
| ^^^^^^^^
|
||||
|
||||
error: aborting due to 3 previous errors
|
||||
|
||||
Some errors have detailed explanations: E0277, E0308.
|
||||
For more information about an error, try `rustc --explain E0277`.
|
||||
|
|
@ -0,0 +1,21 @@
|
|||
//@ compile-flags: -Znext-solver
|
||||
//@ check-pass
|
||||
|
||||
// `(): Trait` is a global where-bound with a projection bound.
|
||||
// This previously resulted in ambiguity as we considered both
|
||||
// the impl and the where-bound while normalizing.
|
||||
|
||||
trait Trait {
|
||||
type Assoc;
|
||||
}
|
||||
impl Trait for () {
|
||||
type Assoc = &'static ();
|
||||
}
|
||||
|
||||
fn foo<'a>(x: <() as Trait>::Assoc)
|
||||
where
|
||||
(): Trait<Assoc = &'a ()>,
|
||||
{
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
Loading…
Add table
Add a link
Reference in a new issue