Merge from rustc

This commit is contained in:
The Miri Cronjob Bot 2025-01-24 05:02:41 +00:00
commit 00cc1ece56
90 changed files with 2426 additions and 524 deletions

View file

@ -4260,7 +4260,6 @@ dependencies = [
"rustc_serialize",
"rustc_type_ir",
"rustc_type_ir_macros",
"smallvec",
"tracing",
]

View file

@ -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 =

View file

@ -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(())
});

View file

@ -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 {

View file

@ -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

View file

@ -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"));

View file

@ -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

View file

@ -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>,

View file

@ -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;

View file

@ -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(..)

View 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)
}
}

View file

@ -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

View file

@ -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>)
()
),)*
}

View file

@ -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

View file

@ -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,
});

View file

@ -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.

View file

@ -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

View file

@ -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()) {

View file

@ -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()
}

View file

@ -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()
}

View file

@ -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
View 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())
}
}

View file

@ -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,

View file

@ -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
View 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)
}
}

View file

@ -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

View file

@ -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

View file

@ -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;

View 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><>!");
}

View file

@ -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
View file

@ -0,0 +1,4 @@
//! The `ByteStr` and `ByteString` types and trait implementations.
#[unstable(feature = "bstr", issue = "134915")]
pub use alloc::bstr::{ByteStr, ByteString};

View file

@ -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;

View file

@ -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")

View file

@ -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 doesnt 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(

View file

@ -121,6 +121,10 @@ impl Cargo {
cargo
}
pub fn compiler(&self) -> Compiler {
self.compiler
}
pub fn into_cmd(self) -> BootstrapCommand {
self.into()
}

View file

@ -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);
}

View file

@ -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:

View file

@ -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);
}

View file

@ -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);
}

View file

@ -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/

View file

@ -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"),

View file

@ -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,
}
}

View file

@ -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(),
};

View file

@ -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 { "&lt;" })?;
@ -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 { "&quot;" };
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)))
}

View file

@ -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 {

View file

@ -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());
});
}

View file

@ -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,

View file

@ -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,

View file

@ -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))))
}
}

View file

@ -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(());
}

View file

@ -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,

View file

@ -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();

View file

@ -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,

View file

@ -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(())
}))

View file

@ -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",

View file

@ -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))
}

View file

@ -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();

View file

@ -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);

View file

@ -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(),
};

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View 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]

View file

@ -0,0 +1,4 @@
error: `-Csplit-debuginfo=packed` is unstable on this platform
error: aborting due to 1 previous error

View file

@ -0,0 +1,4 @@
error: `-Csplit-debuginfo=packed` is unstable on this platform
error: aborting due to 1 previous error

View file

@ -0,0 +1,4 @@
error: `-Csplit-debuginfo=packed` is unstable on this platform
error: aborting due to 1 previous error

View file

@ -0,0 +1,4 @@
error: `-Csplit-debuginfo=packed` is unstable on this platform
error: aborting due to 1 previous error

View 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]

View file

@ -0,0 +1,4 @@
error: `-Csplit-debuginfo=packed` is unstable on this platform
error: aborting due to 1 previous error

View file

@ -0,0 +1,4 @@
error: `-Csplit-debuginfo=packed` is unstable on this platform
error: aborting due to 1 previous error

View file

@ -0,0 +1,4 @@
error: `-Csplit-debuginfo=packed` is unstable on this platform
error: aborting due to 1 previous error

View file

@ -0,0 +1,4 @@
error: `-Csplit-debuginfo=unpacked` is unstable on this platform
error: aborting due to 1 previous error

View file

@ -0,0 +1,4 @@
error: `-Csplit-debuginfo=unpacked` is unstable on this platform
error: aborting due to 1 previous error

View file

@ -0,0 +1,4 @@
error: `-Csplit-debuginfo=unpacked` is unstable on this platform
error: aborting due to 1 previous error

View file

@ -0,0 +1,4 @@
error: `-Csplit-debuginfo=unpacked` is unstable on this platform
error: aborting due to 1 previous error

View 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]

View file

@ -0,0 +1,4 @@
error: `-Csplit-debuginfo=unpacked` is unstable on this platform
error: aborting due to 1 previous error

View file

@ -0,0 +1,4 @@
error: `-Csplit-debuginfo=unpacked` is unstable on this platform
error: aborting due to 1 previous error

View file

@ -0,0 +1,4 @@
error: `-Csplit-debuginfo=unpacked` is unstable on this platform
error: aborting due to 1 previous error

View file

@ -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()))

View file

@ -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() {}

View file

@ -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;

View 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() { }

View 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

View file

@ -248,6 +248,7 @@ mod sameish_members {
mod same_sized_members_clash {
mod a {
#[allow(uses_power_alignment)]
#[repr(C)]
struct Point3 {
x: f32,

View file

@ -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

View 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
}

View 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`.

View file

@ -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() {}