Auto merge of #130768 - compiler-errors:rollup-8ncjy55, r=compiler-errors

Rollup of 7 pull requests

Successful merges:

 - #129545 (rustdoc: redesign toolbar and disclosure widgets)
 - #130618 (Skip query in get_parent_item when possible.)
 - #130727 (Check vtable projections for validity in miri)
 - #130750 (Add new Tier-3 target: `loongarch64-unknown-linux-ohos`)
 - #130758 (Revert "Add recursion limit to FFI safety lint")
 - #130759 (Update books)
 - #130762 (stabilize const_intrinsic_copy)

r? `@ghost`
`@rustbot` modify labels: rollup
This commit is contained in:
bors 2024-09-24 06:02:43 +00:00
commit 4cadeda932
96 changed files with 797 additions and 509 deletions

View File

@ -161,13 +161,13 @@ pub(crate) fn codegen_const_value<'tcx>(
fx.module.declare_func_in_func(func_id, &mut fx.bcx.func);
fx.bcx.ins().func_addr(fx.pointer_type, local_func_id)
}
GlobalAlloc::VTable(ty, trait_ref) => {
GlobalAlloc::VTable(ty, dyn_ty) => {
let data_id = data_id_for_vtable(
fx.tcx,
&mut fx.constants_cx,
fx.module,
ty,
trait_ref,
dyn_ty.principal(),
);
let local_data_id =
fx.module.declare_data_in_func(data_id, &mut fx.bcx.func);
@ -456,8 +456,8 @@ fn define_all_allocs(tcx: TyCtxt<'_>, module: &mut dyn Module, cx: &mut Constant
GlobalAlloc::Memory(target_alloc) => {
data_id_for_alloc_id(cx, module, alloc_id, target_alloc.inner().mutability)
}
GlobalAlloc::VTable(ty, trait_ref) => {
data_id_for_vtable(tcx, cx, module, ty, trait_ref)
GlobalAlloc::VTable(ty, dyn_ty) => {
data_id_for_vtable(tcx, cx, module, ty, dyn_ty.principal())
}
GlobalAlloc::Static(def_id) => {
if tcx.codegen_fn_attrs(def_id).flags.contains(CodegenFnAttrFlags::THREAD_LOCAL)

View File

@ -224,10 +224,10 @@ impl<'gcc, 'tcx> ConstCodegenMethods<'tcx> for CodegenCx<'gcc, 'tcx> {
value
}
GlobalAlloc::Function { instance, .. } => self.get_fn_addr(instance),
GlobalAlloc::VTable(ty, trait_ref) => {
GlobalAlloc::VTable(ty, dyn_ty) => {
let alloc = self
.tcx
.global_alloc(self.tcx.vtable_allocation((ty, trait_ref)))
.global_alloc(self.tcx.vtable_allocation((ty, dyn_ty.principal())))
.unwrap_memory();
let init = const_alloc_to_gcc(self, alloc);
self.static_addr_of(init, alloc.inner().align, None)

View File

@ -290,10 +290,10 @@ impl<'ll, 'tcx> ConstCodegenMethods<'tcx> for CodegenCx<'ll, 'tcx> {
self.get_fn_addr(instance.polymorphize(self.tcx)),
self.data_layout().instruction_address_space,
),
GlobalAlloc::VTable(ty, trait_ref) => {
GlobalAlloc::VTable(ty, dyn_ty) => {
let alloc = self
.tcx
.global_alloc(self.tcx.vtable_allocation((ty, trait_ref)))
.global_alloc(self.tcx.vtable_allocation((ty, dyn_ty.principal())))
.unwrap_memory();
let init = const_alloc_to_llvm(self, alloc, /*static*/ false);
let value = self.static_addr_of(init, alloc.inner().align, None);

View File

@ -198,7 +198,7 @@ const_eval_invalid_vtable_pointer =
using {$pointer} as vtable pointer but it does not point to a vtable
const_eval_invalid_vtable_trait =
using vtable for trait `{$vtable_trait}` but trait `{$expected_trait}` was expected
using vtable for `{$vtable_dyn_type}` but `{$expected_dyn_type}` was expected
const_eval_lazy_lock =
consider wrapping this expression in `std::sync::LazyLock::new(|| ...)`
@ -459,7 +459,7 @@ const_eval_validation_invalid_fn_ptr = {$front_matter}: encountered {$value}, bu
const_eval_validation_invalid_ref_meta = {$front_matter}: encountered invalid reference metadata: total size is bigger than largest supported object
const_eval_validation_invalid_ref_slice_meta = {$front_matter}: encountered invalid reference metadata: slice is bigger than largest supported object
const_eval_validation_invalid_vtable_ptr = {$front_matter}: encountered {$value}, but expected a vtable pointer
const_eval_validation_invalid_vtable_trait = {$front_matter}: wrong trait in wide pointer vtable: expected `{$ref_trait}`, but encountered `{$vtable_trait}`
const_eval_validation_invalid_vtable_trait = {$front_matter}: wrong trait in wide pointer vtable: expected `{$expected_dyn_type}`, but encountered `{$vtable_dyn_type}`
const_eval_validation_mutable_ref_to_immutable = {$front_matter}: encountered mutable reference or box pointing to read-only memory
const_eval_validation_never_val = {$front_matter}: encountered a value of the never type `!`
const_eval_validation_null_box = {$front_matter}: encountered a null box

View File

@ -522,12 +522,9 @@ impl<'a> ReportErrorExt for UndefinedBehaviorInfo<'a> {
UnterminatedCString(ptr) | InvalidFunctionPointer(ptr) | InvalidVTablePointer(ptr) => {
diag.arg("pointer", ptr);
}
InvalidVTableTrait { expected_trait, vtable_trait } => {
diag.arg("expected_trait", expected_trait.to_string());
diag.arg(
"vtable_trait",
vtable_trait.map(|t| t.to_string()).unwrap_or_else(|| format!("<trivial>")),
);
InvalidVTableTrait { expected_dyn_type, vtable_dyn_type } => {
diag.arg("expected_dyn_type", expected_dyn_type.to_string());
diag.arg("vtable_dyn_type", vtable_dyn_type.to_string());
}
PointerUseAfterFree(alloc_id, msg) => {
diag.arg("alloc_id", alloc_id)
@ -777,12 +774,9 @@ impl<'tcx> ReportErrorExt for ValidationErrorInfo<'tcx> {
DanglingPtrNoProvenance { pointer, .. } => {
err.arg("pointer", pointer);
}
InvalidMetaWrongTrait { expected_trait: ref_trait, vtable_trait } => {
err.arg("ref_trait", ref_trait.to_string());
err.arg(
"vtable_trait",
vtable_trait.map(|t| t.to_string()).unwrap_or_else(|| format!("<trivial>")),
);
InvalidMetaWrongTrait { vtable_dyn_type, expected_dyn_type } => {
err.arg("vtable_dyn_type", vtable_dyn_type.to_string());
err.arg("expected_dyn_type", expected_dyn_type.to_string());
}
NullPtr { .. }
| ConstRefToMutable

View File

@ -128,7 +128,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
CastKind::DynStar => {
if let ty::Dynamic(data, _, ty::DynStar) = cast_ty.kind() {
// Initial cast from sized to dyn trait
let vtable = self.get_vtable_ptr(src.layout.ty, data.principal())?;
let vtable = self.get_vtable_ptr(src.layout.ty, data)?;
let vtable = Scalar::from_maybe_pointer(vtable, self);
let data = self.read_immediate(src)?.to_scalar();
let _assert_pointer_like = data.to_pointer(self)?;
@ -446,12 +446,12 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
}
// Get the destination trait vtable and return that.
let new_vptr = self.get_vtable_ptr(ty, data_b.principal())?;
let new_vptr = self.get_vtable_ptr(ty, data_b)?;
self.write_immediate(Immediate::new_dyn_trait(old_data, new_vptr, self), dest)
}
(_, &ty::Dynamic(data, _, ty::Dyn)) => {
// Initial cast from sized to dyn trait
let vtable = self.get_vtable_ptr(src_pointee_ty, data.principal())?;
let vtable = self.get_vtable_ptr(src_pointee_ty, data)?;
let ptr = self.read_pointer(src)?;
let val = Immediate::new_dyn_trait(ptr, vtable, &*self.tcx);
self.write_immediate(val, dest)

View File

@ -943,12 +943,13 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
if offset.bytes() != 0 {
throw_ub!(InvalidVTablePointer(Pointer::new(alloc_id, offset)))
}
let Some(GlobalAlloc::VTable(ty, vtable_trait)) = self.tcx.try_get_global_alloc(alloc_id)
let Some(GlobalAlloc::VTable(ty, vtable_dyn_type)) =
self.tcx.try_get_global_alloc(alloc_id)
else {
throw_ub!(InvalidVTablePointer(Pointer::new(alloc_id, offset)))
};
if let Some(expected_trait) = expected_trait {
self.check_vtable_for_type(vtable_trait, expected_trait)?;
if let Some(expected_dyn_type) = expected_trait {
self.check_vtable_for_type(vtable_dyn_type, expected_dyn_type)?;
}
Ok(ty)
}
@ -1113,11 +1114,8 @@ impl<'a, 'tcx, M: Machine<'tcx>> std::fmt::Debug for DumpAllocs<'a, 'tcx, M> {
Some(GlobalAlloc::Function { instance, .. }) => {
write!(fmt, " (fn: {instance})")?;
}
Some(GlobalAlloc::VTable(ty, Some(trait_ref))) => {
write!(fmt, " (vtable: impl {trait_ref} for {ty})")?;
}
Some(GlobalAlloc::VTable(ty, None)) => {
write!(fmt, " (vtable: impl <auto trait> for {ty})")?;
Some(GlobalAlloc::VTable(ty, dyn_ty)) => {
write!(fmt, " (vtable: impl {dyn_ty} for {ty})")?;
}
Some(GlobalAlloc::Static(did)) => {
write!(fmt, " (static: {})", self.ecx.tcx.def_path_str(did))?;

View File

@ -1,6 +1,6 @@
use rustc_middle::mir::interpret::{InterpResult, Pointer};
use rustc_middle::ty::layout::LayoutOf;
use rustc_middle::ty::{self, Ty, TyCtxt, VtblEntry};
use rustc_middle::ty::{self, ExistentialPredicateStableCmpExt, Ty, TyCtxt, VtblEntry};
use rustc_target::abi::{Align, Size};
use tracing::trace;
@ -11,26 +11,25 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
/// Creates a dynamic vtable for the given type and vtable origin. This is used only for
/// objects.
///
/// The `trait_ref` encodes the erased self type. Hence, if we are making an object `Foo<Trait>`
/// from a value of type `Foo<T>`, then `trait_ref` would map `T: Trait`. `None` here means that
/// this is an auto trait without any methods, so we only need the basic vtable (drop, size,
/// align).
/// The `dyn_ty` encodes the erased self type. Hence, if we are making an object
/// `Foo<dyn Trait<Assoc = A> + Send>` from a value of type `Foo<T>`, then `dyn_ty`
/// would be `Trait<Assoc = A> + Send`. If this list doesn't have a principal trait ref,
/// we only need the basic vtable prefix (drop, size, align).
pub fn get_vtable_ptr(
&self,
ty: Ty<'tcx>,
poly_trait_ref: Option<ty::PolyExistentialTraitRef<'tcx>>,
dyn_ty: &'tcx ty::List<ty::PolyExistentialPredicate<'tcx>>,
) -> InterpResult<'tcx, Pointer<Option<M::Provenance>>> {
trace!("get_vtable(trait_ref={:?})", poly_trait_ref);
trace!("get_vtable(ty={ty:?}, dyn_ty={dyn_ty:?})");
let (ty, poly_trait_ref) = self.tcx.erase_regions((ty, poly_trait_ref));
let (ty, dyn_ty) = self.tcx.erase_regions((ty, dyn_ty));
// All vtables must be monomorphic, bail out otherwise.
ensure_monomorphic_enough(*self.tcx, ty)?;
ensure_monomorphic_enough(*self.tcx, poly_trait_ref)?;
ensure_monomorphic_enough(*self.tcx, dyn_ty)?;
let salt = M::get_global_alloc_salt(self, None);
let vtable_symbolic_allocation =
self.tcx.reserve_and_set_vtable_alloc(ty, poly_trait_ref, salt);
let vtable_symbolic_allocation = self.tcx.reserve_and_set_vtable_alloc(ty, dyn_ty, salt);
let vtable_ptr = self.global_root_pointer(Pointer::from(vtable_symbolic_allocation))?;
Ok(vtable_ptr.into())
}
@ -64,17 +63,45 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
/// expected trait type.
pub(super) fn check_vtable_for_type(
&self,
vtable_trait: Option<ty::PolyExistentialTraitRef<'tcx>>,
expected_trait: &'tcx ty::List<ty::PolyExistentialPredicate<'tcx>>,
vtable_dyn_type: &'tcx ty::List<ty::PolyExistentialPredicate<'tcx>>,
expected_dyn_type: &'tcx ty::List<ty::PolyExistentialPredicate<'tcx>>,
) -> InterpResult<'tcx> {
let eq = match (expected_trait.principal(), vtable_trait) {
(Some(a), Some(b)) => self.eq_in_param_env(a, b),
(None, None) => true,
_ => false,
};
if !eq {
throw_ub!(InvalidVTableTrait { expected_trait, vtable_trait });
// We check validity by comparing the lists of predicates for equality. We *could* instead
// check that the dynamic type to which the vtable belongs satisfies all the expected
// predicates, but that would likely be a lot slower and seems unnecessarily permissive.
// FIXME: we are skipping auto traits for now, but might revisit this in the future.
let mut sorted_vtable: Vec<_> = vtable_dyn_type.without_auto_traits().collect();
let mut sorted_expected: Vec<_> = expected_dyn_type.without_auto_traits().collect();
// `skip_binder` here is okay because `stable_cmp` doesn't look at binders
sorted_vtable.sort_by(|a, b| a.skip_binder().stable_cmp(*self.tcx, &b.skip_binder()));
sorted_vtable.dedup();
sorted_expected.sort_by(|a, b| a.skip_binder().stable_cmp(*self.tcx, &b.skip_binder()));
sorted_expected.dedup();
if sorted_vtable.len() != sorted_expected.len() {
throw_ub!(InvalidVTableTrait { vtable_dyn_type, expected_dyn_type });
}
for (a_pred, b_pred) in std::iter::zip(sorted_vtable, sorted_expected) {
let is_eq = match (a_pred.skip_binder(), b_pred.skip_binder()) {
(
ty::ExistentialPredicate::Trait(a_data),
ty::ExistentialPredicate::Trait(b_data),
) => self.eq_in_param_env(a_pred.rebind(a_data), b_pred.rebind(b_data)),
(
ty::ExistentialPredicate::Projection(a_data),
ty::ExistentialPredicate::Projection(b_data),
) => self.eq_in_param_env(a_pred.rebind(a_data), b_pred.rebind(b_data)),
_ => false,
};
if !is_eq {
throw_ub!(InvalidVTableTrait { vtable_dyn_type, expected_dyn_type });
}
}
Ok(())
}

View File

@ -452,8 +452,8 @@ impl<'rt, 'tcx, M: Machine<'tcx>> ValidityVisitor<'rt, 'tcx, M> {
self.path,
Ub(DanglingIntPointer{ .. } | InvalidVTablePointer(..)) =>
InvalidVTablePtr { value: format!("{vtable}") },
Ub(InvalidVTableTrait { expected_trait, vtable_trait }) => {
InvalidMetaWrongTrait { expected_trait, vtable_trait: *vtable_trait }
Ub(InvalidVTableTrait { vtable_dyn_type, expected_dyn_type }) => {
InvalidMetaWrongTrait { vtable_dyn_type, expected_dyn_type }
},
);
}
@ -1281,8 +1281,8 @@ impl<'rt, 'tcx, M: Machine<'tcx>> ValueVisitor<'tcx, M> for ValidityVisitor<'rt,
self.path,
// It's not great to catch errors here, since we can't give a very good path,
// but it's better than ICEing.
Ub(InvalidVTableTrait { expected_trait, vtable_trait }) => {
InvalidMetaWrongTrait { expected_trait, vtable_trait: *vtable_trait }
Ub(InvalidVTableTrait { vtable_dyn_type, expected_dyn_type }) => {
InvalidMetaWrongTrait { vtable_dyn_type, expected_dyn_type: *expected_dyn_type }
},
);
}

View File

@ -395,8 +395,6 @@ lint_improper_ctypes_opaque = opaque types have no C equivalent
lint_improper_ctypes_pat_help = consider using the base type instead
lint_improper_ctypes_pat_reason = pattern types have no C equivalent
lint_improper_ctypes_recursion_limit_reached = type is infinitely recursive
lint_improper_ctypes_slice_help = consider using a raw pointer instead
lint_improper_ctypes_slice_reason = slices have no C equivalent

View File

@ -592,8 +592,6 @@ struct CTypesVisitorState<'tcx> {
/// The original type being checked, before we recursed
/// to any other types it contains.
base_ty: Ty<'tcx>,
/// Number of times we recursed while checking the type
recursion_depth: usize,
}
enum FfiResult<'tcx> {
@ -899,23 +897,12 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
// Protect against infinite recursion, for example
// `struct S(*mut S);`.
// FIXME: A recursion limit is necessary as well, for irregular
// recursive types.
if !acc.cache.insert(ty) {
return FfiSafe;
}
// Additional recursion check for more complex types like
// `struct A<T> { v: *const A<A<T>>, ... }` for which the
// cache check above won't be enough (fixes #130310)
if !tcx.recursion_limit().value_within_limit(acc.recursion_depth) {
return FfiUnsafe {
ty: acc.base_ty,
reason: fluent::lint_improper_ctypes_recursion_limit_reached,
help: None,
};
}
acc.recursion_depth += 1;
match *ty.kind() {
ty::Adt(def, args) => {
if let Some(boxed) = ty.boxed_ty()
@ -1261,8 +1248,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
return;
}
let mut acc =
CTypesVisitorState { cache: FxHashSet::default(), base_ty: ty, recursion_depth: 0 };
let mut acc = CTypesVisitorState { cache: FxHashSet::default(), base_ty: ty };
match self.check_type_for_ffi(&mut acc, ty) {
FfiResult::FfiSafe => {}
FfiResult::FfiPhantom(ty) => {

View File

@ -598,7 +598,10 @@ impl<'hir> Map<'hir> {
/// in the HIR which is recorded by the map and is an item, either an item
/// in a module, trait, or impl.
pub fn get_parent_item(self, hir_id: HirId) -> OwnerId {
if let Some((def_id, _node)) = self.parent_owner_iter(hir_id).next() {
if hir_id.local_id != ItemLocalId::ZERO {
// If this is a child of a HIR owner, return the owner.
hir_id.owner
} else if let Some((def_id, _node)) = self.parent_owner_iter(hir_id).next() {
def_id
} else {
CRATE_OWNER_ID

View File

@ -365,8 +365,10 @@ pub enum UndefinedBehaviorInfo<'tcx> {
InvalidVTablePointer(Pointer<AllocId>),
/// Using a vtable for the wrong trait.
InvalidVTableTrait {
expected_trait: &'tcx ty::List<ty::PolyExistentialPredicate<'tcx>>,
vtable_trait: Option<ty::PolyExistentialTraitRef<'tcx>>,
/// The vtable that was actually referenced by the wide pointer metadata.
vtable_dyn_type: &'tcx ty::List<ty::PolyExistentialPredicate<'tcx>>,
/// The vtable that was expected at the point in MIR that it was accessed.
expected_dyn_type: &'tcx ty::List<ty::PolyExistentialPredicate<'tcx>>,
},
/// Using a string that is not valid UTF-8,
InvalidStr(std::str::Utf8Error),
@ -479,8 +481,10 @@ pub enum ValidationErrorKind<'tcx> {
value: String,
},
InvalidMetaWrongTrait {
expected_trait: &'tcx ty::List<ty::PolyExistentialPredicate<'tcx>>,
vtable_trait: Option<ty::PolyExistentialTraitRef<'tcx>>,
/// The vtable that was actually referenced by the wide pointer metadata.
vtable_dyn_type: &'tcx ty::List<ty::PolyExistentialPredicate<'tcx>>,
/// The vtable that was expected at the point in MIR that it was accessed.
expected_dyn_type: &'tcx ty::List<ty::PolyExistentialPredicate<'tcx>>,
},
InvalidMetaSliceTooLarge {
ptr_kind: PointerKind,

View File

@ -232,9 +232,8 @@ impl<'s> AllocDecodingSession<'s> {
}
AllocDiscriminant::VTable => {
trace!("creating vtable alloc ID");
let ty = <Ty<'_> as Decodable<D>>::decode(decoder);
let poly_trait_ref =
<Option<ty::PolyExistentialTraitRef<'_>> as Decodable<D>>::decode(decoder);
let ty = Decodable::decode(decoder);
let poly_trait_ref = Decodable::decode(decoder);
trace!("decoded vtable alloc instance: {ty:?}, {poly_trait_ref:?}");
decoder.interner().reserve_and_set_vtable_alloc(ty, poly_trait_ref, CTFE_ALLOC_SALT)
}
@ -259,7 +258,10 @@ pub enum GlobalAlloc<'tcx> {
/// The alloc ID is used as a function pointer.
Function { instance: Instance<'tcx> },
/// This alloc ID points to a symbolic (not-reified) vtable.
VTable(Ty<'tcx>, Option<ty::PolyExistentialTraitRef<'tcx>>),
/// We remember the full dyn type, not just the principal trait, so that
/// const-eval and Miri can detect UB due to invalid transmutes of
/// `dyn Trait` types.
VTable(Ty<'tcx>, &'tcx ty::List<ty::PolyExistentialPredicate<'tcx>>),
/// The alloc ID points to a "lazy" static variable that did not get computed (yet).
/// This is also used to break the cycle in recursive statics.
Static(DefId),
@ -293,7 +295,7 @@ impl<'tcx> GlobalAlloc<'tcx> {
#[inline]
pub fn unwrap_vtable(&self) -> (Ty<'tcx>, Option<ty::PolyExistentialTraitRef<'tcx>>) {
match *self {
GlobalAlloc::VTable(ty, poly_trait_ref) => (ty, poly_trait_ref),
GlobalAlloc::VTable(ty, dyn_ty) => (ty, dyn_ty.principal()),
_ => bug!("expected vtable, got {:?}", self),
}
}
@ -398,10 +400,10 @@ impl<'tcx> TyCtxt<'tcx> {
pub fn reserve_and_set_vtable_alloc(
self,
ty: Ty<'tcx>,
poly_trait_ref: Option<ty::PolyExistentialTraitRef<'tcx>>,
dyn_ty: &'tcx ty::List<ty::PolyExistentialPredicate<'tcx>>,
salt: usize,
) -> AllocId {
self.reserve_and_set_dedup(GlobalAlloc::VTable(ty, poly_trait_ref), salt)
self.reserve_and_set_dedup(GlobalAlloc::VTable(ty, dyn_ty), salt)
}
/// Interns the `Allocation` and return a new `AllocId`, even if there's already an identical

View File

@ -1536,11 +1536,8 @@ pub fn write_allocations<'tcx>(
// gracefully handle it and allow buggy rustc to be debugged via allocation printing.
None => write!(w, " (deallocated)")?,
Some(GlobalAlloc::Function { instance, .. }) => write!(w, " (fn: {instance})")?,
Some(GlobalAlloc::VTable(ty, Some(trait_ref))) => {
write!(w, " (vtable: impl {trait_ref} for {ty})")?
}
Some(GlobalAlloc::VTable(ty, None)) => {
write!(w, " (vtable: impl <auto trait> for {ty})")?
Some(GlobalAlloc::VTable(ty, dyn_ty)) => {
write!(w, " (vtable: impl {dyn_ty} for {ty})")?
}
Some(GlobalAlloc::Static(did)) if !tcx.is_foreign_item(did) => {
match tcx.eval_static_initializer(did) {

View File

@ -1175,8 +1175,8 @@ fn collect_alloc<'tcx>(tcx: TyCtxt<'tcx>, alloc_id: AllocId, output: &mut MonoIt
output.push(create_fn_mono_item(tcx, instance, DUMMY_SP));
}
}
GlobalAlloc::VTable(ty, trait_ref) => {
let alloc_id = tcx.vtable_allocation((ty, trait_ref));
GlobalAlloc::VTable(ty, dyn_ty) => {
let alloc_id = tcx.vtable_allocation((ty, dyn_ty.principal()));
collect_alloc(tcx, alloc_id, output)
}
}

View File

@ -318,10 +318,10 @@ impl<'tcx> ReachableContext<'tcx> {
));
self.visit(instance.args);
}
GlobalAlloc::VTable(ty, trait_ref) => {
GlobalAlloc::VTable(ty, dyn_ty) => {
self.visit(ty);
// Manually visit to actually see the trait's `DefId`. Type visitors won't see it
if let Some(trait_ref) = trait_ref {
if let Some(trait_ref) = dyn_ty.principal() {
let ExistentialTraitRef { def_id, args } = trait_ref.skip_binder();
self.visit_def_id(def_id, "", &"");
self.visit(args);

View File

@ -712,8 +712,9 @@ impl<'tcx> Stable<'tcx> for mir::interpret::GlobalAlloc<'tcx> {
mir::interpret::GlobalAlloc::Function { instance, .. } => {
GlobalAlloc::Function(instance.stable(tables))
}
mir::interpret::GlobalAlloc::VTable(ty, trait_ref) => {
GlobalAlloc::VTable(ty.stable(tables), trait_ref.stable(tables))
mir::interpret::GlobalAlloc::VTable(ty, dyn_ty) => {
// FIXME: Should we record the whole vtable?
GlobalAlloc::VTable(ty.stable(tables), dyn_ty.principal().stable(tables))
}
mir::interpret::GlobalAlloc::Static(def) => {
GlobalAlloc::Static(tables.static_def(*def))

View File

@ -1882,6 +1882,7 @@ supported_targets! {
("aarch64-unknown-linux-ohos", aarch64_unknown_linux_ohos),
("armv7-unknown-linux-ohos", armv7_unknown_linux_ohos),
("loongarch64-unknown-linux-ohos", loongarch64_unknown_linux_ohos),
("x86_64-unknown-linux-ohos", x86_64_unknown_linux_ohos),
("x86_64-unknown-linux-none", x86_64_unknown_linux_none),

View File

@ -0,0 +1,24 @@
use crate::spec::{Target, TargetOptions, base};
pub(crate) fn target() -> Target {
Target {
// LLVM 15 doesn't support OpenHarmony yet, use a linux target instead.
llvm_target: "loongarch64-unknown-linux-musl".into(),
metadata: crate::spec::TargetMetadata {
description: Some("LoongArch64 OpenHarmony".into()),
tier: Some(3),
host_tools: Some(false),
std: Some(true),
},
pointer_width: 64,
data_layout: "e-m:e-p:64:64-i64:64-i128:128-n32:64-S128".into(),
arch: "loongarch64".into(),
options: TargetOptions {
cpu: "generic".into(),
features: "+f,+d".into(),
llvm_abiname: "lp64d".into(),
max_atomic_width: Some(64),
..base::linux_ohos::opts()
},
}
}

View File

@ -3286,13 +3286,13 @@ pub const fn ptr_metadata<P: ptr::Pointee<Metadata = M> + ?Sized, M>(_ptr: *cons
#[doc(alias = "memcpy")]
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_allowed_through_unstable_modules]
#[rustc_const_unstable(feature = "const_intrinsic_copy", issue = "80697")]
#[rustc_const_stable(feature = "const_intrinsic_copy", since = "CURRENT_RUSTC_VERSION")]
#[inline(always)]
#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
#[rustc_diagnostic_item = "ptr_copy_nonoverlapping"]
pub const unsafe fn copy_nonoverlapping<T>(src: *const T, dst: *mut T, count: usize) {
extern "rust-intrinsic" {
#[rustc_const_unstable(feature = "const_intrinsic_copy", issue = "80697")]
#[rustc_const_stable(feature = "const_intrinsic_copy", since = "CURRENT_RUSTC_VERSION")]
#[rustc_nounwind]
pub fn copy_nonoverlapping<T>(src: *const T, dst: *mut T, count: usize);
}
@ -3388,13 +3388,13 @@ pub const unsafe fn copy_nonoverlapping<T>(src: *const T, dst: *mut T, count: us
#[doc(alias = "memmove")]
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_allowed_through_unstable_modules]
#[rustc_const_unstable(feature = "const_intrinsic_copy", issue = "80697")]
#[rustc_const_stable(feature = "const_intrinsic_copy", since = "CURRENT_RUSTC_VERSION")]
#[inline(always)]
#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
#[rustc_diagnostic_item = "ptr_copy"]
pub const unsafe fn copy<T>(src: *const T, dst: *mut T, count: usize) {
extern "rust-intrinsic" {
#[rustc_const_unstable(feature = "const_intrinsic_copy", issue = "80697")]
#[rustc_const_stable(feature = "const_intrinsic_copy", since = "CURRENT_RUSTC_VERSION")]
#[rustc_nounwind]
fn copy<T>(src: *const T, dst: *mut T, count: usize);
}

View File

@ -128,7 +128,6 @@
#![feature(const_hash)]
#![feature(const_heap)]
#![feature(const_index_range_slice_index)]
#![feature(const_intrinsic_copy)]
#![feature(const_intrinsic_forget)]
#![feature(const_ipv4)]
#![feature(const_ipv6)]

View File

@ -1192,7 +1192,7 @@ impl<T: ?Sized> *const T {
/// See [`ptr::copy`] for safety concerns and examples.
///
/// [`ptr::copy`]: crate::ptr::copy()
#[rustc_const_unstable(feature = "const_intrinsic_copy", issue = "80697")]
#[rustc_const_stable(feature = "const_intrinsic_copy", since = "CURRENT_RUSTC_VERSION")]
#[stable(feature = "pointer_methods", since = "1.26.0")]
#[inline]
#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
@ -1212,7 +1212,7 @@ impl<T: ?Sized> *const T {
/// See [`ptr::copy_nonoverlapping`] for safety concerns and examples.
///
/// [`ptr::copy_nonoverlapping`]: crate::ptr::copy_nonoverlapping()
#[rustc_const_unstable(feature = "const_intrinsic_copy", issue = "80697")]
#[rustc_const_stable(feature = "const_intrinsic_copy", since = "CURRENT_RUSTC_VERSION")]
#[stable(feature = "pointer_methods", since = "1.26.0")]
#[inline]
#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces

View File

@ -1516,11 +1516,7 @@ pub const unsafe fn read<T>(src: *const T) -> T {
#[inline]
#[stable(feature = "ptr_unaligned", since = "1.17.0")]
#[rustc_const_stable(feature = "const_ptr_read", since = "1.71.0")]
#[rustc_allow_const_fn_unstable(
const_mut_refs,
const_maybe_uninit_as_mut_ptr,
const_intrinsic_copy
)]
#[cfg_attr(bootstrap, rustc_allow_const_fn_unstable(const_mut_refs))]
#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
#[rustc_diagnostic_item = "ptr_read_unaligned"]
pub const unsafe fn read_unaligned<T>(src: *const T) -> T {

View File

@ -1269,7 +1269,7 @@ impl<T: ?Sized> *mut T {
/// See [`ptr::copy`] for safety concerns and examples.
///
/// [`ptr::copy`]: crate::ptr::copy()
#[rustc_const_unstable(feature = "const_intrinsic_copy", issue = "80697")]
#[rustc_const_stable(feature = "const_intrinsic_copy", since = "CURRENT_RUSTC_VERSION")]
#[stable(feature = "pointer_methods", since = "1.26.0")]
#[inline(always)]
#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
@ -1289,7 +1289,7 @@ impl<T: ?Sized> *mut T {
/// See [`ptr::copy_nonoverlapping`] for safety concerns and examples.
///
/// [`ptr::copy_nonoverlapping`]: crate::ptr::copy_nonoverlapping()
#[rustc_const_unstable(feature = "const_intrinsic_copy", issue = "80697")]
#[rustc_const_stable(feature = "const_intrinsic_copy", since = "CURRENT_RUSTC_VERSION")]
#[stable(feature = "pointer_methods", since = "1.26.0")]
#[inline(always)]
#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
@ -1309,7 +1309,7 @@ impl<T: ?Sized> *mut T {
/// See [`ptr::copy`] for safety concerns and examples.
///
/// [`ptr::copy`]: crate::ptr::copy()
#[rustc_const_unstable(feature = "const_intrinsic_copy", issue = "80697")]
#[rustc_const_stable(feature = "const_intrinsic_copy", since = "CURRENT_RUSTC_VERSION")]
#[stable(feature = "pointer_methods", since = "1.26.0")]
#[inline(always)]
#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
@ -1329,7 +1329,7 @@ impl<T: ?Sized> *mut T {
/// See [`ptr::copy_nonoverlapping`] for safety concerns and examples.
///
/// [`ptr::copy_nonoverlapping`]: crate::ptr::copy_nonoverlapping()
#[rustc_const_unstable(feature = "const_intrinsic_copy", issue = "80697")]
#[rustc_const_stable(feature = "const_intrinsic_copy", since = "CURRENT_RUSTC_VERSION")]
#[stable(feature = "pointer_methods", since = "1.26.0")]
#[inline(always)]
#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces

View File

@ -924,7 +924,7 @@ impl<T: ?Sized> NonNull<T> {
#[inline(always)]
#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
#[stable(feature = "non_null_convenience", since = "1.80.0")]
#[rustc_const_unstable(feature = "const_intrinsic_copy", issue = "80697")]
#[rustc_const_stable(feature = "const_intrinsic_copy", since = "CURRENT_RUSTC_VERSION")]
pub const unsafe fn copy_to(self, dest: NonNull<T>, count: usize)
where
T: Sized,
@ -944,7 +944,7 @@ impl<T: ?Sized> NonNull<T> {
#[inline(always)]
#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
#[stable(feature = "non_null_convenience", since = "1.80.0")]
#[rustc_const_unstable(feature = "const_intrinsic_copy", issue = "80697")]
#[rustc_const_stable(feature = "const_intrinsic_copy", since = "CURRENT_RUSTC_VERSION")]
pub const unsafe fn copy_to_nonoverlapping(self, dest: NonNull<T>, count: usize)
where
T: Sized,
@ -964,7 +964,7 @@ impl<T: ?Sized> NonNull<T> {
#[inline(always)]
#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
#[stable(feature = "non_null_convenience", since = "1.80.0")]
#[rustc_const_unstable(feature = "const_intrinsic_copy", issue = "80697")]
#[rustc_const_stable(feature = "const_intrinsic_copy", since = "CURRENT_RUSTC_VERSION")]
pub const unsafe fn copy_from(self, src: NonNull<T>, count: usize)
where
T: Sized,
@ -984,7 +984,7 @@ impl<T: ?Sized> NonNull<T> {
#[inline(always)]
#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
#[stable(feature = "non_null_convenience", since = "1.80.0")]
#[rustc_const_unstable(feature = "const_intrinsic_copy", issue = "80697")]
#[rustc_const_stable(feature = "const_intrinsic_copy", since = "CURRENT_RUSTC_VERSION")]
pub const unsafe fn copy_from_nonoverlapping(self, src: NonNull<T>, count: usize)
where
T: Sized,

View File

@ -21,7 +21,6 @@
#![feature(const_cell_into_inner)]
#![feature(const_hash)]
#![feature(const_heap)]
#![feature(const_intrinsic_copy)]
#![feature(const_ip)]
#![feature(const_ipv4)]
#![feature(const_ipv6)]

View File

@ -1,8 +1,6 @@
#![no_std]
#![feature(
const_intrinsic_copy,
const_refs_to_cell,
const_maybe_uninit_as_mut_ptr,
const_mut_refs,
convert_float_to_int,
core_intrinsics,

View File

@ -32,13 +32,17 @@
//!
//! Once you are familiar with the contents of the standard library you may
//! begin to find the verbosity of the prose distracting. At this stage in your
//! development you may want to press the `[-]` button near the top of the
//! page to collapse it into a more skimmable view.
//! development you may want to press the <code>
//! <svg style="width:0.75rem;height:0.75rem" viewBox="0 0 12 12"
//! stroke="currentColor" fill="none">
//! <path d="M2,2l4,4l4,-4M2,6l4,4l4,-4"/></svg> Summary</code> button near the
//! top of the page to collapse it into a more skimmable view.
//!
//! While you are looking at that `[-]` button also notice the `source`
//! link. Rust's API documentation comes with the source code and you are
//! encouraged to read it. The standard library source is generally high
//! quality and a peek behind the curtains is often enlightening.
//! While you are looking at the top of the page, also notice the
//! <code>source</code> link. Rust's API documentation comes with the source
//! code and you are encouraged to read it. The standard library source is
//! generally high quality and a peek behind the curtains is
//! often enlightening.
//!
//! # What is in the standard library documentation?
//!

@ -1 +1 @@
Subproject commit e7d217be2a75ef1753f0988d6ccaba4d7e376259
Subproject commit 99cf75a5414fa8adbe3974bd0836661ca901708f

@ -1 +1 @@
Subproject commit b3ca7ade0f87d7e3fb538776defc5b2cc4188172
Subproject commit c7ebae25cb4801a31b6f05353f6d85bfa6feedd1

@ -1 +1 @@
Subproject commit 687faf9958c52116d003b41dfd29cc1cf44f5311
Subproject commit 24fb2687cdbc54fa18ae4acf5d879cfceca77b2c

@ -1 +1 @@
Subproject commit 0ed9229f5b6f7824b333beabd7e3d5ba4b9bd971
Subproject commit 555f3de2fa0d61c4294b74d245f1cbad6fcbf589

View File

@ -313,6 +313,7 @@ target | std | host | notes
`i686-uwp-windows-msvc` | ✓ | | [^x86_32-floats-return-ABI]
[`i686-win7-windows-msvc`](platform-support/win7-windows-msvc.md) | ✓ | | 32-bit Windows 7 support [^x86_32-floats-return-ABI]
[`i686-wrs-vxworks`](platform-support/vxworks.md) | ✓ | | [^x86_32-floats-return-ABI]
[`loongarch64-unknown-linux-ohos`](platform-support/openharmony.md) | ✓ | | LoongArch64 OpenHarmony
[`m68k-unknown-linux-gnu`](platform-support/m68k-unknown-linux-gnu.md) | ? | | Motorola 680x0 Linux
`mips-unknown-linux-gnu` | ✓ | ✓ | MIPS Linux (kernel 4.4, glibc 2.23)
`mips-unknown-linux-musl` | ✓ | | MIPS Linux with musl 1.2.3

View File

@ -2,6 +2,14 @@
**Tier: 2**
* aarch64-unknown-linux-ohos
* armv7-unknown-linux-ohos
* x86_64-unknown-linux-ohos
**Tier: 3**
* loongarch64-unknown-linux-ohos
Targets for the [OpenHarmony](https://gitee.com/openharmony/docs/) operating
system.

View File

@ -26,8 +26,11 @@ pub(crate) fn render(cx: &mut Context<'_>, krate: &clean::Crate) -> Result<(), E
let dst = cx.dst.join("src").join(krate.name(cx.tcx()).as_str());
cx.shared.ensure_dir(&dst)?;
let crate_name = krate.name(cx.tcx());
let crate_name = crate_name.as_str();
let mut collector = SourceCollector { dst, cx, emitted_local_sources: FxHashSet::default() };
let mut collector =
SourceCollector { dst, cx, emitted_local_sources: FxHashSet::default(), crate_name };
collector.visit_crate(krate);
Ok(())
}
@ -115,6 +118,8 @@ struct SourceCollector<'a, 'tcx> {
/// Root destination to place all HTML output into
dst: PathBuf,
emitted_local_sources: FxHashSet<PathBuf>,
crate_name: &'a str,
}
impl DocVisitor for SourceCollector<'_, '_> {
@ -210,6 +215,9 @@ impl SourceCollector<'_, '_> {
},
);
let src_fname = p.file_name().expect("source has no filename").to_os_string();
let mut fname = src_fname.clone();
let root_path = PathBuf::from("../../").join(root_path.into_inner());
let mut root_path = root_path.to_string_lossy();
if let Some(c) = root_path.as_bytes().last()
@ -217,12 +225,12 @@ impl SourceCollector<'_, '_> {
{
root_path += "/";
}
let mut file_path = Path::new(&self.crate_name).join(&*cur.borrow());
file_path.push(&fname);
fname.push(".html");
let mut cur = self.dst.join(cur.into_inner());
shared.ensure_dir(&cur)?;
let src_fname = p.file_name().expect("source has no filename").to_os_string();
let mut fname = src_fname.clone();
fname.push(".html");
cur.push(&fname);
let title = format!("{} - source", src_fname.to_string_lossy());
@ -250,7 +258,7 @@ impl SourceCollector<'_, '_> {
cx,
&root_path,
highlight::DecorationInfo::default(),
SourceContext::Standalone,
SourceContext::Standalone { file_path },
)
},
&shared.style_files,
@ -312,10 +320,11 @@ struct ScrapedSource<'a, Code: std::fmt::Display> {
struct Source<Code: std::fmt::Display> {
lines: RangeInclusive<usize>,
code_html: Code,
file_path: Option<(String, String)>,
}
pub(crate) enum SourceContext<'a> {
Standalone,
Standalone { file_path: PathBuf },
Embedded(ScrapedInfo<'a>),
}
@ -344,9 +353,19 @@ pub(crate) fn print_src(
});
let lines = s.lines().count();
match source_context {
SourceContext::Standalone => {
Source { lines: (1..=lines), code_html: code }.render_into(&mut writer).unwrap()
SourceContext::Standalone { file_path } => Source {
lines: (1..=lines),
code_html: code,
file_path: if let Some(file_name) = file_path.file_name()
&& let Some(file_path) = file_path.parent()
{
Some((file_path.display().to_string(), file_name.display().to_string()))
} else {
None
},
}
.render_into(&mut writer)
.unwrap(),
SourceContext::Embedded(info) => {
let lines = (1 + info.offset)..=(lines + info.offset);
ScrapedSource { info, lines, code_html: code }.render_into(&mut writer).unwrap();

View File

@ -61,6 +61,8 @@ nav.sub {
--copy-path-img-hover-filter: invert(35%);
--code-example-button-color: #7f7f7f;
--code-example-button-hover-color: #595959;
--settings-menu-filter: invert(50%);
--settings-menu-hover-filter: invert(35%);
--codeblock-error-hover-color: rgb(255, 0, 0);
--codeblock-error-color: rgba(255, 0, 0, .5);
--codeblock-ignore-hover-color: rgb(255, 142, 0);
@ -87,7 +89,6 @@ nav.sub {
--search-tab-button-not-selected-background: #e6e6e6;
--search-tab-button-selected-border-top-color: #0089ff;
--search-tab-button-selected-background: #fff;
--settings-menu-filter: none;
--stab-background-color: #fff5d6;
--stab-code-color: #000;
--code-highlight-kw-color: #8959a8;
@ -192,6 +193,8 @@ nav.sub {
--search-tab-button-not-selected-background: #252525;
--search-tab-button-selected-border-top-color: #0089ff;
--search-tab-button-selected-background: #353535;
--settings-menu-filter: invert(50%);
--settings-menu-hover-filter: invert(65%);
--stab-background-color: #314559;
--stab-code-color: #e6e1cf;
--code-highlight-kw-color: #ab8ac1;

View File

@ -34,6 +34,8 @@ xmlns="http://www.w3.org/2000/svg" fill="black" height="18px">\
</g></svg>');
--button-left-margin: 4px;
--button-border-radius: 2px;
--toolbar-button-border-radius: 6px;
--code-block-border-radius: 6px;
}
/* See FiraSans-LICENSE.txt for the Fira Sans license. */
@ -165,7 +167,7 @@ h1, h2, h3, h4 {
.main-heading h1 {
margin: 0;
padding: 0;
flex-grow: 1;
grid-area: main-heading-h1;
/* We use overflow-wrap: break-word for Safari, which doesn't recognize
`anywhere`: https://developer.mozilla.org/en-US/docs/Web/CSS/overflow-wrap */
overflow-wrap: break-word;
@ -174,10 +176,28 @@ h1, h2, h3, h4 {
overflow-wrap: anywhere;
}
.main-heading {
display: flex;
flex-wrap: wrap;
position: relative;
display: grid;
grid-template-areas:
"main-heading-breadcrumbs main-heading-breadcrumbs"
"main-heading-h1 main-heading-toolbar"
"main-heading-sub-heading main-heading-toolbar";
grid-template-columns: 1fr max-content;
grid-template-rows: 25px min-content min-content;
padding-bottom: 6px;
margin-bottom: 15px;
margin-bottom: 11px;
}
.rustdoc-breadcrumbs {
grid-area: main-heading-breadcrumbs;
height: 25px;
line-height: 1.25;
display: flex;
align-items: end;
}
.rustdoc-breadcrumbs a {
padding: 4px 0;
margin: -4px 0;
z-index: 1;
}
/* The only headings that get underlines are:
Markdown-generated headings within the top-doc
@ -218,11 +238,13 @@ h1, h2, h3, h4, h5, h6,
.search-results .result-name,
.item-name > a,
.out-of-band,
.sub-heading,
span.since,
a.src,
#help-button > a,
rustdoc-toolbar,
summary.hideme,
.scraped-example-list,
.rustdoc-breadcrumbs,
/* This selector is for the items listed in the "all items" page. */
ul.all-items {
font-family: "Fira Sans", Arial, NanumBarunGothic, sans-serif;
@ -891,14 +913,27 @@ both the code example and the line numbers, so we need to remove the radius in t
overflow-x: auto;
}
.out-of-band {
.sub-heading {
font-size: 1rem;
flex-grow: 0;
font-size: 1.125rem;
grid-area: main-heading-sub-heading;
line-height: 1.25;
padding-bottom: 4px;
}
.main-heading rustdoc-toolbar, .main-heading .out-of-band {
grid-area: main-heading-toolbar;
}
rustdoc-toolbar {
display: flex;
flex-direction: row;
flex-wrap: nowrap;
}
.docblock code, .docblock-short code,
pre, .rustdoc.src .example-wrap, .example-wrap .src-line-numbers {
background-color: var(--code-block-background-color);
border-radius: var(--code-block-border-radius);
}
#main-content {
@ -945,7 +980,7 @@ div.where {
nav.sub {
flex-grow: 1;
flex-flow: row nowrap;
margin: 4px 0 25px 0;
margin: 4px 0 0 0;
display: flex;
align-items: center;
}
@ -956,7 +991,7 @@ nav.sub {
flex-grow: 1;
}
.src nav.sub {
margin: 0 0 15px 0;
margin: 0 0 -10px 0;
}
.section-header {
@ -1066,6 +1101,11 @@ table,
with boxes (i.e. from the flex layout) */
align-items: baseline;
}
.search-results-title + .sub-heading {
color: var(--main-color);
display: flex;
align-items: center;
}
#crate-search-div {
/* ensures that 100% in properties of #crate-search-div:after
are relative to the size of this div */
@ -1289,10 +1329,16 @@ so that we can apply CSS-filters to change the arrow color in themes */
border-color: var(--settings-input-color) !important;
}
#settings.popover {
--popover-arrow-offset: 202px;
top: calc(100% - 16px);
}
/* use larger max-width for help popover, but not for help.html */
#help.popover {
max-width: 600px;
--popover-arrow-offset: 48px;
--popover-arrow-offset: 118px;
top: calc(100% - 16px);
}
#help dt {
@ -1300,10 +1346,15 @@ so that we can apply CSS-filters to change the arrow color in themes */
clear: left;
margin-right: 0.5rem;
}
#help dd {
margin-bottom: 0.5rem;
}
#help span.top, #help span.bottom {
text-align: center;
display: block;
font-size: 1.125rem;
padding: 0 0.5rem;
text-wrap-style: balance;
}
#help span.top {
margin: 10px 0;
@ -1315,10 +1366,13 @@ so that we can apply CSS-filters to change the arrow color in themes */
clear: both;
border-top: 1px solid var(--border-color);
}
.side-by-side {
display: flex;
margin-bottom: 20px;
}
.side-by-side > div {
width: 50%;
float: left;
padding: 0 20px 20px 17px;
padding: 0 20px 0 17px;
}
.item-info .stab {
@ -1381,7 +1435,9 @@ so that we can apply CSS-filters to change the arrow color in themes */
}
.rightside:not(a),
.out-of-band {
.out-of-band,
.sub-heading,
rustdoc-toolbar {
color: var(--right-side-color);
}
@ -1595,8 +1651,8 @@ instead, we check that it's not a "finger" cursor.
display: block;
}
.out-of-band > span.since {
font-size: 1.25rem;
.main-heading span.since::before {
content: "Since ";
}
.sub-variant h4 {
@ -1698,6 +1754,7 @@ a.tooltip:hover::after {
}
#search-tabs {
margin-top: 0.25rem;
display: flex;
flex-direction: row;
gap: 1px;
@ -1759,9 +1816,10 @@ a.tooltip:hover::after {
border-bottom: 1px solid var(--border-color);
}
#settings-menu, #help-button {
#settings-menu, #help-button, button#toggle-all-docs {
margin-left: var(--button-left-margin);
display: flex;
line-height: 1.25;
}
#sidebar-button {
display: none;
@ -1785,33 +1843,36 @@ a.tooltip:hover::after {
.hide-sidebar .src #sidebar-button {
position: static;
}
#settings-menu > a, #help-button > a, #sidebar-button > a {
#settings-menu > a, #help-button > a, #sidebar-button > a, button#toggle-all-docs {
display: flex;
align-items: center;
justify-content: center;
background-color: var(--button-background-color);
border: 1px solid var(--border-color);
flex-direction: column;
border: 1px solid transparent;
border-radius: var(--button-border-radius);
color: var(--settings-button-color);
/* Rare exception to specifying font sizes in rem. Since this is acting
as an icon, it's okay to specify their sizes in pixels. */
font-size: 20px;
color: var(--main-color);
}
#settings-menu > a, #help-button > a, button#toggle-all-docs {
width: 80px;
border-radius: var(--toolbar-button-border-radius);
}
#sidebar-button > a {
background-color: var(--button-background-color);
border-color: var(--border-color);
width: 33px;
}
#settings-menu > a:hover, #settings-menu > a:focus,
#help-button > a:hover, #help-button > a:focus,
#sidebar-button > a:hover, #sidebar-button > a:focus {
#settings-menu > a:hover, #settings-menu > a:focus-visible,
#help-button > a:hover, #help-button > a:focus-visible,
#sidebar-button > a:hover, #sidebar-button > a:focus-visible,
button#toggle-all-docs:hover, button#toggle-all-docs:focus-visible {
border-color: var(--settings-button-border-focus);
text-decoration: none;
}
#settings-menu > a {
line-height: 0;
font-size: 0;
}
#settings-menu > a:before {
/* Wheel <https://www.svgrepo.com/svg/384069/settings-cog-gear> */
content: url('data:image/svg+xml,<svg width="22" height="22" viewBox="0 0 12 12" \
content: url('data:image/svg+xml,<svg width="18" height="18" viewBox="0 0 12 12" \
enable-background="new 0 0 12 12" xmlns="http://www.w3.org/2000/svg">\
<path d="M10.25,6c0-0.1243286-0.0261841-0.241333-0.0366211-0.362915l1.6077881-1.5545654l\
-1.25-2.1650391 c0,0-1.2674561,0.3625488-2.1323853,0.6099854c-0.2034912-0.1431885-0.421875\
@ -1824,16 +1885,70 @@ a.tooltip:hover::after {
-0.3701782l2.1323853,0.6099854l1.25-2.1650391L10.2133789,6.362915 C10.2238159,6.241333,\
10.25,6.1243286,10.25,6z M6,7.5C5.1715698,7.5,4.5,6.8284302,4.5,6S5.1715698,4.5,6,4.5S7.5\
,5.1715698,7.5,6 S6.8284302,7.5,6,7.5z" fill="black"/></svg>');
width: 22px;
height: 22px;
width: 18px;
height: 18px;
filter: var(--settings-menu-filter);
}
button#toggle-all-docs:before {
/* Custom arrow icon */
content: url('data:image/svg+xml,<svg width="18" height="18" viewBox="0 0 12 12" \
enable-background="new 0 0 12 12" xmlns="http://www.w3.org/2000/svg">\
<path d="M2,2l4,4l4,-4M2,6l4,4l4,-4" stroke="black" fill="none" stroke-width="2px"/></svg>');
width: 18px;
height: 18px;
filter: var(--settings-menu-filter);
}
#help-button > a:before {
/* Question mark with circle */
content: url('data:image/svg+xml,<svg width="18" height="18" viewBox="0 0 12 12" \
enable-background="new 0 0 12 12" xmlns="http://www.w3.org/2000/svg" fill="none">\
<circle r="5.25" cx="6" cy="6" stroke-width="1.25" stroke="black"/>\
<text x="6" y="7" style="font:8px sans-serif;font-weight:1000" text-anchor="middle" \
dominant-baseline="middle" fill="black">?</text></svg>');
width: 18px;
height: 18px;
filter: var(--settings-menu-filter);
}
button#toggle-all-docs:before,
#help-button > a:before,
#settings-menu > a:before {
filter: var(--settings-menu-filter);
margin: 8px;
}
@media not (pointer: coarse) {
button#toggle-all-docs:hover:before,
#help-button > a:hover:before,
#settings-menu > a:hover:before {
filter: var(--settings-menu-hover-filter);
}
}
button[disabled]#toggle-all-docs {
opacity: 0.25;
border: solid 1px var(--main-background-color);
background-size: cover;
}
button[disabled]#toggle-all-docs:hover {
border: solid 1px var(--main-background-color);
cursor: not-allowed;
}
rustdoc-toolbar span.label {
font-size: 1rem;
flex-grow: 1;
padding-bottom: 4px;
}
#sidebar-button > a:before {
/* sidebar resizer image */
content: url('data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 22 22" \
fill="none" stroke="black">\
<rect x="1" y="1" width="20" height="20" ry="1.5" stroke-width="1.5"/>\
<rect x="1" y="1" width="20" height="20" ry="1.5" stroke-width="1.5" stroke="%23777"/>\
<circle cx="4.375" cy="4.375" r="1" stroke-width=".75"/>\
<path d="m7.6121 3v16 M5.375 7.625h-2 m2 3h-2 m2 3h-2" stroke-width="1.25"/></svg>');
width: 22px;
@ -1948,10 +2063,10 @@ details.toggle > summary.hideme > span {
}
details.toggle > summary::before {
/* toggle plus */
background: url('data:image/svg+xml,<svg width="17" height="17" \
shape-rendering="crispEdges" stroke="black" fill="none" xmlns="http://www.w3.org/2000/svg"><path \
d="M5 2.5H2.5v12H5m7-12h2.5v12H12M5 8.5h7M8.5 12V8.625v0V5"/></svg>') no-repeat top left;
/* arrow pointing left */
background: url('data:image/svg+xml,<svg width="16" height="16" viewBox="0 0 12 12" \
enable-background="new 0 0 12 12" xmlns="http://www.w3.org/2000/svg">\
<path d="M4,2l4,4l-4,4" stroke="black" fill="none" stroke-width="1px"/></svg>');
content: "";
cursor: pointer;
width: 16px;
@ -2034,10 +2149,10 @@ details.toggle[open] > summary.hideme > span {
}
details.toggle[open] > summary::before {
/* toggle minus */
background: url('data:image/svg+xml,<svg width="17" height="17" \
shape-rendering="crispEdges" stroke="black" fill="none" xmlns="http://www.w3.org/2000/svg"><path \
d="M5 2.5H2.5v12H5m7-12h2.5v12H12M5 8.5h7"/></svg>') no-repeat top left;
/* arrow pointing down */
background: url('data:image/svg+xml,<svg width="16" height="16" viewBox="0 0 12 12" \
enable-background="new 0 0 12 12" xmlns="http://www.w3.org/2000/svg">\
<path d="M2,4l4,4l4,-4" stroke="black" fill="none" stroke-width="1px"/></svg>');
}
details.toggle[open] > summary::after {
@ -2090,6 +2205,12 @@ However, it's not needed with smaller screen width because the doc/code block is
#search-tabs .count {
display: block;
}
.side-by-side {
flex-direction: column-reverse;
}
.side-by-side > div {
width: auto;
}
}
/*
@ -2106,6 +2227,25 @@ in src-script.js and main.js
scroll-margin-top: 45px;
}
/* We don't display this button on mobile devices. */
#copy-path {
display: none;
}
/* Text label takes up too much space at this size. */
rustdoc-toolbar span.label {
display: none;
}
#settings-menu > a, #help-button > a, button#toggle-all-docs {
width: 33px;
}
#settings.popover {
--popover-arrow-offset: 86px;
}
#help.popover {
--popover-arrow-offset: 48px;
}
.rustdoc {
/* Sidebar should overlay main content, rather than pushing main content to the right.
Turn off `display: flex` on the body element. */
@ -2117,20 +2257,6 @@ in src-script.js and main.js
padding-top: 0px;
}
.main-heading {
flex-direction: column;
}
.out-of-band {
text-align: left;
margin-left: initial;
padding: initial;
}
.out-of-band .since::before {
content: "Since ";
}
/* Hide the logo and item name from the sidebar. Those are displayed
in the mobile-topbar instead. */
.sidebar .logo-container,
@ -2163,6 +2289,9 @@ in src-script.js and main.js
.src .search-form {
margin-left: 40px;
}
.src .main-heading {
margin-left: 8px;
}
.hide-sidebar .search-form {
margin-left: 32px;
}
@ -2234,16 +2363,11 @@ in src-script.js and main.js
left: -11px;
}
/* We don't display these buttons on mobile devices. */
#copy-path, #help-button {
display: none;
}
/* sidebar button becomes topbar button */
#sidebar-button > a:before {
content: url('data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg" \
viewBox="0 0 22 22" fill="none" stroke="black">\
<rect x="1" y="1" width="20" height="20" ry="1.5" stroke-width="1.5"/>\
<rect x="1" y="1" width="20" height="20" ry="1.5" stroke-width="1.5" stroke="%23777"/>\
<circle cx="4.375" cy="4.375" r="1" stroke-width=".75"/>\
<path d="m3 7.375h16m0-3h-4" stroke-width="1.25"/></svg>');
width: 22px;
@ -2305,7 +2429,7 @@ in src-script.js and main.js
}
.src nav.sub {
margin: 0;
margin: 0 0 -25px 0;
padding: var(--nav-sub-mobile-padding);
}
}
@ -2543,6 +2667,8 @@ by default.
--copy-path-img-hover-filter: invert(35%);
--code-example-button-color: #7f7f7f;
--code-example-button-hover-color: #595959;
--settings-menu-filter: invert(50%);
--settings-menu-hover-filter: invert(35%);
--codeblock-error-hover-color: rgb(255, 0, 0);
--codeblock-error-color: rgba(255, 0, 0, .5);
--codeblock-ignore-hover-color: rgb(255, 142, 0);
@ -2569,7 +2695,6 @@ by default.
--search-tab-button-not-selected-background: #e6e6e6;
--search-tab-button-selected-border-top-color: #0089ff;
--search-tab-button-selected-background: #fff;
--settings-menu-filter: none;
--stab-background-color: #fff5d6;
--stab-code-color: #000;
--code-highlight-kw-color: #8959a8;
@ -2673,7 +2798,8 @@ by default.
--search-tab-button-not-selected-background: #252525;
--search-tab-button-selected-border-top-color: #0089ff;
--search-tab-button-selected-background: #353535;
--settings-menu-filter: none;
--settings-menu-filter: invert(50%);
--settings-menu-hover-filter: invert(65%);
--stab-background-color: #314559;
--stab-code-color: #e6e1cf;
--code-highlight-kw-color: #ab8ac1;
@ -2784,7 +2910,8 @@ Original by Dempfi (https://github.com/dempfi/ayu)
--search-tab-button-not-selected-background: transparent !important;
--search-tab-button-selected-border-top-color: none;
--search-tab-button-selected-background: #141920 !important;
--settings-menu-filter: invert(100%);
--settings-menu-filter: invert(70%);
--settings-menu-hover-filter: invert(100%);
--stab-background-color: #314559;
--stab-code-color: #e6e1cf;
--code-highlight-kw-color: #ff7733;

View File

@ -1,6 +1,6 @@
// Local js definitions:
/* global addClass, getSettingValue, hasClass, searchState, updateLocalStorage */
/* global onEach, onEachLazy, removeClass, getVar */
/* global onEachLazy, removeClass, getVar */
"use strict";
@ -19,17 +19,25 @@ function resourcePath(basename, extension) {
function hideMain() {
addClass(document.getElementById(MAIN_ID), "hidden");
const toggle = document.getElementById("toggle-all-docs");
if (toggle) {
toggle.setAttribute("disabled", "disabled");
}
}
function showMain() {
removeClass(document.getElementById(MAIN_ID), "hidden");
}
function blurHandler(event, parentElem, hideCallback) {
if (!parentElem.contains(document.activeElement) &&
!parentElem.contains(event.relatedTarget)
) {
hideCallback();
const main = document.getElementById(MAIN_ID);
removeClass(main, "hidden");
const mainHeading = main.querySelector(".main-heading");
if (mainHeading && searchState.rustdocToolbar) {
if (searchState.rustdocToolbar.parentElement) {
searchState.rustdocToolbar.parentElement.removeChild(searchState.rustdocToolbar);
}
mainHeading.appendChild(searchState.rustdocToolbar);
}
const toggle = document.getElementById("toggle-all-docs");
if (toggle) {
toggle.removeAttribute("disabled");
}
}
@ -167,6 +175,14 @@ function switchDisplayedElement(elemToDisplay) {
el.appendChild(elemToDisplay);
hideMain();
removeClass(el, "hidden");
const mainHeading = elemToDisplay.querySelector(".main-heading");
if (mainHeading && searchState.rustdocToolbar) {
if (searchState.rustdocToolbar.parentElement) {
searchState.rustdocToolbar.parentElement.removeChild(searchState.rustdocToolbar);
}
mainHeading.appendChild(searchState.rustdocToolbar);
}
}
function browserSupportsHistoryApi() {
@ -194,33 +210,36 @@ function preLoadCss(cssUrl) {
document.head.append(script);
}
getSettingsButton().onclick = event => {
if (event.ctrlKey || event.altKey || event.metaKey) {
return;
}
window.hideAllModals(false);
addClass(getSettingsButton(), "rotate");
event.preventDefault();
// Sending request for the CSS and the JS files at the same time so it will
// hopefully be loaded when the JS will generate the settings content.
loadScript(getVar("static-root-path") + getVar("settings-js"));
// Pre-load all theme CSS files, so that switching feels seamless.
//
// When loading settings.html as a standalone page, the equivalent HTML is
// generated in context.rs.
setTimeout(() => {
const themes = getVar("themes").split(",");
for (const theme of themes) {
// if there are no themes, do nothing
// "".split(",") == [""]
if (theme !== "") {
preLoadCss(getVar("root-path") + theme + ".css");
}
if (getSettingsButton()) {
getSettingsButton().onclick = event => {
if (event.ctrlKey || event.altKey || event.metaKey) {
return;
}
}, 0);
};
window.hideAllModals(false);
addClass(getSettingsButton(), "rotate");
event.preventDefault();
// Sending request for the CSS and the JS files at the same time so it will
// hopefully be loaded when the JS will generate the settings content.
loadScript(getVar("static-root-path") + getVar("settings-js"));
// Pre-load all theme CSS files, so that switching feels seamless.
//
// When loading settings.html as a standalone page, the equivalent HTML is
// generated in context.rs.
setTimeout(() => {
const themes = getVar("themes").split(",");
for (const theme of themes) {
// if there are no themes, do nothing
// "".split(",") == [""]
if (theme !== "") {
preLoadCss(getVar("root-path") + theme + ".css");
}
}
}, 0);
};
}
window.searchState = {
rustdocToolbar: document.querySelector("rustdoc-toolbar"),
loadingText: "Loading search results...",
input: document.getElementsByClassName("search-input")[0],
outputElement: () => {
@ -919,8 +938,7 @@ function preLoadCss(cssUrl) {
e.open = true;
}
});
innerToggle.title = "collapse all docs";
innerToggle.children[0].innerText = "\u2212"; // "\u2212" is "" minus sign
innerToggle.children[0].innerText = "Summary";
}
function collapseAllDocs() {
@ -934,8 +952,7 @@ function preLoadCss(cssUrl) {
e.open = false;
}
});
innerToggle.title = "expand all docs";
innerToggle.children[0].innerText = "+";
innerToggle.children[0].innerText = "Show all";
}
function toggleAllDocs() {
@ -1330,7 +1347,13 @@ function preLoadCss(cssUrl) {
}
function helpBlurHandler(event) {
blurHandler(event, getHelpButton(), window.hidePopoverMenus);
if (!getHelpButton().contains(document.activeElement) &&
!getHelpButton().contains(event.relatedTarget) &&
!getSettingsButton().contains(document.activeElement) &&
!getSettingsButton().contains(event.relatedTarget)
) {
window.hidePopoverMenus();
}
}
function buildHelpMenu() {
@ -1433,9 +1456,13 @@ href="https://doc.rust-lang.org/${channel}/rustdoc/read-documentation/search.htm
* Hide all the popover menus.
*/
window.hidePopoverMenus = () => {
onEachLazy(document.querySelectorAll(".search-form .popover"), elem => {
onEachLazy(document.querySelectorAll("rustdoc-toolbar .popover"), elem => {
elem.style.display = "none";
});
const button = getHelpButton();
if (button) {
removeClass(button, "help-open");
}
};
/**
@ -1460,7 +1487,9 @@ href="https://doc.rust-lang.org/${channel}/rustdoc/read-documentation/search.htm
function showHelp() {
// Prevent `blur` events from being dispatched as a result of closing
// other modals.
getHelpButton().querySelector("a").focus();
const button = getHelpButton();
addClass(button, "help-open");
button.querySelector("a").focus();
const menu = getHelpMenu(true);
if (menu.style.display === "none") {
window.hideAllModals();
@ -1468,28 +1497,15 @@ href="https://doc.rust-lang.org/${channel}/rustdoc/read-documentation/search.htm
}
}
const helpLink = document.querySelector(`#${HELP_BUTTON_ID} > a`);
if (isHelpPage) {
showHelp();
document.querySelector(`#${HELP_BUTTON_ID} > a`).addEventListener("click", event => {
// Already on the help page, make help button a no-op.
const target = event.target;
if (target.tagName !== "A" ||
target.parentElement.id !== HELP_BUTTON_ID ||
event.ctrlKey ||
event.altKey ||
event.metaKey) {
return;
}
event.preventDefault();
});
} else {
document.querySelector(`#${HELP_BUTTON_ID} > a`).addEventListener("click", event => {
buildHelpMenu();
} else if (helpLink) {
helpLink.addEventListener("click", event => {
// By default, have help button open docs in a popover.
// If user clicks with a moderator, though, use default browser behavior,
// probably opening in a new window or tab.
const target = event.target;
if (target.tagName !== "A" ||
target.parentElement.id !== HELP_BUTTON_ID ||
if (!helpLink.contains(helpLink) ||
event.ctrlKey ||
event.altKey ||
event.metaKey) {
@ -1812,14 +1828,11 @@ href="https://doc.rust-lang.org/${channel}/rustdoc/read-documentation/search.htm
return;
}
but.onclick = () => {
const parent = but.parentElement;
const path = [];
onEach(parent.childNodes, child => {
if (child.tagName === "A") {
path.push(child.textContent);
}
onEachLazy(document.querySelectorAll(".rustdoc-breadcrumbs a"), a => {
path.push(a.textContent);
});
path.push(document.querySelector("title").textContent.split(" ")[0]);
copyContentToClipboard(path.join("::"));
copyButtonAnimation(but);

View File

@ -3597,15 +3597,16 @@ async function showResults(results, go_to_first, filterCrates) {
let crates = "";
if (rawSearchIndex.size > 1) {
crates = " in&nbsp;<div id=\"crate-search-div\"><select id=\"crate-search\">" +
"<option value=\"all crates\">all crates</option>";
crates = "<div class=\"sub-heading\"> in&nbsp;<div id=\"crate-search-div\">" +
"<select id=\"crate-search\"><option value=\"all crates\">all crates</option>";
for (const c of rawSearchIndex.keys()) {
crates += `<option value="${c}" ${c === filterCrates && "selected"}>${c}</option>`;
}
crates += "</select></div>";
crates += "</select></div></div>";
}
let output = `<h1 class="search-results-title">Results${crates}</h1>`;
let output = `<div class="main-heading">\
<h1 class="search-results-title">Results</h1>${crates}</div>`;
if (results.query.error !== null) {
const error = results.query.error;
error.forEach((value, index) => {
@ -3662,6 +3663,9 @@ async function showResults(results, go_to_first, filterCrates) {
resultsElem.appendChild(ret_returned[0]);
search.innerHTML = output;
if (searchState.rustdocToolbar) {
search.querySelector(".main-heading").appendChild(searchState.rustdocToolbar);
}
const crateSearch = document.getElementById("crate-search");
if (crateSearch) {
crateSearch.addEventListener("input", updateCrate);

View File

@ -1,7 +1,7 @@
// Local js definitions:
/* global getSettingValue, updateLocalStorage, updateTheme */
/* global addClass, removeClass, onEach, onEachLazy, blurHandler */
/* global MAIN_ID, getVar, getSettingsButton */
/* global addClass, removeClass, onEach, onEachLazy */
/* global MAIN_ID, getVar, getSettingsButton, getHelpButton */
"use strict";
@ -267,15 +267,16 @@
}
function settingsBlurHandler(event) {
blurHandler(event, getSettingsButton(), window.hidePopoverMenus);
if (!getHelpButton().contains(document.activeElement) &&
!getHelpButton().contains(event.relatedTarget) &&
!getSettingsButton().contains(document.activeElement) &&
!getSettingsButton().contains(event.relatedTarget)
) {
window.hidePopoverMenus();
}
}
if (isSettingsPage) {
// We replace the existing "onclick" callback to do nothing if clicked.
getSettingsButton().onclick = event => {
event.preventDefault();
};
} else {
if (!isSettingsPage) {
// We replace the existing "onclick" callback.
const settingsButton = getSettingsButton();
const settingsMenu = document.getElementById("settings");

View File

@ -274,16 +274,29 @@ class RustdocSearchElement extends HTMLElement {
spellcheck="false"
placeholder="Type S or / to search, ? for more options…"
type="search">
<div id="help-button" tabindex="-1">
<a href="${rootPath}help.html" title="help">?</a>
</div>
<div id="settings-menu" tabindex="-1">
<a href="${rootPath}settings.html" title="settings">
Settings
</a>
</div>
</form>
</nav>`;
}
}
window.customElements.define("rustdoc-search", RustdocSearchElement);
class RustdocToolbarElement extends HTMLElement {
constructor() {
super();
}
connectedCallback() {
// Avoid replacing the children after they're already here.
if (this.firstElementChild) {
return;
}
const rootPath = getVar("root-path");
this.innerHTML = `
<div id="settings-menu" tabindex="-1">
<a href="${rootPath}settings.html"><span class="label">Settings</span></a>
</div>
<div id="help-button" tabindex="-1">
<a href="${rootPath}help.html"><span class="label">Help</span></a>
</div>
<button id="toggle-all-docs"><span class="label">Summary</span></button>`;
}
}
window.customElements.define("rustdoc-toolbar", RustdocToolbarElement);

View File

@ -1,26 +1,33 @@
<div class="main-heading"> {# #}
{% if !path_components.is_empty() %}
<span class="rustdoc-breadcrumbs">
{% for (i, component) in path_components.iter().enumerate() %}
{% if i != 0 %}
::<wbr>
{% endif %}
<a href="{{component.path|safe}}index.html">{{component.name}}</a>
{% endfor %}
</span>
{% endif %}
<h1>
{{typ}}
{# The breadcrumbs of the item path, like std::string #}
{% for component in path_components %}
<a href="{{component.path|safe}}index.html">{{component.name}}</a>::<wbr>
{% endfor %}
<a class="{{item_type}}" href="#">{{name}}</a> {# #}
<span{% if item_type != "mod" +%} class="{{item_type}}"{% endif %}>
{{name}}
</span> {# #}
<button id="copy-path" title="Copy item path to clipboard"> {# #}
Copy item path {# #}
</button> {# #}
</h1> {# #}
<span class="out-of-band">
<rustdoc-toolbar></rustdoc-toolbar> {# #}
<span class="sub-heading">
{% if !stability_since_raw.is_empty() %}
{{ stability_since_raw|safe +}} · {#+ #}
{{ stability_since_raw|safe +}}
{% endif %}
{% match src_href %}
{% when Some with (href) %}
<a class="src" href="{{href|safe}}">source</a> · {#+ #}
{% if !stability_since_raw.is_empty() +%} · {%+ endif %}
<a class="src" href="{{href|safe}}">source</a> {#+ #}
{% else %}
{% endmatch %}
<button id="toggle-all-docs" title="collapse all docs"> {# #}
[<span>&#x2212;</span>] {# #}
</button> {# #}
</span> {# #}
</div> {# #}

View File

@ -1,4 +1,15 @@
<div class="example-wrap">
{% match file_path %}
{% when Some with ((path, name)) %}
<div class="main-heading"> {# #}
<h1> {# #}
<div class="sub-heading">{{path}}/</div>
{{name}}
</h1> {# #}
<rustdoc-toolbar></rustdoc-toolbar> {# #}
</div>
{% else %}
{% endmatch %}
<div class="example-wrap"> {# #}
{# https://developers.google.com/search/docs/crawling-indexing/robots-meta-tag#data-nosnippet-attr
Do not show "1 2 3 4 5 ..." in web search results. #}
<div data-nosnippet><pre class="src-line-numbers">

View File

@ -10,6 +10,7 @@
#![feature(iter_intersperse)]
#![feature(let_chains)]
#![feature(never_type)]
#![feature(os_str_display)]
#![feature(round_char_boundary)]
#![feature(test)]
#![feature(type_alias_impl_trait)]

View File

@ -1963,7 +1963,7 @@ impl<'test> TestCx<'test> {
#[rustfmt::skip]
let tidy_args = [
"--new-blocklevel-tags", "rustdoc-search",
"--new-blocklevel-tags", "rustdoc-search,rustdoc-toolbar",
"--indent", "yes",
"--indent-spaces", "2",
"--wrap", "0",

View File

@ -31,7 +31,7 @@ fn check_html_file(file: &Path) -> usize {
.arg("--mute-id") // this option is useful in case we want to mute more warnings
.arg("yes")
.arg("--new-blocklevel-tags")
.arg("rustdoc-search") // custom elements
.arg("rustdoc-search,rustdoc-toolbar") // custom elements
.arg("--mute")
.arg(&to_mute_s)
.arg(file);

View File

@ -16,5 +16,5 @@ impl T1 for i32 {
fn main() {
let r = Box::new(0) as Box<dyn T1>;
let r2: Box<dyn T2> = unsafe { std::mem::transmute(r) };
r2.method2(); //~ERROR: using vtable for trait `T1` but trait `T2` was expected
r2.method2(); //~ERROR: using vtable for `T1` but `T2` was expected
}

View File

@ -1,8 +1,8 @@
error: Undefined Behavior: using vtable for trait `T1` but trait `T2` was expected
error: Undefined Behavior: using vtable for `T1` but `T2` was expected
--> tests/fail/dyn-call-trait-mismatch.rs:LL:CC
|
LL | r2.method2();
| ^^^^^^^^^^^^ using vtable for trait `T1` but trait `T2` was expected
| ^^^^^^^^^^^^ using vtable for `T1` but `T2` was expected
|
= help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
= help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information

View File

@ -63,6 +63,6 @@ fn main() {
let baz: &dyn Baz = &1;
let baz_fake: *const dyn Bar = std::mem::transmute(baz);
let _err = baz_fake as *const dyn Foo;
//~^ERROR: using vtable for trait `Baz` but trait `Bar` was expected
//~^ERROR: using vtable for `Baz` but `Bar` was expected
}
}

View File

@ -1,8 +1,8 @@
error: Undefined Behavior: using vtable for trait `Baz` but trait `Bar` was expected
error: Undefined Behavior: using vtable for `Baz` but `Bar` was expected
--> tests/fail/dyn-upcast-trait-mismatch.rs:LL:CC
|
LL | let _err = baz_fake as *const dyn Foo;
| ^^^^^^^^ using vtable for trait `Baz` but trait `Bar` was expected
| ^^^^^^^^ using vtable for `Baz` but `Bar` was expected
|
= help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
= help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information

View File

@ -0,0 +1,18 @@
trait Trait {
type Assoc;
fn foo(&self) -> Self::Assoc;
}
impl<T: Copy> Trait for T {
type Assoc = T;
fn foo(&self) -> T { *self }
}
fn main() {
let v: Box<dyn Trait<Assoc = u8>> = Box::new(2);
let v: Box<dyn Trait<Assoc = bool>> = unsafe { std::mem::transmute(v) }; //~ERROR: wrong trait
if v.foo() {
println!("huh");
}
}

View File

@ -0,0 +1,15 @@
error: Undefined Behavior: constructing invalid value: wrong trait in wide pointer vtable: expected `Trait<Assoc = bool>`, but encountered `Trait<Assoc = u8>`
--> tests/fail/validity/wrong-dyn-trait-assoc-type.rs:LL:CC
|
LL | let v: Box<dyn Trait<Assoc = bool>> = unsafe { std::mem::transmute(v) };
| ^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: wrong trait in wide pointer vtable: expected `Trait<Assoc = bool>`, but encountered `Trait<Assoc = u8>`
|
= help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
= help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
= note: BACKTRACE:
= note: inside `main` at tests/fail/validity/wrong-dyn-trait-assoc-type.rs:LL:CC
note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace
error: aborting due to 1 previous error

View File

@ -1,8 +1,8 @@
error: Undefined Behavior: constructing invalid value: wrong trait in wide pointer vtable: expected `std::fmt::Debug`, but encountered `<trivial>`
error: Undefined Behavior: constructing invalid value: wrong trait in wide pointer vtable: expected `std::fmt::Debug`, but encountered `std::marker::Send`
--> tests/fail/validity/wrong-dyn-trait.rs:LL:CC
|
LL | let _y: *const dyn fmt::Debug = unsafe { mem::transmute(x) };
| ^^^^^^^^^^^^^^^^^ constructing invalid value: wrong trait in wide pointer vtable: expected `std::fmt::Debug`, but encountered `<trivial>`
| ^^^^^^^^^^^^^^^^^ constructing invalid value: wrong trait in wide pointer vtable: expected `std::fmt::Debug`, but encountered `std::marker::Send`
|
= help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
= help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information

View File

@ -249,6 +249,9 @@
//@ revisions: loongarch64_unknown_linux_musl
//@ [loongarch64_unknown_linux_musl] compile-flags: --target loongarch64-unknown-linux-musl
//@ [loongarch64_unknown_linux_musl] needs-llvm-components: loongarch
//@ revisions: loongarch64_unknown_linux_ohos
//@ [loongarch64_unknown_linux_ohos] compile-flags: --target loongarch64-unknown-linux-ohos
//@ [loongarch64_unknown_linux_ohos] needs-llvm-components: loongarch
//@ revisions: loongarch64_unknown_none
//@ [loongarch64_unknown_none] compile-flags: --target loongarch64-unknown-none
//@ [loongarch64_unknown_none] needs-llvm-components: loongarch

15
tests/crashes/130310.rs Normal file
View File

@ -0,0 +1,15 @@
//@ known-bug: rust-lang/rust#130310
use std::marker::PhantomData;
#[repr(C)]
struct A<T> {
a: *const A<A<T>>,
p: PhantomData<T>,
}
extern "C" {
fn f(a: *const A<()>);
}
fn main() {}

View File

@ -12,8 +12,7 @@ define-function: (
call-function: ("switch-theme", {"theme": |theme|})
assert-css: ("#toggle-all-docs", {"color": |main_color|})
assert-css: (".main-heading h1 a:nth-of-type(1)", {"color": |main_heading_color|})
assert-css: (".main-heading a:nth-of-type(2)", {"color": |main_heading_type_color|})
assert-css: (".main-heading h1 span", {"color": |main_heading_type_color|})
assert-css: (
".rightside a.src",
{"color": |src_link_color|, "text-decoration": "none solid " + |src_link_color|},
@ -55,7 +54,7 @@ define-function: (
assert-css: ("#top-doc-prose-title", {"color": |title_color|})
assert-css: (".sidebar .block a", {"color": |sidebar_link_color|})
assert-css: (".main-heading h1 a", {"color": |title_color|})
assert-css: (".main-heading h1", {"color": |title_color|})
// We move the cursor over the "Implementations" title so the anchor is displayed.
move-cursor-to: "h2#implementations"

View File

@ -4,7 +4,7 @@ set-window-size: (1000, 1000) // Try desktop size first.
wait-for: "#help"
assert-css: ("#help", {"display": "block"})
assert-css: ("#help dd", {"font-size": "16px"})
click: "#help-button > a"
assert-false: "#help-button > a"
assert-css: ("#help", {"display": "block"})
compare-elements-property: (".sub", "#help", ["offsetWidth"])
compare-elements-position: (".sub", "#help", ["x"])
@ -50,7 +50,8 @@ call-function: ("check-colors", {
})
// This test ensures that opening the help popover without switching pages works.
go-to: "file://" + |DOC_PATH| + "/test_docs/index.html"
go-to: "file://" + |DOC_PATH| + "/test_docs/index.html?search=a"
wait-for: "#search-tabs" // Waiting for the search.js to load.
set-window-size: (1000, 1000) // Only supported on desktop.
assert-false: "#help"
click: "#help-button > a"
@ -62,7 +63,8 @@ compare-elements-property-false: (".sub", "#help", ["offsetWidth"])
compare-elements-position-false: (".sub", "#help", ["x"])
// This test ensures that the "the rustdoc book" anchor link within the help popover works.
go-to: "file://" + |DOC_PATH| + "/test_docs/index.html"
go-to: "file://" + |DOC_PATH| + "/test_docs/index.html?search=a"
wait-for: "#search-tabs" // Waiting for the search.js to load.
set-window-size: (1000, 1000) // Popover only appears when the screen width is >700px.
assert-false: "#help"
click: "#help-button > a"

View File

@ -20,7 +20,7 @@ store-position: (
{"x": second_line_x, "y": second_line_y},
)
assert: |first_line_x| != |second_line_x| && |first_line_x| == 516 && |second_line_x| == 272
assert: |first_line_y| != |second_line_y| && |first_line_y| == 688 && |second_line_y| == 711
assert: |first_line_y| != |second_line_y| && |first_line_y| == 714 && |second_line_y| == 737
// Now we ensure that they're not rendered on the same line.
set-window-size: (1100, 800)

View File

@ -5,23 +5,8 @@ set-window-size: (400, 600)
set-font-size: 18
wait-for: 100 // wait a bit for the resize and the font-size change to be fully taken into account.
// The out-of-band info (source, stable version, collapse) should be below the
// h1 when the screen gets narrow enough.
assert-css: (".main-heading", {
"display": "flex",
"flex-direction": "column"
})
assert-property: (".mobile-topbar h2", {"offsetHeight": 33})
// Note: We can't use assert-text here because the 'Since' is set by CSS and
// is therefore not part of the DOM.
assert-css: (".content .out-of-band .since::before", { "content": "\"Since \"" })
set-window-size: (1000, 1000)
wait-for: 100 // wait a bit for the resize to be fully taken into account.
assert-css-false: (".content .out-of-band .since::before", { "content": "\"Since \"" })
// On the settings page, the theme buttons should not line-wrap. Instead, they should
// all be placed as a group on a line below the setting name "Theme."
go-to: "file://" + |DOC_PATH| + "/settings.html"

View File

@ -248,12 +248,13 @@ click: "//*[@id='method.create_an_iterator_from_read']//*[@class='tooltip']"
assert-count: ("//*[@class='tooltip popover']", 1)
assert-false: "//*[@class='sidebar shown']"
// Also check the focus handling for the help button.
// Also check the focus handling for the settings button.
set-window-size: (1100, 600)
reload:
assert-count: ("//*[@class='tooltip popover']", 0)
click: "//*[@id='method.create_an_iterator_from_read']//*[@class='tooltip']"
assert-count: ("//*[@class='tooltip popover']", 1)
click: "#help-button a"
click: "#settings-menu a"
wait-for: "#settings"
assert-count: ("//*[@class='tooltip popover']", 0)
assert-false: "#method\.create_an_iterator_from_read .tooltip:focus"

View File

@ -1,6 +1,7 @@
// This test ensures that the "pocket menus" are working as expected.
include: "utils.goml"
go-to: "file://" + |DOC_PATH| + "/test_docs/index.html"
go-to: "file://" + |DOC_PATH| + "/test_docs/index.html?search=test"
wait-for: "#crate-search"
// First we check that the help menu doesn't exist yet.
assert-false: "#help-button .popover"
// Then we display the help menu.

View File

@ -80,8 +80,8 @@ click: ".scraped-example .button-holder .expand"
store-value: (offset_y, 4)
// First with desktop
assert-position: (".scraped-example", {"y": 226})
assert-position: (".scraped-example .prev", {"y": 226 + |offset_y|})
assert-position: (".scraped-example", {"y": 252})
assert-position: (".scraped-example .prev", {"y": 252 + |offset_y|})
// Gradient background should be at the top of the code block.
assert-css: (".scraped-example .example-wrap::before", {"top": "0px"})
@ -90,8 +90,8 @@ assert-css: (".scraped-example .example-wrap::after", {"bottom": "0px"})
// Then with mobile
set-window-size: (600, 600)
store-size: (".scraped-example .scraped-example-title", {"height": title_height})
assert-position: (".scraped-example", {"y": 284})
assert-position: (".scraped-example .prev", {"y": 284 + |offset_y| + |title_height|})
assert-position: (".scraped-example", {"y": 281})
assert-position: (".scraped-example .prev", {"y": 281 + |offset_y| + |title_height|})
define-function: (
"check_title_and_code_position",

View File

@ -56,7 +56,8 @@ assert-property: ("#crate-search", {"value": "lib2"})
assert-false: "#results .externcrate"
// Checking that the text for the "title" is correct (the "all crates" comes from the "<select>").
assert-text: (".search-results-title", "Results in all crates", STARTS_WITH)
assert-text: (".search-results-title", "Results", STARTS_WITH)
assert-text: (".search-results-title + .sub-heading", " in all crates", STARTS_WITH)
// Checking the display of the crate filter.
// We start with the light theme.
@ -84,6 +85,6 @@ wait-for-css: ("#crate-search", {
click: "#theme-ayu"
wait-for-css: ("#crate-search", {
"border": "1px solid #5c6773",
"color": "#fff",
"color": "#c5c5c5",
"background-color": "#0f1419",
})

View File

@ -1,13 +1,14 @@
// This test ensures that the elements in ".search-form" have the expected display.
include: "utils.goml"
go-to: "file://" + |DOC_PATH| + "/test_docs/index.html"
go-to: "file://" + |DOC_PATH| + "/test_docs/index.html?search=test"
wait-for: "#search-tabs" // Waiting for the search.js to load.
show-text: true
define-function: (
"check-search-colors",
[
theme, border, background, search_input_color, search_input_border_focus,
menu_button_border, menu_button_a_color, menu_button_a_border_hover, menu_a_color,
menu_button_a_color, menu_button_a_border_hover, menu_a_color,
],
block {
call-function: ("switch-theme", {"theme": |theme|})
@ -29,30 +30,22 @@ define-function: (
"color": |search_input_color|,
},
)
assert-css: (
"#help-button",
{"border-color": |menu_button_border|},
)
assert-css: (
"#help-button > a",
{
"color": |menu_button_a_color|,
"border-color": |border|,
"background-color": |background|,
"border-color": "transparent",
"background-color": "transparent",
},
)
// Hover help button.
move-cursor-to: "#help-button"
assert-css: (
"#help-button:hover",
{"border-color": |menu_button_border|},
)
assert-css: (
"#help-button > a",
{
"color": |menu_button_a_color|,
"border-color": |menu_button_a_border_hover|,
"background-color": |background|,
"background-color": "transparent",
},
)
// Link color inside
@ -63,30 +56,22 @@ define-function: (
"color": |menu_a_color|,
},
)
assert-css: (
"#settings-menu",
{"border-color": |menu_button_border|},
)
assert-css: (
"#settings-menu > a",
{
"color": |menu_button_a_color|,
"border-color": |border|,
"background-color": |background|,
"border-color": "transparent",
"background-color": "transparent",
},
)
// Hover settings menu.
move-cursor-to: "#settings-menu"
assert-css: (
"#settings-menu:hover",
{"border-color": |menu_button_border|},
)
assert-css: (
"#settings-menu:hover > a",
{
"color": |menu_button_a_color|,
"border-color": |menu_button_a_border_hover|,
"background-color": |background|,
"background-color": "transparent",
},
)
},
@ -100,8 +85,7 @@ call-function: (
"background": "#141920",
"search_input_color": "#fff",
"search_input_border_focus": "#5c6773",
"menu_button_border": "#c5c5c5",
"menu_button_a_color": "#fff",
"menu_button_a_color": "#c5c5c5",
"menu_button_a_border_hover": "#e0e0e0",
"menu_a_color": "#39afd7",
}
@ -114,8 +98,7 @@ call-function: (
"background": "#f0f0f0",
"search_input_color": "#111",
"search_input_border_focus": "#008dfd",
"menu_button_border": "#ddd",
"menu_button_a_color": "#000",
"menu_button_a_color": "#ddd",
"menu_button_a_border_hover": "#ffb900",
"menu_a_color": "#d2991d",
}
@ -128,7 +111,6 @@ call-function: (
"background": "#fff",
"search_input_color": "#000",
"search_input_border_focus": "#66afe9",
"menu_button_border": "#000",
"menu_button_a_color": "#000",
"menu_button_a_border_hover": "#717171",
"menu_a_color": "#3873ad",

View File

@ -50,8 +50,11 @@ compare-elements-size-near: (
set-window-size: (900, 900)
// First we check the current width, height and position.
assert-css: ("#crate-search", {"width": "223px"})
assert-css: (".search-results-title", {"height": "50px", "width": "640px"})
assert-css: ("#crate-search", {"width": "159px"})
store-size: (".search-results-title", {
"height": search_results_title_height,
"width": search_results_title_width,
})
assert-css: ("#search", {"width": "640px"})
// Then we update the text of one of the `<option>`.
@ -61,10 +64,12 @@ set-text: (
)
// Then we compare again to confirm the height didn't change.
assert-size: ("#crate-search", {"width": 527})
assert-size: (".search-results-title", {"height": 50, "width": 640})
// And we check that the `<select>` isn't bigger than its container (".search-results-title").
assert-size: ("#crate-search", {"width": 509})
assert-size: (".search-results-title", {
"height": |search_results_title_height|,
})
assert-css: ("#search", {"width": "640px"})
assert: |search_results_title_width| <= 640
// Now checking that the crate filter is working as expected too.
show-text: true

View File

@ -16,4 +16,5 @@ assert-css: ("#main-content", {"display": "none"})
// Now we can check that the feature is working as expected!
go-to: "file://" + |DOC_PATH| + "/test_docs/index.html?search=struct%3AFoo&go_to_first=true"
// Waiting for the page to load...
wait-for-text: (".main-heading h1", "Struct test_docs::FooCopy item path")
wait-for-text: (".main-heading .rustdoc-breadcrumbs", "test_docs")
wait-for-text: (".main-heading h1", "Struct FooCopy item path")

View File

@ -11,8 +11,8 @@ define-function: (
call-function: ("switch-theme", {"theme": |theme|})
assert-css: ("#settings-menu > a::before", {
"filter": |filter|,
"width": "22px",
"height": "22px",
"width": "18px",
"height": "18px",
})
}
)
@ -23,9 +23,9 @@ call-function: ("check-image", {
})
call-function: ("check-image", {
"theme": "dark",
"filter": "none",
"filter": "invert(0.65)",
})
call-function: ("check-image", {
"theme": "light",
"filter": "none",
"filter": "invert(0.35)",
})

View File

@ -305,6 +305,7 @@ wait-for-css: ("#help-button .popover", {"display": "block"})
// Now we go to the settings page to check that the CSS is loaded as expected.
go-to: "file://" + |DOC_PATH| + "/settings.html"
wait-for: "#settings"
assert-false: "#settings-menu"
assert-css: (".setting-radio", {"cursor": "pointer"})
assert-attribute-false: ("#settings", {"class": "popover"}, CONTAINS)
@ -324,6 +325,5 @@ javascript: true
show-text: true
reload:
set-window-size: (300, 1000)
click: "#settings-menu"
wait-for: "#settings"
assert-css: (".setting-radio", {"cursor": "pointer"})

View File

@ -13,19 +13,19 @@ press-key: "Escape"
assert-css: ("#help-button .popover", {"display": "none"})
// Checking doc collapse and expand.
// It should be displaying a "-":
assert-text: ("#toggle-all-docs", "[]")
assert-text: ("#toggle-all-docs", "Summary")
press-key: "-"
wait-for-text: ("#toggle-all-docs", "[+]")
wait-for-text: ("#toggle-all-docs", "Show all")
assert-attribute: ("#toggle-all-docs", {"class": "will-expand"})
// Pressing it again shouldn't do anything.
press-key: "-"
assert-text: ("#toggle-all-docs", "[+]")
assert-text: ("#toggle-all-docs", "Show all")
assert-attribute: ("#toggle-all-docs", {"class": "will-expand"})
// Expanding now.
press-key: "+"
wait-for-text: ("#toggle-all-docs", "[]")
wait-for-text: ("#toggle-all-docs", "Summary")
assert-attribute: ("#toggle-all-docs", {"class": ""})
// Pressing it again shouldn't do anything.
press-key: "+"
assert-text: ("#toggle-all-docs", "[]")
assert-text: ("#toggle-all-docs", "Summary")
assert-attribute: ("#toggle-all-docs", {"class": ""})

View File

@ -141,7 +141,7 @@ click: "#sidebar-button"
wait-for-css: (".src .sidebar > *", {"visibility": "hidden"})
// We scroll to line 117 to change the scroll position.
scroll-to: '//*[@id="117"]'
store-value: (y_offset, "2493")
store-value: (y_offset, "2564")
assert-window-property: {"pageYOffset": |y_offset|}
// Expanding the sidebar...
click: "#sidebar-button"

View File

@ -160,12 +160,12 @@ click: "//ul[@class='block mod']/preceding-sibling::h3/a"
// PAGE: index.html
assert-css: ("#modules", {"background-color": "#fdffd3"})
// Finally, assert that the `[+]/[]` toggle doesn't affect sidebar width.
// Finally, assert that the Summary toggle doesn't affect sidebar width.
click: "#toggle-all-docs"
assert-text: ("#toggle-all-docs", "[+]")
assert-text: ("#toggle-all-docs", "Show all")
assert-property: (".sidebar", {"clientWidth": "200"})
click: "#toggle-all-docs"
assert-text: ("#toggle-all-docs", "[]")
assert-text: ("#toggle-all-docs", "Summary")
assert-property: (".sidebar", {"clientWidth": "200"})
// Checks that all.html and index.html have their sidebar link in the same place.

View File

@ -8,13 +8,13 @@ set-window-size: (600, 800)
assert-property: ("html", {"scrollTop": "0"})
click: '//a[text() = "barbar" and @href="#5-7"]'
assert-property: ("html", {"scrollTop": "123"})
assert-property: ("html", {"scrollTop": "194"})
click: '//a[text() = "bar" and @href="#28-36"]'
assert-property: ("html", {"scrollTop": "154"})
assert-property: ("html", {"scrollTop": "225"})
click: '//a[normalize-space() = "sub_fn" and @href="#2-4"]'
assert-property: ("html", {"scrollTop": "51"})
assert-property: ("html", {"scrollTop": "122"})
// We now check that clicking on lines doesn't change the scroll
// Extra information: the "sub_fn" function header is on line 1.
click: '//*[@id="6"]'
assert-property: ("html", {"scrollTop": "51"})
assert-property: ("html", {"scrollTop": "122"})

View File

@ -89,9 +89,9 @@ assert-css: (".src-line-numbers", {"text-align": "right"})
// do anything (and certainly not add a `#NaN` to the URL!).
go-to: "file://" + |DOC_PATH| + "/src/test_docs/lib.rs.html"
// We use this assert-position to know where we will click.
assert-position: ("//*[@id='1']", {"x": 88, "y": 86})
assert-position: ("//*[@id='1']", {"x": 88, "y": 163})
// We click on the left of the "1" anchor but still in the "src-line-number" `<pre>`.
click: (87, 77)
click: (163, 77)
assert-document-property: ({"URL": "/lib.rs.html"}, ENDS_WITH)
// Checking the source code sidebar.
@ -159,19 +159,21 @@ call-function: ("check-sidebar-dir-entry", {
// Check the search form
assert-css: ("nav.sub", {"flex-direction": "row"})
// The goal of this test is to ensure the search input is perfectly centered
// between the top of the page and the top of the gray code block.
// between the top of the page and the header.
// To check this, we maintain the invariant:
//
// offsetTop[nav.sub form] = offsetTop[#main-content] - offsetHeight[nav.sub form] - offsetTop[nav.sub form]
assert-property: ("nav.sub form", {"offsetTop": 15, "offsetHeight": 34})
assert-property: ("#main-content", {"offsetTop": 64})
assert-position: ("nav.sub form", {"y": 15})
assert-property: ("nav.sub form", {"offsetHeight": 34})
assert-position: ("h1", {"y": 64})
// 15 = 64 - 34 - 15
// Now do the same check on moderately-sized, tablet mobile.
set-window-size: (700, 700)
assert-css: ("nav.sub", {"flex-direction": "row"})
assert-property: ("nav.sub form", {"offsetTop": 8, "offsetHeight": 34})
assert-property: ("#main-content", {"offsetTop": 50})
assert-position: ("nav.sub form", {"y": 8})
assert-property: ("nav.sub form", {"offsetHeight": 34})
assert-position: ("h1", {"y": 50})
// 8 = 50 - 34 - 8
// Check the sidebar directory entries have a marker and spacing (tablet).

View File

@ -52,6 +52,8 @@
--search-tab-button-selected-border-top-color: #0089ff;
--search-tab-button-selected-background: #fff;
--settings-menu-filter: none;
--settings-menu-hover-filter: invert(35%);
--settings-menu-disabled-filter: invert(14%) sepia(11%) saturate(14%) hue-rotate(337deg);
--stab-background-color: #fff5d6;
--stab-code-color: #000;
--code-highlight-kw-color: #8959a8;

View File

@ -12,4 +12,5 @@ assert-attribute-false: (".impl-items .toggle", {"open": ""})
// Click the "Trait" part of "impl Trait" and verify it navigates.
click: "#impl-Trait-for-Foo h3 a:first-of-type"
assert-text: (".main-heading h1", "Trait lib2::TraitCopy item path")
assert-text: (".main-heading .rustdoc-breadcrumbs", "lib2")
assert-text: (".main-heading h1", "Trait TraitCopy item path")

View File

@ -3,12 +3,12 @@
go-to: "file://" + |DOC_PATH| + "/test_docs/struct.Foo.html"
set-window-size: (433, 600)
assert-attribute: (".top-doc", {"open": ""})
click: (4, 270) // This is the position of the top doc comment toggle
click: (4, 260) // This is the position of the top doc comment toggle
assert-attribute-false: (".top-doc", {"open": ""})
click: (4, 270)
click: (4, 260)
assert-attribute: (".top-doc", {"open": ""})
// To ensure that the toggle isn't over the text, we check that the toggle isn't clicked.
click: (3, 270)
click: (3, 260)
assert-attribute: (".top-doc", {"open": ""})
// Assert the position of the toggle on the top doc block.
@ -24,10 +24,10 @@ assert-position: (
// Now we do the same but with a little bigger width
set-window-size: (600, 600)
assert-attribute: (".top-doc", {"open": ""})
click: (4, 270) // New Y position since all search elements are back on one line.
click: (4, 260) // New Y position since all search elements are back on one line.
assert-attribute-false: (".top-doc", {"open": ""})
click: (4, 270)
click: (4, 260)
assert-attribute: (".top-doc", {"open": ""})
// To ensure that the toggle isn't over the text, we check that the toggle isn't clicked.
click: (3, 270)
click: (3, 260)
assert-attribute: (".top-doc", {"open": ""})

View File

@ -2,12 +2,12 @@
include: "utils.goml"
go-to: "file://" + |DOC_PATH| + "/test_docs/index.html"
assert-attribute: ("#main-content > details.top-doc", {"open": ""})
assert-text: ("#toggle-all-docs", "[]")
assert-text: ("#toggle-all-docs", "Summary")
click: "#toggle-all-docs"
wait-for: 50
// This is now collapsed so there shouldn't be the "open" attribute on details.
assert-attribute-false: ("#main-content > details.top-doc", {"open": ""})
assert-text: ("#toggle-all-docs", "[+]")
assert-text: ("#toggle-all-docs", "Show all")
assert-css: (
"#main-content > details.top-doc > summary",
{"font-family": '"Fira Sans", Arial, NanumBarunGothic, sans-serif'},
@ -15,12 +15,12 @@ assert-css: (
click: "#toggle-all-docs"
// Not collapsed anymore so the "open" attribute should be back.
wait-for-attribute: ("#main-content > details.top-doc", {"open": ""})
assert-text: ("#toggle-all-docs", "[]")
assert-text: ("#toggle-all-docs", "Summary")
// Check that it works on non-module pages as well.
go-to: "file://" + |DOC_PATH| + "/test_docs/struct.Foo.html"
// We first check that everything is visible.
assert-text: ("#toggle-all-docs", "[]")
assert-text: ("#toggle-all-docs", "Summary")
assert-attribute: ("#implementations-list details.toggle", {"open": ""}, ALL)
assert-attribute: ("#trait-implementations-list details.toggle", {"open": ""}, ALL)
assert-attribute-false: (
@ -31,7 +31,7 @@ assert-attribute-false: (
// We collapse them all.
click: "#toggle-all-docs"
wait-for-text: ("#toggle-all-docs", "[+]")
wait-for-text: ("#toggle-all-docs", "Show all")
// We check that all <details> are collapsed (except for the impl block ones).
assert-attribute-false: ("details.toggle:not(.implementors-toggle)", {"open": ""}, ALL)
assert-attribute: ("#implementations-list > details.implementors-toggle", {"open": ""})
@ -43,7 +43,7 @@ assert-attribute-false: (
)
// We open them all again.
click: "#toggle-all-docs"
wait-for-text: ("#toggle-all-docs", "[]")
wait-for-text: ("#toggle-all-docs", "Summary")
assert-attribute: ("details.toggle", {"open": ""}, ALL)
// Checking the toggles style.

View File

@ -51,22 +51,23 @@ store-property: (".mobile-topbar", {"scrollWidth": scrollWidth})
assert-property: (".mobile-topbar", {"clientWidth": |scrollWidth|})
assert-css: (".mobile-topbar h2", {"overflow-x": "hidden"})
// Check wrapping for top main-heading h1 and out-of-band.
// On desktop, they wrap when too big.
// Check that main heading and toolbar go side-by-side, both on desktop and on mobile.
set-window-size: (1100, 800)
go-to: "file://" + |DOC_PATH| + "/lib2/too_long/struct.SuperIncrediblyLongLongLongLongLongLongLongGigaGigaGigaMegaLongLongLongStructName.html"
compare-elements-position-false: (".main-heading h1", ".main-heading .out-of-band", ["y"])
compare-elements-position: (".main-heading h1", ".main-heading rustdoc-toolbar", ["y"])
compare-elements-position-near-false: (".main-heading h1", ".main-heading rustdoc-toolbar", {"x": 550})
go-to: "file://" + |DOC_PATH| + "/lib2/index.html"
compare-elements-position: (".main-heading h1", ".main-heading .out-of-band", ["y"])
// make sure there is a gap between them
compare-elements-position-near-false: (".main-heading h1", ".main-heading .out-of-band", {"x": 550})
compare-elements-position: (".main-heading h1", ".main-heading rustdoc-toolbar", ["y"])
compare-elements-position-near-false: (".main-heading h1", ".main-heading rustdoc-toolbar", {"x": 550})
// On mobile, they always wrap.
set-window-size: (600, 600)
go-to: "file://" + |DOC_PATH| + "/lib2/too_long/struct.SuperIncrediblyLongLongLongLongLongLongLongGigaGigaGigaMegaLongLongLongStructName.html"
compare-elements-position-false: (".main-heading h1", ".main-heading .out-of-band", ["y"])
compare-elements-position: (".main-heading h1", ".main-heading rustdoc-toolbar", ["y"])
compare-elements-position-near-false: (".main-heading h1", ".main-heading rustdoc-toolbar", {"x": 200})
go-to: "file://" + |DOC_PATH| + "/lib2/index.html"
compare-elements-position-false: (".main-heading h1", ".main-heading .out-of-band", ["y"])
compare-elements-position: (".main-heading h1", ".main-heading rustdoc-toolbar", ["y"])
compare-elements-position-near-false: (".main-heading h1", ".main-heading rustdoc-toolbar", {"x": 200})
// Now we will check that the scrolling is working.
// First on an item with "hidden methods".

View File

@ -2,15 +2,18 @@
//@ has 'empty_mod_private/index.html' '//a[@href="foo/index.html"]' 'foo'
//@ hasraw 'empty_mod_private/sidebar-items.js' 'foo'
//@ matches 'empty_mod_private/foo/index.html' '//h1' 'Module empty_mod_private::foo'
//@ matches 'empty_mod_private/foo/index.html' '//h1' 'Module foo'
//@ matches - '//*[@class="rustdoc-breadcrumbs"]' 'empty_mod_private'
mod foo {}
//@ has 'empty_mod_private/index.html' '//a[@href="bar/index.html"]' 'bar'
//@ hasraw 'empty_mod_private/sidebar-items.js' 'bar'
//@ matches 'empty_mod_private/bar/index.html' '//h1' 'Module empty_mod_private::bar'
//@ matches 'empty_mod_private/bar/index.html' '//h1' 'Module bar'
//@ matches - '//*[@class="rustdoc-breadcrumbs"]' 'empty_mod_private'
mod bar {
//@ has 'empty_mod_private/bar/index.html' '//a[@href="baz/index.html"]' 'baz'
//@ hasraw 'empty_mod_private/bar/sidebar-items.js' 'baz'
//@ matches 'empty_mod_private/bar/baz/index.html' '//h1' 'Module empty_mod_private::bar::baz'
//@ matches 'empty_mod_private/bar/baz/index.html' '//h1' 'Module baz'
//@ matches - '//*[@class="rustdoc-breadcrumbs"]' 'empty_mod_private::bar'
mod baz {}
}

View File

@ -1,14 +1,17 @@
//@ has 'empty_mod_public/index.html' '//a[@href="foo/index.html"]' 'foo'
//@ hasraw 'empty_mod_public/sidebar-items.js' 'foo'
//@ matches 'empty_mod_public/foo/index.html' '//h1' 'Module empty_mod_public::foo'
//@ matches 'empty_mod_public/foo/index.html' '//h1' 'Module foo'
//@ matches - '//*[@class="rustdoc-breadcrumbs"]' 'empty_mod_public'
pub mod foo {}
//@ has 'empty_mod_public/index.html' '//a[@href="bar/index.html"]' 'bar'
//@ hasraw 'empty_mod_public/sidebar-items.js' 'bar'
//@ matches 'empty_mod_public/bar/index.html' '//h1' 'Module empty_mod_public::bar'
//@ matches 'empty_mod_public/bar/index.html' '//h1' 'Module bar'
//@ matches - '//*[@class="rustdoc-breadcrumbs"]' 'empty_mod_public'
pub mod bar {
//@ has 'empty_mod_public/bar/index.html' '//a[@href="baz/index.html"]' 'baz'
//@ hasraw 'empty_mod_public/bar/sidebar-items.js' 'baz'
//@ matches 'empty_mod_public/bar/baz/index.html' '//h1' 'Module empty_mod_public::bar::baz'
//@ matches 'empty_mod_public/bar/baz/index.html' '//h1' 'Module baz'
//@ matches - '//*[@class="rustdoc-breadcrumbs"]' 'empty_mod_public::bar'
pub mod baz {}
}

View File

@ -11,14 +11,14 @@
//@ files 'src/foo' '[]'
//@ has foo/fn.foo.html
//@ has - '//div[@class="main-heading"]/*[@class="out-of-band"]' '1.0.0 · '
//@ !has - '//div[@class="main-heading"]/*[@class="out-of-band"]' '1.0.0 · source · '
//@ has - '//div[@class="main-heading"]/*[@class="sub-heading"]' '1.0.0'
//@ !has - '//div[@class="main-heading"]/*[@class="sub-heading"]' '1.0.0 · source'
#[stable(feature = "bar", since = "1.0")]
pub fn foo() {}
//@ has foo/struct.Bar.html
//@ has - '//div[@class="main-heading"]/*[@class="out-of-band"]' '1.0.0 · '
//@ !has - '//div[@class="main-heading"]/*[@class="out-of-band"]' '1.0.0 · source · '
//@ has - '//div[@class="main-heading"]/*[@class="sub-heading"]' '1.0.0'
//@ !has - '//div[@class="main-heading"]/*[@class="sub-heading"]' '1.0.0 · source'
#[stable(feature = "bar", since = "1.0")]
pub struct Bar;

View File

@ -10,15 +10,19 @@ extern crate foo;
//@ has - '//a/[@href="struct.DeprecatedStepBy.html"]' "DeprecatedStepBy"
//@ has - '//a/[@href="struct.StepBy.html"]' "StepBy"
//@ has foo/iter/struct.DeprecatedStepBy.html
//@ has - '//h1' "Struct foo::iter::DeprecatedStepBy"
//@ has - '//h1' "Struct DeprecatedStepBy"
//@ matches - '//*[@class="rustdoc-breadcrumbs"]' 'foo::iter'
//@ has foo/iter/struct.StepBy.html
//@ has - '//h1' "Struct foo::iter::StepBy"
//@ has - '//h1' "Struct StepBy"
//@ matches - '//*[@class="rustdoc-breadcrumbs"]' 'foo::iter'
//@ has bar/iter/index.html
//@ has - '//a/[@href="struct.DeprecatedStepBy.html"]' "DeprecatedStepBy"
//@ has - '//a/[@href="struct.StepBy.html"]' "StepBy"
//@ has bar/iter/struct.DeprecatedStepBy.html
//@ has - '//h1' "Struct bar::iter::DeprecatedStepBy"
//@ has - '//h1' "Struct DeprecatedStepBy"
//@ matches - '//*[@class="rustdoc-breadcrumbs"]' 'bar::iter'
//@ has bar/iter/struct.StepBy.html
//@ has - '//h1' "Struct bar::iter::StepBy"
//@ has - '//h1' "Struct StepBy"
//@ matches - '//*[@class="rustdoc-breadcrumbs"]' 'bar::iter'
pub use foo::iter;

View File

@ -6,7 +6,6 @@
//@ has foo/index.html '//a[@href="keyword.match.html"]' 'match'
//@ has foo/index.html '//div[@class="sidebar-elems"]//li/a' 'Keywords'
//@ has foo/index.html '//div[@class="sidebar-elems"]//li/a/@href' '#keywords'
//@ has foo/keyword.match.html '//a[@class="keyword"]' 'match'
//@ has foo/keyword.match.html '//h1' 'Keyword match'
//@ has foo/keyword.match.html '//section[@id="main-content"]//div[@class="docblock"]//p' 'this is a test!'
//@ has foo/index.html '//a/@href' '../foo/index.html'

View File

@ -8,7 +8,6 @@
//@ has - '//div[@class="sidebar-elems"]//li/a' 'Primitive Types'
//@ has - '//div[@class="sidebar-elems"]//li/a/@href' '#primitives'
//@ has foo/primitive.reference.html
//@ has - '//a[@class="primitive"]' 'reference'
//@ has - '//h1' 'Primitive Type reference'
//@ has - '//section[@id="main-content"]//div[@class="docblock"]//p' 'this is a test!'

View File

@ -3,8 +3,7 @@
#![crate_name = "foo"]
#![feature(rustc_attrs)]
//@ has foo/primitive.slice.html '//a[@class="primitive"]' 'slice'
//@ has - '//h1' 'Primitive Type slice'
//@ has foo/primitive.slice.html '//h1' 'Primitive Type slice'
//@ has - '//section[@id="main-content"]//div[@class="docblock"]//p' 'this is a test!'
//@ has - '//h2[@id="synthetic-implementations"]' 'Auto Trait Implementations'
//@ has - '//div[@id="synthetic-implementations-list"]//h3' 'impl<T> Send for [T]where T: Send'

View File

@ -3,8 +3,7 @@
#![crate_name = "foo"]
#![feature(rustc_attrs)]
//@ has foo/primitive.tuple.html '//a[@class="primitive"]' 'tuple'
//@ has - '//h1' 'Primitive Type tuple'
//@ has foo/primitive.tuple.html '//h1' 'Primitive Type tuple'
//@ has - '//section[@id="main-content"]//div[@class="docblock"]//p' 'this is a test!'
//@ has - '//h2[@id="synthetic-implementations"]' 'Auto Trait Implementations'
//@ has - '//div[@id="synthetic-implementations-list"]//h3' 'Send'

View File

@ -3,8 +3,7 @@
#![crate_name = "foo"]
#![feature(rustc_attrs)]
//@ has foo/primitive.unit.html '//a[@class="primitive"]' 'unit'
//@ has - '//h1' 'Primitive Type unit'
//@ has foo/primitive.unit.html '//h1' 'Primitive Type unit'
//@ has - '//section[@id="main-content"]//div[@class="docblock"]//p' 'this is a test!'
//@ has - '//h2[@id="synthetic-implementations"]' 'Auto Trait Implementations'
//@ has - '//div[@id="synthetic-implementations-list"]//h3' 'impl Send for ()'

View File

@ -3,7 +3,7 @@
#![feature(staged_api)]
//@ has foo/trait.Bar.html
//@ has - '//div[@class="main-heading"]/*[@class="out-of-band"]' '1.0.0 · source · '
//@ has - '//div[@class="main-heading"]/*[@class="sub-heading"]' '1.0.0 · source'
#[stable(feature = "bar", since = "1.0")]
pub trait Bar {
//@ has - '//*[@id="tymethod.foo"]/*[@class="rightside"]' '3.0.0 · source'
@ -14,7 +14,7 @@ pub trait Bar {
//@ has - '//div[@id="implementors-list"]//*[@class="rightside"]' '4.0.0 · source'
//@ has foo/struct.Foo.html
//@ has - '//div[@class="main-heading"]/*[@class="out-of-band"]' '1.0.0 · source · '
//@ has - '//div[@class="main-heading"]/*[@class="sub-heading"]' '1.0.0 · source'
#[stable(feature = "baz", since = "1.0")]
pub struct Foo;

View File

@ -5,53 +5,65 @@
//@ matches 'foo/index.html' '//div[@class="sidebar-crate"]/h2/a' 'foo'
//@ count 'foo/index.html' '//h2[@class="location"]' 0
//@ matches 'foo/foo_mod/index.html' '//h1' 'Module foo::foo_mod'
//@ matches 'foo/foo_mod/index.html' '//h2[@class="location"]' 'Module foo_mod'
//@ matches 'foo/foo_mod/index.html' '//h1' 'Module foo_mod'
//@ matches - '//*[@class="rustdoc-breadcrumbs"]' 'foo'
//@ matches - '//h2[@class="location"]' 'Module foo_mod'
pub mod foo_mod {
pub struct __Thing {}
}
extern "C" {
//@ matches 'foo/fn.foo_ffn.html' '//h1' 'Function foo::foo_ffn'
//@ matches 'foo/fn.foo_ffn.html' '//h1' 'Function foo_ffn'
//@ matches - '//*[@class="rustdoc-breadcrumbs"]' 'foo'
pub fn foo_ffn();
}
//@ matches 'foo/fn.foo_fn.html' '//h1' 'Function foo::foo_fn'
//@ matches 'foo/fn.foo_fn.html' '//h1' 'Function foo_fn'
//@ matches - '//*[@class="rustdoc-breadcrumbs"]' 'foo'
pub fn foo_fn() {}
//@ matches 'foo/trait.FooTrait.html' '//h1' 'Trait foo::FooTrait'
//@ matches 'foo/trait.FooTrait.html' '//h2[@class="location"]' 'FooTrait'
//@ matches 'foo/trait.FooTrait.html' '//h1' 'Trait FooTrait'
//@ matches - '//*[@class="rustdoc-breadcrumbs"]' 'foo'
//@ matches - '//h2[@class="location"]' 'FooTrait'
pub trait FooTrait {}
//@ matches 'foo/struct.FooStruct.html' '//h1' 'Struct foo::FooStruct'
//@ matches 'foo/struct.FooStruct.html' '//h2[@class="location"]' 'FooStruct'
//@ matches 'foo/struct.FooStruct.html' '//h1' 'Struct FooStruct'
//@ matches - '//*[@class="rustdoc-breadcrumbs"]' 'foo'
//@ matches - '//h2[@class="location"]' 'FooStruct'
pub struct FooStruct;
//@ matches 'foo/enum.FooEnum.html' '//h1' 'Enum foo::FooEnum'
//@ matches 'foo/enum.FooEnum.html' '//h2[@class="location"]' 'FooEnum'
//@ matches 'foo/enum.FooEnum.html' '//h1' 'Enum FooEnum'
//@ matches - '//*[@class="rustdoc-breadcrumbs"]' 'foo'
//@ matches - '//h2[@class="location"]' 'FooEnum'
pub enum FooEnum {}
//@ matches 'foo/type.FooType.html' '//h1' 'Type Alias foo::FooType'
//@ matches 'foo/type.FooType.html' '//h2[@class="location"]' 'FooType'
//@ matches 'foo/type.FooType.html' '//h1' 'Type Alias FooType'
//@ matches - '//*[@class="rustdoc-breadcrumbs"]' 'foo'
//@ matches - '//h2[@class="location"]' 'FooType'
pub type FooType = FooStruct;
//@ matches 'foo/macro.foo_macro.html' '//h1' 'Macro foo::foo_macro'
//@ matches 'foo/macro.foo_macro.html' '//h1' 'Macro foo_macro'
//@ matches - '//*[@class="rustdoc-breadcrumbs"]' 'foo'
#[macro_export]
macro_rules! foo_macro {
() => {};
}
//@ matches 'foo/primitive.bool.html' '//h1' 'Primitive Type bool'
//@ count - '//*[@class="rustdoc-breadcrumbs"]' 0
#[rustc_doc_primitive = "bool"]
mod bool {}
//@ matches 'foo/static.FOO_STATIC.html' '//h1' 'Static foo::FOO_STATIC'
//@ matches 'foo/static.FOO_STATIC.html' '//h1' 'Static FOO_STATIC'
//@ matches - '//*[@class="rustdoc-breadcrumbs"]' 'foo'
pub static FOO_STATIC: FooStruct = FooStruct;
extern "C" {
//@ matches 'foo/static.FOO_FSTATIC.html' '//h1' 'Static foo::FOO_FSTATIC'
//@ matches 'foo/static.FOO_FSTATIC.html' '//h1' 'Static FOO_FSTATIC'
//@ matches - '//*[@class="rustdoc-breadcrumbs"]' 'foo'
pub static FOO_FSTATIC: FooStruct;
}
//@ matches 'foo/constant.FOO_CONSTANT.html' '//h1' 'Constant foo::FOO_CONSTANT'
//@ matches 'foo/constant.FOO_CONSTANT.html' '//h1' 'Constant FOO_CONSTANT'
//@ matches - '//*[@class="rustdoc-breadcrumbs"]' 'foo'
pub const FOO_CONSTANT: FooStruct = FooStruct;

View File

@ -4,14 +4,14 @@
#![crate_name = "foo"]
//@ has foo/fn.foo.html
//@ has - '//div[@class="main-heading"]/*[@class="out-of-band"]' '1.0.0 · '
//@ !has - '//div[@class="main-heading"]/*[@class="out-of-band"]' '1.0.0 · source · '
//@ has - '//div[@class="main-heading"]/*[@class="sub-heading"]' '1.0.0'
//@ !has - '//div[@class="main-heading"]/*[@class="sub-heading"]' '1.0.0 · source'
#[stable(feature = "bar", since = "1.0")]
pub fn foo() {}
//@ has foo/struct.Bar.html
//@ has - '//div[@class="main-heading"]/*[@class="out-of-band"]' '1.0.0 · '
//@ !has - '//div[@class="main-heading"]/*[@class="out-of-band"]' '1.0.0 · source · '
//@ has - '//div[@class="main-heading"]/*[@class="sub-heading"]' '1.0.0'
//@ !has - '//div[@class="main-heading"]/*[@class="sub-heading"]' '1.0.0 · source'
#[stable(feature = "bar", since = "1.0")]
pub struct Bar;

View File

@ -1,6 +1,3 @@
#![feature(const_intrinsic_copy)]
const MISALIGNED_LOAD: () = unsafe {
let mem = [0u32; 8];
let ptr = mem.as_ptr().byte_add(1);

View File

@ -1,11 +1,11 @@
error[E0080]: evaluation of constant value failed
--> $DIR/raw-pointer-ub.rs:7:16
--> $DIR/raw-pointer-ub.rs:4:16
|
LL | let _val = *ptr;
| ^^^^ accessing memory based on pointer with alignment 1, but alignment 4 is required
error[E0080]: evaluation of constant value failed
--> $DIR/raw-pointer-ub.rs:14:5
--> $DIR/raw-pointer-ub.rs:11:5
|
LL | *ptr = 0;
| ^^^^^^^^ accessing memory based on pointer with alignment 1, but alignment 4 is required
@ -20,19 +20,19 @@ note: inside `copy_nonoverlapping::<u32>`
note: inside `std::ptr::const_ptr::<impl *const u32>::copy_to_nonoverlapping`
--> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
note: inside `MISALIGNED_COPY`
--> $DIR/raw-pointer-ub.rs:22:5
--> $DIR/raw-pointer-ub.rs:19:5
|
LL | y.copy_to_nonoverlapping(&mut z, 1);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error[E0080]: evaluation of constant value failed
--> $DIR/raw-pointer-ub.rs:34:16
--> $DIR/raw-pointer-ub.rs:31:16
|
LL | let _val = (*ptr).0;
| ^^^^^^^^ accessing memory based on pointer with alignment 4, but alignment 16 is required
error[E0080]: evaluation of constant value failed
--> $DIR/raw-pointer-ub.rs:41:16
--> $DIR/raw-pointer-ub.rs:38:16
|
LL | let _val = *ptr;
| ^^^^ memory access failed: expected a pointer to 8 bytes of memory, but got ALLOC0 which is only 4 bytes from the end of the allocation

View File

@ -1,20 +0,0 @@
// Regression test for #130310
// Tests that we do not fall into infinite
// recursion while checking FFI safety of
// recursive types like `A<T>` below
//@ build-pass
use std::marker::PhantomData;
#[repr(C)]
struct A<T> {
a: *const A<A<T>>, // Recursive because of this field
p: PhantomData<T>,
}
extern "C" {
fn f(a: *const A<()>);
//~^ WARN `extern` block uses type `*const A<()>`, which is not FFI-safe
}
fn main() {}

View File

@ -1,11 +0,0 @@
warning: `extern` block uses type `*const A<()>`, which is not FFI-safe
--> $DIR/improper-types-stack-overflow-130310.rs:16:13
|
LL | fn f(a: *const A<()>);
| ^^^^^^^^^^^^ not FFI-safe
|
= note: type is infinitely recursive
= note: `#[warn(improper_ctypes)]` on by default
warning: 1 warning emitted

View File

@ -0,0 +1,32 @@
//@ check-pass
#![recursion_limit = "5"]
#![allow(unused)]
#![deny(improper_ctypes)]
#[repr(C)]
struct F1(*const ());
#[repr(C)]
struct F2(*const ());
#[repr(C)]
struct F3(*const ());
#[repr(C)]
struct F4(*const ());
#[repr(C)]
struct F5(*const ());
#[repr(C)]
struct F6(*const ());
#[repr(C)]
struct B {
f1: F1,
f2: F2,
f3: F3,
f4: F4,
f5: F5,
f6: F6,
}
extern "C" fn foo(_: B) {}
fn main() {}