Skip to content
Open
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
2 changes: 1 addition & 1 deletion compiler/rustc_borrowck/src/region_infer/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -627,7 +627,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
}

// Type-test failed. Report the error.
let erased_generic_kind = infcx.tcx.erase_regions(type_test.generic_kind);
let erased_generic_kind = infcx.tcx.erase_and_anonymize_regions(type_test.generic_kind);

// Skip duplicate-ish errors.
if deduplicate_errors.insert((
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -344,7 +344,7 @@ fn compute_concrete_types_from_defining_uses<'tcx>(
//
// FIXME(-Znext-solver): This isn't necessary after all. We can remove this check again.
if let Some((prev_decl_key, prev_span)) = decls_modulo_regions.insert(
rcx.infcx.tcx.erase_regions(opaque_type_key),
rcx.infcx.tcx.erase_and_anonymize_regions(opaque_type_key),
(opaque_type_key, hidden_type.span),
) && let Some((arg1, arg2)) = std::iter::zip(
prev_decl_key.iter_captured_args(infcx.tcx).map(|(_, arg)| arg),
Expand Down
8 changes: 5 additions & 3 deletions compiler/rustc_borrowck/src/type_check/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1874,7 +1874,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
if is_diverging {
// The signature in this call can reference region variables,
// so erase them before calling a query.
let output_ty = self.tcx().erase_regions(sig.output());
let output_ty = self.tcx().erase_and_anonymize_regions(sig.output());
if !output_ty
.is_privately_uninhabited(self.tcx(), self.infcx.typing_env(self.infcx.param_env))
{
Expand Down Expand Up @@ -1968,7 +1968,9 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {

let op_arg_ty = self.normalize(op_arg_ty, term_location);
let category = if call_source.from_hir_call() {
ConstraintCategory::CallArgument(Some(self.infcx.tcx.erase_regions(func_ty)))
ConstraintCategory::CallArgument(Some(
self.infcx.tcx.erase_and_anonymize_regions(func_ty),
))
} else {
ConstraintCategory::Boring
};
Expand Down Expand Up @@ -2102,7 +2104,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
// Erase the regions from `ty` to get a global type. The
// `Sized` bound in no way depends on precise regions, so this
// shouldn't affect `is_sized`.
let erased_ty = tcx.erase_regions(ty);
let erased_ty = tcx.erase_and_anonymize_regions(ty);
// FIXME(#132279): Using `Ty::is_sized` causes us to incorrectly handle opaques here.
if !erased_ty.is_sized(tcx, self.infcx.typing_env(self.infcx.param_env)) {
// in current MIR construction, all non-control-flow rvalue
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_codegen_gcc/src/type_of.rs
Original file line number Diff line number Diff line change
Expand Up @@ -240,7 +240,7 @@ impl<'tcx> LayoutGccExt<'tcx> for TyAndLayout<'tcx> {

// Make sure lifetimes are erased, to avoid generating distinct LLVM
// types for Rust types that only differ in the choice of lifetimes.
let normal_ty = cx.tcx.erase_regions(self.ty);
let normal_ty = cx.tcx.erase_and_anonymize_regions(self.ty);

let mut defer = None;
let ty = if self.ty != normal_ty {
Expand Down
4 changes: 2 additions & 2 deletions compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1425,7 +1425,7 @@ fn build_vtable_type_di_node<'ll, 'tcx>(

let vtable_entries = if let Some(poly_trait_ref) = poly_trait_ref {
let trait_ref = poly_trait_ref.with_self_ty(tcx, ty);
let trait_ref = tcx.erase_regions(trait_ref);
let trait_ref = tcx.erase_and_anonymize_regions(trait_ref);

tcx.vtable_entries(trait_ref)
} else {
Expand Down Expand Up @@ -1552,7 +1552,7 @@ pub(crate) fn apply_vcall_visibility_metadata<'ll, 'tcx>(
// Unwrap potential addrspacecast
let vtable = find_vtable_behind_cast(vtable);
let trait_ref_self = trait_ref.with_self_ty(cx.tcx, ty);
let trait_ref_self = cx.tcx.erase_regions(trait_ref_self);
let trait_ref_self = cx.tcx.erase_and_anonymize_regions(trait_ref_self);
let trait_def_id = trait_ref_self.def_id;
let trait_vis = cx.tcx.visibility(trait_def_id);

Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_codegen_llvm/src/type_of.rs
Original file line number Diff line number Diff line change
Expand Up @@ -226,7 +226,7 @@ impl<'tcx> LayoutLlvmExt<'tcx> for TyAndLayout<'tcx> {

// Make sure lifetimes are erased, to avoid generating distinct LLVM
// types for Rust types that only differ in the choice of lifetimes.
let normal_ty = cx.tcx.erase_regions(self.ty);
let normal_ty = cx.tcx.erase_and_anonymize_regions(self.ty);

let mut defer = None;
let llty = if self.ty != normal_ty {
Expand Down
7 changes: 4 additions & 3 deletions compiler/rustc_const_eval/src/interpret/traits.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
) -> InterpResult<'tcx, Pointer<Option<M::Provenance>>> {
trace!("get_vtable(ty={ty:?}, dyn_ty={dyn_ty:?})");

let (ty, dyn_ty) = self.tcx.erase_regions((ty, dyn_ty));
let (ty, dyn_ty) = self.tcx.erase_and_anonymize_regions((ty, dyn_ty));

// All vtables must be monomorphic, bail out otherwise.
ensure_monomorphic_enough(*self.tcx, ty)?;
Expand Down Expand Up @@ -53,8 +53,9 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
) -> &'tcx [VtblEntry<'tcx>] {
if let Some(trait_) = trait_ {
let trait_ref = trait_.with_self_ty(*self.tcx, dyn_ty);
let trait_ref =
self.tcx.erase_regions(self.tcx.instantiate_bound_regions_with_erased(trait_ref));
let trait_ref = self.tcx.erase_and_anonymize_regions(
self.tcx.instantiate_bound_regions_with_erased(trait_ref),
);
self.tcx.vtable_entries(trait_ref)
} else {
TyCtxt::COMMON_VTABLE_ENTRIES
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_hir_analysis/src/check/wfcheck.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1047,7 +1047,7 @@ fn check_type_defn<'tcx>(
let needs_drop_copy = || {
packed && {
let ty = tcx.type_of(variant.tail().did).instantiate_identity();
let ty = tcx.erase_regions(ty);
let ty = tcx.erase_and_anonymize_regions(ty);
assert!(!ty.has_infer());
ty.needs_drop(tcx, wfcx.infcx.typing_env(wfcx.param_env))
}
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_hir_analysis/src/coherence/orphan.rs
Original file line number Diff line number Diff line change
Expand Up @@ -404,7 +404,7 @@ fn emit_orphan_check_error<'tcx>(
of_trait.trait_ref.path.span
};

ty = tcx.erase_regions(ty);
ty = tcx.erase_and_anonymize_regions(ty);

let is_foreign =
!trait_ref.def_id.is_local() && matches!(is_target_ty, IsFirstInputType::No);
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -482,7 +482,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
.map(|header| header.trait_ref.instantiate_identity().self_ty())
// We don't care about blanket impls.
.filter(|self_ty| !self_ty.has_non_region_param())
.map(|self_ty| tcx.erase_regions(self_ty).to_string())
.map(|self_ty| tcx.erase_and_anonymize_regions(self_ty).to_string())
.collect()
};
// FIXME: also look at `tcx.generics_of(self.item_def_id()).params` any that
Expand Down
4 changes: 2 additions & 2 deletions compiler/rustc_hir_typeck/src/cast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -851,8 +851,8 @@ impl<'a, 'tcx> CastCheck<'tcx> {
debug!("check_ptr_ptr_cast m_src={m_src:?} m_dst={m_dst:?}");
// ptr-ptr cast. metadata must match.

let src_kind = fcx.tcx.erase_regions(fcx.pointer_kind(m_src.ty, self.span)?);
let dst_kind = fcx.tcx.erase_regions(fcx.pointer_kind(m_dst.ty, self.span)?);
let src_kind = fcx.tcx.erase_and_anonymize_regions(fcx.pointer_kind(m_src.ty, self.span)?);
let dst_kind = fcx.tcx.erase_and_anonymize_regions(fcx.pointer_kind(m_dst.ty, self.span)?);

// We can't cast if target pointer kind is unknown
let Some(dst_kind) = dst_kind else {
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1292,7 +1292,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
.infcx
.type_implements_trait(
clone_trait_def,
[self.tcx.erase_regions(expected_ty)],
[self.tcx.erase_and_anonymize_regions(expected_ty)],
self.param_env,
)
.must_apply_modulo_regions()
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_hir_typeck/src/inline_asm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ impl<'a, 'tcx> InlineAsmCtxt<'a, 'tcx> {
if ty.has_non_region_infer() {
Ty::new_misc_error(self.tcx())
} else {
self.tcx().erase_regions(ty)
self.tcx().erase_and_anonymize_regions(ty)
}
}

Expand Down
6 changes: 3 additions & 3 deletions compiler/rustc_hir_typeck/src/writeback.rs
Original file line number Diff line number Diff line change
Expand Up @@ -788,7 +788,7 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> {
format!("unexpected inference variable after writeback: {predicate:?}"),
);
} else {
let predicate = self.tcx().erase_regions(predicate);
let predicate = self.tcx().erase_and_anonymize_regions(predicate);
if cause.has_infer() || cause.has_placeholders() {
// We can't use the the obligation cause as it references
// information local to this query.
Expand Down Expand Up @@ -969,8 +969,8 @@ impl<'cx, 'tcx> Resolver<'cx, 'tcx> {
// borrowck, and specifically region constraints will be populated during
// MIR typeck which is run on the new body.
//
// We're not using `tcx.erase_regions` as that also anonymizes bound variables,
// regressing borrowck diagnostics.
// We're not using `tcx.erase_and_anonymize_regions` as that also
// anonymizes bound variables, regressing borrowck diagnostics.
value = fold_regions(tcx, value, |_, _| tcx.lifetimes.re_erased);

// Normalize consts in writeback, because GCE doesn't normalize eagerly.
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_infer/src/infer/outlives/test_type_match.rs
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ pub(super) fn can_match_erased_ty<'tcx>(
erased_ty: Ty<'tcx>,
) -> bool {
assert!(!outlives_predicate.has_escaping_bound_vars());
let erased_outlives_predicate = tcx.erase_regions(outlives_predicate);
let erased_outlives_predicate = tcx.erase_and_anonymize_regions(outlives_predicate);
let outlives_ty = erased_outlives_predicate.skip_binder().0;
if outlives_ty == erased_ty {
// pointless micro-optimization
Expand Down
4 changes: 2 additions & 2 deletions compiler/rustc_infer/src/infer/outlives/verify.rs
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@ impl<'cx, 'tcx> VerifyBoundCx<'cx, 'tcx> {
&self,
alias_ty: ty::AliasTy<'tcx>,
) -> Vec<ty::PolyTypeOutlivesPredicate<'tcx>> {
let erased_alias_ty = self.tcx.erase_regions(alias_ty.to_ty(self.tcx));
let erased_alias_ty = self.tcx.erase_and_anonymize_regions(alias_ty.to_ty(self.tcx));
self.declared_generic_bounds_from_env_for_erased_ty(erased_alias_ty)
}

Expand Down Expand Up @@ -241,7 +241,7 @@ impl<'cx, 'tcx> VerifyBoundCx<'cx, 'tcx> {
}

let p_ty = p.to_ty(tcx);
let erased_p_ty = self.tcx.erase_regions(p_ty);
let erased_p_ty = self.tcx.erase_and_anonymize_regions(p_ty);
(erased_p_ty == erased_ty).then_some(ty::Binder::dummy(ty::OutlivesPredicate(p_ty, r)))
}));

Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_lint/src/deref_into_dyn_supertrait.rs
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ impl<'tcx> LateLintPass<'tcx> for DerefIntoDynSupertrait {
{
// erase regions in self type for better diagnostic presentation
let (self_ty, target_principal, supertrait_principal) =
tcx.erase_regions((self_ty, target_principal, supertrait_principal));
tcx.erase_and_anonymize_regions((self_ty, target_principal, supertrait_principal));
let label2 = tcx
.associated_items(item.owner_id)
.find_by_ident_and_kind(
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_lint/src/for_loops_over_fallibles.rs
Original file line number Diff line number Diff line change
Expand Up @@ -176,7 +176,7 @@ fn suggest_question_mark<'tcx>(
cause,
param_env,
// Erase any region vids from the type, which may not be resolved
infcx.tcx.erase_regions(ty),
infcx.tcx.erase_and_anonymize_regions(ty),
into_iterator_did,
);

Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_lint/src/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1786,7 +1786,7 @@ impl<'tcx> LateLintPass<'tcx> for VariantSizeDifferences {
fn check_item(&mut self, cx: &LateContext<'_>, it: &hir::Item<'_>) {
if let hir::ItemKind::Enum(_, _, ref enum_definition) = it.kind {
let t = cx.tcx.type_of(it.owner_id).instantiate_identity();
let ty = cx.tcx.erase_regions(t);
let ty = cx.tcx.erase_and_anonymize_regions(t);
let Ok(layout) = cx.layout_of(ty) else { return };
let Variants::Multiple { tag_encoding: TagEncoding::Direct, tag, variants, .. } =
&layout.variants
Expand Down
12 changes: 7 additions & 5 deletions compiler/rustc_middle/src/mir/interpret/queries.rs
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ impl<'tcx> TyCtxt<'tcx> {
let instance = ty::Instance::new_raw(def_id, args);
let cid = GlobalId { instance, promoted: None };
let typing_env = ty::TypingEnv::post_analysis(self, def_id);
let inputs = self.erase_regions(typing_env.as_query_input(cid));
let inputs = self.erase_and_anonymize_regions(typing_env.as_query_input(cid));
self.eval_to_allocation_raw(inputs)
}

Expand Down Expand Up @@ -172,8 +172,9 @@ impl<'tcx> TyCtxt<'tcx> {
) -> EvalToConstValueResult<'tcx> {
// Const-eval shouldn't depend on lifetimes at all, so we can erase them, which should
// improve caching of queries.
let inputs =
self.erase_regions(typing_env.with_post_analysis_normalized(self).as_query_input(cid));
let inputs = self.erase_and_anonymize_regions(
typing_env.with_post_analysis_normalized(self).as_query_input(cid),
);
if !span.is_dummy() {
// The query doesn't know where it is being invoked, so we need to fix the span.
self.at(span).eval_to_const_value_raw(inputs).map_err(|e| e.with_span(span))
Expand All @@ -192,8 +193,9 @@ impl<'tcx> TyCtxt<'tcx> {
) -> ConstToValTreeResult<'tcx> {
// Const-eval shouldn't depend on lifetimes at all, so we can erase them, which should
// improve caching of queries.
let inputs =
self.erase_regions(typing_env.with_post_analysis_normalized(self).as_query_input(cid));
let inputs = self.erase_and_anonymize_regions(
typing_env.with_post_analysis_normalized(self).as_query_input(cid),
);
debug!(?inputs);
let res = if !span.is_dummy() {
// The query doesn't know where it is being invoked, so we need to fix the span.
Expand Down
4 changes: 2 additions & 2 deletions compiler/rustc_middle/src/query/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -759,9 +759,9 @@ rustc_queries! {
}

/// Erases regions from `ty` to yield a new type.
/// Normally you would just use `tcx.erase_regions(value)`,
/// Normally you would just use `tcx.erase_and_anonymize_regions(value)`,
/// however, which uses this query as a kind of cache.
query erase_regions_ty(ty: Ty<'tcx>) -> Ty<'tcx> {
query erase_and_anonymize_regions_ty(ty: Ty<'tcx>) -> Ty<'tcx> {
// This query is not expected to have input -- as a result, it
// is not a good candidates for "replay" because it is essentially a
// pure function of its input (and hence the expectation is that
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_middle/src/ty/abstract_const.rs
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ impl<'tcx> TyCtxt<'tcx> {
ty::ConstKind::Unevaluated(uv) => match self.tcx.thir_abstract_const(uv.def) {
Err(e) => ty::Const::new_error(self.tcx, e),
Ok(Some(bac)) => {
let args = self.tcx.erase_regions(uv.args);
let args = self.tcx.erase_and_anonymize_regions(uv.args);
let bac = bac.instantiate(self.tcx, args);
return bac.fold_with(self);
}
Expand Down
28 changes: 14 additions & 14 deletions compiler/rustc_middle/src/ty/erase_regions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,39 +6,39 @@ use crate::ty::{
};

pub(super) fn provide(providers: &mut Providers) {
*providers = Providers { erase_regions_ty, ..*providers };
*providers = Providers { erase_and_anonymize_regions_ty, ..*providers };
}

fn erase_regions_ty<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> Ty<'tcx> {
fn erase_and_anonymize_regions_ty<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> Ty<'tcx> {
// N.B., use `super_fold_with` here. If we used `fold_with`, it
// could invoke the `erase_regions_ty` query recursively.
ty.super_fold_with(&mut RegionEraserVisitor { tcx })
// could invoke the `erase_and_anonymize_regions_ty` query recursively.
ty.super_fold_with(&mut RegionEraserAndAnonymizerVisitor { tcx })
}

impl<'tcx> TyCtxt<'tcx> {
/// Returns an equivalent value with all free regions removed (note
/// that late-bound regions remain, because they are important for
/// subtyping, but they are anonymized and normalized as well)..
pub fn erase_regions<T>(self, value: T) -> T
/// Returns an equivalent value with all free regions removed and
/// bound regions anonymized. (note that bound regions are important
/// for subtyping and generally type equality so *cannot* be removed)
pub fn erase_and_anonymize_regions<T>(self, value: T) -> T
where
T: TypeFoldable<TyCtxt<'tcx>>,
{
// If there's nothing to erase or anonymize, avoid performing the query at all
if !value.has_type_flags(TypeFlags::HAS_BINDER_VARS | TypeFlags::HAS_FREE_REGIONS) {
return value;
}
debug!("erase_regions({:?})", value);
let value1 = value.fold_with(&mut RegionEraserVisitor { tcx: self });
debug!("erase_regions = {:?}", value1);
debug!("erase_and_anonymize_regions({:?})", value);
let value1 = value.fold_with(&mut RegionEraserAndAnonymizerVisitor { tcx: self });
debug!("erase_and_anonymize_regions = {:?}", value1);
value1
}
}

struct RegionEraserVisitor<'tcx> {
struct RegionEraserAndAnonymizerVisitor<'tcx> {
tcx: TyCtxt<'tcx>,
}

impl<'tcx> TypeFolder<TyCtxt<'tcx>> for RegionEraserVisitor<'tcx> {
impl<'tcx> TypeFolder<TyCtxt<'tcx>> for RegionEraserAndAnonymizerVisitor<'tcx> {
fn cx(&self) -> TyCtxt<'tcx> {
self.tcx
}
Expand All @@ -49,7 +49,7 @@ impl<'tcx> TypeFolder<TyCtxt<'tcx>> for RegionEraserVisitor<'tcx> {
} else if ty.has_infer() {
ty.super_fold_with(self)
} else {
self.tcx.erase_regions_ty(ty)
self.tcx.erase_and_anonymize_regions_ty(ty)
}
}

Expand Down
4 changes: 3 additions & 1 deletion compiler/rustc_middle/src/ty/instance.rs
Original file line number Diff line number Diff line change
Expand Up @@ -544,7 +544,9 @@ impl<'tcx> Instance<'tcx> {

// All regions in the result of this query are erased, so it's
// fine to erase all of the input regions.
tcx.resolve_instance_raw(tcx.erase_regions(typing_env.as_query_input((def_id, args))))
tcx.resolve_instance_raw(
tcx.erase_and_anonymize_regions(typing_env.as_query_input((def_id, args))),
)
}

pub fn expect_resolve(
Expand Down
5 changes: 4 additions & 1 deletion compiler/rustc_middle/src/ty/layout.rs
Original file line number Diff line number Diff line change
Expand Up @@ -401,7 +401,10 @@ impl<'tcx> SizeSkeleton<'tcx> {
match tail.kind() {
ty::Param(_) | ty::Alias(ty::Projection | ty::Inherent, _) => {
debug_assert!(tail.has_non_region_param());
Ok(SizeSkeleton::Pointer { non_zero, tail: tcx.erase_regions(tail) })
Ok(SizeSkeleton::Pointer {
non_zero,
tail: tcx.erase_and_anonymize_regions(tail),
})
}
ty::Error(guar) => {
// Fixes ICE #124031
Expand Down
4 changes: 2 additions & 2 deletions compiler/rustc_middle/src/ty/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -831,12 +831,12 @@ impl<'tcx> OpaqueHiddenType<'tcx> {
//
// We erase regions when doing this during HIR typeck.
let this = match defining_scope_kind {
DefiningScopeKind::HirTypeck => tcx.erase_regions(self),
DefiningScopeKind::HirTypeck => tcx.erase_and_anonymize_regions(self),
DefiningScopeKind::MirBorrowck => self,
};
let result = this.fold_with(&mut opaque_types::ReverseMapper::new(tcx, map, self.span));
if cfg!(debug_assertions) && matches!(defining_scope_kind, DefiningScopeKind::HirTypeck) {
assert_eq!(result.ty, tcx.erase_regions(result.ty));
assert_eq!(result.ty, tcx.erase_and_anonymize_regions(result.ty));
}
result
}
Expand Down
Loading
Loading