Auto merge of #129978 - matthiaskrgr:rollup-a7ryoox, r=matthiaskrgr

Rollup of 10 pull requests

Successful merges:

 - #101339 (enable -Zrandomize-layout in debug CI builds )
 - #120736 (rustdoc: add header map to the table of contents)
 - #127021 (Add target support for RTEMS Arm)
 - #128928 (CI: rfl: add more tools and steps)
 - #129584 (warn the user if the upstream master branch is old)
 - #129664 (Arbitrary self types v2: pointers feature gate.)
 - #129752 (Make supertrait and implied predicates queries defaulted)
 - #129918 (Update docs of `missing_abi` lint)
 - #129919 (Stabilize `waker_getters`)
 - #129925 (remove deprecated option `rust.split-debuginfo`)

Failed merges:

 - #129789 (rustdoc: use strategic boxing to shrink `clean::Item`)

r? `@ghost`
`@rustbot` modify labels: rollup
This commit is contained in:
bors 2024-09-05 07:41:22 +00:00
commit eb33b43bab
106 changed files with 1553 additions and 288 deletions

View File

@ -3569,6 +3569,7 @@ dependencies = [
"rustc_hir_pretty",
"rustc_hir_typeck",
"rustc_incremental",
"rustc_index",
"rustc_infer",
"rustc_interface",
"rustc_lint",

View File

@ -30,5 +30,6 @@ features = ['unprefixed_malloc_on_supported_platforms']
jemalloc = ['dep:jemalloc-sys']
llvm = ['rustc_driver_impl/llvm']
max_level_info = ['rustc_driver_impl/max_level_info']
rustc_randomized_layouts = ['rustc_driver_impl/rustc_randomized_layouts']
rustc_use_parallel_compiler = ['rustc_driver_impl/rustc_use_parallel_compiler']
# tidy-alphabetical-end

View File

@ -968,8 +968,8 @@ fn univariant<
let mut align = if pack.is_some() { dl.i8_align } else { dl.aggregate_align };
let mut max_repr_align = repr.align;
let mut inverse_memory_index: IndexVec<u32, FieldIdx> = fields.indices().collect();
let optimize = !repr.inhibit_struct_field_reordering();
if optimize && fields.len() > 1 {
let optimize_field_order = !repr.inhibit_struct_field_reordering();
if optimize_field_order && fields.len() > 1 {
let end = if let StructKind::MaybeUnsized = kind { fields.len() - 1 } else { fields.len() };
let optimizing = &mut inverse_memory_index.raw[..end];
let fields_excluding_tail = &fields.raw[..end];
@ -1176,7 +1176,7 @@ fn univariant<
// If field 5 has offset 0, offsets[0] is 5, and memory_index[5] should be 0.
// Field 5 would be the first element, so memory_index is i:
// Note: if we didn't optimize, it's already right.
let memory_index = if optimize {
let memory_index = if optimize_field_order {
inverse_memory_index.invert_bijective_mapping()
} else {
debug_assert!(inverse_memory_index.iter().copied().eq(fields.indices()));
@ -1189,6 +1189,9 @@ fn univariant<
}
let mut layout_of_single_non_zst_field = None;
let mut abi = Abi::Aggregate { sized };
let optimize_abi = !repr.inhibit_newtype_abi_optimization();
// Try to make this a Scalar/ScalarPair.
if sized && size.bytes() > 0 {
// We skip *all* ZST here and later check if we are good in terms of alignment.
@ -1205,7 +1208,7 @@ fn univariant<
match field.abi {
// For plain scalars, or vectors of them, we can't unpack
// newtypes for `#[repr(C)]`, as that affects C ABIs.
Abi::Scalar(_) | Abi::Vector { .. } if optimize => {
Abi::Scalar(_) | Abi::Vector { .. } if optimize_abi => {
abi = field.abi;
}
// But scalar pairs are Rust-specific and get

View File

@ -43,14 +43,17 @@ bitflags! {
const IS_SIMD = 1 << 1;
const IS_TRANSPARENT = 1 << 2;
// Internal only for now. If true, don't reorder fields.
// On its own it does not prevent ABI optimizations.
const IS_LINEAR = 1 << 3;
// If true, the type's layout can be randomized using
// the seed stored in `ReprOptions.field_shuffle_seed`
// If true, the type's crate has opted into layout randomization.
// Other flags can still inhibit reordering and thus randomization.
// The seed stored in `ReprOptions.field_shuffle_seed`.
const RANDOMIZE_LAYOUT = 1 << 4;
// Any of these flags being set prevent field reordering optimisation.
const IS_UNOPTIMISABLE = ReprFlags::IS_C.bits()
const FIELD_ORDER_UNOPTIMIZABLE = ReprFlags::IS_C.bits()
| ReprFlags::IS_SIMD.bits()
| ReprFlags::IS_LINEAR.bits();
const ABI_UNOPTIMIZABLE = ReprFlags::IS_C.bits() | ReprFlags::IS_SIMD.bits();
}
}
@ -139,10 +142,14 @@ impl ReprOptions {
self.c() || self.int.is_some()
}
pub fn inhibit_newtype_abi_optimization(&self) -> bool {
self.flags.intersects(ReprFlags::ABI_UNOPTIMIZABLE)
}
/// Returns `true` if this `#[repr()]` guarantees a fixed field order,
/// e.g. `repr(C)` or `repr(<int>)`.
pub fn inhibit_struct_field_reordering(&self) -> bool {
self.flags.intersects(ReprFlags::IS_UNOPTIMISABLE) || self.int.is_some()
self.flags.intersects(ReprFlags::FIELD_ORDER_UNOPTIMIZABLE) || self.int.is_some()
}
/// Returns `true` if this type is valid for reordering and `-Z randomize-layout`

View File

@ -23,6 +23,7 @@ rustc_hir_analysis = { path = "../rustc_hir_analysis" }
rustc_hir_pretty = { path = "../rustc_hir_pretty" }
rustc_hir_typeck = { path = "../rustc_hir_typeck" }
rustc_incremental = { path = "../rustc_incremental" }
rustc_index = { path = "../rustc_index" }
rustc_infer = { path = "../rustc_infer" }
rustc_interface = { path = "../rustc_interface" }
rustc_lint = { path = "../rustc_lint" }
@ -72,6 +73,10 @@ ctrlc = "3.4.4"
# tidy-alphabetical-start
llvm = ['rustc_interface/llvm']
max_level_info = ['rustc_log/max_level_info']
rustc_randomized_layouts = [
'rustc_index/rustc_randomized_layouts',
'rustc_middle/rustc_randomized_layouts'
]
rustc_use_parallel_compiler = [
'rustc_data_structures/rustc_use_parallel_compiler',
'rustc_interface/rustc_use_parallel_compiler',

View File

@ -349,8 +349,10 @@ declare_features! (
(unstable, adt_const_params, "1.56.0", Some(95174)),
/// Allows defining an `#[alloc_error_handler]`.
(unstable, alloc_error_handler, "1.29.0", Some(51540)),
/// Allows trait methods with arbitrary self types.
/// Allows inherent and trait methods with arbitrary self types.
(unstable, arbitrary_self_types, "1.23.0", Some(44874)),
/// Allows inherent and trait methods with arbitrary self types that are raw pointers.
(unstable, arbitrary_self_types_pointers, "CURRENT_RUSTC_VERSION", Some(44874)),
/// Enables experimental inline assembly support for additional architectures.
(unstable, asm_experimental_arch, "1.58.0", Some(93335)),
/// Allows using `label` operands in inline assembly.

View File

@ -1652,6 +1652,13 @@ fn check_fn_or_method<'tcx>(
}
}
/// The `arbitrary_self_types_pointers` feature implies `arbitrary_self_types`.
#[derive(Clone, Copy, PartialEq)]
enum ArbitrarySelfTypesLevel {
Basic, // just arbitrary_self_types
WithPointers, // both arbitrary_self_types and arbitrary_self_types_pointers
}
#[instrument(level = "debug", skip(wfcx))]
fn check_method_receiver<'tcx>(
wfcx: &WfCheckingCtxt<'_, 'tcx>,
@ -1684,14 +1691,27 @@ fn check_method_receiver<'tcx>(
return Ok(());
}
if tcx.features().arbitrary_self_types {
if !receiver_is_valid(wfcx, span, receiver_ty, self_ty, true) {
// Report error; `arbitrary_self_types` was enabled.
return Err(tcx.dcx().emit_err(errors::InvalidReceiverTy { span, receiver_ty }));
}
let arbitrary_self_types_level = if tcx.features().arbitrary_self_types_pointers {
Some(ArbitrarySelfTypesLevel::WithPointers)
} else if tcx.features().arbitrary_self_types {
Some(ArbitrarySelfTypesLevel::Basic)
} else {
if !receiver_is_valid(wfcx, span, receiver_ty, self_ty, false) {
return Err(if receiver_is_valid(wfcx, span, receiver_ty, self_ty, true) {
None
};
if !receiver_is_valid(wfcx, span, receiver_ty, self_ty, arbitrary_self_types_level) {
return Err(match arbitrary_self_types_level {
// Wherever possible, emit a message advising folks that the features
// `arbitrary_self_types` or `arbitrary_self_types_pointers` might
// have helped.
None if receiver_is_valid(
wfcx,
span,
receiver_ty,
self_ty,
Some(ArbitrarySelfTypesLevel::Basic),
) =>
{
// Report error; would have worked with `arbitrary_self_types`.
feature_err(
&tcx.sess,
@ -1699,25 +1719,49 @@ fn check_method_receiver<'tcx>(
span,
format!(
"`{receiver_ty}` cannot be used as the type of `self` without \
the `arbitrary_self_types` feature",
the `arbitrary_self_types` feature",
),
)
.with_help(fluent::hir_analysis_invalid_receiver_ty_help)
.emit()
} else {
// Report error; would not have worked with `arbitrary_self_types`.
}
None | Some(ArbitrarySelfTypesLevel::Basic)
if receiver_is_valid(
wfcx,
span,
receiver_ty,
self_ty,
Some(ArbitrarySelfTypesLevel::WithPointers),
) =>
{
// Report error; would have worked with `arbitrary_self_types_pointers`.
feature_err(
&tcx.sess,
sym::arbitrary_self_types_pointers,
span,
format!(
"`{receiver_ty}` cannot be used as the type of `self` without \
the `arbitrary_self_types_pointers` feature",
),
)
.with_help(fluent::hir_analysis_invalid_receiver_ty_help)
.emit()
}
_ =>
// Report error; would not have worked with `arbitrary_self_types[_pointers]`.
{
tcx.dcx().emit_err(errors::InvalidReceiverTy { span, receiver_ty })
});
}
}
});
}
Ok(())
}
/// Returns whether `receiver_ty` would be considered a valid receiver type for `self_ty`. If
/// `arbitrary_self_types` is enabled, `receiver_ty` must transitively deref to `self_ty`, possibly
/// through a `*const/mut T` raw pointer. If the feature is not enabled, the requirements are more
/// strict: `receiver_ty` must implement `Receiver` and directly implement
/// `Deref<Target = self_ty>`.
/// through a `*const/mut T` raw pointer if `arbitrary_self_types_pointers` is also enabled.
/// If neither feature is enabled, the requirements are more strict: `receiver_ty` must implement
/// `Receiver` and directly implement `Deref<Target = self_ty>`.
///
/// N.B., there are cases this function returns `true` but causes an error to be emitted,
/// particularly when `receiver_ty` derefs to a type that is the same as `self_ty` but has the
@ -1727,7 +1771,7 @@ fn receiver_is_valid<'tcx>(
span: Span,
receiver_ty: Ty<'tcx>,
self_ty: Ty<'tcx>,
arbitrary_self_types_enabled: bool,
arbitrary_self_types_enabled: Option<ArbitrarySelfTypesLevel>,
) -> bool {
let infcx = wfcx.infcx;
let tcx = wfcx.tcx();
@ -1745,8 +1789,8 @@ fn receiver_is_valid<'tcx>(
let mut autoderef = Autoderef::new(infcx, wfcx.param_env, wfcx.body_def_id, span, receiver_ty);
// The `arbitrary_self_types` feature allows raw pointer receivers like `self: *const Self`.
if arbitrary_self_types_enabled {
// The `arbitrary_self_types_pointers` feature allows raw pointer receivers like `self: *const Self`.
if arbitrary_self_types_enabled == Some(ArbitrarySelfTypesLevel::WithPointers) {
autoderef = autoderef.include_raw_pointers();
}
@ -1772,7 +1816,7 @@ fn receiver_is_valid<'tcx>(
// Without `feature(arbitrary_self_types)`, we require that each step in the
// deref chain implement `receiver`.
if !arbitrary_self_types_enabled {
if arbitrary_self_types_enabled.is_none() {
if !receiver_is_implemented(
wfcx,
receiver_trait_def_id,

View File

@ -403,7 +403,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
mode,
}));
} else if bad_ty.reached_raw_pointer
&& !self.tcx.features().arbitrary_self_types
&& !self.tcx.features().arbitrary_self_types_pointers
&& !self.tcx.sess.at_least_rust_2018()
{
// this case used to be allowed by the compiler,

View File

@ -20,4 +20,5 @@ nightly = [
"dep:rustc_macros",
"rustc_index_macros/nightly",
]
rustc_randomized_layouts = []
# tidy-alphabetical-end

View File

@ -33,8 +33,19 @@ pub use vec::IndexVec;
///
/// </div>
#[macro_export]
#[cfg(not(feature = "rustc_randomized_layouts"))]
macro_rules! static_assert_size {
($ty:ty, $size:expr) => {
const _: [(); $size] = [(); ::std::mem::size_of::<$ty>()];
};
}
#[macro_export]
#[cfg(feature = "rustc_randomized_layouts")]
macro_rules! static_assert_size {
($ty:ty, $size:expr) => {
// no effect other than using the statements.
// struct sizes are not deterministic under randomized layouts
const _: (usize, usize) = ($size, ::std::mem::size_of::<$ty>());
};
}

View File

@ -3706,7 +3706,7 @@ declare_lint_pass!(UnusedDocComment => [UNUSED_DOC_COMMENTS]);
declare_lint! {
/// The `missing_abi` lint detects cases where the ABI is omitted from
/// extern declarations.
/// `extern` declarations.
///
/// ### Example
///
@ -3720,10 +3720,12 @@ declare_lint! {
///
/// ### Explanation
///
/// Historically, Rust implicitly selected C as the ABI for extern
/// declarations. We expect to add new ABIs, like `C-unwind`, in the future,
/// though this has not yet happened, and especially with their addition
/// seeing the ABI easily will make code review easier.
/// For historic reasons, Rust implicitly selects `C` as the default ABI for
/// `extern` declarations. [Other ABIs] like `C-unwind` and `system` have
/// been added since then, and especially with their addition seeing the ABI
/// easily makes code review easier.
///
/// [Other ABIs]: https://doc.rust-lang.org/reference/items/external-blocks.html#abi
pub MISSING_ABI,
Allow,
"No declared ABI for extern declaration"

View File

@ -247,8 +247,8 @@ provide! { tcx, def_id, other, cdata,
explicit_predicates_of => { table }
generics_of => { table }
inferred_outlives_of => { table_defaulted_array }
explicit_super_predicates_of => { table }
explicit_implied_predicates_of => { table }
explicit_super_predicates_of => { table_defaulted_array }
explicit_implied_predicates_of => { table_defaulted_array }
type_of => { table }
type_alias_is_lazy => { table_direct }
variances_of => { table }

View File

@ -1443,9 +1443,9 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
}
if let DefKind::Trait = def_kind {
record!(self.tables.trait_def[def_id] <- self.tcx.trait_def(def_id));
record_array!(self.tables.explicit_super_predicates_of[def_id] <-
record_defaulted_array!(self.tables.explicit_super_predicates_of[def_id] <-
self.tcx.explicit_super_predicates_of(def_id).skip_binder());
record_array!(self.tables.explicit_implied_predicates_of[def_id] <-
record_defaulted_array!(self.tables.explicit_implied_predicates_of[def_id] <-
self.tcx.explicit_implied_predicates_of(def_id).skip_binder());
let module_children = self.tcx.module_children_local(local_id);
@ -1454,9 +1454,9 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
}
if let DefKind::TraitAlias = def_kind {
record!(self.tables.trait_def[def_id] <- self.tcx.trait_def(def_id));
record_array!(self.tables.explicit_super_predicates_of[def_id] <-
record_defaulted_array!(self.tables.explicit_super_predicates_of[def_id] <-
self.tcx.explicit_super_predicates_of(def_id).skip_binder());
record_array!(self.tables.explicit_implied_predicates_of[def_id] <-
record_defaulted_array!(self.tables.explicit_implied_predicates_of[def_id] <-
self.tcx.explicit_implied_predicates_of(def_id).skip_binder());
}
if let DefKind::Trait | DefKind::Impl { .. } = def_kind {

View File

@ -390,6 +390,8 @@ define_tables! {
explicit_item_bounds: Table<DefIndex, LazyArray<(ty::Clause<'static>, Span)>>,
explicit_item_super_predicates: Table<DefIndex, LazyArray<(ty::Clause<'static>, Span)>>,
inferred_outlives_of: Table<DefIndex, LazyArray<(ty::Clause<'static>, Span)>>,
explicit_super_predicates_of: Table<DefIndex, LazyArray<(ty::Clause<'static>, Span)>>,
explicit_implied_predicates_of: Table<DefIndex, LazyArray<(ty::Clause<'static>, Span)>>,
inherent_impls: Table<DefIndex, LazyArray<DefIndex>>,
associated_types_for_impl_traits_in_associated_fn: Table<DefIndex, LazyArray<DefId>>,
associated_type_for_effects: Table<DefIndex, Option<LazyValue<DefId>>>,
@ -419,10 +421,6 @@ define_tables! {
lookup_deprecation_entry: Table<DefIndex, LazyValue<attr::Deprecation>>,
explicit_predicates_of: Table<DefIndex, LazyValue<ty::GenericPredicates<'static>>>,
generics_of: Table<DefIndex, LazyValue<ty::Generics>>,
explicit_super_predicates_of: Table<DefIndex, LazyArray<(ty::Clause<'static>, Span)>>,
// As an optimization, we only store this for trait aliases,
// since it's identical to explicit_super_predicates_of for traits.
explicit_implied_predicates_of: Table<DefIndex, LazyArray<(ty::Clause<'static>, Span)>>,
type_of: Table<DefIndex, LazyValue<ty::EarlyBinder<'static, Ty<'static>>>>,
variances_of: Table<DefIndex, LazyArray<ty::Variance>>,
fn_sig: Table<DefIndex, LazyValue<ty::EarlyBinder<'static, ty::PolyFnSig<'static>>>>,

View File

@ -40,5 +40,6 @@ tracing = "0.1"
[features]
# tidy-alphabetical-start
rustc_randomized_layouts = []
rustc_use_parallel_compiler = ["dep:rustc-rayon-core"]
# tidy-alphabetical-end

View File

@ -337,6 +337,7 @@ macro_rules! define_callbacks {
// Ensure that values grow no larger than 64 bytes by accident.
// Increase this limit if necessary, but do try to keep the size low if possible
#[cfg(target_pointer_width = "64")]
#[cfg(not(feature = "rustc_randomized_layouts"))]
const _: () = {
if mem::size_of::<Value<'static>>() > 64 {
panic!("{}", concat!(

View File

@ -35,6 +35,7 @@ use rustc_data_structures::tagged_ptr::CopyTaggedPtr;
use rustc_errors::{Diag, ErrorGuaranteed, StashKey};
use rustc_hir::def::{CtorKind, CtorOf, DefKind, DocLinkResMap, LifetimeRes, Res};
use rustc_hir::def_id::{CrateNum, DefId, DefIdMap, LocalDefId, LocalDefIdMap};
use rustc_hir::LangItem;
use rustc_index::IndexVec;
use rustc_macros::{
extension, Decodable, Encodable, HashStable, TyDecodable, TyEncodable, TypeFoldable,
@ -1570,8 +1571,15 @@ impl<'tcx> TyCtxt<'tcx> {
flags.insert(ReprFlags::RANDOMIZE_LAYOUT);
}
// box is special, on the one hand the compiler assumes an ordered layout, with the pointer
// always at offset zero. On the other hand we want scalar abi optimizations.
let is_box = self.is_lang_item(did.to_def_id(), LangItem::OwnedBox);
// This is here instead of layout because the choice must make it into metadata.
if !self.consider_optimizing(|| format!("Reorder fields of {:?}", self.def_path_str(did))) {
if is_box
|| !self
.consider_optimizing(|| format!("Reorder fields of {:?}", self.def_path_str(did)))
{
flags.insert(ReprFlags::IS_LINEAR);
}

View File

@ -407,6 +407,7 @@ symbols! {
append_const_msg,
arbitrary_enum_discriminant,
arbitrary_self_types,
arbitrary_self_types_pointers,
args,
arith_offset,
arm,

View File

@ -1695,6 +1695,8 @@ supported_targets! {
("armv7r-none-eabihf", armv7r_none_eabihf),
("armv8r-none-eabihf", armv8r_none_eabihf),
("armv7-rtems-eabihf", armv7_rtems_eabihf),
("x86_64-pc-solaris", x86_64_pc_solaris),
("sparcv9-sun-solaris", sparcv9_sun_solaris),

View File

@ -0,0 +1,35 @@
use crate::spec::{cvs, Cc, LinkerFlavor, Lld, PanicStrategy, RelocModel, Target, TargetOptions};
pub(crate) fn target() -> Target {
Target {
llvm_target: "armv7-unknown-none-eabihf".into(),
metadata: crate::spec::TargetMetadata {
description: Some("Armv7 RTEMS (Requires RTEMS toolchain and kernel".into()),
tier: Some(3),
host_tools: Some(false),
std: Some(true),
},
pointer_width: 32,
data_layout: "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".into(),
arch: "arm".into(),
options: TargetOptions {
os: "rtems".into(),
families: cvs!["unix"],
abi: "eabihf".into(),
linker_flavor: LinkerFlavor::Gnu(Cc::Yes, Lld::No),
linker: None,
relocation_model: RelocModel::Static,
panic_strategy: PanicStrategy::Abort,
features: "+thumb2,+neon,+vfp3".into(),
max_atomic_width: Some(64),
emit_debug_gdb_scripts: false,
// GCC defaults to 8 for arm-none here.
c_enum_min_bits: Some(8),
eh_frame_header: false,
no_default_libraries: false,
env: "newlib".into(),
..Default::default()
},
}
}

View File

@ -519,6 +519,9 @@
# are disabled statically" because `max_level_info` is enabled, set this value to `true`.
#debug-logging = rust.debug-assertions (boolean)
# Whether or not to build rustc, tools and the libraries with randomized type layout
#randomize-layout = false
# Whether or not overflow checks are enabled for the compiler and standard
# library.
#

View File

@ -52,4 +52,5 @@ check-cfg = [
'cfg(no_global_oom_handling)',
'cfg(no_rc)',
'cfg(no_sync)',
'cfg(randomized_layouts)',
]

View File

@ -90,7 +90,7 @@ fn test_partial_eq() {
#[test]
#[cfg(target_arch = "x86_64")]
#[cfg_attr(miri, ignore)] // We'd like to run Miri with layout randomization
#[cfg_attr(any(miri, randomized_layouts), ignore)] // We'd like to run Miri with layout randomization
fn test_sizes() {
assert_eq!(core::mem::size_of::<LeafNode<(), ()>>(), 16);
assert_eq!(core::mem::size_of::<LeafNode<i64, i64>>(), 16 + CAPACITY * 2 * 8);

View File

@ -43,6 +43,8 @@ check-cfg = [
'cfg(bootstrap)',
'cfg(no_fp_fmt_parse)',
'cfg(stdarch_intel_sde)',
# #[cfg(bootstrap)] rtems
'cfg(target_os, values("rtems"))',
# core use #[path] imports to portable-simd `core_simd` crate
# and to stdarch `core_arch` crate which messes-up with Cargo list
# of declared features, we therefor expect any feature cfg

View File

@ -110,7 +110,7 @@ mod c_char_definition {
all(target_os = "android", any(target_arch = "aarch64", target_arch = "arm")),
all(target_os = "l4re", target_arch = "x86_64"),
all(
any(target_os = "freebsd", target_os = "openbsd"),
any(target_os = "freebsd", target_os = "openbsd", target_os = "rtems"),
any(
target_arch = "aarch64",
target_arch = "arm",

View File

@ -60,22 +60,6 @@ impl RawWaker {
RawWaker { data, vtable }
}
/// Gets the `data` pointer used to create this `RawWaker`.
#[inline]
#[must_use]
#[unstable(feature = "waker_getters", issue = "96992")]
pub fn data(&self) -> *const () {
self.data
}
/// Gets the `vtable` pointer used to create this `RawWaker`.
#[inline]
#[must_use]
#[unstable(feature = "waker_getters", issue = "96992")]
pub fn vtable(&self) -> &'static RawWakerVTable {
self.vtable
}
#[unstable(feature = "noop_waker", issue = "98286")]
const NOOP: RawWaker = {
const VTABLE: RawWakerVTable = RawWakerVTable::new(
@ -509,6 +493,37 @@ impl Waker {
a_data == b_data && ptr::eq(a_vtable, b_vtable)
}
/// Creates a new `Waker` from the provided `data` pointer and `vtable`.
///
/// The `data` pointer can be used to store arbitrary data as required
/// by the executor. This could be e.g. a type-erased pointer to an `Arc`
/// that is associated with the task.
/// The value of this pointer will get passed to all functions that are part
/// of the `vtable` as the first parameter.
///
/// It is important to consider that the `data` pointer must point to a
/// thread safe type such as an `Arc`.
///
/// The `vtable` customizes the behavior of a `Waker`. For each operation
/// on the `Waker`, the associated function in the `vtable` will be called.
///
/// # Safety
///
/// The behavior of the returned `Waker` is undefined if the contract defined
/// in [`RawWakerVTable`]'s documentation is not upheld.
///
/// (Authors wishing to avoid unsafe code may implement the [`Wake`] trait instead, at the
/// cost of a required heap allocation.)
///
/// [`Wake`]: ../../alloc/task/trait.Wake.html
#[inline]
#[must_use]
#[stable(feature = "waker_getters", since = "CURRENT_RUSTC_VERSION")]
#[rustc_const_stable(feature = "waker_getters", since = "CURRENT_RUSTC_VERSION")]
pub const unsafe fn new(data: *const (), vtable: &'static RawWakerVTable) -> Self {
Waker { waker: RawWaker { data, vtable } }
}
/// Creates a new `Waker` from [`RawWaker`].
///
/// # Safety
@ -565,12 +580,20 @@ impl Waker {
WAKER
}
/// Gets a reference to the underlying [`RawWaker`].
/// Gets the `data` pointer used to create this `Waker`.
#[inline]
#[must_use]
#[unstable(feature = "waker_getters", issue = "96992")]
pub fn as_raw(&self) -> &RawWaker {
&self.waker
#[stable(feature = "waker_getters", since = "CURRENT_RUSTC_VERSION")]
pub fn data(&self) -> *const () {
self.waker.data
}
/// Gets the `vtable` pointer used to create this `Waker`.
#[inline]
#[must_use]
#[stable(feature = "waker_getters", since = "CURRENT_RUSTC_VERSION")]
pub fn vtable(&self) -> &'static RawWakerVTable {
self.waker.vtable
}
}
@ -778,6 +801,30 @@ impl LocalWaker {
a_data == b_data && ptr::eq(a_vtable, b_vtable)
}
/// Creates a new `LocalWaker` from the provided `data` pointer and `vtable`.
///
/// The `data` pointer can be used to store arbitrary data as required
/// by the executor. This could be e.g. a type-erased pointer to an `Arc`
/// that is associated with the task.
/// The value of this pointer will get passed to all functions that are part
/// of the `vtable` as the first parameter.
///
/// The `vtable` customizes the behavior of a `LocalWaker`. For each
/// operation on the `LocalWaker`, the associated function in the `vtable`
/// will be called.
///
/// # Safety
///
/// The behavior of the returned `Waker` is undefined if the contract defined
/// in [`RawWakerVTable`]'s documentation is not upheld.
///
#[inline]
#[must_use]
#[unstable(feature = "local_waker", issue = "118959")]
pub const unsafe fn new(data: *const (), vtable: &'static RawWakerVTable) -> Self {
LocalWaker { waker: RawWaker { data, vtable } }
}
/// Creates a new `LocalWaker` from [`RawWaker`].
///
/// The behavior of the returned `LocalWaker` is undefined if the contract defined
@ -831,12 +878,20 @@ impl LocalWaker {
WAKER
}
/// Gets a reference to the underlying [`RawWaker`].
/// Gets the `data` pointer used to create this `LocalWaker`.
#[inline]
#[must_use]
#[unstable(feature = "waker_getters", issue = "96992")]
pub fn as_raw(&self) -> &RawWaker {
&self.waker
#[unstable(feature = "local_waker", issue = "118959")]
pub fn data(&self) -> *const () {
self.waker.data
}
/// Gets the `vtable` pointer used to create this `LocalWaker`.
#[inline]
#[must_use]
#[unstable(feature = "local_waker", issue = "118959")]
pub fn vtable(&self) -> &'static RawWakerVTable {
self.waker.vtable
}
}
#[unstable(feature = "local_waker", issue = "118959")]

View File

@ -112,7 +112,6 @@
#![feature(unsize)]
#![feature(unsized_tuple_coercion)]
#![feature(unwrap_infallible)]
#![feature(waker_getters)]
// tidy-alphabetical-end
#![allow(internal_features)]
#![deny(fuzzy_provenance_casts)]

View File

@ -4,14 +4,13 @@ use std::task::{RawWaker, RawWakerVTable, Waker};
#[test]
fn test_waker_getters() {
let raw_waker = RawWaker::new(ptr::without_provenance_mut(42usize), &WAKER_VTABLE);
assert_eq!(raw_waker.data() as usize, 42);
assert!(ptr::eq(raw_waker.vtable(), &WAKER_VTABLE));
let waker = unsafe { Waker::from_raw(raw_waker) };
assert_eq!(waker.data() as usize, 42);
assert!(ptr::eq(waker.vtable(), &WAKER_VTABLE));
let waker2 = waker.clone();
let raw_waker2 = waker2.as_raw();
assert_eq!(raw_waker2.data() as usize, 43);
assert!(ptr::eq(raw_waker2.vtable(), &WAKER_VTABLE));
assert_eq!(waker2.data() as usize, 43);
assert!(ptr::eq(waker2.vtable(), &WAKER_VTABLE));
}
static WAKER_VTABLE: RawWakerVTable = RawWakerVTable::new(

View File

@ -20,3 +20,10 @@ cfg-if = { version = "1.0", features = ['rustc-dep-of-std'] }
[target.'cfg(not(all(windows, target_env = "msvc")))'.dependencies]
libc = { version = "0.2", default-features = false }
[lints.rust.unexpected_cfgs]
level = "warn"
check-cfg = [
# #[cfg(bootstrap)] rtems
'cfg(target_os, values("rtems"))',
]

View File

@ -48,7 +48,7 @@ cfg_if::cfg_if! {
target_os = "psp",
target_os = "xous",
target_os = "solid_asp3",
all(target_family = "unix", not(target_os = "espidf")),
all(target_family = "unix", not(any(target_os = "espidf", target_os = "rtems"))),
all(target_vendor = "fortanix", target_env = "sgx"),
target_family = "wasm",
))] {

View File

@ -146,4 +146,6 @@ check-cfg = [
# and to the `backtrace` crate which messes-up with Cargo list
# of declared features, we therefor expect any feature cfg
'cfg(feature, values(any()))',
# #[cfg(bootstrap)] rtems
'cfg(target_os, values("rtems"))',
]

View File

@ -53,6 +53,7 @@ fn main() {
|| target_os == "uefi"
|| target_os == "teeos"
|| target_os == "zkvm"
|| target_os == "rtems"
// See src/bootstrap/src/core/build_steps/synthetic_targets.rs
|| env::var("RUSTC_BOOTSTRAP_SYNTHETIC_TARGET").is_ok()

View File

@ -143,6 +143,8 @@ pub mod nto;
pub mod openbsd;
#[cfg(target_os = "redox")]
pub mod redox;
#[cfg(target_os = "rtems")]
pub mod rtems;
#[cfg(target_os = "solaris")]
pub mod solaris;
#[cfg(target_os = "solid_asp3")]

View File

@ -0,0 +1,374 @@
#![stable(feature = "metadata_ext", since = "1.1.0")]
use crate::fs::Metadata;
use crate::sys_common::AsInner;
/// OS-specific extensions to [`fs::Metadata`].
///
/// [`fs::Metadata`]: crate::fs::Metadata
#[stable(feature = "metadata_ext", since = "1.1.0")]
pub trait MetadataExt {
/// Returns the device ID on which this file resides.
///
/// # Examples
///
/// ```no_run
/// use std::fs;
/// use std::io;
/// use std::os::rtems::fs::MetadataExt;
///
/// fn main() -> io::Result<()> {
/// let meta = fs::metadata("some_file")?;
/// println!("{}", meta.st_dev());
/// Ok(())
/// }
/// ```
#[stable(feature = "metadata_ext2", since = "1.8.0")]
fn st_dev(&self) -> u64;
/// Returns the inode number.
///
/// # Examples
///
/// ```no_run
/// use std::fs;
/// use std::io;
/// use std::os::rtems::fs::MetadataExt;
///
/// fn main() -> io::Result<()> {
/// let meta = fs::metadata("some_file")?;
/// println!("{}", meta.st_ino());
/// Ok(())
/// }
/// ```
#[stable(feature = "metadata_ext2", since = "1.8.0")]
fn st_ino(&self) -> u64;
/// Returns the file type and mode.
///
/// # Examples
///
/// ```no_run
/// use std::fs;
/// use std::io;
/// use std::os::rtems::fs::MetadataExt;
///
/// fn main() -> io::Result<()> {
/// let meta = fs::metadata("some_file")?;
/// println!("{}", meta.st_mode());
/// Ok(())
/// }
/// ```
#[stable(feature = "metadata_ext2", since = "1.8.0")]
fn st_mode(&self) -> u32;
/// Returns the number of hard links to file.
///
/// # Examples
///
/// ```no_run
/// use std::fs;
/// use std::io;
/// use std::os::rtems::fs::MetadataExt;
///
/// fn main() -> io::Result<()> {
/// let meta = fs::metadata("some_file")?;
/// println!("{}", meta.st_nlink());
/// Ok(())
/// }
/// ```
#[stable(feature = "metadata_ext2", since = "1.8.0")]
fn st_nlink(&self) -> u64;
/// Returns the user ID of the file owner.
///
/// # Examples
///
/// ```no_run
/// use std::fs;
/// use std::io;
/// use std::os::rtems::fs::MetadataExt;
///
/// fn main() -> io::Result<()> {
/// let meta = fs::metadata("some_file")?;
/// println!("{}", meta.st_uid());
/// Ok(())
/// }
/// ```
#[stable(feature = "metadata_ext2", since = "1.8.0")]
fn st_uid(&self) -> u32;
/// Returns the group ID of the file owner.
///
/// # Examples
///
/// ```no_run
/// use std::fs;
/// use std::io;
/// use std::os::rtems::fs::MetadataExt;
///
/// fn main() -> io::Result<()> {
/// let meta = fs::metadata("some_file")?;
/// println!("{}", meta.st_gid());
/// Ok(())
/// }
/// ```
#[stable(feature = "metadata_ext2", since = "1.8.0")]
fn st_gid(&self) -> u32;
/// Returns the device ID that this file represents. Only relevant for special file.
///
/// # Examples
///
/// ```no_run
/// use std::fs;
/// use std::io;
/// use std::os::rtems::fs::MetadataExt;
///
/// fn main() -> io::Result<()> {
/// let meta = fs::metadata("some_file")?;
/// println!("{}", meta.st_rdev());
/// Ok(())
/// }
/// ```
#[stable(feature = "metadata_ext2", since = "1.8.0")]
fn st_rdev(&self) -> u64;
/// Returns the size of the file (if it is a regular file or a symbolic link) in bytes.
///
/// The size of a symbolic link is the length of the pathname it contains,
/// without a terminating null byte.
///
/// # Examples
///
/// ```no_run
/// use std::fs;
/// use std::io;
/// use std::os::rtems::fs::MetadataExt;
///
/// fn main() -> io::Result<()> {
/// let meta = fs::metadata("some_file")?;
/// println!("{}", meta.st_size());
/// Ok(())
/// }
/// ```
#[stable(feature = "metadata_ext2", since = "1.8.0")]
fn st_size(&self) -> u64;
/// Returns the last access time of the file, in seconds since Unix Epoch.
///
/// # Examples
///
/// ```no_run
/// use std::fs;
/// use std::io;
/// use std::os::rtems::fs::MetadataExt;
///
/// fn main() -> io::Result<()> {
/// let meta = fs::metadata("some_file")?;
/// println!("{}", meta.st_atime());
/// Ok(())
/// }
/// ```
#[stable(feature = "metadata_ext2", since = "1.8.0")]
fn st_atime(&self) -> i64;
/// Returns the last access time of the file, in nanoseconds since [`st_atime`].
///
/// [`st_atime`]: Self::st_atime
///
/// # Examples
///
/// ```no_run
/// use std::fs;
/// use std::io;
/// use std::os::rtems::fs::MetadataExt;
///
/// fn main() -> io::Result<()> {
/// let meta = fs::metadata("some_file")?;
/// println!("{}", meta.st_atime_nsec());
/// Ok(())
/// }
/// ```
#[stable(feature = "metadata_ext2", since = "1.8.0")]
fn st_atime_nsec(&self) -> i64;
/// Returns the last modification time of the file, in seconds since Unix Epoch.
///
/// # Examples
///
/// ```no_run
/// use std::fs;
/// use std::io;
/// use std::os::rtems::fs::MetadataExt;
///
/// fn main() -> io::Result<()> {
/// let meta = fs::metadata("some_file")?;
/// println!("{}", meta.st_mtime());
/// Ok(())
/// }
/// ```
#[stable(feature = "metadata_ext2", since = "1.8.0")]
fn st_mtime(&self) -> i64;
/// Returns the last modification time of the file, in nanoseconds since [`st_mtime`].
///
/// [`st_mtime`]: Self::st_mtime
///
/// # Examples
///
/// ```no_run
/// use std::fs;
/// use std::io;
/// use std::os::rtems::fs::MetadataExt;
///
/// fn main() -> io::Result<()> {
/// let meta = fs::metadata("some_file")?;
/// println!("{}", meta.st_mtime_nsec());
/// Ok(())
/// }
/// ```
#[stable(feature = "metadata_ext2", since = "1.8.0")]
fn st_mtime_nsec(&self) -> i64;
/// Returns the last status change time of the file, in seconds since Unix Epoch.
///
/// # Examples
///
/// ```no_run
/// use std::fs;
/// use std::io;
/// use std::os::rtems::fs::MetadataExt;
///
/// fn main() -> io::Result<()> {
/// let meta = fs::metadata("some_file")?;
/// println!("{}", meta.st_ctime());
/// Ok(())
/// }
/// ```
#[stable(feature = "metadata_ext2", since = "1.8.0")]
fn st_ctime(&self) -> i64;
/// Returns the last status change time of the file, in nanoseconds since [`st_ctime`].
///
/// [`st_ctime`]: Self::st_ctime
///
/// # Examples
///
/// ```no_run
/// use std::fs;
/// use std::io;
/// use std::os::rtems::fs::MetadataExt;
///
/// fn main() -> io::Result<()> {
/// let meta = fs::metadata("some_file")?;
/// println!("{}", meta.st_ctime_nsec());
/// Ok(())
/// }
/// ```
#[stable(feature = "metadata_ext2", since = "1.8.0")]
fn st_ctime_nsec(&self) -> i64;
/// Returns the "preferred" block size for efficient filesystem I/O.
///
/// # Examples
///
/// ```no_run
/// use std::fs;
/// use std::io;
/// use std::os::rtems::fs::MetadataExt;
///
/// fn main() -> io::Result<()> {
/// let meta = fs::metadata("some_file")?;
/// println!("{}", meta.st_blksize());
/// Ok(())
/// }
/// ```
#[stable(feature = "metadata_ext2", since = "1.8.0")]
fn st_blksize(&self) -> u64;
/// Returns the number of blocks allocated to the file, 512-byte units.
///
/// # Examples
///
/// ```no_run
/// use std::fs;
/// use std::io;
/// use std::os::rtems::fs::MetadataExt;
///
/// fn main() -> io::Result<()> {
/// let meta = fs::metadata("some_file")?;
/// println!("{}", meta.st_blocks());
/// Ok(())
/// }
/// ```
#[stable(feature = "metadata_ext2", since = "1.8.0")]
fn st_blocks(&self) -> u64;
}
#[stable(feature = "metadata_ext", since = "1.1.0")]
impl MetadataExt for Metadata {
fn st_dev(&self) -> u64 {
self.as_inner().as_inner().st_dev as u64
}
fn st_ino(&self) -> u64 {
self.as_inner().as_inner().st_ino as u64
}
fn st_mode(&self) -> u32 {
self.as_inner().as_inner().st_mode as u32
}
fn st_nlink(&self) -> u64 {
self.as_inner().as_inner().st_nlink as u64
}
fn st_uid(&self) -> u32 {
self.as_inner().as_inner().st_uid as u32
}
fn st_gid(&self) -> u32 {
self.as_inner().as_inner().st_gid as u32
}
fn st_rdev(&self) -> u64 {
self.as_inner().as_inner().st_rdev as u64
}
fn st_size(&self) -> u64 {
self.as_inner().as_inner().st_size as u64
}
fn st_atime(&self) -> i64 {
self.as_inner().as_inner().st_atime as i64
}
fn st_atime_nsec(&self) -> i64 {
0
}
fn st_mtime(&self) -> i64 {
self.as_inner().as_inner().st_mtime as i64
}
fn st_mtime_nsec(&self) -> i64 {
0
}
fn st_ctime(&self) -> i64 {
self.as_inner().as_inner().st_ctime as i64
}
fn st_ctime_nsec(&self) -> i64 {
0
}
fn st_blksize(&self) -> u64 {
self.as_inner().as_inner().st_blksize as u64
}
fn st_blocks(&self) -> u64 {
self.as_inner().as_inner().st_blocks as u64
}
}

View File

@ -0,0 +1,4 @@
#![stable(feature = "raw_ext", since = "1.1.0")]
#![forbid(unsafe_op_in_unsafe_fn)]
pub mod fs;
pub(crate) mod raw;

View File

@ -0,0 +1,33 @@
//! rtems raw type definitions
#![stable(feature = "raw_ext", since = "1.1.0")]
#![deprecated(
since = "1.8.0",
note = "these type aliases are no longer supported by \
the standard library, the `libc` crate on \
crates.io should be used instead for the correct \
definitions"
)]
#![allow(deprecated)]
#[stable(feature = "pthread_t", since = "1.8.0")]
pub type pthread_t = libc::pthread_t;
#[stable(feature = "raw_ext", since = "1.1.0")]
pub type blkcnt_t = libc::blkcnt_t;
#[stable(feature = "raw_ext", since = "1.1.0")]
pub type blksize_t = libc::blksize_t;
#[stable(feature = "raw_ext", since = "1.1.0")]
pub type dev_t = libc::dev_t;
#[stable(feature = "raw_ext", since = "1.1.0")]
pub type ino_t = libc::ino_t;
#[stable(feature = "raw_ext", since = "1.1.0")]
pub type mode_t = libc::mode_t;
#[stable(feature = "raw_ext", since = "1.1.0")]
pub type nlink_t = libc::nlink_t;
#[stable(feature = "raw_ext", since = "1.1.0")]
pub type off_t = libc::off_t;
#[stable(feature = "raw_ext", since = "1.1.0")]
pub type time_t = libc::time_t;

View File

@ -73,6 +73,8 @@ mod platform {
pub use crate::os::openbsd::*;
#[cfg(target_os = "redox")]
pub use crate::os::redox::*;
#[cfg(target_os = "rtems")]
pub use crate::os::rtems::*;
#[cfg(target_os = "solaris")]
pub use crate::os::solaris::*;
#[cfg(target_os = "vita")]

View File

@ -112,6 +112,7 @@ impl DoubleEndedIterator for Args {
target_os = "aix",
target_os = "nto",
target_os = "hurd",
target_os = "rtems",
))]
mod imp {
use crate::ffi::c_char;

View File

@ -240,6 +240,17 @@ pub mod os {
pub const EXE_EXTENSION: &str = "";
}
#[cfg(target_os = "rtems")]
pub mod os {
pub const FAMILY: &str = "unix";
pub const OS: &str = "rtems";
pub const DLL_PREFIX: &str = "lib";
pub const DLL_SUFFIX: &str = ".so";
pub const DLL_EXTENSION: &str = "so";
pub const EXE_SUFFIX: &str = "";
pub const EXE_EXTENSION: &str = "";
}
#[cfg(target_os = "vxworks")]
pub mod os {
pub const FAMILY: &str = "unix";

View File

@ -478,6 +478,7 @@ impl FileAttr {
target_os = "horizon",
target_os = "vita",
target_os = "hurd",
target_os = "rtems",
)))]
pub fn modified(&self) -> io::Result<SystemTime> {
#[cfg(target_pointer_width = "32")]
@ -490,7 +491,12 @@ impl FileAttr {
SystemTime::new(self.stat.st_mtime as i64, self.stat.st_mtime_nsec as i64)
}
#[cfg(any(target_os = "vxworks", target_os = "espidf", target_os = "vita"))]
#[cfg(any(
target_os = "vxworks",
target_os = "espidf",
target_os = "vita",
target_os = "rtems",
))]
pub fn modified(&self) -> io::Result<SystemTime> {
SystemTime::new(self.stat.st_mtime as i64, 0)
}
@ -506,6 +512,7 @@ impl FileAttr {
target_os = "horizon",
target_os = "vita",
target_os = "hurd",
target_os = "rtems",
)))]
pub fn accessed(&self) -> io::Result<SystemTime> {
#[cfg(target_pointer_width = "32")]
@ -518,7 +525,12 @@ impl FileAttr {
SystemTime::new(self.stat.st_atime as i64, self.stat.st_atime_nsec as i64)
}
#[cfg(any(target_os = "vxworks", target_os = "espidf", target_os = "vita"))]
#[cfg(any(
target_os = "vxworks",
target_os = "espidf",
target_os = "vita",
target_os = "rtems"
))]
pub fn accessed(&self) -> io::Result<SystemTime> {
SystemTime::new(self.stat.st_atime as i64, 0)
}
@ -853,6 +865,7 @@ impl Drop for Dir {
target_os = "fuchsia",
target_os = "horizon",
target_os = "vxworks",
target_os = "rtems",
)))]
{
let fd = unsafe { libc::dirfd(self.0) };
@ -970,6 +983,7 @@ impl DirEntry {
target_os = "aix",
target_os = "nto",
target_os = "hurd",
target_os = "rtems",
target_vendor = "apple",
))]
pub fn ino(&self) -> u64 {

View File

@ -79,6 +79,7 @@ pub unsafe fn init(argc: isize, argv: *const *const u8, sigpipe: u8) {
target_os = "l4re",
target_os = "horizon",
target_os = "vita",
target_os = "rtems",
// The poll on Darwin doesn't set POLLNVAL for closed fds.
target_vendor = "apple",
)))]

View File

@ -31,7 +31,7 @@ cfg_if::cfg_if! {
}
extern "C" {
#[cfg(not(any(target_os = "dragonfly", target_os = "vxworks")))]
#[cfg(not(any(target_os = "dragonfly", target_os = "vxworks", target_os = "rtems")))]
#[cfg_attr(
any(
target_os = "linux",
@ -61,13 +61,14 @@ extern "C" {
}
/// Returns the platform-specific value of errno
#[cfg(not(any(target_os = "dragonfly", target_os = "vxworks")))]
#[cfg(not(any(target_os = "dragonfly", target_os = "vxworks", target_os = "rtems")))]
pub fn errno() -> i32 {
unsafe { (*errno_location()) as i32 }
}
/// Sets the platform-specific value of errno
#[cfg(all(not(target_os = "dragonfly"), not(target_os = "vxworks")))] // needed for readdir and syscall!
// needed for readdir and syscall!
#[cfg(all(not(target_os = "dragonfly"), not(target_os = "vxworks"), not(target_os = "rtems")))]
#[allow(dead_code)] // but not all target cfgs actually end up using it
pub fn set_errno(e: i32) {
unsafe { *errno_location() = e as c_int }
@ -78,6 +79,16 @@ pub fn errno() -> i32 {
unsafe { libc::errnoGet() }
}
#[cfg(target_os = "rtems")]
pub fn errno() -> i32 {
extern "C" {
#[thread_local]
static _tls_errno: c_int;
}
unsafe { _tls_errno as i32 }
}
#[cfg(target_os = "dragonfly")]
pub fn errno() -> i32 {
extern "C" {
@ -472,7 +483,7 @@ pub fn current_exe() -> io::Result<PathBuf> {
}
}
#[cfg(target_os = "redox")]
#[cfg(any(target_os = "redox", target_os = "rtems"))]
pub fn current_exe() -> io::Result<PathBuf> {
crate::fs::read_to_string("sys:exe").map(PathBuf::from)
}

View File

@ -1089,13 +1089,13 @@ fn signal_string(signal: i32) -> &'static str {
libc::SIGURG => " (SIGURG)",
#[cfg(not(target_os = "l4re"))]
libc::SIGXCPU => " (SIGXCPU)",
#[cfg(not(target_os = "l4re"))]
#[cfg(not(any(target_os = "l4re", target_os = "rtems")))]
libc::SIGXFSZ => " (SIGXFSZ)",
#[cfg(not(target_os = "l4re"))]
#[cfg(not(any(target_os = "l4re", target_os = "rtems")))]
libc::SIGVTALRM => " (SIGVTALRM)",
#[cfg(not(target_os = "l4re"))]
libc::SIGPROF => " (SIGPROF)",
#[cfg(not(target_os = "l4re"))]
#[cfg(not(any(target_os = "l4re", target_os = "rtems")))]
libc::SIGWINCH => " (SIGWINCH)",
#[cfg(not(any(target_os = "haiku", target_os = "l4re")))]
libc::SIGIO => " (SIGIO)",

View File

@ -31,7 +31,7 @@ cfg_if::cfg_if! {
target_os = "psp",
target_os = "xous",
target_os = "solid_asp3",
all(target_family = "unix", not(target_os = "espidf"), not(target_os = "l4re")),
all(target_family = "unix", not(target_os = "espidf"), not(target_os = "l4re"), not(target_os = "rtems")),
all(target_vendor = "fortanix", target_env = "sgx"),
))] {
mod gcc;

View File

@ -34,3 +34,10 @@ llvm-libunwind = []
# If crt-static is enabled, static link to `libunwind.a` provided by system
# If crt-static is disabled, dynamic link to `libunwind.so` provided by system
system-llvm-libunwind = []
[lints.rust.unexpected_cfgs]
level = "warn"
check-cfg = [
# #[cfg(bootstrap)] rtems
'cfg(target_os, values("rtems"))',
]

View File

@ -22,6 +22,7 @@ cfg_if::cfg_if! {
target_os = "l4re",
target_os = "none",
target_os = "espidf",
target_os = "rtems",
))] {
// These "unix" family members do not have unwinder.
} else if #[cfg(any(

View File

@ -93,7 +93,6 @@ fn get_modified_rs_files(build: &Builder<'_>) -> Result<Option<Vec<String>>, Str
if !verify_rustfmt_version(build) {
return Ok(None);
}
get_git_modified_files(&build.config.git_config(), Some(&build.config.src), &["rs"])
}

View File

@ -1810,6 +1810,9 @@ NOTE: if you're sure you want to do this, please open an issue as to why. In the
if builder.config.rust_optimize_tests {
cmd.arg("--optimize-tests");
}
if builder.config.rust_randomize_layout {
cmd.arg("--rust-randomized-layout");
}
if builder.config.cmd.only_modified() {
cmd.arg("--only-modified");
}

View File

@ -1618,6 +1618,15 @@ impl<'a> Builder<'a> {
rustflags.arg("-Csymbol-mangling-version=legacy");
}
// FIXME: the following components don't build with `-Zrandomize-layout` yet:
// - wasm-component-ld, due to the `wast`crate
// - rust-analyzer, due to the rowan crate
// so we exclude entire categories of steps here due to lack of fine-grained control over
// rustflags.
if self.config.rust_randomize_layout && mode != Mode::ToolStd && mode != Mode::ToolRustc {
rustflags.arg("-Zrandomize-layout");
}
// Enable compile-time checking of `cfg` names, values and Cargo `features`.
//
// Note: `std`, `alloc` and `core` imports some dependencies by #[path] (like
@ -2193,6 +2202,9 @@ impl<'a> Builder<'a> {
rustflags.arg("-Zvalidate-mir");
rustflags.arg(&format!("-Zmir-opt-level={mir_opt_level}"));
}
if self.config.rust_randomize_layout {
rustflags.arg("--cfg=randomized_layouts");
}
// Always enable inlining MIR when building the standard library.
// Without this flag, MIR inlining is disabled when incremental compilation is enabled.
// That causes some mir-opt tests which inline functions from the standard library to

View File

@ -268,7 +268,6 @@ pub struct Config {
pub rust_debuginfo_level_std: DebuginfoLevel,
pub rust_debuginfo_level_tools: DebuginfoLevel,
pub rust_debuginfo_level_tests: DebuginfoLevel,
pub rust_split_debuginfo_for_build_triple: Option<SplitDebuginfo>, // FIXME: Deprecated field. Remove in Q3'24.
pub rust_rpath: bool,
pub rust_strip: bool,
pub rust_frame_pointers: bool,
@ -280,6 +279,7 @@ pub struct Config {
pub rust_codegen_backends: Vec<String>,
pub rust_verify_llvm_ir: bool,
pub rust_thin_lto_import_instr_limit: Option<u32>,
pub rust_randomize_layout: bool,
pub rust_remap_debuginfo: bool,
pub rust_new_symbol_mangling: Option<bool>,
pub rust_profile_use: Option<String>,
@ -1090,6 +1090,7 @@ define_config! {
codegen_units: Option<u32> = "codegen-units",
codegen_units_std: Option<u32> = "codegen-units-std",
debug_assertions: Option<bool> = "debug-assertions",
randomize_layout: Option<bool> = "randomize-layout",
debug_assertions_std: Option<bool> = "debug-assertions-std",
overflow_checks: Option<bool> = "overflow-checks",
overflow_checks_std: Option<bool> = "overflow-checks-std",
@ -1099,7 +1100,6 @@ define_config! {
debuginfo_level_std: Option<DebuginfoLevel> = "debuginfo-level-std",
debuginfo_level_tools: Option<DebuginfoLevel> = "debuginfo-level-tools",
debuginfo_level_tests: Option<DebuginfoLevel> = "debuginfo-level-tests",
split_debuginfo: Option<String> = "split-debuginfo",
backtrace: Option<bool> = "backtrace",
incremental: Option<bool> = "incremental",
parallel_compiler: Option<bool> = "parallel-compiler",
@ -1181,6 +1181,7 @@ impl Config {
backtrace: true,
rust_optimize: RustOptimize::Bool(true),
rust_optimize_tests: true,
rust_randomize_layout: false,
submodules: None,
docs: true,
docs_minification: true,
@ -1636,10 +1637,10 @@ impl Config {
debuginfo_level_std: debuginfo_level_std_toml,
debuginfo_level_tools: debuginfo_level_tools_toml,
debuginfo_level_tests: debuginfo_level_tests_toml,
split_debuginfo,
backtrace,
incremental,
parallel_compiler,
randomize_layout,
default_linker,
channel,
description,
@ -1695,18 +1696,6 @@ impl Config {
debuginfo_level_tests = debuginfo_level_tests_toml;
lld_enabled = lld_enabled_toml;
config.rust_split_debuginfo_for_build_triple = split_debuginfo
.as_deref()
.map(SplitDebuginfo::from_str)
.map(|v| v.expect("invalid value for rust.split-debuginfo"));
if config.rust_split_debuginfo_for_build_triple.is_some() {
println!(
"WARNING: specifying `rust.split-debuginfo` is deprecated, use `target.{}.split-debuginfo` instead",
config.build
);
}
optimize = optimize_toml;
omit_git_hash = omit_git_hash_toml;
config.rust_new_symbol_mangling = new_symbol_mangling;
@ -1729,6 +1718,7 @@ impl Config {
set(&mut config.lld_mode, lld_mode);
set(&mut config.llvm_bitcode_linker_enabled, llvm_bitcode_linker);
config.rust_randomize_layout = randomize_layout.unwrap_or_default();
config.llvm_tools_enabled = llvm_tools.unwrap_or(true);
config.rustc_parallel =
parallel_compiler.unwrap_or(config.channel == "dev" || config.channel == "nightly");
@ -2504,9 +2494,6 @@ impl Config {
self.target_config
.get(&target)
.and_then(|t| t.split_debuginfo)
.or_else(|| {
if self.build == target { self.rust_split_debuginfo_for_build_triple } else { None }
})
.unwrap_or_else(|| SplitDebuginfo::default_for_platform(target))
}
@ -2900,6 +2887,7 @@ fn check_incompatible_options_for_ci_rustc(
let Rust {
// Following options are the CI rustc incompatible ones.
optimize,
randomize_layout,
debug_logging,
debuginfo_level_rustc,
llvm_tools,
@ -2927,7 +2915,6 @@ fn check_incompatible_options_for_ci_rustc(
debuginfo_level_std: _,
debuginfo_level_tools: _,
debuginfo_level_tests: _,
split_debuginfo: _,
backtrace: _,
parallel_compiler: _,
musl_root: _,
@ -2964,6 +2951,7 @@ fn check_incompatible_options_for_ci_rustc(
// otherwise, we just print a warning with `warn` macro.
err!(current_rust_config.optimize, optimize);
err!(current_rust_config.randomize_layout, randomize_layout);
err!(current_rust_config.debug_logging, debug_logging);
err!(current_rust_config.debuginfo_level_rustc, debuginfo_level_rustc);
err!(current_rust_config.rpath, rpath);

View File

@ -13,6 +13,8 @@ use std::ffi::{OsStr, OsString};
use std::path::PathBuf;
use std::{env, fs};
use build_helper::git::warn_old_master_branch;
#[cfg(not(feature = "bootstrap-self-test"))]
use crate::builder::Builder;
use crate::builder::Kind;
@ -34,6 +36,7 @@ pub struct Finder {
// Targets can be removed from this list once they are present in the stage0 compiler (usually by updating the beta compiler of the bootstrap).
const STAGE0_MISSING_TARGETS: &[&str] = &[
// just a dummy comment so the list doesn't get onelined
"armv7-rtems-eabihf",
];
/// Minimum version threshold for libstdc++ required when using prebuilt LLVM
@ -374,4 +377,14 @@ $ pacman -R cmake && pacman -S mingw-w64-x86_64-cmake
if let Some(ref s) = build.config.ccache {
cmd_finder.must_have(s);
}
// this warning is useless in CI,
// and CI probably won't have the right branches anyway.
if !build_helper::ci::CiEnv::is_ci() {
if let Err(e) = warn_old_master_branch(&build.config.git_config(), &build.config.src)
.map_err(|e| e.to_string())
{
eprintln!("unable to check if upstream branch is old: {e}");
}
}
}

View File

@ -678,6 +678,9 @@ impl Build {
if self.config.rustc_parallel {
features.push("rustc_use_parallel_compiler");
}
if self.config.rust_randomize_layout {
features.push("rustc_randomized_layouts");
}
// If debug logging is on, then we want the default for tracing:
// https://github.com/tokio-rs/tracing/blob/3dd5c03d907afdf2c39444a29931833335171554/tracing/src/level_filters.rs#L26

View File

@ -240,4 +240,9 @@ pub const CONFIG_CHANGE_HISTORY: &[ChangeInfo] = &[
severity: ChangeSeverity::Info,
summary: "New option `build.cargo-clippy` added for supporting the use of custom/external clippy.",
},
ChangeInfo {
change_id: 129925,
severity: ChangeSeverity::Warning,
summary: "Removed `rust.split-debuginfo` as it was deprecated long time ago.",
},
];

View File

@ -50,6 +50,7 @@ ENV RUST_CONFIGURE_ARGS \
--build=x86_64-unknown-linux-gnu \
--llvm-root=/usr/lib/llvm-17 \
--enable-llvm-link-shared \
--set rust.randomize-layout=true \
--set rust.thin-lto-import-instr-limit=10
COPY host-x86_64/dist-x86_64-linux/shared.sh /scripts/

View File

@ -4,8 +4,8 @@ set -euo pipefail
LINUX_VERSION=4c7864e81d8bbd51036dacf92fb0a400e13aaeee
# Build rustc, rustdoc and cargo
../x.py build --stage 1 library rustdoc
# Build rustc, rustdoc, cargo, clippy-driver and rustfmt
../x.py build --stage 2 library rustdoc clippy rustfmt
../x.py build --stage 0 cargo
# Install rustup so that we can use the built toolchain easily, and also
@ -16,7 +16,7 @@ sh rustup.sh -y --default-toolchain none
source /cargo/env
BUILD_DIR=$(realpath ./build)
rustup toolchain link local "${BUILD_DIR}"/x86_64-unknown-linux-gnu/stage1
rustup toolchain link local "${BUILD_DIR}"/x86_64-unknown-linux-gnu/stage2
rustup default local
mkdir -p rfl
@ -62,11 +62,47 @@ make -C linux LLVM=1 -j$(($(nproc) + 1)) \
defconfig \
rfl-for-rust-ci.config
make -C linux LLVM=1 -j$(($(nproc) + 1)) \
samples/rust/rust_minimal.o \
samples/rust/rust_print.o \
drivers/net/phy/ax88796b_rust.o \
BUILD_TARGETS="
samples/rust/rust_minimal.o
samples/rust/rust_print.o
drivers/net/phy/ax88796b_rust.o
rust/doctests_kernel_generated.o
"
# Build a few Rust targets
#
# This does not include building the C side of the kernel nor linking,
# which can find other issues, but it is much faster.
#
# This includes transforming `rustdoc` tests into KUnit ones thanks to
# `CONFIG_RUST_KERNEL_DOCTESTS=y` above (which, for the moment, uses the
# unstable `--test-builder` and `--no-run`).
make -C linux LLVM=1 -j$(($(nproc) + 1)) \
$BUILD_TARGETS
# Generate documentation
make -C linux LLVM=1 -j$(($(nproc) + 1)) \
rustdoc
# Build macro expanded source (`-Zunpretty=expanded`)
#
# This target also formats the macro expanded code, thus it is also
# intended to catch ICEs with formatting `-Zunpretty=expanded` output
# like https://github.com/rust-lang/rustfmt/issues/6105.
make -C linux LLVM=1 -j$(($(nproc) + 1)) \
samples/rust/rust_minimal.rsi
# Re-build with Clippy enabled
#
# This should not introduce Clippy errors, since `CONFIG_WERROR` is not
# set (thus no `-Dwarnings`) and the kernel uses `-W` for all Clippy
# lints, including `clippy::all`. However, it could catch ICEs.
make -C linux LLVM=1 -j$(($(nproc) + 1)) CLIPPY=1 \
$BUILD_TARGETS
# Format the code
#
# This returns successfully even if there were changes, i.e. it is not
# a check.
make -C linux LLVM=1 -j$(($(nproc) + 1)) \
rustfmt

View File

@ -2,7 +2,7 @@
<!-- Completely hide the TOC and the section numbers -->
<style type="text/css">
#TOC { display: none; }
#rustdoc-toc { display: none; }
.header-section-number { display: none; }
li {list-style-type: none; }
#search-input {

View File

@ -40,6 +40,7 @@
- [thumbv8m.base-none-eabi](./platform-support/thumbv8m.base-none-eabi.md)
- [thumbv8m.main-none-eabi\*](./platform-support/thumbv8m.main-none-eabi.md)
- [armv6k-nintendo-3ds](platform-support/armv6k-nintendo-3ds.md)
- [armv7-rtems-eabihf](platform-support/armv7-rtems-eabihf.md)
- [armv7-sony-vita-newlibeabihf](platform-support/armv7-sony-vita-newlibeabihf.md)
- [armv7-unknown-linux-uclibceabi](platform-support/armv7-unknown-linux-uclibceabi.md)
- [armv7-unknown-linux-uclibceabihf](platform-support/armv7-unknown-linux-uclibceabihf.md)

View File

@ -280,6 +280,7 @@ target | std | host | notes
`armv6-unknown-freebsd` | ✓ | ✓ | Armv6 FreeBSD
[`armv6-unknown-netbsd-eabihf`](platform-support/netbsd.md) | ✓ | ✓ | Armv6 NetBSD w/hard-float
[`armv6k-nintendo-3ds`](platform-support/armv6k-nintendo-3ds.md) | ? | | Armv6k Nintendo 3DS, Horizon (Requires devkitARM toolchain)
[`armv7-rtems-eabihf`](platform-support/armv7-rtems-eabihf.md) | ? | | RTEMS OS for ARM BSPs
[`armv7-sony-vita-newlibeabihf`](platform-support/armv7-sony-vita-newlibeabihf.md) | ✓ | | Armv7-A Cortex-A9 Sony PlayStation Vita (requires VITASDK toolchain)
[`armv7-unknown-linux-uclibceabi`](platform-support/armv7-unknown-linux-uclibceabi.md) | ✓ | ✓ | Armv7-A Linux with uClibc, softfloat
[`armv7-unknown-linux-uclibceabihf`](platform-support/armv7-unknown-linux-uclibceabihf.md) | ✓ | ? | Armv7-A Linux with uClibc, hardfloat

View File

@ -0,0 +1,52 @@
# `armv7-rtems-eabihf`
**Tier: 3**
ARM targets for the [RTEMS realtime operating system](https://www.rtems.org) using the RTEMS gcc cross-compiler for linking against the libraries of a specified Board Support Package (BSP).
## Target maintainers
- [@thesummer](https://github.com/thesummer)
## Requirements
The target does not support host tools. Only cross-compilation is possible.
The cross-compiler toolchain can be obtained by following the installation instructions
of the [RTEMS Documentation](https://docs.rtems.org/branches/master/user/index.html). Additionally to the cross-compiler also a compiled BSP
for a board fitting the architecture needs to be available on the host.
Currently tested has been the BSP `xilinx_zynq_a9_qemu` of RTEMS 6.
`std` support is available, but not yet fully tested. Do NOT use in flight software!
The target follows the EABI calling convention for `extern "C"`.
The resulting binaries are in ELF format.
## Building the target
The target can be built by the standard compiler of Rust.
## Building Rust programs
Rust does not yet ship pre-compiled artifacts for this target. To compile for
this target, you will either need to build Rust with the target enabled (see
"Building the target" above), or build your own copy of `core` by using
`build-std` or similar.
In order to build an RTEMS executable it is also necessary to have a basic RTEMS configuration (in C) compiled to link against as this configures the operating system.
An example can be found at this [`rtems-sys`](https://github.com/thesummer/rtems-sys) crate which could be added as an dependency to your application.
## Testing
The resulting binaries run fine on an emulated target (possibly also on a real Zedboard or similar).
For example, on qemu the following command can execute the binary:
```sh
qemu-system-arm -no-reboot -serial null -serial mon:stdio -net none -nographic -M xilinx-zynq-a9 -m 512M -kernel <binary file>
```
While basic execution of the unit test harness seems to work. However, running the Rust testsuite on the (emulated) hardware has not yet been tested.
## Cross-compilation toolchains and C code
Compatible C-code can be built with the RTEMS cross-compiler toolchain `arm-rtems6-gcc`.
For more information how to build the toolchain, RTEMS itself and RTEMS applications please have a look at the [RTEMS Documentation](https://docs.rtems.org/branches/master/user/index.html).

View File

@ -512,9 +512,6 @@ impl Item {
pub(crate) fn is_mod(&self) -> bool {
self.type_() == ItemType::Module
}
pub(crate) fn is_trait(&self) -> bool {
self.type_() == ItemType::Trait
}
pub(crate) fn is_struct(&self) -> bool {
self.type_() == ItemType::Struct
}
@ -542,9 +539,6 @@ impl Item {
pub(crate) fn is_ty_method(&self) -> bool {
self.type_() == ItemType::TyMethod
}
pub(crate) fn is_type_alias(&self) -> bool {
self.type_() == ItemType::TypeAlias
}
pub(crate) fn is_primitive(&self) -> bool {
self.type_() == ItemType::Primitive
}

View File

@ -51,12 +51,12 @@ use tracing::{debug, trace};
use crate::clean::RenderedLink;
use crate::doctest;
use crate::doctest::GlobalTestOptions;
use crate::html::escape::Escape;
use crate::html::escape::{Escape, EscapeBodyText};
use crate::html::format::Buffer;
use crate::html::highlight;
use crate::html::length_limit::HtmlWithLimit;
use crate::html::render::small_url_encode;
use crate::html::toc::TocBuilder;
use crate::html::toc::{Toc, TocBuilder};
#[cfg(test)]
mod tests;
@ -102,6 +102,7 @@ pub struct Markdown<'a> {
/// A struct like `Markdown` that renders the markdown with a table of contents.
pub(crate) struct MarkdownWithToc<'a> {
pub(crate) content: &'a str,
pub(crate) links: &'a [RenderedLink],
pub(crate) ids: &'a mut IdMap,
pub(crate) error_codes: ErrorCodes,
pub(crate) edition: Edition,
@ -533,9 +534,11 @@ impl<'a, 'b, 'ids, I: Iterator<Item = SpannedEvent<'a>>> Iterator
let id = self.id_map.derive(id);
if let Some(ref mut builder) = self.toc {
let mut text_header = String::new();
plain_text_from_events(self.buf.iter().map(|(ev, _)| ev.clone()), &mut text_header);
let mut html_header = String::new();
html::push_html(&mut html_header, self.buf.iter().map(|(ev, _)| ev.clone()));
let sec = builder.push(level as u32, html_header, id.clone());
html_text_from_events(self.buf.iter().map(|(ev, _)| ev.clone()), &mut html_header);
let sec = builder.push(level as u32, text_header, html_header, id.clone());
self.buf.push_front((Event::Html(format!("{sec} ").into()), 0..0));
}
@ -1412,10 +1415,23 @@ impl Markdown<'_> {
}
impl MarkdownWithToc<'_> {
pub(crate) fn into_string(self) -> String {
let MarkdownWithToc { content: md, ids, error_codes: codes, edition, playground } = self;
pub(crate) fn into_parts(self) -> (Toc, String) {
let MarkdownWithToc { content: md, links, ids, error_codes: codes, edition, playground } =
self;
let p = Parser::new_ext(md, main_body_opts()).into_offset_iter();
// This is actually common enough to special-case
if md.is_empty() {
return (Toc { entries: Vec::new() }, String::new());
}
let mut replacer = |broken_link: BrokenLink<'_>| {
links
.iter()
.find(|link| &*link.original_text == &*broken_link.reference)
.map(|link| (link.href.as_str().into(), link.tooltip.as_str().into()))
};
let p = Parser::new_with_broken_link_callback(md, main_body_opts(), Some(&mut replacer));
let p = p.into_offset_iter();
let mut s = String::with_capacity(md.len() * 3 / 2);
@ -1429,7 +1445,11 @@ impl MarkdownWithToc<'_> {
html::push_html(&mut s, p);
}
format!("<nav id=\"TOC\">{toc}</nav>{s}", toc = toc.into_toc().print())
(toc.into_toc(), s)
}
pub(crate) fn into_string(self) -> String {
let (toc, s) = self.into_parts();
format!("<nav id=\"rustdoc\">{toc}</nav>{s}", toc = toc.print())
}
}
@ -1608,7 +1628,16 @@ pub(crate) fn plain_text_summary(md: &str, link_names: &[RenderedLink]) -> Strin
let p = Parser::new_with_broken_link_callback(md, summary_opts(), Some(&mut replacer));
for event in p {
plain_text_from_events(p, &mut s);
s
}
pub(crate) fn plain_text_from_events<'a>(
events: impl Iterator<Item = pulldown_cmark::Event<'a>>,
s: &mut String,
) {
for event in events {
match &event {
Event::Text(text) => s.push_str(text),
Event::Code(code) => {
@ -1623,8 +1652,29 @@ pub(crate) fn plain_text_summary(md: &str, link_names: &[RenderedLink]) -> Strin
_ => (),
}
}
}
s
pub(crate) fn html_text_from_events<'a>(
events: impl Iterator<Item = pulldown_cmark::Event<'a>>,
s: &mut String,
) {
for event in events {
match &event {
Event::Text(text) => {
write!(s, "{}", EscapeBodyText(text)).expect("string alloc infallible")
}
Event::Code(code) => {
s.push_str("<code>");
write!(s, "{}", EscapeBodyText(code)).expect("string alloc infallible");
s.push_str("</code>");
}
Event::HardBreak | Event::SoftBreak => s.push(' '),
Event::Start(Tag::CodeBlock(..)) => break,
Event::End(TagEnd::Paragraph) => break,
Event::End(TagEnd::Heading(..)) => break,
_ => (),
}
}
}
#[derive(Debug)]
@ -1975,7 +2025,8 @@ fn init_id_map() -> FxHashMap<Cow<'static, str>, usize> {
map.insert("default-settings".into(), 1);
map.insert("sidebar-vars".into(), 1);
map.insert("copy-path".into(), 1);
map.insert("TOC".into(), 1);
map.insert("rustdoc-toc".into(), 1);
map.insert("rustdoc-modnav".into(), 1);
// This is the list of IDs used by rustdoc sections (but still generated by
// rustdoc).
map.insert("fields".into(), 1);

View File

@ -15,7 +15,7 @@ use rustc_span::{sym, FileName, Symbol};
use tracing::info;
use super::print_item::{full_path, item_path, print_item};
use super::sidebar::{print_sidebar, sidebar_module_like, Sidebar};
use super::sidebar::{print_sidebar, sidebar_module_like, ModuleLike, Sidebar};
use super::write_shared::write_shared;
use super::{collect_spans_and_sources, scrape_examples_help, AllTypes, LinkFromSrc, StylePath};
use crate::clean::types::ExternalLocation;
@ -617,12 +617,14 @@ impl<'tcx> FormatRenderer<'tcx> for Context<'tcx> {
let all = shared.all.replace(AllTypes::new());
let mut sidebar = Buffer::html();
let blocks = sidebar_module_like(all.item_sections());
// all.html is not customizable, so a blank id map is fine
let blocks = sidebar_module_like(all.item_sections(), &mut IdMap::new(), ModuleLike::Crate);
let bar = Sidebar {
title_prefix: "",
title: "",
is_crate: false,
is_mod: false,
parent_is_crate: false,
blocks: vec![blocks],
path: String::new(),
};

View File

@ -13,7 +13,24 @@ use crate::clean;
use crate::formats::item_type::ItemType;
use crate::formats::Impl;
use crate::html::format::Buffer;
use crate::html::markdown::IdMap;
use crate::html::markdown::{IdMap, MarkdownWithToc};
#[derive(Clone, Copy)]
pub(crate) enum ModuleLike {
Module,
Crate,
}
impl ModuleLike {
pub(crate) fn is_crate(self) -> bool {
matches!(self, ModuleLike::Crate)
}
}
impl<'a> From<&'a clean::Item> for ModuleLike {
fn from(it: &'a clean::Item) -> ModuleLike {
if it.is_crate() { ModuleLike::Crate } else { ModuleLike::Module }
}
}
#[derive(Template)]
#[template(path = "sidebar.html")]
@ -21,6 +38,7 @@ pub(super) struct Sidebar<'a> {
pub(super) title_prefix: &'static str,
pub(super) title: &'a str,
pub(super) is_crate: bool,
pub(super) parent_is_crate: bool,
pub(super) is_mod: bool,
pub(super) blocks: Vec<LinkBlock<'a>>,
pub(super) path: String,
@ -63,15 +81,19 @@ impl<'a> LinkBlock<'a> {
/// A link to an item. Content should not be escaped.
#[derive(PartialOrd, Ord, PartialEq, Eq, Hash, Clone)]
pub(crate) struct Link<'a> {
/// The content for the anchor tag
/// The content for the anchor tag and title attr
name: Cow<'a, str>,
/// The content for the anchor tag (if different from name)
name_html: Option<Cow<'a, str>>,
/// The id of an anchor within the page (without a `#` prefix)
href: Cow<'a, str>,
/// Nested list of links (used only in top-toc)
children: Vec<Link<'a>>,
}
impl<'a> Link<'a> {
pub fn new(href: impl Into<Cow<'a, str>>, name: impl Into<Cow<'a, str>>) -> Self {
Self { href: href.into(), name: name.into() }
Self { href: href.into(), name: name.into(), children: vec![], name_html: None }
}
pub fn empty() -> Link<'static> {
Link::new("", "")
@ -95,17 +117,21 @@ pub(crate) mod filters {
}
pub(super) fn print_sidebar(cx: &Context<'_>, it: &clean::Item, buffer: &mut Buffer) {
let blocks: Vec<LinkBlock<'_>> = match *it.kind {
clean::StructItem(ref s) => sidebar_struct(cx, it, s),
clean::TraitItem(ref t) => sidebar_trait(cx, it, t),
clean::PrimitiveItem(_) => sidebar_primitive(cx, it),
clean::UnionItem(ref u) => sidebar_union(cx, it, u),
clean::EnumItem(ref e) => sidebar_enum(cx, it, e),
clean::TypeAliasItem(ref t) => sidebar_type_alias(cx, it, t),
clean::ModuleItem(ref m) => vec![sidebar_module(&m.items)],
clean::ForeignTypeItem => sidebar_foreign_type(cx, it),
_ => vec![],
};
let mut ids = IdMap::new();
let mut blocks: Vec<LinkBlock<'_>> = docblock_toc(cx, it, &mut ids).into_iter().collect();
match *it.kind {
clean::StructItem(ref s) => sidebar_struct(cx, it, s, &mut blocks),
clean::TraitItem(ref t) => sidebar_trait(cx, it, t, &mut blocks),
clean::PrimitiveItem(_) => sidebar_primitive(cx, it, &mut blocks),
clean::UnionItem(ref u) => sidebar_union(cx, it, u, &mut blocks),
clean::EnumItem(ref e) => sidebar_enum(cx, it, e, &mut blocks),
clean::TypeAliasItem(ref t) => sidebar_type_alias(cx, it, t, &mut blocks),
clean::ModuleItem(ref m) => {
blocks.push(sidebar_module(&m.items, &mut ids, ModuleLike::from(it)))
}
clean::ForeignTypeItem => sidebar_foreign_type(cx, it, &mut blocks),
_ => {}
}
// The sidebar is designed to display sibling functions, modules and
// other miscellaneous information. since there are lots of sibling
// items (and that causes quadratic growth in large modules),
@ -113,15 +139,9 @@ pub(super) fn print_sidebar(cx: &Context<'_>, it: &clean::Item, buffer: &mut Buf
// still, we don't move everything into JS because we want to preserve
// as much HTML as possible in order to allow non-JS-enabled browsers
// to navigate the documentation (though slightly inefficiently).
let (title_prefix, title) = if it.is_struct()
|| it.is_trait()
|| it.is_primitive()
|| it.is_union()
|| it.is_enum()
// crate title is displayed as part of logo lockup
|| (it.is_mod() && !it.is_crate())
|| it.is_type_alias()
{
//
// crate title is displayed as part of logo lockup
let (title_prefix, title) = if !blocks.is_empty() && !it.is_crate() {
(
match *it.kind {
clean::ModuleItem(..) => "Module ",
@ -146,8 +166,15 @@ pub(super) fn print_sidebar(cx: &Context<'_>, it: &clean::Item, buffer: &mut Buf
} else {
"".into()
};
let sidebar =
Sidebar { title_prefix, title, is_mod: it.is_mod(), is_crate: it.is_crate(), blocks, path };
let sidebar = Sidebar {
title_prefix,
title,
is_mod: it.is_mod(),
is_crate: it.is_crate(),
parent_is_crate: sidebar_path.len() == 1,
blocks,
path,
};
sidebar.render_into(buffer).unwrap();
}
@ -163,30 +190,80 @@ fn get_struct_fields_name<'a>(fields: &'a [clean::Item]) -> Vec<Link<'a>> {
fields
}
fn docblock_toc<'a>(
cx: &'a Context<'_>,
it: &'a clean::Item,
ids: &mut IdMap,
) -> Option<LinkBlock<'a>> {
let (toc, _) = MarkdownWithToc {
content: &it.doc_value(),
links: &it.links(cx),
ids,
error_codes: cx.shared.codes,
edition: cx.shared.edition(),
playground: &cx.shared.playground,
}
.into_parts();
let links: Vec<Link<'_>> = toc
.entries
.into_iter()
.map(|entry| {
Link {
name_html: if entry.html == entry.name { None } else { Some(entry.html.into()) },
name: entry.name.into(),
href: entry.id.into(),
children: entry
.children
.entries
.into_iter()
.map(|entry| Link {
name_html: if entry.html == entry.name {
None
} else {
Some(entry.html.into())
},
name: entry.name.into(),
href: entry.id.into(),
// Only a single level of nesting is shown here.
// Going the full six could break the layout,
// so we have to cut it off somewhere.
children: vec![],
})
.collect(),
}
})
.collect();
if links.is_empty() {
None
} else {
Some(LinkBlock::new(Link::new("", "Sections"), "top-toc", links))
}
}
fn sidebar_struct<'a>(
cx: &'a Context<'_>,
it: &'a clean::Item,
s: &'a clean::Struct,
) -> Vec<LinkBlock<'a>> {
items: &mut Vec<LinkBlock<'a>>,
) {
let fields = get_struct_fields_name(&s.fields);
let field_name = match s.ctor_kind {
Some(CtorKind::Fn) => Some("Tuple Fields"),
None => Some("Fields"),
_ => None,
};
let mut items = vec![];
if let Some(name) = field_name {
items.push(LinkBlock::new(Link::new("fields", name), "structfield", fields));
}
sidebar_assoc_items(cx, it, &mut items);
items
sidebar_assoc_items(cx, it, items);
}
fn sidebar_trait<'a>(
cx: &'a Context<'_>,
it: &'a clean::Item,
t: &'a clean::Trait,
) -> Vec<LinkBlock<'a>> {
blocks: &mut Vec<LinkBlock<'a>>,
) {
fn filter_items<'a>(
items: &'a [clean::Item],
filt: impl Fn(&clean::Item) -> bool,
@ -223,19 +300,20 @@ fn sidebar_trait<'a>(
foreign_impls.sort();
}
let mut blocks: Vec<LinkBlock<'_>> = [
("required-associated-types", "Required Associated Types", req_assoc),
("provided-associated-types", "Provided Associated Types", prov_assoc),
("required-associated-consts", "Required Associated Constants", req_assoc_const),
("provided-associated-consts", "Provided Associated Constants", prov_assoc_const),
("required-methods", "Required Methods", req_method),
("provided-methods", "Provided Methods", prov_method),
("foreign-impls", "Implementations on Foreign Types", foreign_impls),
]
.into_iter()
.map(|(id, title, items)| LinkBlock::new(Link::new(id, title), "", items))
.collect();
sidebar_assoc_items(cx, it, &mut blocks);
blocks.extend(
[
("required-associated-types", "Required Associated Types", req_assoc),
("provided-associated-types", "Provided Associated Types", prov_assoc),
("required-associated-consts", "Required Associated Constants", req_assoc_const),
("provided-associated-consts", "Provided Associated Constants", prov_assoc_const),
("required-methods", "Required Methods", req_method),
("provided-methods", "Provided Methods", prov_method),
("foreign-impls", "Implementations on Foreign Types", foreign_impls),
]
.into_iter()
.map(|(id, title, items)| LinkBlock::new(Link::new(id, title), "", items)),
);
sidebar_assoc_items(cx, it, blocks);
if !t.is_object_safe(cx.tcx()) {
blocks.push(LinkBlock::forced(
@ -251,20 +329,17 @@ fn sidebar_trait<'a>(
"impl-auto",
));
}
blocks
}
fn sidebar_primitive<'a>(cx: &'a Context<'_>, it: &'a clean::Item) -> Vec<LinkBlock<'a>> {
fn sidebar_primitive<'a>(cx: &'a Context<'_>, it: &'a clean::Item, items: &mut Vec<LinkBlock<'a>>) {
if it.name.map(|n| n.as_str() != "reference").unwrap_or(false) {
let mut items = vec![];
sidebar_assoc_items(cx, it, &mut items);
items
sidebar_assoc_items(cx, it, items);
} else {
let shared = Rc::clone(&cx.shared);
let (concrete, synthetic, blanket_impl) =
super::get_filtered_impls_for_reference(&shared, it);
sidebar_render_assoc_items(cx, &mut IdMap::new(), concrete, synthetic, blanket_impl).into()
sidebar_render_assoc_items(cx, &mut IdMap::new(), concrete, synthetic, blanket_impl, items);
}
}
@ -272,8 +347,8 @@ fn sidebar_type_alias<'a>(
cx: &'a Context<'_>,
it: &'a clean::Item,
t: &'a clean::TypeAlias,
) -> Vec<LinkBlock<'a>> {
let mut items = vec![];
items: &mut Vec<LinkBlock<'a>>,
) {
if let Some(inner_type) = &t.inner_type {
items.push(LinkBlock::forced(Link::new("aliased-type", "Aliased type"), "type"));
match inner_type {
@ -295,19 +370,18 @@ fn sidebar_type_alias<'a>(
}
}
}
sidebar_assoc_items(cx, it, &mut items);
items
sidebar_assoc_items(cx, it, items);
}
fn sidebar_union<'a>(
cx: &'a Context<'_>,
it: &'a clean::Item,
u: &'a clean::Union,
) -> Vec<LinkBlock<'a>> {
items: &mut Vec<LinkBlock<'a>>,
) {
let fields = get_struct_fields_name(&u.fields);
let mut items = vec![LinkBlock::new(Link::new("fields", "Fields"), "structfield", fields)];
sidebar_assoc_items(cx, it, &mut items);
items
items.push(LinkBlock::new(Link::new("fields", "Fields"), "structfield", fields));
sidebar_assoc_items(cx, it, items);
}
/// Adds trait implementations into the blocks of links
@ -346,33 +420,6 @@ fn sidebar_assoc_items<'a>(
methods.sort();
}
let mut deref_methods = Vec::new();
let [concrete, synthetic, blanket] = if v.iter().any(|i| i.inner_impl().trait_.is_some()) {
if let Some(impl_) =
v.iter().find(|i| i.trait_did() == cx.tcx().lang_items().deref_trait())
{
let mut derefs = DefIdSet::default();
derefs.insert(did);
sidebar_deref_methods(
cx,
&mut deref_methods,
impl_,
v,
&mut derefs,
&mut used_links,
);
}
let (synthetic, concrete): (Vec<&Impl>, Vec<&Impl>) =
v.iter().partition::<Vec<_>, _>(|i| i.inner_impl().kind.is_auto());
let (blanket_impl, concrete): (Vec<&Impl>, Vec<&Impl>) =
concrete.into_iter().partition::<Vec<_>, _>(|i| i.inner_impl().kind.is_blanket());
sidebar_render_assoc_items(cx, &mut id_map, concrete, synthetic, blanket_impl)
} else {
std::array::from_fn(|_| LinkBlock::new(Link::empty(), "", vec![]))
};
let mut blocks = vec![
LinkBlock::new(
Link::new("implementations", "Associated Constants"),
@ -381,8 +428,30 @@ fn sidebar_assoc_items<'a>(
),
LinkBlock::new(Link::new("implementations", "Methods"), "method", methods),
];
blocks.append(&mut deref_methods);
blocks.extend([concrete, synthetic, blanket]);
if v.iter().any(|i| i.inner_impl().trait_.is_some()) {
if let Some(impl_) =
v.iter().find(|i| i.trait_did() == cx.tcx().lang_items().deref_trait())
{
let mut derefs = DefIdSet::default();
derefs.insert(did);
sidebar_deref_methods(cx, &mut blocks, impl_, v, &mut derefs, &mut used_links);
}
let (synthetic, concrete): (Vec<&Impl>, Vec<&Impl>) =
v.iter().partition::<Vec<_>, _>(|i| i.inner_impl().kind.is_auto());
let (blanket_impl, concrete): (Vec<&Impl>, Vec<&Impl>) =
concrete.into_iter().partition::<Vec<_>, _>(|i| i.inner_impl().kind.is_blanket());
sidebar_render_assoc_items(
cx,
&mut id_map,
concrete,
synthetic,
blanket_impl,
&mut blocks,
);
}
links.append(&mut blocks);
}
}
@ -472,7 +541,8 @@ fn sidebar_enum<'a>(
cx: &'a Context<'_>,
it: &'a clean::Item,
e: &'a clean::Enum,
) -> Vec<LinkBlock<'a>> {
items: &mut Vec<LinkBlock<'a>>,
) {
let mut variants = e
.variants()
.filter_map(|v| v.name)
@ -480,24 +550,37 @@ fn sidebar_enum<'a>(
.collect::<Vec<_>>();
variants.sort_unstable();
let mut items = vec![LinkBlock::new(Link::new("variants", "Variants"), "variant", variants)];
sidebar_assoc_items(cx, it, &mut items);
items
items.push(LinkBlock::new(Link::new("variants", "Variants"), "variant", variants));
sidebar_assoc_items(cx, it, items);
}
pub(crate) fn sidebar_module_like(
item_sections_in_use: FxHashSet<ItemSection>,
ids: &mut IdMap,
module_like: ModuleLike,
) -> LinkBlock<'static> {
let item_sections = ItemSection::ALL
let item_sections: Vec<Link<'_>> = ItemSection::ALL
.iter()
.copied()
.filter(|sec| item_sections_in_use.contains(sec))
.map(|sec| Link::new(sec.id(), sec.name()))
.map(|sec| Link::new(ids.derive(sec.id()), sec.name()))
.collect();
LinkBlock::new(Link::empty(), "", item_sections)
let header = if let Some(first_section) = item_sections.get(0) {
Link::new(
first_section.href.to_owned(),
if module_like.is_crate() { "Crate Items" } else { "Module Items" },
)
} else {
Link::empty()
};
LinkBlock::new(header, "", item_sections)
}
fn sidebar_module(items: &[clean::Item]) -> LinkBlock<'static> {
fn sidebar_module(
items: &[clean::Item],
ids: &mut IdMap,
module_like: ModuleLike,
) -> LinkBlock<'static> {
let item_sections_in_use: FxHashSet<_> = items
.iter()
.filter(|it| {
@ -518,13 +601,15 @@ fn sidebar_module(items: &[clean::Item]) -> LinkBlock<'static> {
.map(|it| item_ty_to_section(it.type_()))
.collect();
sidebar_module_like(item_sections_in_use)
sidebar_module_like(item_sections_in_use, ids, module_like)
}
fn sidebar_foreign_type<'a>(cx: &'a Context<'_>, it: &'a clean::Item) -> Vec<LinkBlock<'a>> {
let mut items = vec![];
sidebar_assoc_items(cx, it, &mut items);
items
fn sidebar_foreign_type<'a>(
cx: &'a Context<'_>,
it: &'a clean::Item,
items: &mut Vec<LinkBlock<'a>>,
) {
sidebar_assoc_items(cx, it, items);
}
/// Renders the trait implementations for this type
@ -534,7 +619,8 @@ fn sidebar_render_assoc_items(
concrete: Vec<&Impl>,
synthetic: Vec<&Impl>,
blanket_impl: Vec<&Impl>,
) -> [LinkBlock<'static>; 3] {
items: &mut Vec<LinkBlock<'_>>,
) {
let format_impls = |impls: Vec<&Impl>, id_map: &mut IdMap| {
let mut links = FxHashSet::default();
@ -559,7 +645,7 @@ fn sidebar_render_assoc_items(
let concrete = format_impls(concrete, id_map);
let synthetic = format_impls(synthetic, id_map);
let blanket = format_impls(blanket_impl, id_map);
[
items.extend([
LinkBlock::new(
Link::new("trait-implementations", "Trait Implementations"),
"trait-implementation",
@ -575,7 +661,7 @@ fn sidebar_render_assoc_items(
"blanket-implementation",
blanket,
),
]
]);
}
fn get_next_url(used_links: &mut FxHashSet<String>, url: String) -> String {

View File

@ -568,12 +568,16 @@ img {
width: 48px;
}
ul.block, .block li {
ul.block, .block li, .block ul {
padding: 0;
margin: 0;
list-style: none;
}
.block ul a {
padding-left: 1rem;
}
.sidebar-elems a,
.sidebar > h2 a {
display: block;
@ -585,6 +589,14 @@ ul.block, .block li {
background-clip: border-box;
}
.hide-toc #rustdoc-toc, .hide-toc .in-crate {
display: none;
}
.hide-modnav #rustdoc-modnav {
display: none;
}
.sidebar h2 {
text-wrap: balance;
overflow-wrap: anywhere;

View File

@ -499,7 +499,7 @@ function preLoadCss(cssUrl) {
if (!window.SIDEBAR_ITEMS) {
return;
}
const sidebar = document.getElementsByClassName("sidebar-elems")[0];
const sidebar = document.getElementById("rustdoc-modnav");
/**
* Append to the sidebar a "block" of links - a heading along with a list (`<ul>`) of items.
@ -885,7 +885,7 @@ function preLoadCss(cssUrl) {
if (!window.ALL_CRATES) {
return;
}
const sidebarElems = document.getElementsByClassName("sidebar-elems")[0];
const sidebarElems = document.getElementById("rustdoc-modnav");
if (!sidebarElems) {
return;
}

View File

@ -36,6 +36,20 @@
removeClass(document.documentElement, "hide-sidebar");
}
break;
case "hide-toc":
if (value === true) {
addClass(document.documentElement, "hide-toc");
} else {
removeClass(document.documentElement, "hide-toc");
}
break;
case "hide-modnav":
if (value === true) {
addClass(document.documentElement, "hide-modnav");
} else {
removeClass(document.documentElement, "hide-modnav");
}
break;
}
}
@ -102,6 +116,11 @@
let output = "";
for (const setting of settings) {
if (setting === "hr") {
output += "<hr>";
continue;
}
const js_data_name = setting["js_name"];
const setting_name = setting["name"];
@ -198,6 +217,16 @@
"js_name": "hide-sidebar",
"default": false,
},
{
"name": "Hide table of contents",
"js_name": "hide-toc",
"default": false,
},
{
"name": "Hide module navigation",
"js_name": "hide-modnav",
"default": false,
},
{
"name": "Disable keyboard shortcuts",
"js_name": "disable-shortcuts",

View File

@ -196,16 +196,21 @@ updateTheme();
// This needs to be done here because this JS is render-blocking,
// so that the sidebar doesn't "jump" after appearing on screen.
// The user interaction to change this is set up in main.js.
//
// At this point in page load, `document.body` is not available yet.
// Set a class on the `<html>` element instead.
if (getSettingValue("source-sidebar-show") === "true") {
// At this point in page load, `document.body` is not available yet.
// Set a class on the `<html>` element instead.
addClass(document.documentElement, "src-sidebar-expanded");
}
if (getSettingValue("hide-sidebar") === "true") {
// At this point in page load, `document.body` is not available yet.
// Set a class on the `<html>` element instead.
addClass(document.documentElement, "hide-sidebar");
}
if (getSettingValue("hide-toc") === "true") {
addClass(document.documentElement, "hide-toc");
}
if (getSettingValue("hide-modnav") === "true") {
addClass(document.documentElement, "hide-modnav");
}
function updateSidebarWidth() {
const desktopSidebarWidth = getSettingValue("desktop-sidebar-width");
if (desktopSidebarWidth && desktopSidebarWidth !== "null") {

View File

@ -1,8 +1,3 @@
{% if !title.is_empty() %}
<h2 class="location"> {# #}
<a href="#">{{title_prefix}}{{title|wrapped|safe}}</a> {# #}
</h2>
{% endif %}
<div class="sidebar-elems">
{% if is_crate %}
<ul class="block"> {# #}
@ -11,18 +6,46 @@
{% endif %}
{% if self.should_render_blocks() %}
<section>
<section id="rustdoc-toc">
{% if !title.is_empty() %}
<h2 class="location"> {# #}
<a href="#">{{title_prefix}}{{title|wrapped|safe}}</a> {# #}
</h2>
{% endif %}
{% for block in blocks %}
{% if block.should_render() %}
{% if !block.heading.name.is_empty() %}
<h3><a href="#{{block.heading.href|safe}}"> {# #}
{{block.heading.name|wrapped|safe}} {# #}
</a></h3> {# #}
<h3> {# #}
<a href="#{{block.heading.href|safe}}">{{block.heading.name|wrapped|safe}}</a> {# #}
</h3>
{% endif %}
{% if !block.links.is_empty() %}
<ul class="block{% if !block.class.is_empty() +%} {{+block.class}}{% endif %}">
{% for link in block.links %}
<li><a href="#{{link.href|safe}}">{{link.name}}</a></li>
<li> {# #}
<a href="#{{link.href|safe}}" title="{{link.name}}">
{% match link.name_html %}
{% when Some with (html) %}
{{html|safe}}
{% else %}
{{link.name}}
{% endmatch %}
</a> {# #}
{% if !link.children.is_empty() %}
<ul>
{% for child in link.children %}
<li><a href="#{{child.href|safe}}" title="{{child.name}}">
{% match child.name_html %}
{% when Some with (html) %}
{{html|safe}}
{% else %}
{{child.name}}
{% endmatch %}
</a></li>
{% endfor %}
</ul>
{% endif %}
</li>
{% endfor %}
</ul>
{% endif %}
@ -30,7 +53,11 @@
{% endfor %}
</section>
{% endif %}
<div id="rustdoc-modnav">
{% if !path.is_empty() %}
<h2><a href="{% if is_mod %}../{% endif %}index.html">In {{+ path|wrapped|safe}}</a></h2>
<h2{% if parent_is_crate +%} class="in-crate"{% endif %}> {# #}
<a href="{% if is_mod %}../{% endif %}index.html">In {{+ path|wrapped|safe}}</a> {# #}
</h2>
{% endif %}
</div> {# #}
</div>

View File

@ -1,4 +1,5 @@
//! Table-of-contents creation.
use crate::html::escape::Escape;
/// A (recursive) table of contents
#[derive(Debug, PartialEq)]
@ -16,7 +17,7 @@ pub(crate) struct Toc {
/// ### A
/// ## B
/// ```
entries: Vec<TocEntry>,
pub(crate) entries: Vec<TocEntry>,
}
impl Toc {
@ -27,11 +28,16 @@ impl Toc {
#[derive(Debug, PartialEq)]
pub(crate) struct TocEntry {
level: u32,
sec_number: String,
name: String,
id: String,
children: Toc,
pub(crate) level: u32,
pub(crate) sec_number: String,
// name is a plain text header that works in a `title` tag
// html includes `<code>` tags
// the tooltip is used so that, when a toc is truncated,
// you can mouse over it to see the whole thing
pub(crate) name: String,
pub(crate) html: String,
pub(crate) id: String,
pub(crate) children: Toc,
}
/// Progressive construction of a table of contents.
@ -115,7 +121,7 @@ impl TocBuilder {
/// Push a level `level` heading into the appropriate place in the
/// hierarchy, returning a string containing the section number in
/// `<num>.<num>.<num>` format.
pub(crate) fn push(&mut self, level: u32, name: String, id: String) -> &str {
pub(crate) fn push(&mut self, level: u32, name: String, html: String, id: String) -> &str {
assert!(level >= 1);
// collapse all previous sections into their parents until we
@ -149,6 +155,7 @@ impl TocBuilder {
self.chain.push(TocEntry {
level,
name,
html,
sec_number,
id,
children: Toc { entries: Vec::new() },
@ -170,10 +177,11 @@ impl Toc {
// recursively format this table of contents
let _ = write!(
v,
"\n<li><a href=\"#{id}\">{num} {name}</a>",
"\n<li><a href=\"#{id}\" title=\"{name}\">{num} {html}</a>",
id = entry.id,
num = entry.sec_number,
name = entry.name
name = Escape(&entry.name),
html = &entry.html,
);
entry.children.print_inner(&mut *v);
v.push_str("</li>");

View File

@ -9,7 +9,10 @@ fn builder_smoke() {
// there's been no macro mistake.
macro_rules! push {
($level: expr, $name: expr) => {
assert_eq!(builder.push($level, $name.to_string(), "".to_string()), $name);
assert_eq!(
builder.push($level, $name.to_string(), $name.to_string(), "".to_string()),
$name
);
};
}
push!(2, "0.1");
@ -48,6 +51,7 @@ fn builder_smoke() {
TocEntry {
level: $level,
name: $name.to_string(),
html: $name.to_string(),
sec_number: $name.to_string(),
id: "".to_string(),
children: toc!($($sub),*)

View File

@ -72,6 +72,7 @@ pub(crate) fn render<P: AsRef<Path>>(
let text = if !options.markdown_no_toc {
MarkdownWithToc {
content: text,
links: &[],
ids: &mut ids,
error_codes,
edition,

View File

@ -159,3 +159,37 @@ pub fn get_git_untracked_files(
.collect();
Ok(Some(files))
}
/// Print a warning if the branch returned from `updated_master_branch` is old
///
/// For certain configurations of git repository, this remote will not be
/// updated when running `git pull`.
///
/// This can result in formatting thousands of files instead of a dozen,
/// so we should warn the user something is wrong.
pub fn warn_old_master_branch(
config: &GitConfig<'_>,
git_dir: &Path,
) -> Result<(), Box<dyn std::error::Error>> {
use std::time::Duration;
const WARN_AFTER: Duration = Duration::from_secs(60 * 60 * 24 * 10);
let updated_master = updated_master_branch(config, Some(git_dir))?;
let branch_path = git_dir.join(".git/refs/remotes").join(&updated_master);
match std::fs::metadata(branch_path) {
Ok(meta) => {
if meta.modified()?.elapsed()? > WARN_AFTER {
eprintln!("warning: {updated_master} has not been updated in 10 days");
} else {
return Ok(());
}
}
Err(err) => {
eprintln!("warning: unable to check if {updated_master} is old due to error: {err}")
}
}
eprintln!(
"warning: {updated_master} is used to determine if files have been modified\n\
warning: if it is not updated, this may cause files to be needlessly reformatted"
);
Ok(())
}

View File

@ -136,6 +136,7 @@ const KNOWN_DIRECTIVE_NAMES: &[&str] = &[
"min-llvm-version",
"min-system-llvm-version",
"needs-asm-support",
"needs-deterministic-layouts",
"needs-dlltool",
"needs-dynamic-linking",
"needs-force-clang-based-tests",

View File

@ -274,6 +274,9 @@ pub struct Config {
/// Flags to pass to the compiler when building for the target
pub target_rustcflags: Vec<String>,
/// Whether the compiler and stdlib has been built with randomized struct layouts
pub rust_randomized_layout: bool,
/// Whether tests should be optimized by default. Individual test-suites and test files may
/// override this setting.
pub optimize_tests: bool,

View File

@ -134,6 +134,11 @@ pub(super) fn handle_needs(
condition: config.target_cfg().relocation_model == "pic",
ignore_reason: "ignored on targets without PIC relocation model",
},
Need {
name: "needs-deterministic-layouts",
condition: !config.rust_randomized_layout,
ignore_reason: "ignored when randomizing layouts",
},
Need {
name: "needs-wasmtime",
condition: config.runner.as_ref().is_some_and(|r| r.contains("wasmtime")),

View File

@ -99,6 +99,11 @@ pub fn parse_config(args: Vec<String>) -> Config {
)
.optmulti("", "host-rustcflags", "flags to pass to rustc for host", "FLAGS")
.optmulti("", "target-rustcflags", "flags to pass to rustc for target", "FLAGS")
.optflag(
"",
"rust-randomized-layout",
"set this when rustc/stdlib were compiled with randomized layouts",
)
.optflag("", "optimize-tests", "run tests with optimizations enabled")
.optflag("", "verbose", "run tests verbosely, showing all output")
.optflag(
@ -286,6 +291,7 @@ pub fn parse_config(args: Vec<String>) -> Config {
host_rustcflags: matches.opt_strs("host-rustcflags"),
target_rustcflags: matches.opt_strs("target-rustcflags"),
optimize_tests: matches.opt_present("optimize-tests"),
rust_randomized_layout: matches.opt_present("rust-randomized-layout"),
target,
host: opt_str2(matches.opt_str("host")),
cdb,

View File

@ -1,6 +1,6 @@
//@revisions: stack tree
//@[tree]compile-flags: -Zmiri-tree-borrows
#![feature(arbitrary_self_types, unsize, coerce_unsized, dispatch_from_dyn)]
#![feature(arbitrary_self_types_pointers, unsize, coerce_unsized, dispatch_from_dyn)]
#![feature(rustc_attrs)]
fn pin_box_dyn() {

View File

@ -129,6 +129,9 @@
//@ revisions: armv7_linux_androideabi
//@ [armv7_linux_androideabi] compile-flags: --target armv7-linux-androideabi
//@ [armv7_linux_androideabi] needs-llvm-components: arm
//@ revisions: armv7_rtems_eabihf
//@ [armv7_rtems_eabihf] compile-flags: --target armv7-rtems-eabihf
//@ [armv7_rtems_eabihf] needs-llvm-components: arm
//@ revisions: armv7_sony_vita_newlibeabihf
//@ [armv7_sony_vita_newlibeabihf] compile-flags: --target armv7-sony-vita-newlibeabihf
//@ [armv7_sony_vita_newlibeabihf] needs-llvm-components: arm

View File

@ -1,5 +1,6 @@
//@ only-64bit llvm appears to use stores instead of memset on 32bit
//@ compile-flags: -C opt-level=3 -Z merge-functions=disabled
//@ needs-deterministic-layouts
// The below two functions ensure that both `String::new()` and `"".to_string()`
// produce the identical code.

View File

@ -5,6 +5,7 @@
//@ compile-flags: -C no-prepopulate-passes -Zinline-mir=no
//@ ignore-debug: precondition checks in ptr::read make them a bad candidate for MIR inlining
//@ needs-deterministic-layouts
#![crate_type = "lib"]

View File

@ -1,4 +1,5 @@
//@ compile-flags: -O
//@ needs-deterministic-layouts
#![crate_type = "lib"]
#![feature(exact_size_is_empty)]

View File

@ -1,6 +1,7 @@
// Check that draining at the front or back doesn't copy memory.
//@ compile-flags: -O
//@ needs-deterministic-layouts
//@ ignore-debug: FIXME: checks for call detect scoped noalias metadata
#![crate_type = "lib"]

View File

@ -1,7 +1,7 @@
// skip-filecheck
// EMIT_MIR receiver_ptr_mutability.main.built.after.mir
#![feature(arbitrary_self_types)]
#![feature(arbitrary_self_types_pointers)]
struct Test {}

View File

@ -1,3 +1,4 @@
//@needs-deterministic-layouts
// Verify that we do not ICE when printing an invalid constant.
// EMIT_MIR_FOR_EACH_BIT_WIDTH
// EMIT_MIR_FOR_EACH_PANIC_STRATEGY

View File

@ -0,0 +1,44 @@
// Verifies that, when TOC is hidden, modnav is always in exactly the same spot
// This is driven by a reasonably common use case:
//
// - There are three or more items that might meet my needs.
// - I open the first one, decide it's not what I want, switch to the second one using the sidebar.
// - The second one also doesn't meet my needs, so I switch to the third.
// - The third also doesn't meet my needs, so...
//
// because the sibling module nav is in exactly the same place every time,
// it's very easy to find and switch between pages that way.
go-to: "file://" + |DOC_PATH| + "/test_docs/enum.WhoLetTheDogOut.html"
show-text: true
set-local-storage: {"rustdoc-hide-toc": "true"}
define-function: (
"check-positions",
[url],
block {
go-to: "file://" + |DOC_PATH| + |url|
// Checking results colors.
assert-position: ("#rustdoc-modnav > h2", {"x": |h2_x|, "y": |h2_y|})
assert-position: (
"#rustdoc-modnav > ul:first-of-type > li:first-of-type",
{"x": |x|, "y": |y|}
)
},
)
// First, at test_docs root
go-to: "file://" + |DOC_PATH| + "/test_docs/enum.WhoLetTheDogOut.html"
store-position: ("#rustdoc-modnav > h2", {"x": h2_x, "y": h2_y})
store-position: ("#rustdoc-modnav > ul:first-of-type > li:first-of-type", {"x": x, "y": y})
call-function: ("check-positions", {"url": "/test_docs/enum.WhoLetTheDogOut.html"})
call-function: ("check-positions", {"url": "/test_docs/struct.StructWithPublicUndocumentedFields.html"})
call-function: ("check-positions", {"url": "/test_docs/codeblock_sub/index.html"})
// Now in a submodule
go-to: "file://" + |DOC_PATH| + "/test_docs/fields/struct.Struct.html"
store-position: ("#rustdoc-modnav > h2", {"x": h2_x, "y": h2_y})
store-position: ("#rustdoc-modnav > ul:first-of-type > li:first-of-type", {"x": x, "y": y})
call-function: ("check-positions", {"url": "/test_docs/fields/struct.Struct.html"})
call-function: ("check-positions", {"url": "/test_docs/fields/union.Union.html"})
call-function: ("check-positions", {"url": "/test_docs/fields/enum.Enum.html"})

View File

@ -118,7 +118,7 @@ assert-false: ".sidebar-elems > .crate"
go-to: "./module/index.html"
assert-property: (".sidebar", {"clientWidth": "200"})
assert-text: (".sidebar > .sidebar-crate > h2 > a", "lib2")
assert-text: (".sidebar > .location", "Module module")
assert-text: (".sidebar .location", "Module module")
assert-count: (".sidebar .location", 1)
assert-text: (".sidebar-elems ul.block > li.current > a", "module")
// Module page requires three headings:
@ -126,8 +126,8 @@ assert-text: (".sidebar-elems ul.block > li.current > a", "module")
// - Module name, followed by TOC for module headings
// - "In crate [name]" parent pointer, followed by sibling navigation
assert-count: (".sidebar h2", 3)
assert-text: (".sidebar > .sidebar-elems > h2", "In crate lib2")
assert-property: (".sidebar > .sidebar-elems > h2 > a", {
assert-text: (".sidebar > .sidebar-elems > #rustdoc-modnav > h2", "In crate lib2")
assert-property: (".sidebar > .sidebar-elems > #rustdoc-modnav > h2 > a", {
"href": "/lib2/index.html",
}, ENDS_WITH)
// We check that we don't have the crate list.
@ -136,9 +136,9 @@ assert-false: ".sidebar-elems > .crate"
go-to: "./sub_module/sub_sub_module/index.html"
assert-property: (".sidebar", {"clientWidth": "200"})
assert-text: (".sidebar > .sidebar-crate > h2 > a", "lib2")
assert-text: (".sidebar > .location", "Module sub_sub_module")
assert-text: (".sidebar > .sidebar-elems > h2", "In lib2::module::sub_module")
assert-property: (".sidebar > .sidebar-elems > h2 > a", {
assert-text: (".sidebar .location", "Module sub_sub_module")
assert-text: (".sidebar > .sidebar-elems > #rustdoc-modnav > h2", "In lib2::module::sub_module")
assert-property: (".sidebar > .sidebar-elems > #rustdoc-modnav > h2 > a", {
"href": "/module/sub_module/index.html",
}, ENDS_WITH)
assert-text: (".sidebar-elems ul.block > li.current > a", "sub_sub_module")
@ -198,3 +198,36 @@ assert-position-false: (".sidebar-crate > h2 > a", {"x": -3})
// when line-wrapped, see that it becomes flush-left again
drag-and-drop: ((205, 100), (108, 100))
assert-position: (".sidebar-crate > h2 > a", {"x": -3})
// Configuration option to show TOC in sidebar.
set-local-storage: {"rustdoc-hide-toc": "true"}
go-to: "file://" + |DOC_PATH| + "/test_docs/enum.WhoLetTheDogOut.html"
assert-css: ("#rustdoc-toc", {"display": "none"})
assert-css: (".sidebar .in-crate", {"display": "none"})
set-local-storage: {"rustdoc-hide-toc": "false"}
go-to: "file://" + |DOC_PATH| + "/test_docs/enum.WhoLetTheDogOut.html"
assert-css: ("#rustdoc-toc", {"display": "block"})
assert-css: (".sidebar .in-crate", {"display": "block"})
set-local-storage: {"rustdoc-hide-modnav": "true"}
go-to: "file://" + |DOC_PATH| + "/test_docs/enum.WhoLetTheDogOut.html"
assert-css: ("#rustdoc-modnav", {"display": "none"})
set-local-storage: {"rustdoc-hide-modnav": "false"}
go-to: "file://" + |DOC_PATH| + "/test_docs/enum.WhoLetTheDogOut.html"
assert-css: ("#rustdoc-modnav", {"display": "block"})
set-local-storage: {"rustdoc-hide-toc": "true"}
go-to: "file://" + |DOC_PATH| + "/test_docs/index.html"
assert-css: ("#rustdoc-toc", {"display": "none"})
assert-false: ".sidebar .in-crate"
set-local-storage: {"rustdoc-hide-toc": "false"}
go-to: "file://" + |DOC_PATH| + "/test_docs/index.html"
assert-css: ("#rustdoc-toc", {"display": "block"})
assert-false: ".sidebar .in-crate"
set-local-storage: {"rustdoc-hide-modnav": "true"}
go-to: "file://" + |DOC_PATH| + "/test_docs/index.html"
assert-css: ("#rustdoc-modnav", {"display": "none"})
set-local-storage: {"rustdoc-hide-modnav": "false"}
go-to: "file://" + |DOC_PATH| + "/test_docs/index.html"
assert-css: ("#rustdoc-modnav", {"display": "block"})

View File

@ -0,0 +1,16 @@
#![crate_name = "foo"]
//@ has 'foo/index.html'
//@ has - '//section[@id="rustdoc-toc"]/h3' 'Crate Items'
//@ has 'foo/bar/index.html'
//@ has - '//section[@id="rustdoc-toc"]/h3' 'Module Items'
pub mod bar {
//@ has 'foo/bar/struct.Baz.html'
//@ !has - '//section[@id="rustdoc-toc"]/h3' 'Module Items'
pub struct Baz;
}
//@ has 'foo/baz/index.html'
//@ !has - '//section[@id="rustdoc-toc"]/h3' 'Module Items'
pub mod baz {}

View File

@ -0,0 +1,23 @@
// ignore-tidy-linelength
#![crate_name = "foo"]
#![feature(lazy_type_alias)]
#![allow(incomplete_features)]
//! # Basic [link](https://example.com), *emphasis*, **_very emphasis_** and `code`
//!
//! This test case covers TOC entries with rich text inside.
//! Rustdoc normally supports headers with links, but for the
//! TOC, that would break the layout.
//!
//! For consistency, emphasis is also filtered out.
//@ has foo/index.html
// User header
//@ has - '//section[@id="rustdoc-toc"]/h3' 'Sections'
//@ has - '//section[@id="rustdoc-toc"]/ul[@class="block top-toc"]/li/a[@href="#basic-link-emphasis-very-emphasis-and-code"]/@title' 'Basic link, emphasis, very emphasis and `code`'
//@ has - '//section[@id="rustdoc-toc"]/ul[@class="block top-toc"]/li/a[@href="#basic-link-emphasis-very-emphasis-and-code"]' 'Basic link, emphasis, very emphasis and code'
//@ count - '//section[@id="rustdoc-toc"]/ul[@class="block top-toc"]/li/a[@href="#basic-link-emphasis-very-emphasis-and-code"]/em' 0
//@ count - '//section[@id="rustdoc-toc"]/ul[@class="block top-toc"]/li/a[@href="#basic-link-emphasis-very-emphasis-and-code"]/a' 0
//@ count - '//section[@id="rustdoc-toc"]/ul[@class="block top-toc"]/li/a[@href="#basic-link-emphasis-very-emphasis-and-code"]/code' 1
//@ has - '//section[@id="rustdoc-toc"]/ul[@class="block top-toc"]/li/a[@href="#basic-link-emphasis-very-emphasis-and-code"]/code' 'code'

View File

@ -0,0 +1,44 @@
#![crate_name = "foo"]
#![feature(lazy_type_alias)]
#![allow(incomplete_features)]
//! # Structs
//!
//! This header has the same name as a built-in header,
//! and we need to make sure they're disambiguated with
//! suffixes.
//!
//! Module-like headers get derived from the internal ID map,
//! so the *internal* one gets a suffix here. To make sure it
//! works right, the one in the `top-toc` needs to match the one
//! in the `top-doc`, and the one that's not in the `top-doc`
//! needs to match the one that isn't in the `top-toc`.
//@ has foo/index.html
// User header
//@ has - '//section[@id="rustdoc-toc"]/ul[@class="block top-toc"]/li/a[@href="#structs"]' 'Structs'
//@ has - '//details[@class="toggle top-doc"]/div[@class="docblock"]/h2[@id="structs"]' 'Structs'
// Built-in header
//@ has - '//section[@id="rustdoc-toc"]/ul[@class="block"]/li/a[@href="#structs-1"]' 'Structs'
//@ has - '//section[@id="main-content"]/h2[@id="structs-1"]' 'Structs'
/// # Fields
/// ## Fields
/// ### Fields
///
/// The difference between struct-like headers and module-like headers
/// is strange, but not actually a problem as long as we're consistent.
//@ has foo/struct.MyStruct.html
// User header
//@ has - '//section[@id="rustdoc-toc"]/ul[@class="block top-toc"]/li/a[@href="#fields-1"]' 'Fields'
//@ has - '//details[@class="toggle top-doc"]/div[@class="docblock"]/h2[@id="fields-1"]' 'Fields'
// Only one level of nesting
//@ count - '//section[@id="rustdoc-toc"]/ul[@class="block top-toc"]//a' 2
// Built-in header
//@ has - '//section[@id="rustdoc-toc"]/h3/a[@href="#fields"]' 'Fields'
//@ has - '//section[@id="main-content"]/h2[@id="fields"]' 'Fields'
pub struct MyStruct {
pub fields: i32,
}

View File

@ -0,0 +1,7 @@
#![crate_name = "foo"]
//! This test case covers missing top TOC entries.
//@ has foo/index.html
// User header
//@ !has - '//section[@id="rustdoc-toc"]/ul[@class="block top-toc"]' 'Basic link and emphasis'

View File

@ -1 +1 @@
<ul class="block variant"><li><a href="#variant.Shown">Shown</a></li></ul>
<ul class="block variant"><li><a href="#variant.Shown" title="Shown">Shown</a></li></ul>

View File

@ -2,7 +2,7 @@
//
// issue: <https://github.com/rust-lang/rust/issues/120217>
#![feature(arbitrary_self_types)]
#![feature(arbitrary_self_types_pointers)]
trait Static<'a> {
fn proof(self: *const Self, s: &'a str) -> &'static str;

View File

@ -210,7 +210,7 @@ warning: unexpected `cfg` condition value: `_UNEXPECTED_VALUE`
LL | target_os = "_UNEXPECTED_VALUE",
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: expected values for `target_os` are: `aix`, `android`, `cuda`, `dragonfly`, `emscripten`, `espidf`, `freebsd`, `fuchsia`, `haiku`, `hermit`, `horizon`, `hurd`, `illumos`, `ios`, `l4re`, `linux`, `macos`, `netbsd`, `none`, `nto`, `nuttx`, `openbsd`, `psp`, `redox`, `solaris`, `solid_asp3`, `teeos`, `trusty`, `tvos`, `uefi`, `unknown`, `visionos`, `vita`, `vxworks`, `wasi`, `watchos`, `windows`, `xous`, and `zkvm`
= note: expected values for `target_os` are: `aix`, `android`, `cuda`, `dragonfly`, `emscripten`, `espidf`, `freebsd`, `fuchsia`, `haiku`, `hermit`, `horizon`, `hurd`, `illumos`, `ios`, `l4re`, `linux`, `macos`, `netbsd`, `none`, `nto`, `nuttx`, `openbsd`, `psp`, `redox`, `rtems`, `solaris`, `solid_asp3`, `teeos`, `trusty`, `tvos`, `uefi`, `unknown`, `visionos`, `vita`, `vxworks`, `wasi`, `watchos`, `windows`, `xous`, and `zkvm`
= note: see <https://doc.rust-lang.org/nightly/rustc/check-cfg.html> for more information about checking conditional configuration
warning: unexpected `cfg` condition value: `_UNEXPECTED_VALUE`
@ -294,7 +294,7 @@ LL | #[cfg(target_os = "linuz")] // testing that we suggest `linux`
| |
| help: there is a expected value with a similar name: `"linux"`
|
= note: expected values for `target_os` are: `aix`, `android`, `cuda`, `dragonfly`, `emscripten`, `espidf`, `freebsd`, `fuchsia`, `haiku`, `hermit`, `horizon`, `hurd`, `illumos`, `ios`, `l4re`, `linux`, `macos`, `netbsd`, `none`, `nto`, `nuttx`, `openbsd`, `psp`, `redox`, `solaris`, `solid_asp3`, `teeos`, `trusty`, `tvos`, `uefi`, `unknown`, `visionos`, `vita`, `vxworks`, `wasi`, `watchos`, `windows`, `xous`, and `zkvm`
= note: expected values for `target_os` are: `aix`, `android`, `cuda`, `dragonfly`, `emscripten`, `espidf`, `freebsd`, `fuchsia`, `haiku`, `hermit`, `horizon`, `hurd`, `illumos`, `ios`, `l4re`, `linux`, `macos`, `netbsd`, `none`, `nto`, `nuttx`, `openbsd`, `psp`, `redox`, `rtems`, `solaris`, `solid_asp3`, `teeos`, `trusty`, `tvos`, `uefi`, `unknown`, `visionos`, `vita`, `vxworks`, `wasi`, `watchos`, `windows`, `xous`, and `zkvm`
= note: see <https://doc.rust-lang.org/nightly/rustc/check-cfg.html> for more information about checking conditional configuration
warning: 30 warnings emitted

View File

@ -0,0 +1,15 @@
trait Foo {
fn foo(self: *const Self); //~ ERROR `*const Self` cannot be used as the type of `self`
}
struct Bar;
impl Foo for Bar {
fn foo(self: *const Self) {} //~ ERROR `*const Bar` cannot be used as the type of `self`
}
impl Bar {
fn bar(self: *mut Self) {} //~ ERROR `*mut Bar` cannot be used as the type of `self`
}
fn main() {}

View File

@ -0,0 +1,36 @@
error[E0658]: `*const Bar` cannot be used as the type of `self` without the `arbitrary_self_types_pointers` feature
--> $DIR/feature-gate-arbitrary-self-types-pointers.rs:8:18
|
LL | fn foo(self: *const Self) {}
| ^^^^^^^^^^^
|
= note: see issue #44874 <https://github.com/rust-lang/rust/issues/44874> for more information
= help: add `#![feature(arbitrary_self_types_pointers)]` to the crate attributes to enable
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
= help: consider changing to `self`, `&self`, `&mut self`, `self: Box<Self>`, `self: Rc<Self>`, `self: Arc<Self>`, or `self: Pin<P>` (where P is one of the previous types except `Self`)
error[E0658]: `*mut Bar` cannot be used as the type of `self` without the `arbitrary_self_types_pointers` feature
--> $DIR/feature-gate-arbitrary-self-types-pointers.rs:12:18
|
LL | fn bar(self: *mut Self) {}
| ^^^^^^^^^
|
= note: see issue #44874 <https://github.com/rust-lang/rust/issues/44874> for more information
= help: add `#![feature(arbitrary_self_types_pointers)]` to the crate attributes to enable
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
= help: consider changing to `self`, `&self`, `&mut self`, `self: Box<Self>`, `self: Rc<Self>`, `self: Arc<Self>`, or `self: Pin<P>` (where P is one of the previous types except `Self`)
error[E0658]: `*const Self` cannot be used as the type of `self` without the `arbitrary_self_types_pointers` feature
--> $DIR/feature-gate-arbitrary-self-types-pointers.rs:2:18
|
LL | fn foo(self: *const Self);
| ^^^^^^^^^^^
|
= note: see issue #44874 <https://github.com/rust-lang/rust/issues/44874> for more information
= help: add `#![feature(arbitrary_self_types_pointers)]` to the crate attributes to enable
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
= help: consider changing to `self`, `&self`, `&mut self`, `self: Box<Self>`, `self: Rc<Self>`, `self: Arc<Self>`, or `self: Pin<P>` (where P is one of the previous types except `Self`)
error: aborting due to 3 previous errors
For more information about this error, try `rustc --explain E0658`.

View File

@ -1,33 +1,33 @@
error[E0658]: `*const Foo` cannot be used as the type of `self` without the `arbitrary_self_types` feature
error[E0658]: `*const Foo` cannot be used as the type of `self` without the `arbitrary_self_types_pointers` feature
--> $DIR/feature-gate-arbitrary_self_types-raw-pointer.rs:4:18
|
LL | fn foo(self: *const Self) {}
| ^^^^^^^^^^^
|
= note: see issue #44874 <https://github.com/rust-lang/rust/issues/44874> for more information
= help: add `#![feature(arbitrary_self_types)]` to the crate attributes to enable
= help: add `#![feature(arbitrary_self_types_pointers)]` to the crate attributes to enable
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
= help: consider changing to `self`, `&self`, `&mut self`, `self: Box<Self>`, `self: Rc<Self>`, `self: Arc<Self>`, or `self: Pin<P>` (where P is one of the previous types except `Self`)
error[E0658]: `*const ()` cannot be used as the type of `self` without the `arbitrary_self_types` feature
error[E0658]: `*const ()` cannot be used as the type of `self` without the `arbitrary_self_types_pointers` feature
--> $DIR/feature-gate-arbitrary_self_types-raw-pointer.rs:14:18
|
LL | fn bar(self: *const Self) {}
| ^^^^^^^^^^^
|
= note: see issue #44874 <https://github.com/rust-lang/rust/issues/44874> for more information
= help: add `#![feature(arbitrary_self_types)]` to the crate attributes to enable
= help: add `#![feature(arbitrary_self_types_pointers)]` to the crate attributes to enable
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
= help: consider changing to `self`, `&self`, `&mut self`, `self: Box<Self>`, `self: Rc<Self>`, `self: Arc<Self>`, or `self: Pin<P>` (where P is one of the previous types except `Self`)
error[E0658]: `*const Self` cannot be used as the type of `self` without the `arbitrary_self_types` feature
error[E0658]: `*const Self` cannot be used as the type of `self` without the `arbitrary_self_types_pointers` feature
--> $DIR/feature-gate-arbitrary_self_types-raw-pointer.rs:9:18
|
LL | fn bar(self: *const Self);
| ^^^^^^^^^^^
|
= note: see issue #44874 <https://github.com/rust-lang/rust/issues/44874> for more information
= help: add `#![feature(arbitrary_self_types)]` to the crate attributes to enable
= help: add `#![feature(arbitrary_self_types_pointers)]` to the crate attributes to enable
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
= help: consider changing to `self`, `&self`, `&mut self`, `self: Box<Self>`, `self: Rc<Self>`, `self: Arc<Self>`, or `self: Pin<P>` (where P is one of the previous types except `Self`)

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