Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Rollup of 6 pull requests #97211

Merged
merged 14 commits into from
May 20, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 7 additions & 4 deletions .mailmap
Original file line number Diff line number Diff line change
Expand Up @@ -105,10 +105,13 @@ Chris Vittal <christopher.vittal@gmail.com> Christopher Vittal <christopher.vitt
Christiaan Dirkx <christiaan@dirkx.email> <christiaan@dirkx.com>
Christiaan Dirkx <christiaan@dirkx.email> CDirkx <christiaan@dirkx.com>
Christiaan Dirkx <christiaan@dirkx.email> CDirkx <christiaan@dirkx.email>
Christian Poveda <git@christianpoveda.xyz> <christianpoveda@protonmail.com>
Christian Poveda <git@christianpoveda.xyz> <cn.poveda.ruiz@gmail.com>
Christian Poveda <git@christianpoveda.xyz> <z1mvader@protonmail.com>
Christian Poveda <git@christianpoveda.xyz> <cpovedar@fnal.gov>
Christian Poveda <git@pvdrz.com> <christianpoveda@protonmail.com>
Christian Poveda <git@pvdrz.com> <cn.poveda.ruiz@gmail.com>
Christian Poveda <git@pvdrz.com> <z1mvader@protonmail.com>
Christian Poveda <git@pvdrz.com> <cpovedar@fnal.gov>
Christian Poveda <git@pvdrz.com> <git@christianpoveda.xyz>
Christian Poveda <git@pvdrz.com> <31802960+christianpoveda@users.noreply.github.com>
Christian Poveda <git@pvdrz.com> <christianpoveda@uhura.edef.eu>
Christian Vallentin <vallentinsource@gmail.com>
Christoffer Buchholz <chris@chrisbuchholz.me>
Christopher Durham <cad97@cad97.com>
Expand Down
3 changes: 0 additions & 3 deletions compiler/rustc_const_eval/src/interpret/cast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -225,9 +225,6 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
let addr = u64::try_from(size.truncate(v)).unwrap();

let ptr = M::ptr_from_addr_cast(&self, addr);
if addr == 0 {
assert!(ptr.provenance.is_none(), "null pointer can never have an AllocId");
}
Scalar::from_maybe_pointer(ptr, self)
}

Expand Down
15 changes: 11 additions & 4 deletions compiler/rustc_const_eval/src/interpret/machine.rs
Original file line number Diff line number Diff line change
Expand Up @@ -133,9 +133,11 @@ pub trait Machine<'mir, 'tcx>: Sized {
/// Whether to enforce the validity invariant
fn enforce_validity(ecx: &InterpCx<'mir, 'tcx, Self>) -> bool;

/// Whether to enforce validity (e.g., initialization and not having ptr provenance)
/// of integers and floats.
fn enforce_number_validity(ecx: &InterpCx<'mir, 'tcx, Self>) -> bool;
/// Whether to enforce integers and floats being initialized.
fn enforce_number_init(ecx: &InterpCx<'mir, 'tcx, Self>) -> bool;

/// Whether to enforce integers and floats not having provenance.
fn enforce_number_no_provenance(ecx: &InterpCx<'mir, 'tcx, Self>) -> bool;

/// Whether function calls should be [ABI](Abi)-checked.
fn enforce_abi(_ecx: &InterpCx<'mir, 'tcx, Self>) -> bool {
Expand Down Expand Up @@ -453,7 +455,12 @@ pub macro compile_time_machine(<$mir: lifetime, $tcx: lifetime>) {
}

#[inline(always)]
fn enforce_number_validity(_ecx: &InterpCx<$mir, $tcx, Self>) -> bool {
fn enforce_number_init(_ecx: &InterpCx<$mir, $tcx, Self>) -> bool {
true
}

#[inline(always)]
fn enforce_number_no_provenance(_ecx: &InterpCx<$mir, $tcx, Self>) -> bool {
true
}

Expand Down
15 changes: 8 additions & 7 deletions compiler/rustc_const_eval/src/interpret/memory.rs
Original file line number Diff line number Diff line change
Expand Up @@ -924,10 +924,15 @@ impl<'tcx, 'a, Tag: Provenance, Extra> AllocRef<'a, 'tcx, Tag, Extra> {
self.read_scalar(alloc_range(offset, self.tcx.data_layout().pointer_size))
}

pub fn check_bytes(&self, range: AllocRange, allow_uninit_and_ptr: bool) -> InterpResult<'tcx> {
pub fn check_bytes(
&self,
range: AllocRange,
allow_uninit: bool,
allow_ptr: bool,
) -> InterpResult<'tcx> {
Ok(self
.alloc
.check_bytes(&self.tcx, self.range.subrange(range), allow_uninit_and_ptr)
.check_bytes(&self.tcx, self.range.subrange(range), allow_uninit, allow_ptr)
.map_err(|e| e.to_interp_error(self.alloc_id))?)
}
}
Expand Down Expand Up @@ -1144,11 +1149,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
Err(ptr) => ptr.into(),
Ok(bits) => {
let addr = u64::try_from(bits).unwrap();
let ptr = M::ptr_from_addr_transmute(&self, addr);
if addr == 0 {
assert!(ptr.provenance.is_none(), "null pointer can never have an AllocId");
}
ptr
M::ptr_from_addr_transmute(&self, addr)
}
},
)
Expand Down
24 changes: 15 additions & 9 deletions compiler/rustc_const_eval/src/interpret/validity.rs
Original file line number Diff line number Diff line change
Expand Up @@ -536,15 +536,21 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, '
let value = self.read_scalar(value)?;
// NOTE: Keep this in sync with the array optimization for int/float
// types below!
if M::enforce_number_validity(self.ecx) {
// Integers/floats with number validity: Must be scalar bits, pointers are dangerous.
if M::enforce_number_init(self.ecx) {
try_validation!(
value.check_init(),
self.path,
err_ub!(InvalidUninitBytes(..)) =>
{ "{:x}", value } expected { "initialized bytes" }
);
}
if M::enforce_number_no_provenance(self.ecx) {
// As a special exception we *do* match on a `Scalar` here, since we truly want
// to know its underlying representation (and *not* cast it to an integer).
let is_bits =
value.check_init().map_or(false, |v| matches!(v, Scalar::Int(..)));
if !is_bits {
let is_ptr = value.check_init().map_or(false, |v| matches!(v, Scalar::Ptr(..)));
if is_ptr {
throw_validation_failure!(self.path,
{ "{:x}", value } expected { "initialized plain (non-pointer) bytes" }
{ "{:x}", value } expected { "plain (non-pointer) bytes" }
)
}
}
Expand Down Expand Up @@ -651,7 +657,7 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, '
let size = scalar_layout.size(self.ecx);
let is_full_range = match scalar_layout {
ScalarAbi::Initialized { .. } => {
if M::enforce_number_validity(self.ecx) {
if M::enforce_number_init(self.ecx) {
false // not "full" since uninit is not accepted
} else {
scalar_layout.is_always_valid(self.ecx)
Expand Down Expand Up @@ -910,10 +916,10 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValueVisitor<'mir, 'tcx, M>
return Ok(());
};

let allow_uninit_and_ptr = !M::enforce_number_validity(self.ecx);
match alloc.check_bytes(
alloc_range(Size::ZERO, size),
allow_uninit_and_ptr,
/*allow_uninit*/ !M::enforce_number_init(self.ecx),
/*allow_ptr*/ !M::enforce_number_no_provenance(self.ecx),
) {
// In the happy case, we needn't check anything else.
Ok(()) => {}
Expand Down
11 changes: 7 additions & 4 deletions compiler/rustc_middle/src/mir/interpret/allocation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -350,19 +350,22 @@ impl<Tag: Provenance, Extra> Allocation<Tag, Extra> {
/// Reading and writing.
impl<Tag: Provenance, Extra> Allocation<Tag, Extra> {
/// Validates that `ptr.offset` and `ptr.offset + size` do not point to the middle of a
/// relocation. If `allow_uninit_and_ptr` is `false`, also enforces that the memory in the
/// given range contains neither relocations nor uninitialized bytes.
/// relocation. If `allow_uninit`/`allow_ptr` is `false`, also enforces that the memory in the
/// given range contains no uninitialized bytes/relocations.
pub fn check_bytes(
&self,
cx: &impl HasDataLayout,
range: AllocRange,
allow_uninit_and_ptr: bool,
allow_uninit: bool,
allow_ptr: bool,
) -> AllocResult {
// Check bounds and relocations on the edges.
self.get_bytes_with_uninit_and_ptr(cx, range)?;
// Check uninit and ptr.
if !allow_uninit_and_ptr {
if !allow_uninit {
self.check_init(range)?;
}
if !allow_ptr {
self.check_relocations(cx, range)?;
}
Ok(())
Expand Down
2 changes: 1 addition & 1 deletion library/core/src/str/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1158,7 +1158,7 @@ impl str {
pat.into_searcher(self).next_match().map(|(i, _)| i)
}

/// Returns the byte index for the first character of the rightmost match of the pattern in
/// Returns the byte index for the first character of the last match of the pattern in
/// this string slice.
///
/// Returns [`None`] if the pattern doesn't match.
Expand Down
11 changes: 10 additions & 1 deletion src/librustdoc/formats/cache.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ use std::mem;
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
use rustc_hir::def_id::{CrateNum, DefId};
use rustc_middle::middle::privacy::AccessLevels;
use rustc_middle::ty::TyCtxt;
use rustc_middle::ty::{self, TyCtxt};
use rustc_span::{sym, Symbol};

use crate::clean::{self, types::ExternalLocation, ExternalCrate, ItemId, PrimitiveType};
Expand Down Expand Up @@ -452,6 +452,15 @@ impl<'a, 'tcx> DocFolder for CacheBuilder<'a, 'tcx> {
clean::Type::Path { ref path }
| clean::BorrowedRef { type_: box clean::Type::Path { ref path }, .. } => {
dids.insert(path.def_id());
if let Some(generics) = path.generics() &&
let ty::Adt(adt, _) = self.tcx.type_of(path.def_id()).kind() &&
adt.is_fundamental() {
for ty in generics {
if let Some(did) = ty.def_id(&self.cache) {
dids.insert(did);
}
}
}
}
clean::DynTrait(ref bounds, _)
| clean::BorrowedRef { type_: box clean::DynTrait(ref bounds, _), .. } => {
Expand Down
4 changes: 4 additions & 0 deletions src/librustdoc/html/static/.eslintrc.js
Original file line number Diff line number Diff line change
Expand Up @@ -34,5 +34,9 @@ module.exports = {
"1tbs",
{ "allowSingleLine": false }
],
"keyword-spacing": [
"error",
{ "before": true, "after": true }
],
}
};
4 changes: 2 additions & 2 deletions src/librustdoc/html/static/js/storage.js
Original file line number Diff line number Diff line change
Expand Up @@ -103,15 +103,15 @@ function onEachLazy(lazyArray, func, reversed) {
function updateLocalStorage(name, value) {
try {
window.localStorage.setItem("rustdoc-" + name, value);
} catch(e) {
} catch (e) {
// localStorage is not accessible, do nothing
}
}

function getCurrentValue(name) {
try {
return window.localStorage.getItem("rustdoc-" + name);
} catch(e) {
} catch (e) {
return null;
}
}
Expand Down
16 changes: 16 additions & 0 deletions src/test/rustdoc/impl-box.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
// https://github.com/rust-lang/rust/issues/92940
//
// Show traits implemented on fundamental types that wrap local ones.

pub struct MyType;

// @has 'impl_box/struct.MyType.html'
// @has '-' '//*[@id="impl-Iterator"]' 'impl Iterator for Box<MyType>'

impl Iterator for Box<MyType> {
type Item = ();

fn next(&mut self) -> Option<Self::Item> {
todo!()
}
}
2 changes: 1 addition & 1 deletion src/test/ui/consts/const-err4.32bit.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ error[E0080]: it is undefined behavior to use this value
--> $DIR/const-err4.rs:9:11
|
LL | Boo = [unsafe { Foo { b: () }.a }; 4][3],
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered uninitialized bytes, but expected initialized plain (non-pointer) bytes
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered uninitialized bytes, but expected initialized bytes
|
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
= note: the raw bytes of the constant (size: 4, align: 4) {
Expand Down
2 changes: 1 addition & 1 deletion src/test/ui/consts/const-err4.64bit.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ error[E0080]: it is undefined behavior to use this value
--> $DIR/const-err4.rs:9:11
|
LL | Boo = [unsafe { Foo { b: () }.a }; 4][3],
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered uninitialized bytes, but expected initialized plain (non-pointer) bytes
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered uninitialized bytes, but expected initialized bytes
|
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
= note: the raw bytes of the constant (size: 8, align: 8) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ error[E0080]: it is undefined behavior to use this value
--> $DIR/const-pointer-values-in-various-types.rs:26:5
|
LL | const I32_REF_USIZE_UNION: usize = unsafe { Nonsense { int_32_ref: &3 }.u };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered pointer to alloc3, but expected initialized plain (non-pointer) bytes
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered pointer to alloc3, but expected plain (non-pointer) bytes
|
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
= note: the raw bytes of the constant (size: 8, align: 8) {
Expand Down Expand Up @@ -47,7 +47,7 @@ error[E0080]: it is undefined behavior to use this value
--> $DIR/const-pointer-values-in-various-types.rs:41:5
|
LL | const I32_REF_U64_UNION: u64 = unsafe { Nonsense { int_32_ref: &3 }.uint_64 };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered pointer to alloc19, but expected initialized plain (non-pointer) bytes
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered pointer to alloc19, but expected plain (non-pointer) bytes
|
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
= note: the raw bytes of the constant (size: 8, align: 8) {
Expand All @@ -58,7 +58,7 @@ error[E0080]: it is undefined behavior to use this value
--> $DIR/const-pointer-values-in-various-types.rs:44:5
|
LL | const I32_REF_U128_UNION: u128 = unsafe { Nonsense { int_32_ref: &3 }.uint_128 };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered uninitialized bytes, but expected initialized plain (non-pointer) bytes
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered uninitialized bytes, but expected initialized bytes
|
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
= note: the raw bytes of the constant (size: 16, align: 8) {
Expand Down Expand Up @@ -102,7 +102,7 @@ error[E0080]: it is undefined behavior to use this value
--> $DIR/const-pointer-values-in-various-types.rs:59:5
|
LL | const I32_REF_I64_UNION: i64 = unsafe { Nonsense { int_32_ref: &3 }.int_64 };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered pointer to alloc39, but expected initialized plain (non-pointer) bytes
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered pointer to alloc39, but expected plain (non-pointer) bytes
|
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
= note: the raw bytes of the constant (size: 8, align: 8) {
Expand All @@ -113,7 +113,7 @@ error[E0080]: it is undefined behavior to use this value
--> $DIR/const-pointer-values-in-various-types.rs:62:5
|
LL | const I32_REF_I128_UNION: i128 = unsafe { Nonsense { int_32_ref: &3 }.int_128 };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered uninitialized bytes, but expected initialized plain (non-pointer) bytes
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered uninitialized bytes, but expected initialized bytes
|
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
= note: the raw bytes of the constant (size: 16, align: 8) {
Expand All @@ -135,7 +135,7 @@ error[E0080]: it is undefined behavior to use this value
--> $DIR/const-pointer-values-in-various-types.rs:69:5
|
LL | const I32_REF_F64_UNION: f64 = unsafe { Nonsense { int_32_ref: &3 }.float_64 };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered pointer to alloc51, but expected initialized plain (non-pointer) bytes
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered pointer to alloc51, but expected plain (non-pointer) bytes
|
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
= note: the raw bytes of the constant (size: 8, align: 8) {
Expand Down Expand Up @@ -201,7 +201,7 @@ error[E0080]: it is undefined behavior to use this value
--> $DIR/const-pointer-values-in-various-types.rs:92:5
|
LL | const STR_U64_UNION: u64 = unsafe { Nonsense { stringy: "3" }.uint_64 };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered pointer to alloc72, but expected initialized plain (non-pointer) bytes
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered pointer to alloc72, but expected plain (non-pointer) bytes
|
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
= note: the raw bytes of the constant (size: 8, align: 8) {
Expand Down Expand Up @@ -256,7 +256,7 @@ error[E0080]: it is undefined behavior to use this value
--> $DIR/const-pointer-values-in-various-types.rs:111:5
|
LL | const STR_I64_UNION: i64 = unsafe { Nonsense { stringy: "3" }.int_64 };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered pointer to alloc87, but expected initialized plain (non-pointer) bytes
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered pointer to alloc87, but expected plain (non-pointer) bytes
|
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
= note: the raw bytes of the constant (size: 8, align: 8) {
Expand Down Expand Up @@ -289,7 +289,7 @@ error[E0080]: it is undefined behavior to use this value
--> $DIR/const-pointer-values-in-various-types.rs:122:5
|
LL | const STR_F64_UNION: f64 = unsafe { Nonsense { stringy: "3" }.float_64 };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered pointer to alloc96, but expected initialized plain (non-pointer) bytes
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered pointer to alloc96, but expected plain (non-pointer) bytes
|
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
= note: the raw bytes of the constant (size: 8, align: 8) {
Expand Down
Loading