mirror of
https://github.com/rust-lang/rust.git
synced 2024-11-26 08:44:35 +00:00
Auto merge of #111358 - compiler-errors:rollup-yv27vrp, r=compiler-errors
Rollup of 6 pull requests Successful merges: - #104070 (Prevent aborting guard from aborting the process in a forced unwind) - #109410 (Introduce `AliasKind::Inherent` for inherent associated types) - #111004 (Migrate `mir_transform` to translatable diagnostics) - #111118 (Suggest struct when we get colon in fileds in enum) - #111170 (Diagnostic args are still args if they're documented) - #111354 (Fix miscompilation when calling default methods on `Future`) Failed merges: r? `@ghost` `@rustbot` modify labels: rollup
This commit is contained in:
commit
2f2c438dce
@ -3353,6 +3353,7 @@ dependencies = [
|
|||||||
"rustc_middle",
|
"rustc_middle",
|
||||||
"rustc_mir_build",
|
"rustc_mir_build",
|
||||||
"rustc_mir_dataflow",
|
"rustc_mir_dataflow",
|
||||||
|
"rustc_mir_transform",
|
||||||
"rustc_monomorphize",
|
"rustc_monomorphize",
|
||||||
"rustc_parse",
|
"rustc_parse",
|
||||||
"rustc_passes",
|
"rustc_passes",
|
||||||
@ -3861,8 +3862,10 @@ dependencies = [
|
|||||||
"rustc_const_eval",
|
"rustc_const_eval",
|
||||||
"rustc_data_structures",
|
"rustc_data_structures",
|
||||||
"rustc_errors",
|
"rustc_errors",
|
||||||
|
"rustc_fluent_macro",
|
||||||
"rustc_hir",
|
"rustc_hir",
|
||||||
"rustc_index",
|
"rustc_index",
|
||||||
|
"rustc_macros",
|
||||||
"rustc_middle",
|
"rustc_middle",
|
||||||
"rustc_mir_dataflow",
|
"rustc_mir_dataflow",
|
||||||
"rustc_serialize",
|
"rustc_serialize",
|
||||||
|
@ -1227,6 +1227,11 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> {
|
|||||||
(value1, value2)
|
(value1, value2)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn filter_landing_pad(&mut self, pers_fn: RValue<'gcc>) -> (RValue<'gcc>, RValue<'gcc>) {
|
||||||
|
// TODO(antoyo): generate the correct landing pad
|
||||||
|
self.cleanup_landing_pad(pers_fn)
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(feature="master")]
|
#[cfg(feature="master")]
|
||||||
fn resume(&mut self, exn0: RValue<'gcc>, _exn1: RValue<'gcc>) {
|
fn resume(&mut self, exn0: RValue<'gcc>, _exn1: RValue<'gcc>) {
|
||||||
let exn_type = exn0.get_type();
|
let exn_type = exn0.get_type();
|
||||||
|
@ -985,13 +985,20 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> {
|
|||||||
|
|
||||||
fn cleanup_landing_pad(&mut self, pers_fn: &'ll Value) -> (&'ll Value, &'ll Value) {
|
fn cleanup_landing_pad(&mut self, pers_fn: &'ll Value) -> (&'ll Value, &'ll Value) {
|
||||||
let ty = self.type_struct(&[self.type_i8p(), self.type_i32()], false);
|
let ty = self.type_struct(&[self.type_i8p(), self.type_i32()], false);
|
||||||
let landing_pad = self.landing_pad(ty, pers_fn, 1 /* FIXME should this be 0? */);
|
let landing_pad = self.landing_pad(ty, pers_fn, 0);
|
||||||
unsafe {
|
unsafe {
|
||||||
llvm::LLVMSetCleanup(landing_pad, llvm::True);
|
llvm::LLVMSetCleanup(landing_pad, llvm::True);
|
||||||
}
|
}
|
||||||
(self.extract_value(landing_pad, 0), self.extract_value(landing_pad, 1))
|
(self.extract_value(landing_pad, 0), self.extract_value(landing_pad, 1))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn filter_landing_pad(&mut self, pers_fn: &'ll Value) -> (&'ll Value, &'ll Value) {
|
||||||
|
let ty = self.type_struct(&[self.type_i8p(), self.type_i32()], false);
|
||||||
|
let landing_pad = self.landing_pad(ty, pers_fn, 1);
|
||||||
|
self.add_clause(landing_pad, self.const_array(self.type_i8p(), &[]));
|
||||||
|
(self.extract_value(landing_pad, 0), self.extract_value(landing_pad, 1))
|
||||||
|
}
|
||||||
|
|
||||||
fn resume(&mut self, exn0: &'ll Value, exn1: &'ll Value) {
|
fn resume(&mut self, exn0: &'ll Value, exn1: &'ll Value) {
|
||||||
let ty = self.type_struct(&[self.type_i8p(), self.type_i32()], false);
|
let ty = self.type_struct(&[self.type_i8p(), self.type_i32()], false);
|
||||||
let mut exn = self.const_poison(ty);
|
let mut exn = self.const_poison(ty);
|
||||||
|
@ -1600,7 +1600,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
|||||||
bx = Bx::build(self.cx, llbb);
|
bx = Bx::build(self.cx, llbb);
|
||||||
|
|
||||||
let llpersonality = self.cx.eh_personality();
|
let llpersonality = self.cx.eh_personality();
|
||||||
bx.cleanup_landing_pad(llpersonality);
|
bx.filter_landing_pad(llpersonality);
|
||||||
|
|
||||||
funclet = None;
|
funclet = None;
|
||||||
}
|
}
|
||||||
|
@ -274,6 +274,7 @@ pub trait BuilderMethods<'a, 'tcx>:
|
|||||||
|
|
||||||
// These are used by everyone except msvc
|
// These are used by everyone except msvc
|
||||||
fn cleanup_landing_pad(&mut self, pers_fn: Self::Value) -> (Self::Value, Self::Value);
|
fn cleanup_landing_pad(&mut self, pers_fn: Self::Value) -> (Self::Value, Self::Value);
|
||||||
|
fn filter_landing_pad(&mut self, pers_fn: Self::Value) -> (Self::Value, Self::Value);
|
||||||
fn resume(&mut self, exn0: Self::Value, exn1: Self::Value);
|
fn resume(&mut self, exn0: Self::Value, exn1: Self::Value);
|
||||||
|
|
||||||
// These are used only by msvc
|
// These are used only by msvc
|
||||||
|
@ -51,6 +51,7 @@ rustc_interface = { path = "../rustc_interface" }
|
|||||||
rustc_ast = { path = "../rustc_ast" }
|
rustc_ast = { path = "../rustc_ast" }
|
||||||
rustc_span = { path = "../rustc_span" }
|
rustc_span = { path = "../rustc_span" }
|
||||||
rustc_hir_analysis = { path = "../rustc_hir_analysis" }
|
rustc_hir_analysis = { path = "../rustc_hir_analysis" }
|
||||||
|
rustc_mir_transform = { path = "../rustc_mir_transform" }
|
||||||
|
|
||||||
[target.'cfg(unix)'.dependencies]
|
[target.'cfg(unix)'.dependencies]
|
||||||
libc = "0.2"
|
libc = "0.2"
|
||||||
@ -64,5 +65,8 @@ features = [
|
|||||||
[features]
|
[features]
|
||||||
llvm = ['rustc_interface/llvm']
|
llvm = ['rustc_interface/llvm']
|
||||||
max_level_info = ['rustc_log/max_level_info']
|
max_level_info = ['rustc_log/max_level_info']
|
||||||
rustc_use_parallel_compiler = ['rustc_data_structures/rustc_use_parallel_compiler', 'rustc_interface/rustc_use_parallel_compiler',
|
rustc_use_parallel_compiler = [
|
||||||
'rustc_middle/rustc_use_parallel_compiler']
|
'rustc_data_structures/rustc_use_parallel_compiler',
|
||||||
|
'rustc_interface/rustc_use_parallel_compiler',
|
||||||
|
'rustc_middle/rustc_use_parallel_compiler'
|
||||||
|
]
|
||||||
|
@ -99,6 +99,7 @@ pub static DEFAULT_LOCALE_RESOURCES: &[&str] = &[
|
|||||||
rustc_middle::DEFAULT_LOCALE_RESOURCE,
|
rustc_middle::DEFAULT_LOCALE_RESOURCE,
|
||||||
rustc_mir_build::DEFAULT_LOCALE_RESOURCE,
|
rustc_mir_build::DEFAULT_LOCALE_RESOURCE,
|
||||||
rustc_mir_dataflow::DEFAULT_LOCALE_RESOURCE,
|
rustc_mir_dataflow::DEFAULT_LOCALE_RESOURCE,
|
||||||
|
rustc_mir_transform::DEFAULT_LOCALE_RESOURCE,
|
||||||
rustc_monomorphize::DEFAULT_LOCALE_RESOURCE,
|
rustc_monomorphize::DEFAULT_LOCALE_RESOURCE,
|
||||||
rustc_parse::DEFAULT_LOCALE_RESOURCE,
|
rustc_parse::DEFAULT_LOCALE_RESOURCE,
|
||||||
rustc_passes::DEFAULT_LOCALE_RESOURCE,
|
rustc_passes::DEFAULT_LOCALE_RESOURCE,
|
||||||
|
@ -571,6 +571,14 @@ impl<'a, G: EmissionGuarantee> DiagnosticBuilder<'a, G> {
|
|||||||
Some((diagnostic, handler))
|
Some((diagnostic, handler))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Retrieves the [`Handler`] if available
|
||||||
|
pub fn handler(&self) -> Option<&Handler> {
|
||||||
|
match self.inner.state {
|
||||||
|
DiagnosticBuilderState::Emittable(handler) => Some(handler),
|
||||||
|
DiagnosticBuilderState::AlreadyEmittedOrDuringCancellation => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Buffers the diagnostic for later emission,
|
/// Buffers the diagnostic for later emission,
|
||||||
/// unless handler has disabled such buffering.
|
/// unless handler has disabled such buffering.
|
||||||
pub fn buffer(self, buffered_diagnostics: &mut Vec<Diagnostic>) {
|
pub fn buffer(self, buffered_diagnostics: &mut Vec<Diagnostic>) {
|
||||||
|
@ -2419,6 +2419,10 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
|
|||||||
return Ok(None);
|
return Ok(None);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Select applicable inherent associated type candidates modulo regions.
|
||||||
|
//
|
||||||
|
|
||||||
// In contexts that have no inference context, just make a new one.
|
// In contexts that have no inference context, just make a new one.
|
||||||
// We do need a local variable to store it, though.
|
// We do need a local variable to store it, though.
|
||||||
let infcx_;
|
let infcx_;
|
||||||
@ -2431,7 +2435,9 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
let param_env = tcx.param_env(block.owner.to_def_id());
|
// FIXME(inherent_associated_types): Acquiring the ParamEnv this early leads to cycle errors
|
||||||
|
// when inside of an ADT (#108491) or where clause.
|
||||||
|
let param_env = tcx.param_env(block.owner);
|
||||||
let cause = ObligationCause::misc(span, block.owner.def_id);
|
let cause = ObligationCause::misc(span, block.owner.def_id);
|
||||||
|
|
||||||
let mut fulfillment_errors = Vec::new();
|
let mut fulfillment_errors = Vec::new();
|
||||||
@ -2439,6 +2445,8 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
|
|||||||
let universe = infcx.create_next_universe();
|
let universe = infcx.create_next_universe();
|
||||||
|
|
||||||
// Regions are not considered during selection.
|
// Regions are not considered during selection.
|
||||||
|
// FIXME(non_lifetime_binders): Here we are "truncating" or "flattening" the universes
|
||||||
|
// of type and const binders. Is that correct in the selection phase? See also #109505.
|
||||||
let self_ty = tcx.replace_escaping_bound_vars_uncached(
|
let self_ty = tcx.replace_escaping_bound_vars_uncached(
|
||||||
self_ty,
|
self_ty,
|
||||||
FnMutDelegate {
|
FnMutDelegate {
|
||||||
@ -2454,41 +2462,40 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
|
|||||||
|
|
||||||
candidates
|
candidates
|
||||||
.iter()
|
.iter()
|
||||||
.filter_map(|&(impl_, (assoc_item, def_scope))| {
|
.copied()
|
||||||
|
.filter(|&(impl_, _)| {
|
||||||
infcx.probe(|_| {
|
infcx.probe(|_| {
|
||||||
let ocx = ObligationCtxt::new_in_snapshot(&infcx);
|
let ocx = ObligationCtxt::new_in_snapshot(&infcx);
|
||||||
|
|
||||||
let impl_ty = tcx.type_of(impl_);
|
|
||||||
let impl_substs = infcx.fresh_item_substs(impl_);
|
let impl_substs = infcx.fresh_item_substs(impl_);
|
||||||
let impl_ty = impl_ty.subst(tcx, impl_substs);
|
let impl_ty = tcx.type_of(impl_).subst(tcx, impl_substs);
|
||||||
let impl_ty = ocx.normalize(&cause, param_env, impl_ty);
|
let impl_ty = ocx.normalize(&cause, param_env, impl_ty);
|
||||||
|
|
||||||
// Check that the Self-types can be related.
|
// Check that the self types can be related.
|
||||||
// FIXME(fmease): Should we use `eq` here?
|
// FIXME(inherent_associated_types): Should we use `eq` here? Method probing uses
|
||||||
ocx.sup(&ObligationCause::dummy(), param_env, impl_ty, self_ty).ok()?;
|
// `sup` for this situtation, too. What for? To constrain inference variables?
|
||||||
|
if ocx.sup(&ObligationCause::dummy(), param_env, impl_ty, self_ty).is_err()
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
// Check whether the impl imposes obligations we have to worry about.
|
// Check whether the impl imposes obligations we have to worry about.
|
||||||
let impl_bounds = tcx.predicates_of(impl_);
|
let impl_bounds = tcx.predicates_of(impl_).instantiate(tcx, impl_substs);
|
||||||
let impl_bounds = impl_bounds.instantiate(tcx, impl_substs);
|
|
||||||
|
|
||||||
let impl_bounds = ocx.normalize(&cause, param_env, impl_bounds);
|
let impl_bounds = ocx.normalize(&cause, param_env, impl_bounds);
|
||||||
|
|
||||||
let impl_obligations = traits::predicates_for_generics(
|
let impl_obligations = traits::predicates_for_generics(
|
||||||
|_, _| cause.clone(),
|
|_, _| cause.clone(),
|
||||||
param_env,
|
param_env,
|
||||||
impl_bounds,
|
impl_bounds,
|
||||||
);
|
);
|
||||||
|
|
||||||
ocx.register_obligations(impl_obligations);
|
ocx.register_obligations(impl_obligations);
|
||||||
|
|
||||||
let mut errors = ocx.select_where_possible();
|
let mut errors = ocx.select_where_possible();
|
||||||
if !errors.is_empty() {
|
if !errors.is_empty() {
|
||||||
fulfillment_errors.append(&mut errors);
|
fulfillment_errors.append(&mut errors);
|
||||||
return None;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// FIXME(fmease): Unsolved vars can escape this InferCtxt snapshot.
|
true
|
||||||
Some((assoc_item, def_scope, infcx.resolve_vars_if_possible(impl_substs)))
|
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
.collect()
|
.collect()
|
||||||
@ -2497,24 +2504,26 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
|
|||||||
if applicable_candidates.len() > 1 {
|
if applicable_candidates.len() > 1 {
|
||||||
return Err(self.complain_about_ambiguous_inherent_assoc_type(
|
return Err(self.complain_about_ambiguous_inherent_assoc_type(
|
||||||
name,
|
name,
|
||||||
applicable_candidates.into_iter().map(|(candidate, ..)| candidate).collect(),
|
applicable_candidates.into_iter().map(|(_, (candidate, _))| candidate).collect(),
|
||||||
span,
|
span,
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some((assoc_item, def_scope, impl_substs)) = applicable_candidates.pop() {
|
if let Some((impl_, (assoc_item, def_scope))) = applicable_candidates.pop() {
|
||||||
self.check_assoc_ty(assoc_item, name, def_scope, block, span);
|
self.check_assoc_ty(assoc_item, name, def_scope, block, span);
|
||||||
|
|
||||||
// FIXME(inherent_associated_types): To fully *confirm* the *probed* candidate, we still
|
// FIXME(fmease): Currently creating throwaway `parent_substs` to please
|
||||||
// need to relate the Self-type with fresh item substs & register region obligations for
|
// `create_substs_for_associated_item`. Modify the latter instead (or sth. similar) to
|
||||||
// regionck to prove/disprove.
|
// not require the parent substs logic.
|
||||||
|
let parent_substs = InternalSubsts::identity_for_item(tcx, impl_);
|
||||||
|
let substs =
|
||||||
|
self.create_substs_for_associated_item(span, assoc_item, segment, parent_substs);
|
||||||
|
let substs = tcx.mk_substs_from_iter(
|
||||||
|
std::iter::once(ty::GenericArg::from(self_ty))
|
||||||
|
.chain(substs.into_iter().skip(parent_substs.len())),
|
||||||
|
);
|
||||||
|
|
||||||
let item_substs =
|
let ty = tcx.mk_alias(ty::Inherent, tcx.mk_alias_ty(assoc_item, substs));
|
||||||
self.create_substs_for_associated_item(span, assoc_item, segment, impl_substs);
|
|
||||||
|
|
||||||
// FIXME(fmease, #106722): Check if the bounds on the parameters of the
|
|
||||||
// associated type hold, if any.
|
|
||||||
let ty = tcx.type_of(assoc_item).subst(tcx, item_substs);
|
|
||||||
|
|
||||||
return Ok(Some((ty, assoc_item)));
|
return Ok(Some((ty, assoc_item)));
|
||||||
}
|
}
|
||||||
|
@ -210,6 +210,19 @@ fn do_orphan_check_impl<'tcx>(
|
|||||||
NonlocalImpl::DisallowOther,
|
NonlocalImpl::DisallowOther,
|
||||||
),
|
),
|
||||||
|
|
||||||
|
// ```
|
||||||
|
// struct S<T>(T);
|
||||||
|
// impl<T: ?Sized> S<T> {
|
||||||
|
// type This = T;
|
||||||
|
// }
|
||||||
|
// impl<T: ?Sized> AutoTrait for S<T>::This {}
|
||||||
|
// ```
|
||||||
|
// FIXME(inherent_associated_types): The example code above currently leads to a cycle
|
||||||
|
ty::Alias(AliasKind::Inherent, _) => (
|
||||||
|
LocalImpl::Disallow { problematic_kind: "associated type" },
|
||||||
|
NonlocalImpl::DisallowOther,
|
||||||
|
),
|
||||||
|
|
||||||
// type Opaque = impl Trait;
|
// type Opaque = impl Trait;
|
||||||
// impl AutoTrait for Opaque {}
|
// impl AutoTrait for Opaque {}
|
||||||
ty::Alias(AliasKind::Opaque, _) => (
|
ty::Alias(AliasKind::Opaque, _) => (
|
||||||
|
@ -1948,7 +1948,7 @@ fn is_late_bound_map(
|
|||||||
ty::Param(param_ty) => {
|
ty::Param(param_ty) => {
|
||||||
self.arg_is_constrained[param_ty.index as usize] = true;
|
self.arg_is_constrained[param_ty.index as usize] = true;
|
||||||
}
|
}
|
||||||
ty::Alias(ty::Projection, _) => return ControlFlow::Continue(()),
|
ty::Alias(ty::Projection | ty::Inherent, _) => return ControlFlow::Continue(()),
|
||||||
_ => (),
|
_ => (),
|
||||||
}
|
}
|
||||||
t.super_visit_with(self)
|
t.super_visit_with(self)
|
||||||
|
@ -127,7 +127,7 @@ fn anon_const_type_of<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> Ty<'tcx> {
|
|||||||
// the def_id that this query was called with. We filter to only type and const args here
|
// the def_id that this query was called with. We filter to only type and const args here
|
||||||
// as a precaution for if it's ever allowed to elide lifetimes in GAT's. It currently isn't
|
// as a precaution for if it's ever allowed to elide lifetimes in GAT's. It currently isn't
|
||||||
// but it can't hurt to be safe ^^
|
// but it can't hurt to be safe ^^
|
||||||
if let ty::Alias(ty::Projection, projection) = ty.kind() {
|
if let ty::Alias(ty::Projection | ty::Inherent, projection) = ty.kind() {
|
||||||
let generics = tcx.generics_of(projection.def_id);
|
let generics = tcx.generics_of(projection.def_id);
|
||||||
|
|
||||||
let arg_index = segment
|
let arg_index = segment
|
||||||
|
@ -59,7 +59,7 @@ struct ParameterCollector {
|
|||||||
impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for ParameterCollector {
|
impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for ParameterCollector {
|
||||||
fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
|
fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
|
||||||
match *t.kind() {
|
match *t.kind() {
|
||||||
ty::Alias(ty::Projection, ..) if !self.include_nonconstraining => {
|
ty::Alias(ty::Projection | ty::Inherent, ..) if !self.include_nonconstraining => {
|
||||||
// projections are not injective
|
// projections are not injective
|
||||||
return ControlFlow::Continue(());
|
return ControlFlow::Continue(());
|
||||||
}
|
}
|
||||||
|
@ -210,6 +210,9 @@ fn insert_required_predicates_to_be_wf<'tcx>(
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// FIXME(inherent_associated_types): Handle this case properly.
|
||||||
|
ty::Alias(ty::Inherent, _) => {}
|
||||||
|
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -843,7 +843,7 @@ fn find_param_in_ty<'tcx>(
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if let ty::GenericArgKind::Type(ty) = arg.unpack()
|
if let ty::GenericArgKind::Type(ty) = arg.unpack()
|
||||||
&& let ty::Alias(ty::Projection, ..) = ty.kind()
|
&& let ty::Alias(ty::Projection | ty::Inherent, ..) = ty.kind()
|
||||||
{
|
{
|
||||||
// This logic may seem a bit strange, but typically when
|
// This logic may seem a bit strange, but typically when
|
||||||
// we have a projection type in a function signature, the
|
// we have a projection type in a function signature, the
|
||||||
|
@ -300,7 +300,7 @@ impl<'a, 'tcx> AstConv<'tcx> for FnCtxt<'a, 'tcx> {
|
|||||||
match ty.kind() {
|
match ty.kind() {
|
||||||
ty::Adt(adt_def, _) => Some(*adt_def),
|
ty::Adt(adt_def, _) => Some(*adt_def),
|
||||||
// FIXME(#104767): Should we handle bound regions here?
|
// FIXME(#104767): Should we handle bound regions here?
|
||||||
ty::Alias(ty::Projection, _) if !ty.has_escaping_bound_vars() => {
|
ty::Alias(ty::Projection | ty::Inherent, _) if !ty.has_escaping_bound_vars() => {
|
||||||
self.normalize(span, ty).ty_adt_def()
|
self.normalize(span, ty).ty_adt_def()
|
||||||
}
|
}
|
||||||
_ => None,
|
_ => None,
|
||||||
|
@ -2211,7 +2211,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||||||
| ty::Float(_)
|
| ty::Float(_)
|
||||||
| ty::Adt(_, _)
|
| ty::Adt(_, _)
|
||||||
| ty::Str
|
| ty::Str
|
||||||
| ty::Alias(ty::Projection, _)
|
| ty::Alias(ty::Projection | ty::Inherent, _)
|
||||||
| ty::Param(_) => format!("{deref_ty}"),
|
| ty::Param(_) => format!("{deref_ty}"),
|
||||||
// we need to test something like <&[_]>::len or <(&[u32])>::len
|
// we need to test something like <&[_]>::len or <(&[u32])>::len
|
||||||
// and Vec::function();
|
// and Vec::function();
|
||||||
|
@ -127,7 +127,8 @@ impl<'tcx> InferCtxt<'tcx> {
|
|||||||
bug!()
|
bug!()
|
||||||
}
|
}
|
||||||
|
|
||||||
(_, ty::Alias(AliasKind::Projection, _)) | (ty::Alias(AliasKind::Projection, _), _)
|
(_, ty::Alias(AliasKind::Projection | AliasKind::Inherent, _))
|
||||||
|
| (ty::Alias(AliasKind::Projection | AliasKind::Inherent, _), _)
|
||||||
if self.tcx.trait_solver_next() =>
|
if self.tcx.trait_solver_next() =>
|
||||||
{
|
{
|
||||||
relation.register_type_relate_obligation(a, b);
|
relation.register_type_relate_obligation(a, b);
|
||||||
|
@ -2354,7 +2354,9 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
|
|||||||
let labeled_user_string = match bound_kind {
|
let labeled_user_string = match bound_kind {
|
||||||
GenericKind::Param(ref p) => format!("the parameter type `{}`", p),
|
GenericKind::Param(ref p) => format!("the parameter type `{}`", p),
|
||||||
GenericKind::Alias(ref p) => match p.kind(self.tcx) {
|
GenericKind::Alias(ref p) => match p.kind(self.tcx) {
|
||||||
ty::AliasKind::Projection => format!("the associated type `{}`", p),
|
ty::AliasKind::Projection | ty::AliasKind::Inherent => {
|
||||||
|
format!("the associated type `{}`", p)
|
||||||
|
}
|
||||||
ty::AliasKind::Opaque => format!("the opaque type `{}`", p),
|
ty::AliasKind::Opaque => format!("the opaque type `{}`", p),
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
@ -71,9 +71,10 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
|
|||||||
#traits-as-parameters",
|
#traits-as-parameters",
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
(ty::Alias(ty::Projection, _), ty::Alias(ty::Projection, _)) => {
|
(ty::Alias(ty::Projection | ty::Inherent, _), ty::Alias(ty::Projection | ty::Inherent, _)) => {
|
||||||
diag.note("an associated type was expected, but a different one was found");
|
diag.note("an associated type was expected, but a different one was found");
|
||||||
}
|
}
|
||||||
|
// FIXME(inherent_associated_types): Extend this to support `ty::Inherent`, too.
|
||||||
(ty::Param(p), ty::Alias(ty::Projection, proj)) | (ty::Alias(ty::Projection, proj), ty::Param(p))
|
(ty::Param(p), ty::Alias(ty::Projection, proj)) | (ty::Alias(ty::Projection, proj), ty::Param(p))
|
||||||
if !tcx.is_impl_trait_in_trait(proj.def_id) =>
|
if !tcx.is_impl_trait_in_trait(proj.def_id) =>
|
||||||
{
|
{
|
||||||
@ -222,7 +223,7 @@ impl<T> Trait<T> for X {
|
|||||||
diag.span_label(p_span, "this type parameter");
|
diag.span_label(p_span, "this type parameter");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
(ty::Alias(ty::Projection, proj_ty), _) if !tcx.is_impl_trait_in_trait(proj_ty.def_id) => {
|
(ty::Alias(ty::Projection | ty::Inherent, proj_ty), _) if !tcx.is_impl_trait_in_trait(proj_ty.def_id) => {
|
||||||
self.expected_projection(
|
self.expected_projection(
|
||||||
diag,
|
diag,
|
||||||
proj_ty,
|
proj_ty,
|
||||||
@ -231,7 +232,7 @@ impl<T> Trait<T> for X {
|
|||||||
cause.code(),
|
cause.code(),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
(_, ty::Alias(ty::Projection, proj_ty)) if !tcx.is_impl_trait_in_trait(proj_ty.def_id) => {
|
(_, ty::Alias(ty::Projection | ty::Inherent, proj_ty)) if !tcx.is_impl_trait_in_trait(proj_ty.def_id) => {
|
||||||
let msg = format!(
|
let msg = format!(
|
||||||
"consider constraining the associated type `{}` to `{}`",
|
"consider constraining the associated type `{}` to `{}`",
|
||||||
values.found, values.expected,
|
values.found, values.expected,
|
||||||
|
@ -549,6 +549,7 @@ impl<'tcx> InferCtxt<'tcx> {
|
|||||||
// We can't normalize associated types from `rustc_infer`,
|
// We can't normalize associated types from `rustc_infer`,
|
||||||
// but we can eagerly register inference variables for them.
|
// but we can eagerly register inference variables for them.
|
||||||
// FIXME(RPITIT): Don't replace RPITITs with inference vars.
|
// FIXME(RPITIT): Don't replace RPITITs with inference vars.
|
||||||
|
// FIXME(inherent_associated_types): Extend this to support `ty::Inherent`, too.
|
||||||
ty::Alias(ty::Projection, projection_ty)
|
ty::Alias(ty::Projection, projection_ty)
|
||||||
if !projection_ty.has_escaping_bound_vars()
|
if !projection_ty.has_escaping_bound_vars()
|
||||||
&& !tcx.is_impl_trait_in_trait(projection_ty.def_id) =>
|
&& !tcx.is_impl_trait_in_trait(projection_ty.def_id) =>
|
||||||
@ -569,6 +570,7 @@ impl<'tcx> InferCtxt<'tcx> {
|
|||||||
hidden_ty
|
hidden_ty
|
||||||
}
|
}
|
||||||
// FIXME(RPITIT): This can go away when we move to associated types
|
// FIXME(RPITIT): This can go away when we move to associated types
|
||||||
|
// FIXME(inherent_associated_types): Extend this to support `ty::Inherent`, too.
|
||||||
ty::Alias(
|
ty::Alias(
|
||||||
ty::Projection,
|
ty::Projection,
|
||||||
ty::AliasTy { def_id: def_id2, substs: substs2, .. },
|
ty::AliasTy { def_id: def_id2, substs: substs2, .. },
|
||||||
|
@ -62,6 +62,7 @@ use rustc_middle::lint::in_external_macro;
|
|||||||
use rustc_middle::ty::layout::{LayoutError, LayoutOf};
|
use rustc_middle::ty::layout::{LayoutError, LayoutOf};
|
||||||
use rustc_middle::ty::print::with_no_trimmed_paths;
|
use rustc_middle::ty::print::with_no_trimmed_paths;
|
||||||
use rustc_middle::ty::subst::GenericArgKind;
|
use rustc_middle::ty::subst::GenericArgKind;
|
||||||
|
use rustc_middle::ty::TypeVisitableExt;
|
||||||
use rustc_middle::ty::{self, Instance, Ty, TyCtxt, VariantDef};
|
use rustc_middle::ty::{self, Instance, Ty, TyCtxt, VariantDef};
|
||||||
use rustc_session::config::ExpectedValues;
|
use rustc_session::config::ExpectedValues;
|
||||||
use rustc_session::lint::{BuiltinLintDiagnostics, FutureIncompatibilityReason};
|
use rustc_session::lint::{BuiltinLintDiagnostics, FutureIncompatibilityReason};
|
||||||
@ -1442,6 +1443,10 @@ impl<'tcx> LateLintPass<'tcx> for TypeAliasBounds {
|
|||||||
// Bounds are respected for `type X = impl Trait`
|
// Bounds are respected for `type X = impl Trait`
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
if cx.tcx.type_of(item.owner_id).skip_binder().has_inherent_projections() {
|
||||||
|
// Bounds are respected for `type X = … Type::Inherent …`
|
||||||
|
return;
|
||||||
|
}
|
||||||
// There must not be a where clause
|
// There must not be a where clause
|
||||||
if type_alias_generics.predicates.is_empty() {
|
if type_alias_generics.predicates.is_empty() {
|
||||||
return;
|
return;
|
||||||
@ -1561,7 +1566,6 @@ declare_lint_pass!(
|
|||||||
|
|
||||||
impl<'tcx> LateLintPass<'tcx> for TrivialConstraints {
|
impl<'tcx> LateLintPass<'tcx> for TrivialConstraints {
|
||||||
fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::Item<'tcx>) {
|
fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::Item<'tcx>) {
|
||||||
use rustc_middle::ty::visit::TypeVisitableExt;
|
|
||||||
use rustc_middle::ty::Clause;
|
use rustc_middle::ty::Clause;
|
||||||
use rustc_middle::ty::PredicateKind::*;
|
use rustc_middle::ty::PredicateKind::*;
|
||||||
|
|
||||||
@ -2898,6 +2902,7 @@ impl ClashingExternDeclarations {
|
|||||||
| (Generator(..), Generator(..))
|
| (Generator(..), Generator(..))
|
||||||
| (GeneratorWitness(..), GeneratorWitness(..))
|
| (GeneratorWitness(..), GeneratorWitness(..))
|
||||||
| (Alias(ty::Projection, ..), Alias(ty::Projection, ..))
|
| (Alias(ty::Projection, ..), Alias(ty::Projection, ..))
|
||||||
|
| (Alias(ty::Inherent, ..), Alias(ty::Inherent, ..))
|
||||||
| (Alias(ty::Opaque, ..), Alias(ty::Opaque, ..)) => false,
|
| (Alias(ty::Opaque, ..), Alias(ty::Opaque, ..)) => false,
|
||||||
|
|
||||||
// These definitely should have been caught above.
|
// These definitely should have been caught above.
|
||||||
|
@ -1119,14 +1119,14 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
|
|||||||
|
|
||||||
// `extern "C" fn` functions can have type parameters, which may or may not be FFI-safe,
|
// `extern "C" fn` functions can have type parameters, which may or may not be FFI-safe,
|
||||||
// so they are currently ignored for the purposes of this lint.
|
// so they are currently ignored for the purposes of this lint.
|
||||||
ty::Param(..) | ty::Alias(ty::Projection, ..)
|
ty::Param(..) | ty::Alias(ty::Projection | ty::Inherent, ..)
|
||||||
if matches!(self.mode, CItemKind::Definition) =>
|
if matches!(self.mode, CItemKind::Definition) =>
|
||||||
{
|
{
|
||||||
FfiSafe
|
FfiSafe
|
||||||
}
|
}
|
||||||
|
|
||||||
ty::Param(..)
|
ty::Param(..)
|
||||||
| ty::Alias(ty::Projection, ..)
|
| ty::Alias(ty::Projection | ty::Inherent, ..)
|
||||||
| ty::Infer(..)
|
| ty::Infer(..)
|
||||||
| ty::Bound(..)
|
| ty::Bound(..)
|
||||||
| ty::Error(_)
|
| ty::Error(_)
|
||||||
|
@ -9,7 +9,7 @@ use crate::diagnostics::utils::{
|
|||||||
FieldInnerTy, FieldMap, HasFieldMap, SetOnce, SpannedOption, SubdiagnosticKind,
|
FieldInnerTy, FieldMap, HasFieldMap, SetOnce, SpannedOption, SubdiagnosticKind,
|
||||||
};
|
};
|
||||||
use proc_macro2::{Ident, Span, TokenStream};
|
use proc_macro2::{Ident, Span, TokenStream};
|
||||||
use quote::{format_ident, quote};
|
use quote::{format_ident, quote, quote_spanned};
|
||||||
use syn::Token;
|
use syn::Token;
|
||||||
use syn::{parse_quote, spanned::Spanned, Attribute, Meta, Path, Type};
|
use syn::{parse_quote, spanned::Spanned, Attribute, Meta, Path, Type};
|
||||||
use synstructure::{BindingInfo, Structure, VariantInfo};
|
use synstructure::{BindingInfo, Structure, VariantInfo};
|
||||||
@ -251,7 +251,8 @@ impl<'a> DiagnosticDeriveVariantBuilder<'a> {
|
|||||||
let diag = &self.parent.diag;
|
let diag = &self.parent.diag;
|
||||||
|
|
||||||
let field = binding_info.ast();
|
let field = binding_info.ast();
|
||||||
let field_binding = &binding_info.binding;
|
let mut field_binding = binding_info.binding.clone();
|
||||||
|
field_binding.set_span(field.ty.span());
|
||||||
|
|
||||||
let ident = field.ident.as_ref().unwrap();
|
let ident = field.ident.as_ref().unwrap();
|
||||||
let ident = format_ident!("{}", ident); // strip `r#` prefix, if present
|
let ident = format_ident!("{}", ident); // strip `r#` prefix, if present
|
||||||
@ -284,9 +285,9 @@ impl<'a> DiagnosticDeriveVariantBuilder<'a> {
|
|||||||
name == "primary_span" && matches!(inner_ty, FieldInnerTy::Vec(_));
|
name == "primary_span" && matches!(inner_ty, FieldInnerTy::Vec(_));
|
||||||
let (binding, needs_destructure) = if needs_clone {
|
let (binding, needs_destructure) = if needs_clone {
|
||||||
// `primary_span` can accept a `Vec<Span>` so don't destructure that.
|
// `primary_span` can accept a `Vec<Span>` so don't destructure that.
|
||||||
(quote! { #field_binding.clone() }, false)
|
(quote_spanned! {inner_ty.span()=> #field_binding.clone() }, false)
|
||||||
} else {
|
} else {
|
||||||
(quote! { #field_binding }, true)
|
(quote_spanned! {inner_ty.span()=> #field_binding }, true)
|
||||||
};
|
};
|
||||||
|
|
||||||
let generated_code = self
|
let generated_code = self
|
||||||
|
@ -4,17 +4,16 @@ use crate::diagnostics::error::{
|
|||||||
invalid_attr, span_err, throw_invalid_attr, throw_span_err, DiagnosticDeriveError,
|
invalid_attr, span_err, throw_invalid_attr, throw_span_err, DiagnosticDeriveError,
|
||||||
};
|
};
|
||||||
use crate::diagnostics::utils::{
|
use crate::diagnostics::utils::{
|
||||||
build_field_mapping, is_doc_comment, new_code_ident,
|
build_field_mapping, build_suggestion_code, is_doc_comment, new_code_ident,
|
||||||
report_error_if_not_applied_to_applicability, report_error_if_not_applied_to_span, FieldInfo,
|
report_error_if_not_applied_to_applicability, report_error_if_not_applied_to_span,
|
||||||
FieldInnerTy, FieldMap, HasFieldMap, SetOnce, SpannedOption, SubdiagnosticKind,
|
should_generate_set_arg, AllowMultipleAlternatives, FieldInfo, FieldInnerTy, FieldMap,
|
||||||
|
HasFieldMap, SetOnce, SpannedOption, SubdiagnosticKind,
|
||||||
};
|
};
|
||||||
use proc_macro2::TokenStream;
|
use proc_macro2::TokenStream;
|
||||||
use quote::{format_ident, quote};
|
use quote::{format_ident, quote};
|
||||||
use syn::{spanned::Spanned, Attribute, Meta, MetaList, Path};
|
use syn::{spanned::Spanned, Attribute, Meta, MetaList, Path};
|
||||||
use synstructure::{BindingInfo, Structure, VariantInfo};
|
use synstructure::{BindingInfo, Structure, VariantInfo};
|
||||||
|
|
||||||
use super::utils::{build_suggestion_code, AllowMultipleAlternatives};
|
|
||||||
|
|
||||||
/// The central struct for constructing the `add_to_diagnostic` method from an annotated struct.
|
/// The central struct for constructing the `add_to_diagnostic` method from an annotated struct.
|
||||||
pub(crate) struct SubdiagnosticDeriveBuilder {
|
pub(crate) struct SubdiagnosticDeriveBuilder {
|
||||||
diag: syn::Ident,
|
diag: syn::Ident,
|
||||||
@ -210,19 +209,20 @@ impl<'parent, 'a> SubdiagnosticDeriveVariantBuilder<'parent, 'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Generates the code for a field with no attributes.
|
/// Generates the code for a field with no attributes.
|
||||||
fn generate_field_set_arg(&mut self, binding: &BindingInfo<'_>) -> TokenStream {
|
fn generate_field_set_arg(&mut self, binding_info: &BindingInfo<'_>) -> TokenStream {
|
||||||
let ast = binding.ast();
|
|
||||||
assert_eq!(ast.attrs.len(), 0, "field with attribute used as diagnostic arg");
|
|
||||||
|
|
||||||
let diag = &self.parent.diag;
|
let diag = &self.parent.diag;
|
||||||
let ident = ast.ident.as_ref().unwrap();
|
|
||||||
// strip `r#` prefix, if present
|
let field = binding_info.ast();
|
||||||
let ident = format_ident!("{}", ident);
|
let mut field_binding = binding_info.binding.clone();
|
||||||
|
field_binding.set_span(field.ty.span());
|
||||||
|
|
||||||
|
let ident = field.ident.as_ref().unwrap();
|
||||||
|
let ident = format_ident!("{}", ident); // strip `r#` prefix, if present
|
||||||
|
|
||||||
quote! {
|
quote! {
|
||||||
#diag.set_arg(
|
#diag.set_arg(
|
||||||
stringify!(#ident),
|
stringify!(#ident),
|
||||||
#binding
|
#field_binding
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -399,7 +399,8 @@ impl<'parent, 'a> SubdiagnosticDeriveVariantBuilder<'parent, 'a> {
|
|||||||
clone_suggestion_code: bool,
|
clone_suggestion_code: bool,
|
||||||
) -> Result<TokenStream, DiagnosticDeriveError> {
|
) -> Result<TokenStream, DiagnosticDeriveError> {
|
||||||
let span = attr.span().unwrap();
|
let span = attr.span().unwrap();
|
||||||
let ident = &list.path.segments.last().unwrap().ident;
|
let mut ident = list.path.segments.last().unwrap().ident.clone();
|
||||||
|
ident.set_span(info.ty.span());
|
||||||
let name = ident.to_string();
|
let name = ident.to_string();
|
||||||
let name = name.as_str();
|
let name = name.as_str();
|
||||||
|
|
||||||
@ -498,7 +499,7 @@ impl<'parent, 'a> SubdiagnosticDeriveVariantBuilder<'parent, 'a> {
|
|||||||
.variant
|
.variant
|
||||||
.bindings()
|
.bindings()
|
||||||
.iter()
|
.iter()
|
||||||
.filter(|binding| !binding.ast().attrs.is_empty())
|
.filter(|binding| !should_generate_set_arg(binding.ast()))
|
||||||
.map(|binding| self.generate_field_attr_code(binding, kind_stats))
|
.map(|binding| self.generate_field_attr_code(binding, kind_stats))
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
@ -580,7 +581,7 @@ impl<'parent, 'a> SubdiagnosticDeriveVariantBuilder<'parent, 'a> {
|
|||||||
.variant
|
.variant
|
||||||
.bindings()
|
.bindings()
|
||||||
.iter()
|
.iter()
|
||||||
.filter(|binding| binding.ast().attrs.is_empty())
|
.filter(|binding| should_generate_set_arg(binding.ast()))
|
||||||
.map(|binding| self.generate_field_set_arg(binding))
|
.map(|binding| self.generate_field_set_arg(binding))
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
|
@ -207,6 +207,12 @@ impl<'ty> FieldInnerTy<'ty> {
|
|||||||
FieldInnerTy::Plain(..) => quote! { #inner },
|
FieldInnerTy::Plain(..) => quote! { #inner },
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn span(&self) -> proc_macro2::Span {
|
||||||
|
match self {
|
||||||
|
FieldInnerTy::Option(ty) | FieldInnerTy::Vec(ty) | FieldInnerTy::Plain(ty) => ty.span(),
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Field information passed to the builder. Deliberately omits attrs to discourage the
|
/// Field information passed to the builder. Deliberately omits attrs to discourage the
|
||||||
@ -851,7 +857,8 @@ impl quote::IdentFragment for SubdiagnosticKind {
|
|||||||
/// Returns `true` if `field` should generate a `set_arg` call rather than any other diagnostic
|
/// Returns `true` if `field` should generate a `set_arg` call rather than any other diagnostic
|
||||||
/// call (like `span_label`).
|
/// call (like `span_label`).
|
||||||
pub(super) fn should_generate_set_arg(field: &Field) -> bool {
|
pub(super) fn should_generate_set_arg(field: &Field) -> bool {
|
||||||
field.attrs.is_empty()
|
// Perhaps this should be an exhaustive list...
|
||||||
|
field.attrs.iter().all(|attr| is_doc_comment(attr))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(super) fn is_doc_comment(attr: &Attribute) -> bool {
|
pub(super) fn is_doc_comment(attr: &Attribute) -> bool {
|
||||||
|
@ -1821,6 +1821,16 @@ rustc_queries! {
|
|||||||
desc { "normalizing `{}`", goal.value.value }
|
desc { "normalizing `{}`", goal.value.value }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Do not call this query directly: invoke `normalize` instead.
|
||||||
|
query normalize_inherent_projection_ty(
|
||||||
|
goal: CanonicalProjectionGoal<'tcx>
|
||||||
|
) -> Result<
|
||||||
|
&'tcx Canonical<'tcx, canonical::QueryResponse<'tcx, NormalizationResult<'tcx>>>,
|
||||||
|
NoSolution,
|
||||||
|
> {
|
||||||
|
desc { "normalizing `{}`", goal.value.value }
|
||||||
|
}
|
||||||
|
|
||||||
/// Do not call this query directly: invoke `try_normalize_erasing_regions` instead.
|
/// Do not call this query directly: invoke `try_normalize_erasing_regions` instead.
|
||||||
query try_normalize_generic_arg_after_erasing_regions(
|
query try_normalize_generic_arg_after_erasing_regions(
|
||||||
goal: ParamEnvAnd<'tcx, GenericArg<'tcx>>
|
goal: ParamEnvAnd<'tcx, GenericArg<'tcx>>
|
||||||
|
@ -1848,7 +1848,17 @@ impl<'tcx> TyCtxt<'tcx> {
|
|||||||
let substs = substs.into_iter().map(Into::into);
|
let substs = substs.into_iter().map(Into::into);
|
||||||
#[cfg(debug_assertions)]
|
#[cfg(debug_assertions)]
|
||||||
{
|
{
|
||||||
let n = self.generics_of(_def_id).count();
|
let generics = self.generics_of(_def_id);
|
||||||
|
|
||||||
|
let n = if let DefKind::AssocTy = self.def_kind(_def_id)
|
||||||
|
&& let DefKind::Impl { of_trait: false } = self.def_kind(self.parent(_def_id))
|
||||||
|
{
|
||||||
|
// If this is an inherent projection.
|
||||||
|
|
||||||
|
generics.params.len() + 1
|
||||||
|
} else {
|
||||||
|
generics.count()
|
||||||
|
};
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
(n, Some(n)),
|
(n, Some(n)),
|
||||||
substs.size_hint(),
|
substs.size_hint(),
|
||||||
@ -2009,7 +2019,7 @@ impl<'tcx> TyCtxt<'tcx> {
|
|||||||
debug_assert_matches!(
|
debug_assert_matches!(
|
||||||
(kind, self.def_kind(alias_ty.def_id)),
|
(kind, self.def_kind(alias_ty.def_id)),
|
||||||
(ty::Opaque, DefKind::OpaqueTy)
|
(ty::Opaque, DefKind::OpaqueTy)
|
||||||
| (ty::Projection, DefKind::AssocTy)
|
| (ty::Projection | ty::Inherent, DefKind::AssocTy)
|
||||||
| (ty::Opaque | ty::Projection, DefKind::ImplTraitPlaceholder)
|
| (ty::Opaque | ty::Projection, DefKind::ImplTraitPlaceholder)
|
||||||
);
|
);
|
||||||
self.mk_ty_from_kind(Alias(kind, alias_ty))
|
self.mk_ty_from_kind(Alias(kind, alias_ty))
|
||||||
|
@ -265,7 +265,7 @@ impl<'tcx> Ty<'tcx> {
|
|||||||
ty::Infer(ty::FreshTy(_)) => "fresh type".into(),
|
ty::Infer(ty::FreshTy(_)) => "fresh type".into(),
|
||||||
ty::Infer(ty::FreshIntTy(_)) => "fresh integral type".into(),
|
ty::Infer(ty::FreshIntTy(_)) => "fresh integral type".into(),
|
||||||
ty::Infer(ty::FreshFloatTy(_)) => "fresh floating-point type".into(),
|
ty::Infer(ty::FreshFloatTy(_)) => "fresh floating-point type".into(),
|
||||||
ty::Alias(ty::Projection, _) => "associated type".into(),
|
ty::Alias(ty::Projection | ty::Inherent, _) => "associated type".into(),
|
||||||
ty::Param(p) => format!("type parameter `{p}`").into(),
|
ty::Param(p) => format!("type parameter `{p}`").into(),
|
||||||
ty::Alias(ty::Opaque, ..) => if tcx.ty_is_opaque_future(self) { "future".into() } else { "opaque type".into() },
|
ty::Alias(ty::Opaque, ..) => if tcx.ty_is_opaque_future(self) { "future".into() } else { "opaque type".into() },
|
||||||
ty::Error(_) => "type error".into(),
|
ty::Error(_) => "type error".into(),
|
||||||
@ -312,7 +312,7 @@ impl<'tcx> Ty<'tcx> {
|
|||||||
ty::Tuple(..) => "tuple".into(),
|
ty::Tuple(..) => "tuple".into(),
|
||||||
ty::Placeholder(..) => "higher-ranked type".into(),
|
ty::Placeholder(..) => "higher-ranked type".into(),
|
||||||
ty::Bound(..) => "bound type variable".into(),
|
ty::Bound(..) => "bound type variable".into(),
|
||||||
ty::Alias(ty::Projection, _) => "associated type".into(),
|
ty::Alias(ty::Projection | ty::Inherent, _) => "associated type".into(),
|
||||||
ty::Param(_) => "type parameter".into(),
|
ty::Param(_) => "type parameter".into(),
|
||||||
ty::Alias(ty::Opaque, ..) => "opaque type".into(),
|
ty::Alias(ty::Opaque, ..) => "opaque type".into(),
|
||||||
}
|
}
|
||||||
|
@ -176,14 +176,14 @@ impl FlagComputation {
|
|||||||
self.add_substs(substs);
|
self.add_substs(substs);
|
||||||
}
|
}
|
||||||
|
|
||||||
&ty::Alias(ty::Projection, data) => {
|
&ty::Alias(kind, data) => {
|
||||||
self.add_flags(TypeFlags::HAS_TY_PROJECTION);
|
self.add_flags(match kind {
|
||||||
self.add_alias_ty(data);
|
ty::Projection => TypeFlags::HAS_TY_PROJECTION,
|
||||||
}
|
ty::Inherent => TypeFlags::HAS_TY_INHERENT,
|
||||||
|
ty::Opaque => TypeFlags::HAS_TY_OPAQUE,
|
||||||
|
});
|
||||||
|
|
||||||
&ty::Alias(ty::Opaque, ty::AliasTy { substs, .. }) => {
|
self.add_alias_ty(data);
|
||||||
self.add_flags(TypeFlags::HAS_TY_OPAQUE);
|
|
||||||
self.add_substs(substs);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
&ty::Dynamic(obj, r, _) => {
|
&ty::Dynamic(obj, r, _) => {
|
||||||
|
@ -113,6 +113,12 @@ impl<'tcx> Ty<'tcx> {
|
|||||||
}
|
}
|
||||||
Never => InhabitedPredicate::False,
|
Never => InhabitedPredicate::False,
|
||||||
Param(_) | Alias(ty::Projection, _) => InhabitedPredicate::GenericType(self),
|
Param(_) | Alias(ty::Projection, _) => InhabitedPredicate::GenericType(self),
|
||||||
|
// FIXME(inherent_associated_types): Most likely we can just map to `GenericType` like above.
|
||||||
|
// However it's unclear if the substs passed to `InhabitedPredicate::subst` are of the correct
|
||||||
|
// format, i.e. don't contain parent substs. If you hit this case, please verify this beforehand.
|
||||||
|
Alias(ty::Inherent, _) => {
|
||||||
|
bug!("unimplemented: inhabitedness checking for inherent projections")
|
||||||
|
}
|
||||||
Tuple(tys) if tys.is_empty() => InhabitedPredicate::True,
|
Tuple(tys) if tys.is_empty() => InhabitedPredicate::True,
|
||||||
// use a query for more complex cases
|
// use a query for more complex cases
|
||||||
Adt(..) | Array(..) | Tuple(_) => tcx.inhabited_predicate_type(self),
|
Adt(..) | Array(..) | Tuple(_) => tcx.inhabited_predicate_type(self),
|
||||||
|
@ -324,7 +324,7 @@ impl<'tcx> SizeSkeleton<'tcx> {
|
|||||||
let non_zero = !ty.is_unsafe_ptr();
|
let non_zero = !ty.is_unsafe_ptr();
|
||||||
let tail = tcx.struct_tail_erasing_lifetimes(pointee, param_env);
|
let tail = tcx.struct_tail_erasing_lifetimes(pointee, param_env);
|
||||||
match tail.kind() {
|
match tail.kind() {
|
||||||
ty::Param(_) | ty::Alias(ty::Projection, _) => {
|
ty::Param(_) | ty::Alias(ty::Projection | ty::Inherent, _) => {
|
||||||
debug_assert!(tail.has_non_region_param());
|
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_regions(tail) })
|
||||||
}
|
}
|
||||||
|
@ -1004,7 +1004,7 @@ impl<'tcx> Term<'tcx> {
|
|||||||
match self.unpack() {
|
match self.unpack() {
|
||||||
TermKind::Ty(ty) => match ty.kind() {
|
TermKind::Ty(ty) => match ty.kind() {
|
||||||
ty::Alias(kind, alias_ty) => match kind {
|
ty::Alias(kind, alias_ty) => match kind {
|
||||||
AliasKind::Projection => Some(*alias_ty),
|
AliasKind::Projection | AliasKind::Inherent => Some(*alias_ty),
|
||||||
AliasKind::Opaque => None,
|
AliasKind::Opaque => None,
|
||||||
},
|
},
|
||||||
_ => None,
|
_ => None,
|
||||||
|
@ -729,7 +729,7 @@ pub trait PrettyPrinter<'tcx>:
|
|||||||
ty::Foreign(def_id) => {
|
ty::Foreign(def_id) => {
|
||||||
p!(print_def_path(def_id, &[]));
|
p!(print_def_path(def_id, &[]));
|
||||||
}
|
}
|
||||||
ty::Alias(ty::Projection, ref data) => {
|
ty::Alias(ty::Projection | ty::Inherent, ref data) => {
|
||||||
if !(self.should_print_verbose() || NO_QUERIES.with(|q| q.get()))
|
if !(self.should_print_verbose() || NO_QUERIES.with(|q| q.get()))
|
||||||
&& self.tcx().is_impl_trait_in_trait(data.def_id)
|
&& self.tcx().is_impl_trait_in_trait(data.def_id)
|
||||||
{
|
{
|
||||||
|
@ -550,6 +550,11 @@ pub fn super_relate_tys<'tcx, R: TypeRelation<'tcx>>(
|
|||||||
Ok(tcx.mk_projection(projection_ty.def_id, projection_ty.substs))
|
Ok(tcx.mk_projection(projection_ty.def_id, projection_ty.substs))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
(&ty::Alias(ty::Inherent, a_data), &ty::Alias(ty::Inherent, b_data)) => {
|
||||||
|
let alias_ty = relation.relate(a_data, b_data)?;
|
||||||
|
Ok(tcx.mk_alias(ty::Inherent, tcx.mk_alias_ty(alias_ty.def_id, alias_ty.substs)))
|
||||||
|
}
|
||||||
|
|
||||||
(
|
(
|
||||||
&ty::Alias(ty::Opaque, ty::AliasTy { def_id: a_def_id, substs: a_substs, .. }),
|
&ty::Alias(ty::Opaque, ty::AliasTy { def_id: a_def_id, substs: a_substs, .. }),
|
||||||
&ty::Alias(ty::Opaque, ty::AliasTy { def_id: b_def_id, substs: b_substs, .. }),
|
&ty::Alias(ty::Opaque, ty::AliasTy { def_id: b_def_id, substs: b_substs, .. }),
|
||||||
|
@ -1190,9 +1190,9 @@ where
|
|||||||
|
|
||||||
/// Represents the projection of an associated type.
|
/// Represents the projection of an associated type.
|
||||||
///
|
///
|
||||||
/// For a projection, this would be `<Ty as Trait<...>>::N`.
|
/// * For a projection, this would be `<Ty as Trait<...>>::N<...>`.
|
||||||
///
|
/// * For an inherent projection, this would be `Ty::N<...>`.
|
||||||
/// For an opaque type, there is no explicit syntax.
|
/// * For an opaque type, there is no explicit syntax.
|
||||||
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, TyEncodable, TyDecodable)]
|
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, TyEncodable, TyDecodable)]
|
||||||
#[derive(HashStable, TypeFoldable, TypeVisitable, Lift)]
|
#[derive(HashStable, TypeFoldable, TypeVisitable, Lift)]
|
||||||
pub struct AliasTy<'tcx> {
|
pub struct AliasTy<'tcx> {
|
||||||
@ -1201,12 +1201,16 @@ pub struct AliasTy<'tcx> {
|
|||||||
/// For a projection, these are the substitutions for the trait and the
|
/// For a projection, these are the substitutions for the trait and the
|
||||||
/// GAT substitutions, if there are any.
|
/// GAT substitutions, if there are any.
|
||||||
///
|
///
|
||||||
|
/// For an inherent projection, they consist of the self type and the GAT substitutions,
|
||||||
|
/// if there are any.
|
||||||
|
///
|
||||||
/// For RPIT the substitutions are for the generics of the function,
|
/// For RPIT the substitutions are for the generics of the function,
|
||||||
/// while for TAIT it is used for the generic parameters of the alias.
|
/// while for TAIT it is used for the generic parameters of the alias.
|
||||||
pub substs: SubstsRef<'tcx>,
|
pub substs: SubstsRef<'tcx>,
|
||||||
|
|
||||||
/// The `DefId` of the `TraitItem` for the associated type `N` if this is a projection,
|
/// The `DefId` of the `TraitItem` or `ImplItem` for the associated type `N` depending on whether
|
||||||
/// or the `OpaqueType` item if this is an opaque.
|
/// this is a projection or an inherent projection or the `DefId` of the `OpaqueType` item if
|
||||||
|
/// this is an opaque.
|
||||||
///
|
///
|
||||||
/// During codegen, `tcx.type_of(def_id)` can be used to get the type of the
|
/// During codegen, `tcx.type_of(def_id)` can be used to get the type of the
|
||||||
/// underlying type if the type is an opaque.
|
/// underlying type if the type is an opaque.
|
||||||
@ -1224,6 +1228,7 @@ pub struct AliasTy<'tcx> {
|
|||||||
impl<'tcx> AliasTy<'tcx> {
|
impl<'tcx> AliasTy<'tcx> {
|
||||||
pub fn kind(self, tcx: TyCtxt<'tcx>) -> ty::AliasKind {
|
pub fn kind(self, tcx: TyCtxt<'tcx>) -> ty::AliasKind {
|
||||||
match tcx.def_kind(self.def_id) {
|
match tcx.def_kind(self.def_id) {
|
||||||
|
DefKind::AssocTy if let DefKind::Impl { of_trait: false } = tcx.def_kind(tcx.parent(self.def_id)) => ty::Inherent,
|
||||||
DefKind::AssocTy | DefKind::ImplTraitPlaceholder => ty::Projection,
|
DefKind::AssocTy | DefKind::ImplTraitPlaceholder => ty::Projection,
|
||||||
DefKind::OpaqueTy => ty::Opaque,
|
DefKind::OpaqueTy => ty::Opaque,
|
||||||
kind => bug!("unexpected DefKind in AliasTy: {kind:?}"),
|
kind => bug!("unexpected DefKind in AliasTy: {kind:?}"),
|
||||||
@ -1236,6 +1241,17 @@ impl<'tcx> AliasTy<'tcx> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// The following methods work only with associated type projections.
|
/// The following methods work only with associated type projections.
|
||||||
|
impl<'tcx> AliasTy<'tcx> {
|
||||||
|
pub fn self_ty(self) -> Ty<'tcx> {
|
||||||
|
self.substs.type_at(0)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn with_self_ty(self, tcx: TyCtxt<'tcx>, self_ty: Ty<'tcx>) -> Self {
|
||||||
|
tcx.mk_alias_ty(self.def_id, [self_ty.into()].into_iter().chain(self.substs.iter().skip(1)))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The following methods work only with trait associated type projections.
|
||||||
impl<'tcx> AliasTy<'tcx> {
|
impl<'tcx> AliasTy<'tcx> {
|
||||||
pub fn trait_def_id(self, tcx: TyCtxt<'tcx>) -> DefId {
|
pub fn trait_def_id(self, tcx: TyCtxt<'tcx>) -> DefId {
|
||||||
match tcx.def_kind(self.def_id) {
|
match tcx.def_kind(self.def_id) {
|
||||||
@ -1274,13 +1290,28 @@ impl<'tcx> AliasTy<'tcx> {
|
|||||||
let def_id = self.trait_def_id(tcx);
|
let def_id = self.trait_def_id(tcx);
|
||||||
ty::TraitRef::new(tcx, def_id, self.substs.truncate_to(tcx, tcx.generics_of(def_id)))
|
ty::TraitRef::new(tcx, def_id, self.substs.truncate_to(tcx, tcx.generics_of(def_id)))
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn self_ty(self) -> Ty<'tcx> {
|
/// The following methods work only with inherent associated type projections.
|
||||||
self.substs.type_at(0)
|
impl<'tcx> AliasTy<'tcx> {
|
||||||
}
|
/// Transform the substitutions to have the given `impl` substs as the base and the GAT substs on top of that.
|
||||||
|
///
|
||||||
|
/// Does the following transformation:
|
||||||
|
///
|
||||||
|
/// ```text
|
||||||
|
/// [Self, P_0...P_m] -> [I_0...I_n, P_0...P_m]
|
||||||
|
///
|
||||||
|
/// I_i impl subst
|
||||||
|
/// P_j GAT subst
|
||||||
|
/// ```
|
||||||
|
pub fn rebase_substs_onto_impl(
|
||||||
|
self,
|
||||||
|
impl_substs: ty::SubstsRef<'tcx>,
|
||||||
|
tcx: TyCtxt<'tcx>,
|
||||||
|
) -> ty::SubstsRef<'tcx> {
|
||||||
|
debug_assert_eq!(self.kind(tcx), ty::Inherent);
|
||||||
|
|
||||||
pub fn with_self_ty(self, tcx: TyCtxt<'tcx>, self_ty: Ty<'tcx>) -> Self {
|
tcx.mk_substs_from_iter(impl_substs.into_iter().chain(self.substs.into_iter().skip(1)))
|
||||||
tcx.mk_alias_ty(self.def_id, [self_ty.into()].into_iter().chain(self.substs.iter().skip(1)))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -49,6 +49,9 @@ pub trait TypeVisitableExt<'tcx>: TypeVisitable<TyCtxt<'tcx>> {
|
|||||||
fn has_projections(&self) -> bool {
|
fn has_projections(&self) -> bool {
|
||||||
self.has_type_flags(TypeFlags::HAS_PROJECTION)
|
self.has_type_flags(TypeFlags::HAS_PROJECTION)
|
||||||
}
|
}
|
||||||
|
fn has_inherent_projections(&self) -> bool {
|
||||||
|
self.has_type_flags(TypeFlags::HAS_TY_INHERENT)
|
||||||
|
}
|
||||||
fn has_opaque_types(&self) -> bool {
|
fn has_opaque_types(&self) -> bool {
|
||||||
self.has_type_flags(TypeFlags::HAS_TY_OPAQUE)
|
self.has_type_flags(TypeFlags::HAS_TY_OPAQUE)
|
||||||
}
|
}
|
||||||
|
@ -24,6 +24,8 @@ rustc_session = { path = "../rustc_session" }
|
|||||||
rustc_target = { path = "../rustc_target" }
|
rustc_target = { path = "../rustc_target" }
|
||||||
rustc_trait_selection = { path = "../rustc_trait_selection" }
|
rustc_trait_selection = { path = "../rustc_trait_selection" }
|
||||||
rustc_span = { path = "../rustc_span" }
|
rustc_span = { path = "../rustc_span" }
|
||||||
|
rustc_fluent_macro = { path = "../rustc_fluent_macro" }
|
||||||
|
rustc_macros = { path = "../rustc_macros" }
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
coverage_test_macros = { path = "src/coverage/test_macros" }
|
coverage_test_macros = { path = "src/coverage/test_macros" }
|
||||||
|
66
compiler/rustc_mir_transform/messages.ftl
Normal file
66
compiler/rustc_mir_transform/messages.ftl
Normal file
@ -0,0 +1,66 @@
|
|||||||
|
mir_transform_const_modify = attempting to modify a `const` item
|
||||||
|
.note = each usage of a `const` item creates a new temporary; the original `const` item will not be modified
|
||||||
|
|
||||||
|
mir_transform_const_mut_borrow = taking a mutable reference to a `const` item
|
||||||
|
.note = each usage of a `const` item creates a new temporary
|
||||||
|
.note2 = the mutable reference will refer to this temporary, not the original `const` item
|
||||||
|
.note3 = mutable reference created due to call to this method
|
||||||
|
|
||||||
|
mir_transform_const_defined_here = `const` item defined here
|
||||||
|
|
||||||
|
mir_transform_unaligned_packed_ref = reference to packed field is unaligned
|
||||||
|
.note = packed structs are only aligned by one byte, and many modern architectures penalize unaligned field accesses
|
||||||
|
.note_ub = creating a misaligned reference is undefined behavior (even if that reference is never dereferenced)
|
||||||
|
.help = copy the field contents to a local variable, or replace the reference with a raw pointer and use `read_unaligned`/`write_unaligned` (loads and stores via `*p` must be properly aligned even when using raw pointers)
|
||||||
|
|
||||||
|
mir_transform_unused_unsafe = unnecessary `unsafe` block
|
||||||
|
.label = because it's nested under this `unsafe` block
|
||||||
|
|
||||||
|
mir_transform_requires_unsafe = {$details} is unsafe and requires unsafe {$op_in_unsafe_fn_allowed ->
|
||||||
|
[true] function or block
|
||||||
|
*[false] block
|
||||||
|
}
|
||||||
|
.not_inherited = items do not inherit unsafety from separate enclosing items
|
||||||
|
|
||||||
|
mir_transform_call_to_unsafe_label = call to unsafe function
|
||||||
|
mir_transform_call_to_unsafe_note = consult the function's documentation for information on how to avoid undefined behavior
|
||||||
|
mir_transform_use_of_asm_label = use of inline assembly
|
||||||
|
mir_transform_use_of_asm_note = inline assembly is entirely unchecked and can cause undefined behavior
|
||||||
|
mir_transform_initializing_valid_range_label = initializing type with `rustc_layout_scalar_valid_range` attr
|
||||||
|
mir_transform_initializing_valid_range_note = initializing a layout restricted type's field with a value outside the valid range is undefined behavior
|
||||||
|
mir_transform_const_ptr2int_label = cast of pointer to int
|
||||||
|
mir_transform_const_ptr2int_note = casting pointers to integers in constants
|
||||||
|
mir_transform_use_of_static_mut_label = use of mutable static
|
||||||
|
mir_transform_use_of_static_mut_note = mutable statics can be mutated by multiple threads: aliasing violations or data races will cause undefined behavior
|
||||||
|
mir_transform_use_of_extern_static_label = use of extern static
|
||||||
|
mir_transform_use_of_extern_static_note = extern statics are not controlled by the Rust type system: invalid data, aliasing violations or data races will cause undefined behavior
|
||||||
|
mir_transform_deref_ptr_label = dereference of raw pointer
|
||||||
|
mir_transform_deref_ptr_note = raw pointers may be null, dangling or unaligned; they can violate aliasing rules and cause data races: all of these are undefined behavior
|
||||||
|
mir_transform_union_access_label = access to union field
|
||||||
|
mir_transform_union_access_note = the field may not be properly initialized: using uninitialized data will cause undefined behavior
|
||||||
|
mir_transform_mutation_layout_constrained_label = mutation of layout constrained field
|
||||||
|
mir_transform_mutation_layout_constrained_note = mutating layout constrained fields cannot statically be checked for valid values
|
||||||
|
mir_transform_mutation_layout_constrained_borrow_label = borrow of layout constrained field with interior mutability
|
||||||
|
mir_transform_mutation_layout_constrained_borrow_note = references to fields of layout constrained fields lose the constraints. Coupled with interior mutability, the field can be changed to invalid values
|
||||||
|
mir_transform_target_feature_call_label = call to function with `#[target_feature]`
|
||||||
|
mir_transform_target_feature_call_note = can only be called if the required target features are available
|
||||||
|
|
||||||
|
mir_transform_unsafe_op_in_unsafe_fn = {$details} is unsafe and requires unsafe block (error E0133)
|
||||||
|
|
||||||
|
mir_transform_arithmetic_overflow = this arithmetic operation will overflow
|
||||||
|
mir_transform_operation_will_panic = this operation will panic at runtime
|
||||||
|
|
||||||
|
mir_transform_ffi_unwind_call = call to {$foreign ->
|
||||||
|
[true] foreign function
|
||||||
|
*[false] function pointer
|
||||||
|
} with FFI-unwind ABI
|
||||||
|
|
||||||
|
mir_transform_fn_item_ref = taking a reference to a function item does not give a function pointer
|
||||||
|
.suggestion = cast `{$ident}` to obtain a function pointer
|
||||||
|
|
||||||
|
mir_transform_must_not_suspend = {$pre}`{$def_path}`{$post} held across a suspend point, but should not be
|
||||||
|
.label = the value is held across this suspend point
|
||||||
|
.note = {$reason}
|
||||||
|
.help = consider using a block (`{"{ ... }"}`) to shrink the value's scope, ending before the suspend point
|
||||||
|
|
||||||
|
mir_transform_simd_shuffle_last_const = last argument of `simd_shuffle` is required to be a `const` item
|
@ -1,11 +1,12 @@
|
|||||||
use rustc_errors::{DiagnosticBuilder, DiagnosticMessage};
|
use rustc_hir::HirId;
|
||||||
use rustc_middle::mir::visit::Visitor;
|
use rustc_middle::mir::visit::Visitor;
|
||||||
use rustc_middle::mir::*;
|
use rustc_middle::mir::*;
|
||||||
use rustc_middle::ty::TyCtxt;
|
use rustc_middle::ty::TyCtxt;
|
||||||
use rustc_session::lint::builtin::CONST_ITEM_MUTATION;
|
use rustc_session::lint::builtin::CONST_ITEM_MUTATION;
|
||||||
use rustc_span::def_id::DefId;
|
use rustc_span::def_id::DefId;
|
||||||
|
use rustc_span::Span;
|
||||||
|
|
||||||
use crate::MirLint;
|
use crate::{errors, MirLint};
|
||||||
|
|
||||||
pub struct CheckConstItemMutation;
|
pub struct CheckConstItemMutation;
|
||||||
|
|
||||||
@ -58,16 +59,14 @@ impl<'tcx> ConstMutationChecker<'_, 'tcx> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn lint_const_item_usage(
|
/// If we should lint on this usage, return the [`HirId`], source [`Span`]
|
||||||
|
/// and [`Span`] of the const item to use in the lint.
|
||||||
|
fn should_lint_const_item_usage(
|
||||||
&self,
|
&self,
|
||||||
place: &Place<'tcx>,
|
place: &Place<'tcx>,
|
||||||
const_item: DefId,
|
const_item: DefId,
|
||||||
location: Location,
|
location: Location,
|
||||||
msg: impl Into<DiagnosticMessage>,
|
) -> Option<(HirId, Span, Span)> {
|
||||||
decorate: impl for<'a, 'b> FnOnce(
|
|
||||||
&'a mut DiagnosticBuilder<'b, ()>,
|
|
||||||
) -> &'a mut DiagnosticBuilder<'b, ()>,
|
|
||||||
) {
|
|
||||||
// Don't lint on borrowing/assigning when a dereference is involved.
|
// Don't lint on borrowing/assigning when a dereference is involved.
|
||||||
// If we 'leave' the temporary via a dereference, we must
|
// If we 'leave' the temporary via a dereference, we must
|
||||||
// be modifying something else
|
// be modifying something else
|
||||||
@ -83,16 +82,9 @@ impl<'tcx> ConstMutationChecker<'_, 'tcx> {
|
|||||||
.assert_crate_local()
|
.assert_crate_local()
|
||||||
.lint_root;
|
.lint_root;
|
||||||
|
|
||||||
self.tcx.struct_span_lint_hir(
|
Some((lint_root, source_info.span, self.tcx.def_span(const_item)))
|
||||||
CONST_ITEM_MUTATION,
|
} else {
|
||||||
lint_root,
|
None
|
||||||
source_info.span,
|
|
||||||
msg,
|
|
||||||
|lint| {
|
|
||||||
decorate(lint)
|
|
||||||
.span_note(self.tcx.def_span(const_item), "`const` item defined here")
|
|
||||||
},
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -104,10 +96,14 @@ impl<'tcx> Visitor<'tcx> for ConstMutationChecker<'_, 'tcx> {
|
|||||||
// Assigning directly to a constant (e.g. `FOO = true;`) is a hard error,
|
// Assigning directly to a constant (e.g. `FOO = true;`) is a hard error,
|
||||||
// so emitting a lint would be redundant.
|
// so emitting a lint would be redundant.
|
||||||
if !lhs.projection.is_empty() {
|
if !lhs.projection.is_empty() {
|
||||||
if let Some(def_id) = self.is_const_item_without_destructor(lhs.local) {
|
if let Some(def_id) = self.is_const_item_without_destructor(lhs.local)
|
||||||
self.lint_const_item_usage(&lhs, def_id, loc, "attempting to modify a `const` item",|lint| {
|
&& let Some((lint_root, span, item)) = self.should_lint_const_item_usage(&lhs, def_id, loc) {
|
||||||
lint.note("each usage of a `const` item creates a new temporary; the original `const` item will not be modified")
|
self.tcx.emit_spanned_lint(
|
||||||
})
|
CONST_ITEM_MUTATION,
|
||||||
|
lint_root,
|
||||||
|
span,
|
||||||
|
errors::ConstMutate::Modify { konst: item }
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// We are looking for MIR of the form:
|
// We are looking for MIR of the form:
|
||||||
@ -143,17 +139,22 @@ impl<'tcx> Visitor<'tcx> for ConstMutationChecker<'_, 'tcx> {
|
|||||||
});
|
});
|
||||||
let lint_loc =
|
let lint_loc =
|
||||||
if method_did.is_some() { self.body.terminator_loc(loc.block) } else { loc };
|
if method_did.is_some() { self.body.terminator_loc(loc.block) } else { loc };
|
||||||
self.lint_const_item_usage(place, def_id, lint_loc, "taking a mutable reference to a `const` item", |lint| {
|
|
||||||
lint
|
|
||||||
.note("each usage of a `const` item creates a new temporary")
|
|
||||||
.note("the mutable reference will refer to this temporary, not the original `const` item");
|
|
||||||
|
|
||||||
if let Some((method_did, _substs)) = method_did {
|
let method_call = if let Some((method_did, _)) = method_did {
|
||||||
lint.span_note(self.tcx.def_span(method_did), "mutable reference created due to call to this method");
|
Some(self.tcx.def_span(method_did))
|
||||||
}
|
} else {
|
||||||
|
None
|
||||||
lint
|
};
|
||||||
});
|
if let Some((lint_root, span, item)) =
|
||||||
|
self.should_lint_const_item_usage(place, def_id, lint_loc)
|
||||||
|
{
|
||||||
|
self.tcx.emit_spanned_lint(
|
||||||
|
CONST_ITEM_MUTATION,
|
||||||
|
lint_root,
|
||||||
|
span,
|
||||||
|
errors::ConstMutate::MutBorrow { method_call, konst: item },
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
self.super_rvalue(rvalue, loc);
|
self.super_rvalue(rvalue, loc);
|
||||||
|
@ -1,10 +1,9 @@
|
|||||||
use rustc_errors::struct_span_err;
|
|
||||||
use rustc_middle::mir::visit::{PlaceContext, Visitor};
|
use rustc_middle::mir::visit::{PlaceContext, Visitor};
|
||||||
use rustc_middle::mir::*;
|
use rustc_middle::mir::*;
|
||||||
use rustc_middle::ty::{self, TyCtxt};
|
use rustc_middle::ty::{self, TyCtxt};
|
||||||
|
|
||||||
use crate::util;
|
|
||||||
use crate::MirLint;
|
use crate::MirLint;
|
||||||
|
use crate::{errors, util};
|
||||||
|
|
||||||
pub struct CheckPackedRef;
|
pub struct CheckPackedRef;
|
||||||
|
|
||||||
@ -49,25 +48,7 @@ impl<'tcx> Visitor<'tcx> for PackedRefChecker<'_, 'tcx> {
|
|||||||
// shouldn't do.
|
// shouldn't do.
|
||||||
span_bug!(self.source_info.span, "builtin derive created an unaligned reference");
|
span_bug!(self.source_info.span, "builtin derive created an unaligned reference");
|
||||||
} else {
|
} else {
|
||||||
struct_span_err!(
|
self.tcx.sess.emit_err(errors::UnalignedPackedRef { span: self.source_info.span });
|
||||||
self.tcx.sess,
|
|
||||||
self.source_info.span,
|
|
||||||
E0793,
|
|
||||||
"reference to packed field is unaligned"
|
|
||||||
)
|
|
||||||
.note(
|
|
||||||
"packed structs are only aligned by one byte, and many modern architectures \
|
|
||||||
penalize unaligned field accesses"
|
|
||||||
)
|
|
||||||
.note(
|
|
||||||
"creating a misaligned reference is undefined behavior (even if that \
|
|
||||||
reference is never dereferenced)",
|
|
||||||
).help(
|
|
||||||
"copy the field contents to a local variable, or replace the \
|
|
||||||
reference with a raw pointer and use `read_unaligned`/`write_unaligned` \
|
|
||||||
(loads and stores via `*p` must be properly aligned even when using raw pointers)"
|
|
||||||
)
|
|
||||||
.emit();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
use rustc_data_structures::unord::{UnordItems, UnordSet};
|
use rustc_data_structures::unord::{UnordItems, UnordSet};
|
||||||
use rustc_errors::struct_span_err;
|
|
||||||
use rustc_hir as hir;
|
use rustc_hir as hir;
|
||||||
use rustc_hir::def::DefKind;
|
use rustc_hir::def::DefKind;
|
||||||
use rustc_hir::def_id::{DefId, LocalDefId};
|
use rustc_hir::def_id::{DefId, LocalDefId};
|
||||||
@ -15,6 +14,8 @@ use rustc_session::lint::Level;
|
|||||||
|
|
||||||
use std::ops::Bound;
|
use std::ops::Bound;
|
||||||
|
|
||||||
|
use crate::errors;
|
||||||
|
|
||||||
pub struct UnsafetyChecker<'a, 'tcx> {
|
pub struct UnsafetyChecker<'a, 'tcx> {
|
||||||
body: &'a Body<'tcx>,
|
body: &'a Body<'tcx>,
|
||||||
body_did: LocalDefId,
|
body_did: LocalDefId,
|
||||||
@ -509,21 +510,12 @@ fn unsafety_check_result(tcx: TyCtxt<'_>, def: LocalDefId) -> &UnsafetyCheckResu
|
|||||||
|
|
||||||
fn report_unused_unsafe(tcx: TyCtxt<'_>, kind: UnusedUnsafe, id: HirId) {
|
fn report_unused_unsafe(tcx: TyCtxt<'_>, kind: UnusedUnsafe, id: HirId) {
|
||||||
let span = tcx.sess.source_map().guess_head_span(tcx.hir().span(id));
|
let span = tcx.sess.source_map().guess_head_span(tcx.hir().span(id));
|
||||||
let msg = "unnecessary `unsafe` block";
|
let nested_parent = if let UnusedUnsafe::InUnsafeBlock(id) = kind {
|
||||||
tcx.struct_span_lint_hir(UNUSED_UNSAFE, id, span, msg, |lint| {
|
Some(tcx.sess.source_map().guess_head_span(tcx.hir().span(id)))
|
||||||
lint.span_label(span, msg);
|
} else {
|
||||||
match kind {
|
None
|
||||||
UnusedUnsafe::Unused => {}
|
};
|
||||||
UnusedUnsafe::InUnsafeBlock(id) => {
|
tcx.emit_spanned_lint(UNUSED_UNSAFE, id, span, errors::UnusedUnsafe { span, nested_parent });
|
||||||
lint.span_label(
|
|
||||||
tcx.sess.source_map().guess_head_span(tcx.hir().span(id)),
|
|
||||||
"because it's nested under this `unsafe` block",
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
lint
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn check_unsafety(tcx: TyCtxt<'_>, def_id: LocalDefId) {
|
pub fn check_unsafety(tcx: TyCtxt<'_>, def_id: LocalDefId) {
|
||||||
@ -537,26 +529,11 @@ pub fn check_unsafety(tcx: TyCtxt<'_>, def_id: LocalDefId) {
|
|||||||
let UnsafetyCheckResult { violations, unused_unsafes, .. } = tcx.unsafety_check_result(def_id);
|
let UnsafetyCheckResult { violations, unused_unsafes, .. } = tcx.unsafety_check_result(def_id);
|
||||||
|
|
||||||
for &UnsafetyViolation { source_info, lint_root, kind, details } in violations.iter() {
|
for &UnsafetyViolation { source_info, lint_root, kind, details } in violations.iter() {
|
||||||
let (description, note) = details.description_and_note();
|
let details = errors::RequiresUnsafeDetail { violation: details, span: source_info.span };
|
||||||
|
|
||||||
match kind {
|
match kind {
|
||||||
UnsafetyViolationKind::General => {
|
UnsafetyViolationKind::General => {
|
||||||
// once
|
let op_in_unsafe_fn_allowed = unsafe_op_in_unsafe_fn_allowed(tcx, lint_root);
|
||||||
let unsafe_fn_msg = if unsafe_op_in_unsafe_fn_allowed(tcx, lint_root) {
|
|
||||||
" function or"
|
|
||||||
} else {
|
|
||||||
""
|
|
||||||
};
|
|
||||||
|
|
||||||
let mut err = struct_span_err!(
|
|
||||||
tcx.sess,
|
|
||||||
source_info.span,
|
|
||||||
E0133,
|
|
||||||
"{} is unsafe and requires unsafe{} block",
|
|
||||||
description,
|
|
||||||
unsafe_fn_msg,
|
|
||||||
);
|
|
||||||
err.span_label(source_info.span, description).note(note);
|
|
||||||
let note_non_inherited = tcx.hir().parent_iter(lint_root).find(|(id, node)| {
|
let note_non_inherited = tcx.hir().parent_iter(lint_root).find(|(id, node)| {
|
||||||
if let Node::Expr(block) = node
|
if let Node::Expr(block) = node
|
||||||
&& let ExprKind::Block(block, _) = block.kind
|
&& let ExprKind::Block(block, _) = block.kind
|
||||||
@ -572,22 +549,23 @@ pub fn check_unsafety(tcx: TyCtxt<'_>, def_id: LocalDefId) {
|
|||||||
false
|
false
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
if let Some((id, _)) = note_non_inherited {
|
let enclosing = if let Some((id, _)) = note_non_inherited {
|
||||||
let span = tcx.hir().span(id);
|
Some(tcx.sess.source_map().guess_head_span(tcx.hir().span(id)))
|
||||||
err.span_label(
|
} else {
|
||||||
tcx.sess.source_map().guess_head_span(span),
|
None
|
||||||
"items do not inherit unsafety from separate enclosing items",
|
};
|
||||||
);
|
tcx.sess.emit_err(errors::RequiresUnsafe {
|
||||||
}
|
span: source_info.span,
|
||||||
|
enclosing,
|
||||||
err.emit();
|
details,
|
||||||
|
op_in_unsafe_fn_allowed,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
UnsafetyViolationKind::UnsafeFn => tcx.struct_span_lint_hir(
|
UnsafetyViolationKind::UnsafeFn => tcx.emit_spanned_lint(
|
||||||
UNSAFE_OP_IN_UNSAFE_FN,
|
UNSAFE_OP_IN_UNSAFE_FN,
|
||||||
lint_root,
|
lint_root,
|
||||||
source_info.span,
|
source_info.span,
|
||||||
format!("{} is unsafe and requires unsafe block (error E0133)", description,),
|
errors::UnsafeOpInUnsafeFn { details },
|
||||||
|lint| lint.span_label(source_info.span, description).note(note),
|
|
||||||
),
|
),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,8 @@
|
|||||||
//! Propagates constants for early reporting of statically known
|
//! Propagates constants for early reporting of statically known
|
||||||
//! assertion failures
|
//! assertion failures
|
||||||
|
|
||||||
|
use std::fmt::Debug;
|
||||||
|
|
||||||
use either::Left;
|
use either::Left;
|
||||||
|
|
||||||
use rustc_const_eval::interpret::Immediate;
|
use rustc_const_eval::interpret::Immediate;
|
||||||
@ -17,7 +19,6 @@ use rustc_middle::ty::InternalSubsts;
|
|||||||
use rustc_middle::ty::{
|
use rustc_middle::ty::{
|
||||||
self, ConstInt, Instance, ParamEnv, ScalarInt, Ty, TyCtxt, TypeVisitableExt,
|
self, ConstInt, Instance, ParamEnv, ScalarInt, Ty, TyCtxt, TypeVisitableExt,
|
||||||
};
|
};
|
||||||
use rustc_session::lint;
|
|
||||||
use rustc_span::Span;
|
use rustc_span::Span;
|
||||||
use rustc_target::abi::{HasDataLayout, Size, TargetDataLayout};
|
use rustc_target::abi::{HasDataLayout, Size, TargetDataLayout};
|
||||||
use rustc_trait_selection::traits;
|
use rustc_trait_selection::traits;
|
||||||
@ -25,6 +26,7 @@ use rustc_trait_selection::traits;
|
|||||||
use crate::const_prop::CanConstProp;
|
use crate::const_prop::CanConstProp;
|
||||||
use crate::const_prop::ConstPropMachine;
|
use crate::const_prop::ConstPropMachine;
|
||||||
use crate::const_prop::ConstPropMode;
|
use crate::const_prop::ConstPropMode;
|
||||||
|
use crate::errors::AssertLint;
|
||||||
use crate::MirLint;
|
use crate::MirLint;
|
||||||
|
|
||||||
/// The maximum number of bytes that we'll allocate space for a local or the return value.
|
/// The maximum number of bytes that we'll allocate space for a local or the return value.
|
||||||
@ -311,18 +313,9 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn report_assert_as_lint(
|
fn report_assert_as_lint(&self, source_info: &SourceInfo, lint: AssertLint<impl Debug>) {
|
||||||
&self,
|
|
||||||
lint: &'static lint::Lint,
|
|
||||||
location: Location,
|
|
||||||
message: &'static str,
|
|
||||||
panic: AssertKind<impl std::fmt::Debug>,
|
|
||||||
) {
|
|
||||||
let source_info = self.body().source_info(location);
|
|
||||||
if let Some(lint_root) = self.lint_root(*source_info) {
|
if let Some(lint_root) = self.lint_root(*source_info) {
|
||||||
self.tcx.struct_span_lint_hir(lint, lint_root, source_info.span, message, |lint| {
|
self.tcx.emit_spanned_lint(lint.lint(), lint_root, source_info.span, lint);
|
||||||
lint.span_label(source_info.span, format!("{:?}", panic))
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -335,11 +328,13 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
|
|||||||
// `AssertKind` only has an `OverflowNeg` variant, so make sure that is
|
// `AssertKind` only has an `OverflowNeg` variant, so make sure that is
|
||||||
// appropriate to use.
|
// appropriate to use.
|
||||||
assert_eq!(op, UnOp::Neg, "Neg is the only UnOp that can overflow");
|
assert_eq!(op, UnOp::Neg, "Neg is the only UnOp that can overflow");
|
||||||
|
let source_info = self.body().source_info(location);
|
||||||
self.report_assert_as_lint(
|
self.report_assert_as_lint(
|
||||||
lint::builtin::ARITHMETIC_OVERFLOW,
|
source_info,
|
||||||
location,
|
AssertLint::ArithmeticOverflow(
|
||||||
"this arithmetic operation will overflow",
|
source_info.span,
|
||||||
AssertKind::OverflowNeg(val.to_const_int()),
|
AssertKind::OverflowNeg(val.to_const_int()),
|
||||||
|
),
|
||||||
);
|
);
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
@ -370,23 +365,23 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
|
|||||||
let r_bits = r.to_scalar().to_bits(right_size).ok();
|
let r_bits = r.to_scalar().to_bits(right_size).ok();
|
||||||
if r_bits.map_or(false, |b| b >= left_size.bits() as u128) {
|
if r_bits.map_or(false, |b| b >= left_size.bits() as u128) {
|
||||||
debug!("check_binary_op: reporting assert for {:?}", location);
|
debug!("check_binary_op: reporting assert for {:?}", location);
|
||||||
|
let source_info = self.body().source_info(location);
|
||||||
|
let panic = AssertKind::Overflow(
|
||||||
|
op,
|
||||||
|
match l {
|
||||||
|
Some(l) => l.to_const_int(),
|
||||||
|
// Invent a dummy value, the diagnostic ignores it anyway
|
||||||
|
None => ConstInt::new(
|
||||||
|
ScalarInt::try_from_uint(1_u8, left_size).unwrap(),
|
||||||
|
left_ty.is_signed(),
|
||||||
|
left_ty.is_ptr_sized_integral(),
|
||||||
|
),
|
||||||
|
},
|
||||||
|
r.to_const_int(),
|
||||||
|
);
|
||||||
self.report_assert_as_lint(
|
self.report_assert_as_lint(
|
||||||
lint::builtin::ARITHMETIC_OVERFLOW,
|
source_info,
|
||||||
location,
|
AssertLint::ArithmeticOverflow(source_info.span, panic),
|
||||||
"this arithmetic operation will overflow",
|
|
||||||
AssertKind::Overflow(
|
|
||||||
op,
|
|
||||||
match l {
|
|
||||||
Some(l) => l.to_const_int(),
|
|
||||||
// Invent a dummy value, the diagnostic ignores it anyway
|
|
||||||
None => ConstInt::new(
|
|
||||||
ScalarInt::try_from_uint(1_u8, left_size).unwrap(),
|
|
||||||
left_ty.is_signed(),
|
|
||||||
left_ty.is_ptr_sized_integral(),
|
|
||||||
),
|
|
||||||
},
|
|
||||||
r.to_const_int(),
|
|
||||||
),
|
|
||||||
);
|
);
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
@ -398,11 +393,13 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
|
|||||||
let (_res, overflow, _ty) = this.ecx.overflowing_binary_op(op, &l, &r)?;
|
let (_res, overflow, _ty) = this.ecx.overflowing_binary_op(op, &l, &r)?;
|
||||||
Ok(overflow)
|
Ok(overflow)
|
||||||
})? {
|
})? {
|
||||||
|
let source_info = self.body().source_info(location);
|
||||||
self.report_assert_as_lint(
|
self.report_assert_as_lint(
|
||||||
lint::builtin::ARITHMETIC_OVERFLOW,
|
source_info,
|
||||||
location,
|
AssertLint::ArithmeticOverflow(
|
||||||
"this arithmetic operation will overflow",
|
source_info.span,
|
||||||
AssertKind::Overflow(op, l.to_const_int(), r.to_const_int()),
|
AssertKind::Overflow(op, l.to_const_int(), r.to_const_int()),
|
||||||
|
),
|
||||||
);
|
);
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
@ -543,11 +540,10 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
|
|||||||
// Need proper const propagator for these.
|
// Need proper const propagator for these.
|
||||||
_ => return None,
|
_ => return None,
|
||||||
};
|
};
|
||||||
|
let source_info = self.body().source_info(location);
|
||||||
self.report_assert_as_lint(
|
self.report_assert_as_lint(
|
||||||
lint::builtin::UNCONDITIONAL_PANIC,
|
source_info,
|
||||||
location,
|
AssertLint::UnconditionalPanic(source_info.span, msg),
|
||||||
"this operation will panic at runtime",
|
|
||||||
msg,
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
245
compiler/rustc_mir_transform/src/errors.rs
Normal file
245
compiler/rustc_mir_transform/src/errors.rs
Normal file
@ -0,0 +1,245 @@
|
|||||||
|
use rustc_errors::{
|
||||||
|
DecorateLint, DiagnosticBuilder, DiagnosticMessage, EmissionGuarantee, Handler, IntoDiagnostic,
|
||||||
|
};
|
||||||
|
use rustc_macros::{Diagnostic, LintDiagnostic, Subdiagnostic};
|
||||||
|
use rustc_middle::mir::{AssertKind, UnsafetyViolationDetails};
|
||||||
|
use rustc_session::lint::{self, Lint};
|
||||||
|
use rustc_span::Span;
|
||||||
|
|
||||||
|
#[derive(LintDiagnostic)]
|
||||||
|
pub(crate) enum ConstMutate {
|
||||||
|
#[diag(mir_transform_const_modify)]
|
||||||
|
#[note]
|
||||||
|
Modify {
|
||||||
|
#[note(mir_transform_const_defined_here)]
|
||||||
|
konst: Span,
|
||||||
|
},
|
||||||
|
#[diag(mir_transform_const_mut_borrow)]
|
||||||
|
#[note]
|
||||||
|
#[note(mir_transform_note2)]
|
||||||
|
MutBorrow {
|
||||||
|
#[note(mir_transform_note3)]
|
||||||
|
method_call: Option<Span>,
|
||||||
|
#[note(mir_transform_const_defined_here)]
|
||||||
|
konst: Span,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Diagnostic)]
|
||||||
|
#[diag(mir_transform_unaligned_packed_ref, code = "E0793")]
|
||||||
|
#[note]
|
||||||
|
#[note(mir_transform_note_ub)]
|
||||||
|
#[help]
|
||||||
|
pub(crate) struct UnalignedPackedRef {
|
||||||
|
#[primary_span]
|
||||||
|
pub span: Span,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(LintDiagnostic)]
|
||||||
|
#[diag(mir_transform_unused_unsafe)]
|
||||||
|
pub(crate) struct UnusedUnsafe {
|
||||||
|
#[label(mir_transform_unused_unsafe)]
|
||||||
|
pub span: Span,
|
||||||
|
#[label]
|
||||||
|
pub nested_parent: Option<Span>,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) struct RequiresUnsafe {
|
||||||
|
pub span: Span,
|
||||||
|
pub details: RequiresUnsafeDetail,
|
||||||
|
pub enclosing: Option<Span>,
|
||||||
|
pub op_in_unsafe_fn_allowed: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
// The primary message for this diagnostic should be '{$label} is unsafe and...',
|
||||||
|
// so we need to eagerly translate the label here, which isn't supported by the derive API
|
||||||
|
// We could also exhaustively list out the primary messages for all unsafe violations,
|
||||||
|
// but this would result in a lot of duplication.
|
||||||
|
impl<'sess, G: EmissionGuarantee> IntoDiagnostic<'sess, G> for RequiresUnsafe {
|
||||||
|
#[track_caller]
|
||||||
|
fn into_diagnostic(self, handler: &'sess Handler) -> DiagnosticBuilder<'sess, G> {
|
||||||
|
let mut diag =
|
||||||
|
handler.struct_diagnostic(crate::fluent_generated::mir_transform_requires_unsafe);
|
||||||
|
diag.code(rustc_errors::DiagnosticId::Error("E0133".to_string()));
|
||||||
|
diag.set_span(self.span);
|
||||||
|
diag.span_label(self.span, self.details.label());
|
||||||
|
diag.note(self.details.note());
|
||||||
|
let desc = handler.eagerly_translate_to_string(self.details.label(), [].into_iter());
|
||||||
|
diag.set_arg("details", desc);
|
||||||
|
diag.set_arg("op_in_unsafe_fn_allowed", self.op_in_unsafe_fn_allowed);
|
||||||
|
if let Some(sp) = self.enclosing {
|
||||||
|
diag.span_label(sp, crate::fluent_generated::mir_transform_not_inherited);
|
||||||
|
}
|
||||||
|
diag
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Copy, Clone)]
|
||||||
|
pub(crate) struct RequiresUnsafeDetail {
|
||||||
|
pub span: Span,
|
||||||
|
pub violation: UnsafetyViolationDetails,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl RequiresUnsafeDetail {
|
||||||
|
fn note(self) -> DiagnosticMessage {
|
||||||
|
use UnsafetyViolationDetails::*;
|
||||||
|
match self.violation {
|
||||||
|
CallToUnsafeFunction => crate::fluent_generated::mir_transform_call_to_unsafe_note,
|
||||||
|
UseOfInlineAssembly => crate::fluent_generated::mir_transform_use_of_asm_note,
|
||||||
|
InitializingTypeWith => {
|
||||||
|
crate::fluent_generated::mir_transform_initializing_valid_range_note
|
||||||
|
}
|
||||||
|
CastOfPointerToInt => crate::fluent_generated::mir_transform_const_ptr2int_note,
|
||||||
|
UseOfMutableStatic => crate::fluent_generated::mir_transform_use_of_static_mut_note,
|
||||||
|
UseOfExternStatic => crate::fluent_generated::mir_transform_use_of_extern_static_note,
|
||||||
|
DerefOfRawPointer => crate::fluent_generated::mir_transform_deref_ptr_note,
|
||||||
|
AccessToUnionField => crate::fluent_generated::mir_transform_union_access_note,
|
||||||
|
MutationOfLayoutConstrainedField => {
|
||||||
|
crate::fluent_generated::mir_transform_mutation_layout_constrained_note
|
||||||
|
}
|
||||||
|
BorrowOfLayoutConstrainedField => {
|
||||||
|
crate::fluent_generated::mir_transform_mutation_layout_constrained_borrow_note
|
||||||
|
}
|
||||||
|
CallToFunctionWith => crate::fluent_generated::mir_transform_target_feature_call_note,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn label(self) -> DiagnosticMessage {
|
||||||
|
use UnsafetyViolationDetails::*;
|
||||||
|
match self.violation {
|
||||||
|
CallToUnsafeFunction => crate::fluent_generated::mir_transform_call_to_unsafe_label,
|
||||||
|
UseOfInlineAssembly => crate::fluent_generated::mir_transform_use_of_asm_label,
|
||||||
|
InitializingTypeWith => {
|
||||||
|
crate::fluent_generated::mir_transform_initializing_valid_range_label
|
||||||
|
}
|
||||||
|
CastOfPointerToInt => crate::fluent_generated::mir_transform_const_ptr2int_label,
|
||||||
|
UseOfMutableStatic => crate::fluent_generated::mir_transform_use_of_static_mut_label,
|
||||||
|
UseOfExternStatic => crate::fluent_generated::mir_transform_use_of_extern_static_label,
|
||||||
|
DerefOfRawPointer => crate::fluent_generated::mir_transform_deref_ptr_label,
|
||||||
|
AccessToUnionField => crate::fluent_generated::mir_transform_union_access_label,
|
||||||
|
MutationOfLayoutConstrainedField => {
|
||||||
|
crate::fluent_generated::mir_transform_mutation_layout_constrained_label
|
||||||
|
}
|
||||||
|
BorrowOfLayoutConstrainedField => {
|
||||||
|
crate::fluent_generated::mir_transform_mutation_layout_constrained_borrow_label
|
||||||
|
}
|
||||||
|
CallToFunctionWith => crate::fluent_generated::mir_transform_target_feature_call_label,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) struct UnsafeOpInUnsafeFn {
|
||||||
|
pub details: RequiresUnsafeDetail,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> DecorateLint<'a, ()> for UnsafeOpInUnsafeFn {
|
||||||
|
#[track_caller]
|
||||||
|
fn decorate_lint<'b>(
|
||||||
|
self,
|
||||||
|
diag: &'b mut DiagnosticBuilder<'a, ()>,
|
||||||
|
) -> &'b mut DiagnosticBuilder<'a, ()> {
|
||||||
|
let desc = diag
|
||||||
|
.handler()
|
||||||
|
.expect("lint should not yet be emitted")
|
||||||
|
.eagerly_translate_to_string(self.details.label(), [].into_iter());
|
||||||
|
diag.set_arg("details", desc);
|
||||||
|
diag.span_label(self.details.span, self.details.label());
|
||||||
|
diag.note(self.details.note());
|
||||||
|
diag
|
||||||
|
}
|
||||||
|
|
||||||
|
fn msg(&self) -> DiagnosticMessage {
|
||||||
|
crate::fluent_generated::mir_transform_unsafe_op_in_unsafe_fn
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) enum AssertLint<P> {
|
||||||
|
ArithmeticOverflow(Span, AssertKind<P>),
|
||||||
|
UnconditionalPanic(Span, AssertKind<P>),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, P: std::fmt::Debug> DecorateLint<'a, ()> for AssertLint<P> {
|
||||||
|
fn decorate_lint<'b>(
|
||||||
|
self,
|
||||||
|
diag: &'b mut DiagnosticBuilder<'a, ()>,
|
||||||
|
) -> &'b mut DiagnosticBuilder<'a, ()> {
|
||||||
|
diag.span_label(self.span(), format!("{:?}", self.panic()));
|
||||||
|
diag
|
||||||
|
}
|
||||||
|
|
||||||
|
fn msg(&self) -> DiagnosticMessage {
|
||||||
|
match self {
|
||||||
|
AssertLint::ArithmeticOverflow(..) => {
|
||||||
|
crate::fluent_generated::mir_transform_arithmetic_overflow
|
||||||
|
}
|
||||||
|
AssertLint::UnconditionalPanic(..) => {
|
||||||
|
crate::fluent_generated::mir_transform_operation_will_panic
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<P> AssertLint<P> {
|
||||||
|
pub fn lint(&self) -> &'static Lint {
|
||||||
|
match self {
|
||||||
|
AssertLint::ArithmeticOverflow(..) => lint::builtin::ARITHMETIC_OVERFLOW,
|
||||||
|
AssertLint::UnconditionalPanic(..) => lint::builtin::UNCONDITIONAL_PANIC,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pub fn span(&self) -> Span {
|
||||||
|
match self {
|
||||||
|
AssertLint::ArithmeticOverflow(sp, _) | AssertLint::UnconditionalPanic(sp, _) => *sp,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pub fn panic(&self) -> &AssertKind<P> {
|
||||||
|
match self {
|
||||||
|
AssertLint::ArithmeticOverflow(_, p) | AssertLint::UnconditionalPanic(_, p) => p,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(LintDiagnostic)]
|
||||||
|
#[diag(mir_transform_ffi_unwind_call)]
|
||||||
|
pub(crate) struct FfiUnwindCall {
|
||||||
|
#[label(mir_transform_ffi_unwind_call)]
|
||||||
|
pub span: Span,
|
||||||
|
pub foreign: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(LintDiagnostic)]
|
||||||
|
#[diag(mir_transform_fn_item_ref)]
|
||||||
|
pub(crate) struct FnItemRef {
|
||||||
|
#[suggestion(code = "{sugg}", applicability = "unspecified")]
|
||||||
|
pub span: Span,
|
||||||
|
pub sugg: String,
|
||||||
|
pub ident: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(LintDiagnostic)]
|
||||||
|
#[diag(mir_transform_must_not_suspend)]
|
||||||
|
pub(crate) struct MustNotSupend<'a> {
|
||||||
|
#[label]
|
||||||
|
pub yield_sp: Span,
|
||||||
|
#[subdiagnostic]
|
||||||
|
pub reason: Option<MustNotSuspendReason>,
|
||||||
|
#[help]
|
||||||
|
pub src_sp: Span,
|
||||||
|
pub pre: &'a str,
|
||||||
|
pub def_path: String,
|
||||||
|
pub post: &'a str,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Subdiagnostic)]
|
||||||
|
#[note(mir_transform_note)]
|
||||||
|
pub(crate) struct MustNotSuspendReason {
|
||||||
|
#[primary_span]
|
||||||
|
pub span: Span,
|
||||||
|
pub reason: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Diagnostic)]
|
||||||
|
#[diag(mir_transform_simd_shuffle_last_const)]
|
||||||
|
pub(crate) struct SimdShuffleLastConst {
|
||||||
|
#[primary_span]
|
||||||
|
pub span: Span,
|
||||||
|
}
|
@ -8,6 +8,8 @@ use rustc_session::lint::builtin::FFI_UNWIND_CALLS;
|
|||||||
use rustc_target::spec::abi::Abi;
|
use rustc_target::spec::abi::Abi;
|
||||||
use rustc_target::spec::PanicStrategy;
|
use rustc_target::spec::PanicStrategy;
|
||||||
|
|
||||||
|
use crate::errors;
|
||||||
|
|
||||||
fn abi_can_unwind(abi: Abi) -> bool {
|
fn abi_can_unwind(abi: Abi) -> bool {
|
||||||
use Abi::*;
|
use Abi::*;
|
||||||
match abi {
|
match abi {
|
||||||
@ -107,13 +109,13 @@ fn has_ffi_unwind_calls(tcx: TyCtxt<'_>, local_def_id: LocalDefId) -> bool {
|
|||||||
.lint_root;
|
.lint_root;
|
||||||
let span = terminator.source_info.span;
|
let span = terminator.source_info.span;
|
||||||
|
|
||||||
let msg = match fn_def_id {
|
let foreign = fn_def_id.is_some();
|
||||||
Some(_) => "call to foreign function with FFI-unwind ABI",
|
tcx.emit_spanned_lint(
|
||||||
None => "call to function pointer with FFI-unwind ABI",
|
FFI_UNWIND_CALLS,
|
||||||
};
|
lint_root,
|
||||||
tcx.struct_span_lint_hir(FFI_UNWIND_CALLS, lint_root, span, msg, |lint| {
|
span,
|
||||||
lint.span_label(span, msg)
|
errors::FfiUnwindCall { span, foreign },
|
||||||
});
|
);
|
||||||
|
|
||||||
tainted = true;
|
tainted = true;
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
use itertools::Itertools;
|
use itertools::Itertools;
|
||||||
use rustc_errors::Applicability;
|
|
||||||
use rustc_hir::def_id::DefId;
|
use rustc_hir::def_id::DefId;
|
||||||
use rustc_middle::mir::visit::Visitor;
|
use rustc_middle::mir::visit::Visitor;
|
||||||
use rustc_middle::mir::*;
|
use rustc_middle::mir::*;
|
||||||
@ -8,7 +7,7 @@ use rustc_session::lint::builtin::FUNCTION_ITEM_REFERENCES;
|
|||||||
use rustc_span::{symbol::sym, Span};
|
use rustc_span::{symbol::sym, Span};
|
||||||
use rustc_target::spec::abi::Abi;
|
use rustc_target::spec::abi::Abi;
|
||||||
|
|
||||||
use crate::MirLint;
|
use crate::{errors, MirLint};
|
||||||
|
|
||||||
pub struct FunctionItemReferences;
|
pub struct FunctionItemReferences;
|
||||||
|
|
||||||
@ -174,27 +173,21 @@ impl<'tcx> FunctionItemRefChecker<'_, 'tcx> {
|
|||||||
let num_args = fn_sig.inputs().map_bound(|inputs| inputs.len()).skip_binder();
|
let num_args = fn_sig.inputs().map_bound(|inputs| inputs.len()).skip_binder();
|
||||||
let variadic = if fn_sig.c_variadic() { ", ..." } else { "" };
|
let variadic = if fn_sig.c_variadic() { ", ..." } else { "" };
|
||||||
let ret = if fn_sig.output().skip_binder().is_unit() { "" } else { " -> _" };
|
let ret = if fn_sig.output().skip_binder().is_unit() { "" } else { " -> _" };
|
||||||
self.tcx.struct_span_lint_hir(
|
let sugg = format!(
|
||||||
|
"{} as {}{}fn({}{}){}",
|
||||||
|
if params.is_empty() { ident.clone() } else { format!("{}::<{}>", ident, params) },
|
||||||
|
unsafety,
|
||||||
|
abi,
|
||||||
|
vec!["_"; num_args].join(", "),
|
||||||
|
variadic,
|
||||||
|
ret,
|
||||||
|
);
|
||||||
|
|
||||||
|
self.tcx.emit_spanned_lint(
|
||||||
FUNCTION_ITEM_REFERENCES,
|
FUNCTION_ITEM_REFERENCES,
|
||||||
lint_root,
|
lint_root,
|
||||||
span,
|
span,
|
||||||
"taking a reference to a function item does not give a function pointer",
|
errors::FnItemRef { span, sugg, ident },
|
||||||
|lint| {
|
|
||||||
lint.span_suggestion(
|
|
||||||
span,
|
|
||||||
format!("cast `{}` to obtain a function pointer", ident),
|
|
||||||
format!(
|
|
||||||
"{} as {}{}fn({}{}){}",
|
|
||||||
if params.is_empty() { ident } else { format!("{}::<{}>", ident, params) },
|
|
||||||
unsafety,
|
|
||||||
abi,
|
|
||||||
vec!["_"; num_args].join(", "),
|
|
||||||
variadic,
|
|
||||||
ret,
|
|
||||||
),
|
|
||||||
Applicability::Unspecified,
|
|
||||||
)
|
|
||||||
},
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -51,6 +51,7 @@
|
|||||||
//! Otherwise it drops all the values in scope at the last suspension point.
|
//! Otherwise it drops all the values in scope at the last suspension point.
|
||||||
|
|
||||||
use crate::deref_separator::deref_finder;
|
use crate::deref_separator::deref_finder;
|
||||||
|
use crate::errors;
|
||||||
use crate::simplify;
|
use crate::simplify;
|
||||||
use crate::MirPass;
|
use crate::MirPass;
|
||||||
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
|
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
|
||||||
@ -1891,36 +1892,21 @@ fn check_must_not_suspend_def(
|
|||||||
data: SuspendCheckData<'_>,
|
data: SuspendCheckData<'_>,
|
||||||
) -> bool {
|
) -> bool {
|
||||||
if let Some(attr) = tcx.get_attr(def_id, sym::must_not_suspend) {
|
if let Some(attr) = tcx.get_attr(def_id, sym::must_not_suspend) {
|
||||||
let msg = rustc_errors::DelayDm(|| {
|
let reason = attr.value_str().map(|s| errors::MustNotSuspendReason {
|
||||||
format!(
|
span: data.source_span,
|
||||||
"{}`{}`{} held across a suspend point, but should not be",
|
reason: s.as_str().to_string(),
|
||||||
data.descr_pre,
|
|
||||||
tcx.def_path_str(def_id),
|
|
||||||
data.descr_post,
|
|
||||||
)
|
|
||||||
});
|
});
|
||||||
tcx.struct_span_lint_hir(
|
tcx.emit_spanned_lint(
|
||||||
rustc_session::lint::builtin::MUST_NOT_SUSPEND,
|
rustc_session::lint::builtin::MUST_NOT_SUSPEND,
|
||||||
hir_id,
|
hir_id,
|
||||||
data.source_span,
|
data.source_span,
|
||||||
msg,
|
errors::MustNotSupend {
|
||||||
|lint| {
|
yield_sp: data.yield_span,
|
||||||
// add span pointing to the offending yield/await
|
reason,
|
||||||
lint.span_label(data.yield_span, "the value is held across this suspend point");
|
src_sp: data.source_span,
|
||||||
|
pre: data.descr_pre,
|
||||||
// Add optional reason note
|
def_path: tcx.def_path_str(def_id),
|
||||||
if let Some(note) = attr.value_str() {
|
post: data.descr_post,
|
||||||
// FIXME(guswynn): consider formatting this better
|
|
||||||
lint.span_note(data.source_span, note.as_str());
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add some quick suggestions on what to do
|
|
||||||
// FIXME: can `drop` work as a suggestion here as well?
|
|
||||||
lint.span_help(
|
|
||||||
data.source_span,
|
|
||||||
"consider using a block (`{ ... }`) \
|
|
||||||
to shrink the value's scope, ending before the suspend point",
|
|
||||||
)
|
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -1,4 +1,6 @@
|
|||||||
#![allow(rustc::potential_query_instability)]
|
#![allow(rustc::potential_query_instability)]
|
||||||
|
#![deny(rustc::untranslatable_diagnostic)]
|
||||||
|
#![deny(rustc::diagnostic_outside_of_impl)]
|
||||||
#![feature(box_patterns)]
|
#![feature(box_patterns)]
|
||||||
#![feature(drain_filter)]
|
#![feature(drain_filter)]
|
||||||
#![feature(let_chains)]
|
#![feature(let_chains)]
|
||||||
@ -69,6 +71,7 @@ pub mod dump_mir;
|
|||||||
mod early_otherwise_branch;
|
mod early_otherwise_branch;
|
||||||
mod elaborate_box_derefs;
|
mod elaborate_box_derefs;
|
||||||
mod elaborate_drops;
|
mod elaborate_drops;
|
||||||
|
mod errors;
|
||||||
mod ffi_unwind_calls;
|
mod ffi_unwind_calls;
|
||||||
mod function_item_references;
|
mod function_item_references;
|
||||||
mod generator;
|
mod generator;
|
||||||
@ -105,6 +108,11 @@ use rustc_const_eval::transform::promote_consts;
|
|||||||
use rustc_const_eval::transform::validate;
|
use rustc_const_eval::transform::validate;
|
||||||
use rustc_mir_dataflow::rustc_peek;
|
use rustc_mir_dataflow::rustc_peek;
|
||||||
|
|
||||||
|
use rustc_errors::{DiagnosticMessage, SubdiagnosticMessage};
|
||||||
|
use rustc_fluent_macro::fluent_messages;
|
||||||
|
|
||||||
|
fluent_messages! { "../messages.ftl" }
|
||||||
|
|
||||||
pub fn provide(providers: &mut Providers) {
|
pub fn provide(providers: &mut Providers) {
|
||||||
check_unsafety::provide(providers);
|
check_unsafety::provide(providers);
|
||||||
coverage::query::provide(providers);
|
coverage::query::provide(providers);
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
//! Lowers intrinsic calls
|
//! Lowers intrinsic calls
|
||||||
|
|
||||||
use crate::MirPass;
|
use crate::{errors, MirPass};
|
||||||
use rustc_middle::mir::*;
|
use rustc_middle::mir::*;
|
||||||
use rustc_middle::ty::subst::SubstsRef;
|
use rustc_middle::ty::subst::SubstsRef;
|
||||||
use rustc_middle::ty::{self, Ty, TyCtxt};
|
use rustc_middle::ty::{self, Ty, TyCtxt};
|
||||||
@ -310,11 +310,7 @@ fn resolve_rust_intrinsic<'tcx>(
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn validate_simd_shuffle<'tcx>(tcx: TyCtxt<'tcx>, args: &[Operand<'tcx>], span: Span) {
|
fn validate_simd_shuffle<'tcx>(tcx: TyCtxt<'tcx>, args: &[Operand<'tcx>], span: Span) {
|
||||||
match &args[2] {
|
if !matches!(args[2], Operand::Constant(_)) {
|
||||||
Operand::Constant(_) => {} // all good
|
tcx.sess.emit_err(errors::SimdShuffleLastConst { span });
|
||||||
_ => {
|
|
||||||
let msg = "last argument of `simd_shuffle` is required to be a `const` item";
|
|
||||||
tcx.sess.span_err(span, msg);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1262,6 +1262,7 @@ impl<'a> Parser<'a> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let prev_span = self.prev_token.span;
|
||||||
let id = self.parse_ident()?;
|
let id = self.parse_ident()?;
|
||||||
let mut generics = self.parse_generics()?;
|
let mut generics = self.parse_generics()?;
|
||||||
generics.where_clause = self.parse_where_clause()?;
|
generics.where_clause = self.parse_where_clause()?;
|
||||||
@ -1273,10 +1274,28 @@ impl<'a> Parser<'a> {
|
|||||||
(thin_vec![], false)
|
(thin_vec![], false)
|
||||||
} else {
|
} else {
|
||||||
self.parse_delim_comma_seq(Delimiter::Brace, |p| p.parse_enum_variant()).map_err(
|
self.parse_delim_comma_seq(Delimiter::Brace, |p| p.parse_enum_variant()).map_err(
|
||||||
|mut e| {
|
|mut err| {
|
||||||
e.span_label(id.span, "while parsing this enum");
|
err.span_label(id.span, "while parsing this enum");
|
||||||
|
if self.token == token::Colon {
|
||||||
|
let snapshot = self.create_snapshot_for_diagnostic();
|
||||||
|
self.bump();
|
||||||
|
match self.parse_ty() {
|
||||||
|
Ok(_) => {
|
||||||
|
err.span_suggestion_verbose(
|
||||||
|
prev_span,
|
||||||
|
"perhaps you meant to use `struct` here",
|
||||||
|
"struct".to_string(),
|
||||||
|
Applicability::MaybeIncorrect,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
Err(e) => {
|
||||||
|
e.cancel();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
self.restore_snapshot(snapshot);
|
||||||
|
}
|
||||||
self.recover_stmt();
|
self.recover_stmt();
|
||||||
e
|
err
|
||||||
},
|
},
|
||||||
)?
|
)?
|
||||||
};
|
};
|
||||||
|
@ -243,6 +243,39 @@ where
|
|||||||
// This will also visit substs if necessary, so we don't need to recurse.
|
// This will also visit substs if necessary, so we don't need to recurse.
|
||||||
return self.visit_projection_ty(proj);
|
return self.visit_projection_ty(proj);
|
||||||
}
|
}
|
||||||
|
ty::Alias(ty::Inherent, data) => {
|
||||||
|
if self.def_id_visitor.skip_assoc_tys() {
|
||||||
|
// Visitors searching for minimal visibility/reachability want to
|
||||||
|
// conservatively approximate associated types like `Type::Alias`
|
||||||
|
// as visible/reachable even if `Type` is private.
|
||||||
|
// Ideally, associated types should be substituted in the same way as
|
||||||
|
// free type aliases, but this isn't done yet.
|
||||||
|
return ControlFlow::Continue(());
|
||||||
|
}
|
||||||
|
|
||||||
|
self.def_id_visitor.visit_def_id(
|
||||||
|
data.def_id,
|
||||||
|
"associated type",
|
||||||
|
&LazyDefPathStr { def_id: data.def_id, tcx },
|
||||||
|
)?;
|
||||||
|
|
||||||
|
struct LazyDefPathStr<'tcx> {
|
||||||
|
def_id: DefId,
|
||||||
|
tcx: TyCtxt<'tcx>,
|
||||||
|
}
|
||||||
|
impl<'tcx> fmt::Display for LazyDefPathStr<'tcx> {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
write!(f, "{}", self.tcx.def_path_str(self.def_id))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// This will also visit substs if necessary, so we don't need to recurse.
|
||||||
|
return if self.def_id_visitor.shallow() {
|
||||||
|
ControlFlow::Continue(())
|
||||||
|
} else {
|
||||||
|
data.substs.iter().try_for_each(|subst| subst.visit_with(self))
|
||||||
|
};
|
||||||
|
}
|
||||||
ty::Dynamic(predicates, ..) => {
|
ty::Dynamic(predicates, ..) => {
|
||||||
// All traits in the list are considered the "primary" part of the type
|
// All traits in the list are considered the "primary" part of the type
|
||||||
// and are visited by shallow visitors.
|
// and are visited by shallow visitors.
|
||||||
|
@ -20,3 +20,5 @@ trait_selection_negative_positive_conflict = found both positive and negative im
|
|||||||
.negative_implementation_in_crate = negative implementation in crate `{$negative_impl_cname}`
|
.negative_implementation_in_crate = negative implementation in crate `{$negative_impl_cname}`
|
||||||
.positive_implementation_here = positive implementation here
|
.positive_implementation_here = positive implementation here
|
||||||
.positive_implementation_in_crate = positive implementation in crate `{$positive_impl_cname}`
|
.positive_implementation_in_crate = positive implementation in crate `{$positive_impl_cname}`
|
||||||
|
|
||||||
|
trait_selection_inherent_projection_normalization_overflow = overflow evaluating associated type `{$ty}`
|
||||||
|
@ -89,3 +89,11 @@ impl IntoDiagnostic<'_> for NegativePositiveConflict<'_> {
|
|||||||
diag
|
diag
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Diagnostic)]
|
||||||
|
#[diag(trait_selection_inherent_projection_normalization_overflow)]
|
||||||
|
pub struct InherentProjectionNormalizationOverflow {
|
||||||
|
#[primary_span]
|
||||||
|
pub span: Span,
|
||||||
|
pub ty: String,
|
||||||
|
}
|
||||||
|
@ -33,7 +33,7 @@ pub(in crate::solve) fn instantiate_constituent_tys_for_auto_trait<'tcx>(
|
|||||||
ty::Dynamic(..)
|
ty::Dynamic(..)
|
||||||
| ty::Param(..)
|
| ty::Param(..)
|
||||||
| ty::Foreign(..)
|
| ty::Foreign(..)
|
||||||
| ty::Alias(ty::Projection, ..)
|
| ty::Alias(ty::Projection | ty::Inherent, ..)
|
||||||
| ty::Placeholder(..)
|
| ty::Placeholder(..)
|
||||||
| ty::Bound(..)
|
| ty::Bound(..)
|
||||||
| ty::Infer(_) => {
|
| ty::Infer(_) => {
|
||||||
|
@ -655,7 +655,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
|
|||||||
ty::Dynamic(..)
|
ty::Dynamic(..)
|
||||||
| ty::Param(..)
|
| ty::Param(..)
|
||||||
| ty::Foreign(..)
|
| ty::Foreign(..)
|
||||||
| ty::Alias(ty::Projection, ..)
|
| ty::Alias(ty::Projection | ty::Inherent, ..)
|
||||||
| ty::Placeholder(..) => Some(Err(NoSolution)),
|
| ty::Placeholder(..) => Some(Err(NoSolution)),
|
||||||
|
|
||||||
ty::Infer(_) | ty::Bound(_, _) => bug!("unexpected type `{self_ty}`"),
|
ty::Infer(_) | ty::Bound(_, _) => bug!("unexpected type `{self_ty}`"),
|
||||||
|
@ -673,7 +673,7 @@ impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for OrphanChecker<'tcx> {
|
|||||||
| ty::RawPtr(..)
|
| ty::RawPtr(..)
|
||||||
| ty::Never
|
| ty::Never
|
||||||
| ty::Tuple(..)
|
| ty::Tuple(..)
|
||||||
| ty::Alias(ty::Projection, ..) => self.found_non_local_ty(ty),
|
| ty::Alias(ty::Projection | ty::Inherent, ..) => self.found_non_local_ty(ty),
|
||||||
|
|
||||||
ty::Param(..) => self.found_param_ty(ty),
|
ty::Param(..) => self.found_param_ty(ty),
|
||||||
|
|
||||||
|
@ -1687,13 +1687,14 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
|
|||||||
ty::Tuple(..) => Some(10),
|
ty::Tuple(..) => Some(10),
|
||||||
ty::Param(..) => Some(11),
|
ty::Param(..) => Some(11),
|
||||||
ty::Alias(ty::Projection, ..) => Some(12),
|
ty::Alias(ty::Projection, ..) => Some(12),
|
||||||
ty::Alias(ty::Opaque, ..) => Some(13),
|
ty::Alias(ty::Inherent, ..) => Some(13),
|
||||||
ty::Never => Some(14),
|
ty::Alias(ty::Opaque, ..) => Some(14),
|
||||||
ty::Adt(..) => Some(15),
|
ty::Never => Some(15),
|
||||||
ty::Generator(..) => Some(16),
|
ty::Adt(..) => Some(16),
|
||||||
ty::Foreign(..) => Some(17),
|
ty::Generator(..) => Some(17),
|
||||||
ty::GeneratorWitness(..) => Some(18),
|
ty::Foreign(..) => Some(18),
|
||||||
ty::GeneratorWitnessMIR(..) => Some(19),
|
ty::GeneratorWitness(..) => Some(19),
|
||||||
|
ty::GeneratorWitnessMIR(..) => Some(20),
|
||||||
ty::Placeholder(..) | ty::Bound(..) | ty::Infer(..) | ty::Error(_) => None,
|
ty::Placeholder(..) | ty::Bound(..) | ty::Infer(..) | ty::Error(_) => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -49,7 +49,8 @@ pub use self::object_safety::astconv_object_safety_violations;
|
|||||||
pub use self::object_safety::is_vtable_safe_method;
|
pub use self::object_safety::is_vtable_safe_method;
|
||||||
pub use self::object_safety::MethodViolationCode;
|
pub use self::object_safety::MethodViolationCode;
|
||||||
pub use self::object_safety::ObjectSafetyViolation;
|
pub use self::object_safety::ObjectSafetyViolation;
|
||||||
pub use self::project::{normalize_projection_type, NormalizeExt};
|
pub use self::project::NormalizeExt;
|
||||||
|
pub use self::project::{normalize_inherent_projection, normalize_projection_type};
|
||||||
pub use self::select::{EvaluationCache, SelectionCache, SelectionContext};
|
pub use self::select::{EvaluationCache, SelectionCache, SelectionContext};
|
||||||
pub use self::select::{EvaluationResult, IntercrateAmbiguityCause, OverflowError};
|
pub use self::select::{EvaluationResult, IntercrateAmbiguityCause, OverflowError};
|
||||||
pub use self::specialize::specialization_graph::FutureCompatOverlapError;
|
pub use self::specialize::specialization_graph::FutureCompatOverlapError;
|
||||||
|
@ -16,6 +16,7 @@ use super::{
|
|||||||
};
|
};
|
||||||
use super::{Normalized, NormalizedTy, ProjectionCacheEntry, ProjectionCacheKey};
|
use super::{Normalized, NormalizedTy, ProjectionCacheEntry, ProjectionCacheKey};
|
||||||
|
|
||||||
|
use crate::errors::InherentProjectionNormalizationOverflow;
|
||||||
use crate::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
|
use crate::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
|
||||||
use crate::infer::{InferCtxt, InferOk, LateBoundRegionConversionTime};
|
use crate::infer::{InferCtxt, InferOk, LateBoundRegionConversionTime};
|
||||||
use crate::traits::error_reporting::TypeErrCtxtExt as _;
|
use crate::traits::error_reporting::TypeErrCtxtExt as _;
|
||||||
@ -370,10 +371,14 @@ pub(crate) fn needs_normalization<'tcx, T: TypeVisitable<TyCtxt<'tcx>>>(
|
|||||||
reveal: Reveal,
|
reveal: Reveal,
|
||||||
) -> bool {
|
) -> bool {
|
||||||
match reveal {
|
match reveal {
|
||||||
Reveal::UserFacing => value
|
Reveal::UserFacing => value.has_type_flags(
|
||||||
.has_type_flags(ty::TypeFlags::HAS_TY_PROJECTION | ty::TypeFlags::HAS_CT_PROJECTION),
|
ty::TypeFlags::HAS_TY_PROJECTION
|
||||||
|
| ty::TypeFlags::HAS_TY_INHERENT
|
||||||
|
| ty::TypeFlags::HAS_CT_PROJECTION,
|
||||||
|
),
|
||||||
Reveal::All => value.has_type_flags(
|
Reveal::All => value.has_type_flags(
|
||||||
ty::TypeFlags::HAS_TY_PROJECTION
|
ty::TypeFlags::HAS_TY_PROJECTION
|
||||||
|
| ty::TypeFlags::HAS_TY_INHERENT
|
||||||
| ty::TypeFlags::HAS_TY_OPAQUE
|
| ty::TypeFlags::HAS_TY_OPAQUE
|
||||||
| ty::TypeFlags::HAS_CT_PROJECTION,
|
| ty::TypeFlags::HAS_CT_PROJECTION,
|
||||||
),
|
),
|
||||||
@ -616,6 +621,51 @@ impl<'a, 'b, 'tcx> TypeFolder<TyCtxt<'tcx>> for AssocTypeNormalizer<'a, 'b, 'tcx
|
|||||||
);
|
);
|
||||||
normalized_ty
|
normalized_ty
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ty::Inherent if !data.has_escaping_bound_vars() => {
|
||||||
|
// This branch is *mostly* just an optimization: when we don't
|
||||||
|
// have escaping bound vars, we don't need to replace them with
|
||||||
|
// placeholders (see branch below). *Also*, we know that we can
|
||||||
|
// register an obligation to *later* project, since we know
|
||||||
|
// there won't be bound vars there.
|
||||||
|
|
||||||
|
let data = data.fold_with(self);
|
||||||
|
|
||||||
|
// FIXME(inherent_associated_types): Do we need to honor `self.eager_inference_replacement`
|
||||||
|
// here like `ty::Projection`?
|
||||||
|
normalize_inherent_projection(
|
||||||
|
self.selcx,
|
||||||
|
self.param_env,
|
||||||
|
data,
|
||||||
|
self.cause.clone(),
|
||||||
|
self.depth,
|
||||||
|
&mut self.obligations,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
ty::Inherent => {
|
||||||
|
let infcx = self.selcx.infcx;
|
||||||
|
let (data, mapped_regions, mapped_types, mapped_consts) =
|
||||||
|
BoundVarReplacer::replace_bound_vars(infcx, &mut self.universes, data);
|
||||||
|
let data = data.fold_with(self);
|
||||||
|
let ty = normalize_inherent_projection(
|
||||||
|
self.selcx,
|
||||||
|
self.param_env,
|
||||||
|
data,
|
||||||
|
self.cause.clone(),
|
||||||
|
self.depth,
|
||||||
|
&mut self.obligations,
|
||||||
|
);
|
||||||
|
|
||||||
|
PlaceholderReplacer::replace_placeholders(
|
||||||
|
infcx,
|
||||||
|
mapped_regions,
|
||||||
|
mapped_types,
|
||||||
|
mapped_consts,
|
||||||
|
&self.universes,
|
||||||
|
ty,
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1204,6 +1254,115 @@ fn normalize_to_error<'a, 'tcx>(
|
|||||||
Normalized { value: new_value, obligations: vec![trait_obligation] }
|
Normalized { value: new_value, obligations: vec![trait_obligation] }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Confirm and normalize the given inherent projection.
|
||||||
|
#[instrument(level = "debug", skip(selcx, param_env, cause, obligations))]
|
||||||
|
pub fn normalize_inherent_projection<'a, 'b, 'tcx>(
|
||||||
|
selcx: &'a mut SelectionContext<'b, 'tcx>,
|
||||||
|
param_env: ty::ParamEnv<'tcx>,
|
||||||
|
alias_ty: ty::AliasTy<'tcx>,
|
||||||
|
cause: ObligationCause<'tcx>,
|
||||||
|
depth: usize,
|
||||||
|
obligations: &mut Vec<PredicateObligation<'tcx>>,
|
||||||
|
) -> Ty<'tcx> {
|
||||||
|
let tcx = selcx.tcx();
|
||||||
|
|
||||||
|
if !tcx.recursion_limit().value_within_limit(depth) {
|
||||||
|
// Halt compilation because it is important that overflows never be masked.
|
||||||
|
tcx.sess.emit_fatal(InherentProjectionNormalizationOverflow {
|
||||||
|
span: cause.span,
|
||||||
|
ty: alias_ty.to_string(),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
let substs = compute_inherent_assoc_ty_substs(
|
||||||
|
selcx,
|
||||||
|
param_env,
|
||||||
|
alias_ty,
|
||||||
|
cause.clone(),
|
||||||
|
depth,
|
||||||
|
obligations,
|
||||||
|
);
|
||||||
|
|
||||||
|
// Register the obligations arising from the impl and from the associated type itself.
|
||||||
|
let predicates = tcx.predicates_of(alias_ty.def_id).instantiate(tcx, substs);
|
||||||
|
for (predicate, span) in predicates {
|
||||||
|
let predicate = normalize_with_depth_to(
|
||||||
|
selcx,
|
||||||
|
param_env,
|
||||||
|
cause.clone(),
|
||||||
|
depth + 1,
|
||||||
|
predicate,
|
||||||
|
obligations,
|
||||||
|
);
|
||||||
|
|
||||||
|
let nested_cause = ObligationCause::new(
|
||||||
|
cause.span,
|
||||||
|
cause.body_id,
|
||||||
|
// FIXME(inherent_associated_types): Since we can't pass along the self type to the
|
||||||
|
// cause code, inherent projections will be printed with identity substitutions in
|
||||||
|
// diagnostics which is not ideal.
|
||||||
|
// Consider creating separate cause codes for this specific situation.
|
||||||
|
if span.is_dummy() {
|
||||||
|
super::ItemObligation(alias_ty.def_id)
|
||||||
|
} else {
|
||||||
|
super::BindingObligation(alias_ty.def_id, span)
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
obligations.push(Obligation::with_depth(
|
||||||
|
tcx,
|
||||||
|
nested_cause,
|
||||||
|
depth + 1,
|
||||||
|
param_env,
|
||||||
|
predicate,
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
let ty = tcx.type_of(alias_ty.def_id).subst(tcx, substs);
|
||||||
|
|
||||||
|
let mut ty = selcx.infcx.resolve_vars_if_possible(ty);
|
||||||
|
if ty.has_projections() {
|
||||||
|
ty = normalize_with_depth_to(selcx, param_env, cause.clone(), depth + 1, ty, obligations);
|
||||||
|
}
|
||||||
|
|
||||||
|
ty
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn compute_inherent_assoc_ty_substs<'a, 'b, 'tcx>(
|
||||||
|
selcx: &'a mut SelectionContext<'b, 'tcx>,
|
||||||
|
param_env: ty::ParamEnv<'tcx>,
|
||||||
|
alias_ty: ty::AliasTy<'tcx>,
|
||||||
|
cause: ObligationCause<'tcx>,
|
||||||
|
depth: usize,
|
||||||
|
obligations: &mut Vec<PredicateObligation<'tcx>>,
|
||||||
|
) -> ty::SubstsRef<'tcx> {
|
||||||
|
let tcx = selcx.tcx();
|
||||||
|
|
||||||
|
let impl_def_id = tcx.parent(alias_ty.def_id);
|
||||||
|
let impl_substs = selcx.infcx.fresh_substs_for_item(cause.span, impl_def_id);
|
||||||
|
|
||||||
|
let impl_ty = tcx.type_of(impl_def_id).subst(tcx, impl_substs);
|
||||||
|
let impl_ty =
|
||||||
|
normalize_with_depth_to(selcx, param_env, cause.clone(), depth + 1, impl_ty, obligations);
|
||||||
|
|
||||||
|
// Infer the generic parameters of the impl by unifying the
|
||||||
|
// impl type with the self type of the projection.
|
||||||
|
let self_ty = alias_ty.self_ty();
|
||||||
|
match selcx.infcx.at(&cause, param_env).eq(DefineOpaqueTypes::No, impl_ty, self_ty) {
|
||||||
|
Ok(mut ok) => obligations.append(&mut ok.obligations),
|
||||||
|
Err(_) => {
|
||||||
|
tcx.sess.delay_span_bug(
|
||||||
|
cause.span,
|
||||||
|
format!(
|
||||||
|
"{self_ty:?} was a subtype of {impl_ty:?} during selection but now it is not"
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
alias_ty.rebase_substs_onto_impl(impl_substs, tcx)
|
||||||
|
}
|
||||||
|
|
||||||
enum Projected<'tcx> {
|
enum Projected<'tcx> {
|
||||||
Progress(Progress<'tcx>),
|
Progress(Progress<'tcx>),
|
||||||
NoProgress(ty::Term<'tcx>),
|
NoProgress(ty::Term<'tcx>),
|
||||||
|
@ -257,11 +257,11 @@ impl<'cx, 'tcx> FallibleTypeFolder<TyCtxt<'tcx>> for QueryNormalizer<'cx, 'tcx>
|
|||||||
|
|
||||||
ty::Opaque => ty.try_super_fold_with(self)?,
|
ty::Opaque => ty.try_super_fold_with(self)?,
|
||||||
|
|
||||||
ty::Projection => {
|
ty::Projection | ty::Inherent => {
|
||||||
// See note in `rustc_trait_selection::traits::project`
|
// See note in `rustc_trait_selection::traits::project`
|
||||||
|
|
||||||
let tcx = self.infcx.tcx;
|
|
||||||
let infcx = self.infcx;
|
let infcx = self.infcx;
|
||||||
|
let tcx = infcx.tcx;
|
||||||
// Just an optimization: When we don't have escaping bound vars,
|
// Just an optimization: When we don't have escaping bound vars,
|
||||||
// we don't need to replace them with placeholders.
|
// we don't need to replace them with placeholders.
|
||||||
let (data, maps) = if data.has_escaping_bound_vars() {
|
let (data, maps) = if data.has_escaping_bound_vars() {
|
||||||
@ -276,12 +276,15 @@ impl<'cx, 'tcx> FallibleTypeFolder<TyCtxt<'tcx>> for QueryNormalizer<'cx, 'tcx>
|
|||||||
let mut orig_values = OriginalQueryValues::default();
|
let mut orig_values = OriginalQueryValues::default();
|
||||||
// HACK(matthewjasper) `'static` is special-cased in selection,
|
// HACK(matthewjasper) `'static` is special-cased in selection,
|
||||||
// so we cannot canonicalize it.
|
// so we cannot canonicalize it.
|
||||||
let c_data = self
|
let c_data = infcx
|
||||||
.infcx
|
|
||||||
.canonicalize_query_keep_static(self.param_env.and(data), &mut orig_values);
|
.canonicalize_query_keep_static(self.param_env.and(data), &mut orig_values);
|
||||||
debug!("QueryNormalizer: c_data = {:#?}", c_data);
|
debug!("QueryNormalizer: c_data = {:#?}", c_data);
|
||||||
debug!("QueryNormalizer: orig_values = {:#?}", orig_values);
|
debug!("QueryNormalizer: orig_values = {:#?}", orig_values);
|
||||||
let result = tcx.normalize_projection_ty(c_data)?;
|
let result = match kind {
|
||||||
|
ty::Projection => tcx.normalize_projection_ty(c_data),
|
||||||
|
ty::Inherent => tcx.normalize_inherent_projection_ty(c_data),
|
||||||
|
_ => unreachable!(),
|
||||||
|
}?;
|
||||||
// We don't expect ambiguity.
|
// We don't expect ambiguity.
|
||||||
if result.is_ambiguous() {
|
if result.is_ambiguous() {
|
||||||
// Rustdoc normalizes possibly not well-formed types, so only
|
// Rustdoc normalizes possibly not well-formed types, so only
|
||||||
@ -294,8 +297,8 @@ impl<'cx, 'tcx> FallibleTypeFolder<TyCtxt<'tcx>> for QueryNormalizer<'cx, 'tcx>
|
|||||||
}
|
}
|
||||||
return Err(NoSolution);
|
return Err(NoSolution);
|
||||||
}
|
}
|
||||||
let InferOk { value: result, obligations } =
|
let InferOk { value: result, obligations } = infcx
|
||||||
self.infcx.instantiate_query_response_and_region_obligations(
|
.instantiate_query_response_and_region_obligations(
|
||||||
self.cause,
|
self.cause,
|
||||||
self.param_env,
|
self.param_env,
|
||||||
&orig_values,
|
&orig_values,
|
||||||
|
@ -498,7 +498,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
|||||||
// this trait and type.
|
// this trait and type.
|
||||||
}
|
}
|
||||||
ty::Param(..)
|
ty::Param(..)
|
||||||
| ty::Alias(ty::Projection, ..)
|
| ty::Alias(ty::Projection | ty::Inherent, ..)
|
||||||
| ty::Placeholder(..)
|
| ty::Placeholder(..)
|
||||||
| ty::Bound(..) => {
|
| ty::Bound(..) => {
|
||||||
// In these cases, we don't know what the actual
|
// In these cases, we don't know what the actual
|
||||||
|
@ -1268,7 +1268,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
|||||||
|
|
||||||
// If we have a projection type, make sure to normalize it so we replace it
|
// If we have a projection type, make sure to normalize it so we replace it
|
||||||
// with a fresh infer variable
|
// with a fresh infer variable
|
||||||
ty::Alias(ty::Projection, ..) => {
|
ty::Alias(ty::Projection | ty::Inherent, ..) => {
|
||||||
let predicate = normalize_with_depth_to(
|
let predicate = normalize_with_depth_to(
|
||||||
self,
|
self,
|
||||||
obligation.param_env,
|
obligation.param_env,
|
||||||
|
@ -2315,7 +2315,7 @@ impl<'tcx> SelectionContext<'_, 'tcx> {
|
|||||||
| ty::Dynamic(..)
|
| ty::Dynamic(..)
|
||||||
| ty::Param(..)
|
| ty::Param(..)
|
||||||
| ty::Foreign(..)
|
| ty::Foreign(..)
|
||||||
| ty::Alias(ty::Projection, ..)
|
| ty::Alias(ty::Projection | ty::Inherent, ..)
|
||||||
| ty::Bound(..)
|
| ty::Bound(..)
|
||||||
| ty::Infer(ty::TyVar(_) | ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_)) => {
|
| ty::Infer(ty::TyVar(_) | ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_)) => {
|
||||||
bug!("asked to assemble constituent types of unexpected type: {:?}", t);
|
bug!("asked to assemble constituent types of unexpected type: {:?}", t);
|
||||||
|
@ -58,15 +58,8 @@ pub fn obligations<'tcx>(
|
|||||||
GenericArgKind::Lifetime(..) => return Some(Vec::new()),
|
GenericArgKind::Lifetime(..) => return Some(Vec::new()),
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut wf = WfPredicates {
|
let mut wf =
|
||||||
tcx: infcx.tcx,
|
WfPredicates { infcx, param_env, body_id, span, out: vec![], recursion_depth, item: None };
|
||||||
param_env,
|
|
||||||
body_id,
|
|
||||||
span,
|
|
||||||
out: vec![],
|
|
||||||
recursion_depth,
|
|
||||||
item: None,
|
|
||||||
};
|
|
||||||
wf.compute(arg);
|
wf.compute(arg);
|
||||||
debug!("wf::obligations({:?}, body_id={:?}) = {:?}", arg, body_id, wf.out);
|
debug!("wf::obligations({:?}, body_id={:?}) = {:?}", arg, body_id, wf.out);
|
||||||
|
|
||||||
@ -91,7 +84,7 @@ pub fn unnormalized_obligations<'tcx>(
|
|||||||
debug_assert_eq!(arg, infcx.resolve_vars_if_possible(arg));
|
debug_assert_eq!(arg, infcx.resolve_vars_if_possible(arg));
|
||||||
|
|
||||||
let mut wf = WfPredicates {
|
let mut wf = WfPredicates {
|
||||||
tcx: infcx.tcx,
|
infcx,
|
||||||
param_env,
|
param_env,
|
||||||
body_id: CRATE_DEF_ID,
|
body_id: CRATE_DEF_ID,
|
||||||
span: DUMMY_SP,
|
span: DUMMY_SP,
|
||||||
@ -116,7 +109,7 @@ pub fn trait_obligations<'tcx>(
|
|||||||
item: &'tcx hir::Item<'tcx>,
|
item: &'tcx hir::Item<'tcx>,
|
||||||
) -> Vec<traits::PredicateObligation<'tcx>> {
|
) -> Vec<traits::PredicateObligation<'tcx>> {
|
||||||
let mut wf = WfPredicates {
|
let mut wf = WfPredicates {
|
||||||
tcx: infcx.tcx,
|
infcx,
|
||||||
param_env,
|
param_env,
|
||||||
body_id,
|
body_id,
|
||||||
span,
|
span,
|
||||||
@ -138,7 +131,7 @@ pub fn predicate_obligations<'tcx>(
|
|||||||
span: Span,
|
span: Span,
|
||||||
) -> Vec<traits::PredicateObligation<'tcx>> {
|
) -> Vec<traits::PredicateObligation<'tcx>> {
|
||||||
let mut wf = WfPredicates {
|
let mut wf = WfPredicates {
|
||||||
tcx: infcx.tcx,
|
infcx,
|
||||||
param_env,
|
param_env,
|
||||||
body_id,
|
body_id,
|
||||||
span,
|
span,
|
||||||
@ -190,8 +183,8 @@ pub fn predicate_obligations<'tcx>(
|
|||||||
wf.normalize(infcx)
|
wf.normalize(infcx)
|
||||||
}
|
}
|
||||||
|
|
||||||
struct WfPredicates<'tcx> {
|
struct WfPredicates<'a, 'tcx> {
|
||||||
tcx: TyCtxt<'tcx>,
|
infcx: &'a InferCtxt<'tcx>,
|
||||||
param_env: ty::ParamEnv<'tcx>,
|
param_env: ty::ParamEnv<'tcx>,
|
||||||
body_id: LocalDefId,
|
body_id: LocalDefId,
|
||||||
span: Span,
|
span: Span,
|
||||||
@ -290,9 +283,9 @@ fn extend_cause_with_original_assoc_item_obligation<'tcx>(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'tcx> WfPredicates<'tcx> {
|
impl<'a, 'tcx> WfPredicates<'a, 'tcx> {
|
||||||
fn tcx(&self) -> TyCtxt<'tcx> {
|
fn tcx(&self) -> TyCtxt<'tcx> {
|
||||||
self.tcx
|
self.infcx.tcx
|
||||||
}
|
}
|
||||||
|
|
||||||
fn cause(&self, code: traits::ObligationCauseCode<'tcx>) -> traits::ObligationCause<'tcx> {
|
fn cause(&self, code: traits::ObligationCauseCode<'tcx>) -> traits::ObligationCause<'tcx> {
|
||||||
@ -325,7 +318,7 @@ impl<'tcx> WfPredicates<'tcx> {
|
|||||||
|
|
||||||
/// Pushes the obligations required for `trait_ref` to be WF into `self.out`.
|
/// Pushes the obligations required for `trait_ref` to be WF into `self.out`.
|
||||||
fn compute_trait_pred(&mut self, trait_pred: &ty::TraitPredicate<'tcx>, elaborate: Elaborate) {
|
fn compute_trait_pred(&mut self, trait_pred: &ty::TraitPredicate<'tcx>, elaborate: Elaborate) {
|
||||||
let tcx = self.tcx;
|
let tcx = self.tcx();
|
||||||
let trait_ref = &trait_pred.trait_ref;
|
let trait_ref = &trait_pred.trait_ref;
|
||||||
|
|
||||||
// Negative trait predicates don't require supertraits to hold, just
|
// Negative trait predicates don't require supertraits to hold, just
|
||||||
@ -369,7 +362,6 @@ impl<'tcx> WfPredicates<'tcx> {
|
|||||||
self.out.extend(obligations);
|
self.out.extend(obligations);
|
||||||
}
|
}
|
||||||
|
|
||||||
let tcx = self.tcx();
|
|
||||||
self.out.extend(
|
self.out.extend(
|
||||||
trait_ref
|
trait_ref
|
||||||
.substs
|
.substs
|
||||||
@ -436,13 +428,45 @@ impl<'tcx> WfPredicates<'tcx> {
|
|||||||
let obligations = self.nominal_obligations_without_const(data.def_id, data.substs);
|
let obligations = self.nominal_obligations_without_const(data.def_id, data.substs);
|
||||||
self.out.extend(obligations);
|
self.out.extend(obligations);
|
||||||
|
|
||||||
|
self.compute_projection_substs(data.substs);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn compute_inherent_projection(&mut self, data: ty::AliasTy<'tcx>) {
|
||||||
|
// An inherent projection is well-formed if
|
||||||
|
//
|
||||||
|
// (a) its predicates hold (*)
|
||||||
|
// (b) its substs are wf
|
||||||
|
//
|
||||||
|
// (*) The predicates of an inherent associated type include the
|
||||||
|
// predicates of the impl that it's contained in.
|
||||||
|
|
||||||
|
if !data.self_ty().has_escaping_bound_vars() {
|
||||||
|
// FIXME(inherent_associated_types): Should this happen inside of a snapshot?
|
||||||
|
// FIXME(inherent_associated_types): This is incompatible with the new solver and lazy norm!
|
||||||
|
let substs = traits::project::compute_inherent_assoc_ty_substs(
|
||||||
|
&mut traits::SelectionContext::new(self.infcx),
|
||||||
|
self.param_env,
|
||||||
|
data,
|
||||||
|
self.cause(traits::WellFormed(None)),
|
||||||
|
self.recursion_depth,
|
||||||
|
&mut self.out,
|
||||||
|
);
|
||||||
|
// Inherent projection types do not require const predicates.
|
||||||
|
let obligations = self.nominal_obligations_without_const(data.def_id, substs);
|
||||||
|
self.out.extend(obligations);
|
||||||
|
}
|
||||||
|
|
||||||
|
self.compute_projection_substs(data.substs);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn compute_projection_substs(&mut self, substs: SubstsRef<'tcx>) {
|
||||||
let tcx = self.tcx();
|
let tcx = self.tcx();
|
||||||
let cause = self.cause(traits::WellFormed(None));
|
let cause = self.cause(traits::WellFormed(None));
|
||||||
let param_env = self.param_env;
|
let param_env = self.param_env;
|
||||||
let depth = self.recursion_depth;
|
let depth = self.recursion_depth;
|
||||||
|
|
||||||
self.out.extend(
|
self.out.extend(
|
||||||
data.substs
|
substs
|
||||||
.iter()
|
.iter()
|
||||||
.filter(|arg| {
|
.filter(|arg| {
|
||||||
matches!(arg.unpack(), GenericArgKind::Type(..) | GenericArgKind::Const(..))
|
matches!(arg.unpack(), GenericArgKind::Type(..) | GenericArgKind::Const(..))
|
||||||
@ -464,9 +488,9 @@ impl<'tcx> WfPredicates<'tcx> {
|
|||||||
if !subty.has_escaping_bound_vars() {
|
if !subty.has_escaping_bound_vars() {
|
||||||
let cause = self.cause(cause);
|
let cause = self.cause(cause);
|
||||||
let trait_ref =
|
let trait_ref =
|
||||||
ty::TraitRef::from_lang_item(self.tcx, LangItem::Sized, cause.span, [subty]);
|
ty::TraitRef::from_lang_item(self.tcx(), LangItem::Sized, cause.span, [subty]);
|
||||||
self.out.push(traits::Obligation::with_depth(
|
self.out.push(traits::Obligation::with_depth(
|
||||||
self.tcx,
|
self.tcx(),
|
||||||
cause,
|
cause,
|
||||||
self.recursion_depth,
|
self.recursion_depth,
|
||||||
self.param_env,
|
self.param_env,
|
||||||
@ -605,6 +629,10 @@ impl<'tcx> WfPredicates<'tcx> {
|
|||||||
walker.skip_current_subtree(); // Subtree handled by compute_projection.
|
walker.skip_current_subtree(); // Subtree handled by compute_projection.
|
||||||
self.compute_projection(data);
|
self.compute_projection(data);
|
||||||
}
|
}
|
||||||
|
ty::Alias(ty::Inherent, data) => {
|
||||||
|
walker.skip_current_subtree(); // Subtree handled by compute_inherent_projection.
|
||||||
|
self.compute_inherent_projection(data);
|
||||||
|
}
|
||||||
|
|
||||||
ty::Adt(def, substs) => {
|
ty::Adt(def, substs) => {
|
||||||
// WfNominalType
|
// WfNominalType
|
||||||
@ -697,7 +725,7 @@ impl<'tcx> WfPredicates<'tcx> {
|
|||||||
// All of the requirements on type parameters
|
// All of the requirements on type parameters
|
||||||
// have already been checked for `impl Trait` in
|
// have already been checked for `impl Trait` in
|
||||||
// return position. We do need to check type-alias-impl-trait though.
|
// return position. We do need to check type-alias-impl-trait though.
|
||||||
if self.tcx.is_type_alias_impl_trait(def_id) {
|
if self.tcx().is_type_alias_impl_trait(def_id) {
|
||||||
let obligations = self.nominal_obligations(def_id, substs);
|
let obligations = self.nominal_obligations(def_id, substs);
|
||||||
self.out.extend(obligations);
|
self.out.extend(obligations);
|
||||||
}
|
}
|
||||||
@ -767,15 +795,15 @@ impl<'tcx> WfPredicates<'tcx> {
|
|||||||
substs: SubstsRef<'tcx>,
|
substs: SubstsRef<'tcx>,
|
||||||
remap_constness: bool,
|
remap_constness: bool,
|
||||||
) -> Vec<traits::PredicateObligation<'tcx>> {
|
) -> Vec<traits::PredicateObligation<'tcx>> {
|
||||||
let predicates = self.tcx.predicates_of(def_id);
|
let predicates = self.tcx().predicates_of(def_id);
|
||||||
let mut origins = vec![def_id; predicates.predicates.len()];
|
let mut origins = vec![def_id; predicates.predicates.len()];
|
||||||
let mut head = predicates;
|
let mut head = predicates;
|
||||||
while let Some(parent) = head.parent {
|
while let Some(parent) = head.parent {
|
||||||
head = self.tcx.predicates_of(parent);
|
head = self.tcx().predicates_of(parent);
|
||||||
origins.extend(iter::repeat(parent).take(head.predicates.len()));
|
origins.extend(iter::repeat(parent).take(head.predicates.len()));
|
||||||
}
|
}
|
||||||
|
|
||||||
let predicates = predicates.instantiate(self.tcx, substs);
|
let predicates = predicates.instantiate(self.tcx(), substs);
|
||||||
trace!("{:#?}", predicates);
|
trace!("{:#?}", predicates);
|
||||||
debug_assert_eq!(predicates.predicates.len(), origins.len());
|
debug_assert_eq!(predicates.predicates.len(), origins.len());
|
||||||
|
|
||||||
@ -788,10 +816,10 @@ impl<'tcx> WfPredicates<'tcx> {
|
|||||||
};
|
};
|
||||||
let cause = self.cause(code);
|
let cause = self.cause(code);
|
||||||
if remap_constness {
|
if remap_constness {
|
||||||
pred = pred.without_const(self.tcx);
|
pred = pred.without_const(self.tcx());
|
||||||
}
|
}
|
||||||
traits::Obligation::with_depth(
|
traits::Obligation::with_depth(
|
||||||
self.tcx,
|
self.tcx(),
|
||||||
cause,
|
cause,
|
||||||
self.recursion_depth,
|
self.recursion_depth,
|
||||||
self.param_env,
|
self.param_env,
|
||||||
@ -856,7 +884,7 @@ impl<'tcx> WfPredicates<'tcx> {
|
|||||||
// Note: in fact we only permit builtin traits, not `Bar<'d>`, I
|
// Note: in fact we only permit builtin traits, not `Bar<'d>`, I
|
||||||
// am looking forward to the future here.
|
// am looking forward to the future here.
|
||||||
if !data.has_escaping_bound_vars() && !region.has_escaping_bound_vars() {
|
if !data.has_escaping_bound_vars() && !region.has_escaping_bound_vars() {
|
||||||
let implicit_bounds = object_region_bounds(self.tcx, data);
|
let implicit_bounds = object_region_bounds(self.tcx(), data);
|
||||||
|
|
||||||
let explicit_bound = region;
|
let explicit_bound = region;
|
||||||
|
|
||||||
@ -866,7 +894,7 @@ impl<'tcx> WfPredicates<'tcx> {
|
|||||||
let outlives =
|
let outlives =
|
||||||
ty::Binder::dummy(ty::OutlivesPredicate(explicit_bound, implicit_bound));
|
ty::Binder::dummy(ty::OutlivesPredicate(explicit_bound, implicit_bound));
|
||||||
self.out.push(traits::Obligation::with_depth(
|
self.out.push(traits::Obligation::with_depth(
|
||||||
self.tcx,
|
self.tcx(),
|
||||||
cause,
|
cause,
|
||||||
self.recursion_depth,
|
self.recursion_depth,
|
||||||
self.param_env,
|
self.param_env,
|
||||||
|
@ -372,6 +372,7 @@ impl<'tcx> LowerInto<'tcx, chalk_ir::Ty<RustInterner<'tcx>>> for Ty<'tcx> {
|
|||||||
substitution: substs.lower_into(interner),
|
substitution: substs.lower_into(interner),
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
|
ty::Alias(ty::Inherent, _) => unimplemented!(),
|
||||||
ty::Alias(ty::Opaque, ty::AliasTy { def_id, substs, .. }) => {
|
ty::Alias(ty::Opaque, ty::AliasTy { def_id, substs, .. }) => {
|
||||||
chalk_ir::TyKind::Alias(chalk_ir::AliasTy::Opaque(chalk_ir::OpaqueTy {
|
chalk_ir::TyKind::Alias(chalk_ir::AliasTy::Opaque(chalk_ir::OpaqueTy {
|
||||||
opaque_ty_id: chalk_ir::OpaqueTyId(def_id),
|
opaque_ty_id: chalk_ir::OpaqueTyId(def_id),
|
||||||
|
@ -10,7 +10,7 @@ use rustc_trait_selection::traits::{self, ObligationCause, SelectionContext};
|
|||||||
use std::sync::atomic::Ordering;
|
use std::sync::atomic::Ordering;
|
||||||
|
|
||||||
pub(crate) fn provide(p: &mut Providers) {
|
pub(crate) fn provide(p: &mut Providers) {
|
||||||
*p = Providers { normalize_projection_ty, ..*p };
|
*p = Providers { normalize_projection_ty, normalize_inherent_projection_ty, ..*p };
|
||||||
}
|
}
|
||||||
|
|
||||||
fn normalize_projection_ty<'tcx>(
|
fn normalize_projection_ty<'tcx>(
|
||||||
@ -42,3 +42,30 @@ fn normalize_projection_ty<'tcx>(
|
|||||||
},
|
},
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn normalize_inherent_projection_ty<'tcx>(
|
||||||
|
tcx: TyCtxt<'tcx>,
|
||||||
|
goal: CanonicalProjectionGoal<'tcx>,
|
||||||
|
) -> Result<&'tcx Canonical<'tcx, QueryResponse<'tcx, NormalizationResult<'tcx>>>, NoSolution> {
|
||||||
|
debug!("normalize_provider(goal={:#?})", goal);
|
||||||
|
|
||||||
|
tcx.infer_ctxt().enter_canonical_trait_query(
|
||||||
|
&goal,
|
||||||
|
|ocx, ParamEnvAnd { param_env, value: goal }| {
|
||||||
|
let selcx = &mut SelectionContext::new(ocx.infcx);
|
||||||
|
let cause = ObligationCause::dummy();
|
||||||
|
let mut obligations = vec![];
|
||||||
|
let answer = traits::normalize_inherent_projection(
|
||||||
|
selcx,
|
||||||
|
param_env,
|
||||||
|
goal,
|
||||||
|
cause,
|
||||||
|
0,
|
||||||
|
&mut obligations,
|
||||||
|
);
|
||||||
|
ocx.register_obligations(obligations);
|
||||||
|
|
||||||
|
Ok(NormalizationResult { normalized_ty: answer })
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
@ -194,21 +194,18 @@ fn resolve_associated_item<'tcx>(
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
traits::ImplSource::Future(future_data) => {
|
traits::ImplSource::Future(future_data) => {
|
||||||
if cfg!(debug_assertions) && tcx.item_name(trait_item_id) != sym::poll {
|
if Some(trait_item_id) == tcx.lang_items().future_poll_fn() {
|
||||||
// For compiler developers who'd like to add new items to `Future`,
|
// `Future::poll` is generated by the compiler.
|
||||||
// you either need to generate a shim body, or perhaps return
|
Some(Instance {
|
||||||
// `InstanceDef::Item` pointing to a trait default method body if
|
def: ty::InstanceDef::Item(future_data.generator_def_id),
|
||||||
// it is given a default implementation by the trait.
|
substs: future_data.substs,
|
||||||
span_bug!(
|
})
|
||||||
tcx.def_span(future_data.generator_def_id),
|
} else {
|
||||||
"no definition for `{trait_ref}::{}` for built-in async generator type",
|
// All other methods are default methods of the `Future` trait.
|
||||||
tcx.item_name(trait_item_id)
|
// (this assumes that `ImplSource::Future` is only used for methods on `Future`)
|
||||||
)
|
debug_assert!(tcx.impl_defaultness(trait_item_id).has_value());
|
||||||
|
Some(Instance::new(trait_item_id, rcvr_substs))
|
||||||
}
|
}
|
||||||
Some(Instance {
|
|
||||||
def: ty::InstanceDef::Item(future_data.generator_def_id),
|
|
||||||
substs: future_data.substs,
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
traits::ImplSource::Closure(closure_data) => {
|
traits::ImplSource::Closure(closure_data) => {
|
||||||
if cfg!(debug_assertions)
|
if cfg!(debug_assertions)
|
||||||
|
@ -229,29 +229,32 @@ bitflags! {
|
|||||||
|
|
||||||
/// Does this have `Projection`?
|
/// Does this have `Projection`?
|
||||||
const HAS_TY_PROJECTION = 1 << 10;
|
const HAS_TY_PROJECTION = 1 << 10;
|
||||||
|
/// Does this have `Inherent`?
|
||||||
|
const HAS_TY_INHERENT = 1 << 11;
|
||||||
/// Does this have `Opaque`?
|
/// Does this have `Opaque`?
|
||||||
const HAS_TY_OPAQUE = 1 << 11;
|
const HAS_TY_OPAQUE = 1 << 12;
|
||||||
/// Does this have `ConstKind::Unevaluated`?
|
/// Does this have `ConstKind::Unevaluated`?
|
||||||
const HAS_CT_PROJECTION = 1 << 12;
|
const HAS_CT_PROJECTION = 1 << 13;
|
||||||
|
|
||||||
/// Could this type be normalized further?
|
/// Could this type be normalized further?
|
||||||
const HAS_PROJECTION = TypeFlags::HAS_TY_PROJECTION.bits
|
const HAS_PROJECTION = TypeFlags::HAS_TY_PROJECTION.bits
|
||||||
| TypeFlags::HAS_TY_OPAQUE.bits
|
| TypeFlags::HAS_TY_OPAQUE.bits
|
||||||
|
| TypeFlags::HAS_TY_INHERENT.bits
|
||||||
| TypeFlags::HAS_CT_PROJECTION.bits;
|
| TypeFlags::HAS_CT_PROJECTION.bits;
|
||||||
|
|
||||||
/// Is an error type/const reachable?
|
/// Is an error type/const reachable?
|
||||||
const HAS_ERROR = 1 << 13;
|
const HAS_ERROR = 1 << 14;
|
||||||
|
|
||||||
/// Does this have any region that "appears free" in the type?
|
/// Does this have any region that "appears free" in the type?
|
||||||
/// Basically anything but `ReLateBound` and `ReErased`.
|
/// Basically anything but `ReLateBound` and `ReErased`.
|
||||||
const HAS_FREE_REGIONS = 1 << 14;
|
const HAS_FREE_REGIONS = 1 << 15;
|
||||||
|
|
||||||
/// Does this have any `ReLateBound` regions?
|
/// Does this have any `ReLateBound` regions?
|
||||||
const HAS_RE_LATE_BOUND = 1 << 15;
|
const HAS_RE_LATE_BOUND = 1 << 16;
|
||||||
/// Does this have any `Bound` types?
|
/// Does this have any `Bound` types?
|
||||||
const HAS_TY_LATE_BOUND = 1 << 16;
|
const HAS_TY_LATE_BOUND = 1 << 17;
|
||||||
/// Does this have any `ConstKind::Bound` consts?
|
/// Does this have any `ConstKind::Bound` consts?
|
||||||
const HAS_CT_LATE_BOUND = 1 << 17;
|
const HAS_CT_LATE_BOUND = 1 << 18;
|
||||||
/// Does this have any bound variables?
|
/// Does this have any bound variables?
|
||||||
/// Used to check if a global bound is safe to evaluate.
|
/// Used to check if a global bound is safe to evaluate.
|
||||||
const HAS_LATE_BOUND = TypeFlags::HAS_RE_LATE_BOUND.bits
|
const HAS_LATE_BOUND = TypeFlags::HAS_RE_LATE_BOUND.bits
|
||||||
@ -259,20 +262,20 @@ bitflags! {
|
|||||||
| TypeFlags::HAS_CT_LATE_BOUND.bits;
|
| TypeFlags::HAS_CT_LATE_BOUND.bits;
|
||||||
|
|
||||||
/// Does this have any `ReErased` regions?
|
/// Does this have any `ReErased` regions?
|
||||||
const HAS_RE_ERASED = 1 << 18;
|
const HAS_RE_ERASED = 1 << 19;
|
||||||
|
|
||||||
/// Does this value have parameters/placeholders/inference variables which could be
|
/// Does this value have parameters/placeholders/inference variables which could be
|
||||||
/// replaced later, in a way that would change the results of `impl` specialization?
|
/// replaced later, in a way that would change the results of `impl` specialization?
|
||||||
const STILL_FURTHER_SPECIALIZABLE = 1 << 19;
|
const STILL_FURTHER_SPECIALIZABLE = 1 << 20;
|
||||||
|
|
||||||
/// Does this value have `InferTy::FreshTy/FreshIntTy/FreshFloatTy`?
|
/// Does this value have `InferTy::FreshTy/FreshIntTy/FreshFloatTy`?
|
||||||
const HAS_TY_FRESH = 1 << 20;
|
const HAS_TY_FRESH = 1 << 21;
|
||||||
|
|
||||||
/// Does this value have `InferConst::Fresh`?
|
/// Does this value have `InferConst::Fresh`?
|
||||||
const HAS_CT_FRESH = 1 << 21;
|
const HAS_CT_FRESH = 1 << 22;
|
||||||
|
|
||||||
/// Does this have `Generator` or `GeneratorWitness`?
|
/// Does this have `Generator` or `GeneratorWitness`?
|
||||||
const HAS_TY_GENERATOR = 1 << 22;
|
const HAS_TY_GENERATOR = 1 << 23;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -37,6 +37,7 @@ pub enum DynKind {
|
|||||||
#[derive(Encodable, Decodable, HashStable_Generic)]
|
#[derive(Encodable, Decodable, HashStable_Generic)]
|
||||||
pub enum AliasKind {
|
pub enum AliasKind {
|
||||||
Projection,
|
Projection,
|
||||||
|
Inherent,
|
||||||
Opaque,
|
Opaque,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -47,6 +47,7 @@ pub enum EHAction {
|
|||||||
None,
|
None,
|
||||||
Cleanup(usize),
|
Cleanup(usize),
|
||||||
Catch(usize),
|
Catch(usize),
|
||||||
|
Filter(usize),
|
||||||
Terminate,
|
Terminate,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -142,9 +143,11 @@ unsafe fn interpret_cs_action(
|
|||||||
let ttype_index = action_reader.read_sleb128();
|
let ttype_index = action_reader.read_sleb128();
|
||||||
if ttype_index == 0 {
|
if ttype_index == 0 {
|
||||||
EHAction::Cleanup(lpad)
|
EHAction::Cleanup(lpad)
|
||||||
} else {
|
} else if ttype_index > 0 {
|
||||||
// Stop unwinding Rust panics at catch_unwind.
|
// Stop unwinding Rust panics at catch_unwind.
|
||||||
EHAction::Catch(lpad)
|
EHAction::Catch(lpad)
|
||||||
|
} else {
|
||||||
|
EHAction::Filter(lpad)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -135,7 +135,7 @@ cfg_if::cfg_if! {
|
|||||||
EHAction::None | EHAction::Cleanup(_) => {
|
EHAction::None | EHAction::Cleanup(_) => {
|
||||||
return continue_unwind(exception_object, context);
|
return continue_unwind(exception_object, context);
|
||||||
}
|
}
|
||||||
EHAction::Catch(_) => {
|
EHAction::Catch(_) | EHAction::Filter(_) => {
|
||||||
// EHABI requires the personality routine to update the
|
// EHABI requires the personality routine to update the
|
||||||
// SP value in the barrier cache of the exception object.
|
// SP value in the barrier cache of the exception object.
|
||||||
(*exception_object).private[5] =
|
(*exception_object).private[5] =
|
||||||
@ -147,7 +147,8 @@ cfg_if::cfg_if! {
|
|||||||
} else {
|
} else {
|
||||||
match eh_action {
|
match eh_action {
|
||||||
EHAction::None => return continue_unwind(exception_object, context),
|
EHAction::None => return continue_unwind(exception_object, context),
|
||||||
EHAction::Cleanup(lpad) | EHAction::Catch(lpad) => {
|
EHAction::Filter(_) if state & uw::_US_FORCE_UNWIND as c_int != 0 => return continue_unwind(exception_object, context),
|
||||||
|
EHAction::Cleanup(lpad) | EHAction::Catch(lpad) | EHAction::Filter(lpad) => {
|
||||||
uw::_Unwind_SetGR(
|
uw::_Unwind_SetGR(
|
||||||
context,
|
context,
|
||||||
UNWIND_DATA_REG.0,
|
UNWIND_DATA_REG.0,
|
||||||
@ -201,13 +202,15 @@ cfg_if::cfg_if! {
|
|||||||
if actions as i32 & uw::_UA_SEARCH_PHASE as i32 != 0 {
|
if actions as i32 & uw::_UA_SEARCH_PHASE as i32 != 0 {
|
||||||
match eh_action {
|
match eh_action {
|
||||||
EHAction::None | EHAction::Cleanup(_) => uw::_URC_CONTINUE_UNWIND,
|
EHAction::None | EHAction::Cleanup(_) => uw::_URC_CONTINUE_UNWIND,
|
||||||
EHAction::Catch(_) => uw::_URC_HANDLER_FOUND,
|
EHAction::Catch(_) | EHAction::Filter(_) => uw::_URC_HANDLER_FOUND,
|
||||||
EHAction::Terminate => uw::_URC_FATAL_PHASE1_ERROR,
|
EHAction::Terminate => uw::_URC_FATAL_PHASE1_ERROR,
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
match eh_action {
|
match eh_action {
|
||||||
EHAction::None => uw::_URC_CONTINUE_UNWIND,
|
EHAction::None => uw::_URC_CONTINUE_UNWIND,
|
||||||
EHAction::Cleanup(lpad) | EHAction::Catch(lpad) => {
|
// Forced unwinding hits a terminate action.
|
||||||
|
EHAction::Filter(_) if actions as i32 & uw::_UA_FORCE_UNWIND as i32 != 0 => uw::_URC_CONTINUE_UNWIND,
|
||||||
|
EHAction::Cleanup(lpad) | EHAction::Catch(lpad) | EHAction::Filter(lpad) => {
|
||||||
uw::_Unwind_SetGR(
|
uw::_Unwind_SetGR(
|
||||||
context,
|
context,
|
||||||
UNWIND_DATA_REG.0,
|
UNWIND_DATA_REG.0,
|
||||||
|
@ -556,7 +556,10 @@ where
|
|||||||
WherePredicate::EqPredicate { lhs, rhs, bound_params } => {
|
WherePredicate::EqPredicate { lhs, rhs, bound_params } => {
|
||||||
match *lhs {
|
match *lhs {
|
||||||
Type::QPath(box QPathData {
|
Type::QPath(box QPathData {
|
||||||
ref assoc, ref self_type, ref trait_, ..
|
ref assoc,
|
||||||
|
ref self_type,
|
||||||
|
trait_: Some(ref trait_),
|
||||||
|
..
|
||||||
}) => {
|
}) => {
|
||||||
let ty = &*self_type;
|
let ty = &*self_type;
|
||||||
let mut new_trait = trait_.clone();
|
let mut new_trait = trait_.clone();
|
||||||
|
@ -706,7 +706,12 @@ fn filter_non_trait_generics(trait_did: DefId, mut g: clean::Generics) -> clean:
|
|||||||
|
|
||||||
g.where_predicates.retain(|pred| match pred {
|
g.where_predicates.retain(|pred| match pred {
|
||||||
clean::WherePredicate::BoundPredicate {
|
clean::WherePredicate::BoundPredicate {
|
||||||
ty: clean::QPath(box clean::QPathData { self_type: clean::Generic(ref s), trait_, .. }),
|
ty:
|
||||||
|
clean::QPath(box clean::QPathData {
|
||||||
|
self_type: clean::Generic(ref s),
|
||||||
|
trait_: Some(trait_),
|
||||||
|
..
|
||||||
|
}),
|
||||||
bounds,
|
bounds,
|
||||||
..
|
..
|
||||||
} => !(bounds.is_empty() || *s == kw::SelfUpper && trait_.def_id() == trait_did),
|
} => !(bounds.is_empty() || *s == kw::SelfUpper && trait_.def_id() == trait_did),
|
||||||
|
@ -441,7 +441,7 @@ fn clean_projection<'tcx>(
|
|||||||
assoc: projection_to_path_segment(ty, cx),
|
assoc: projection_to_path_segment(ty, cx),
|
||||||
should_show_cast,
|
should_show_cast,
|
||||||
self_type,
|
self_type,
|
||||||
trait_,
|
trait_: Some(trait_),
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1330,7 +1330,13 @@ pub(crate) fn clean_middle_assoc_item<'tcx>(
|
|||||||
let mut bounds: Vec<GenericBound> = Vec::new();
|
let mut bounds: Vec<GenericBound> = Vec::new();
|
||||||
generics.where_predicates.retain_mut(|pred| match *pred {
|
generics.where_predicates.retain_mut(|pred| match *pred {
|
||||||
WherePredicate::BoundPredicate {
|
WherePredicate::BoundPredicate {
|
||||||
ty: QPath(box QPathData { ref assoc, ref self_type, ref trait_, .. }),
|
ty:
|
||||||
|
QPath(box QPathData {
|
||||||
|
ref assoc,
|
||||||
|
ref self_type,
|
||||||
|
trait_: Some(ref trait_),
|
||||||
|
..
|
||||||
|
}),
|
||||||
bounds: ref mut pred_bounds,
|
bounds: ref mut pred_bounds,
|
||||||
..
|
..
|
||||||
} => {
|
} => {
|
||||||
@ -1492,25 +1498,30 @@ fn clean_qpath<'tcx>(hir_ty: &hir::Ty<'tcx>, cx: &mut DocContext<'tcx>) -> Type
|
|||||||
assoc: clean_path_segment(p.segments.last().expect("segments were empty"), cx),
|
assoc: clean_path_segment(p.segments.last().expect("segments were empty"), cx),
|
||||||
should_show_cast,
|
should_show_cast,
|
||||||
self_type,
|
self_type,
|
||||||
trait_,
|
trait_: Some(trait_),
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
hir::QPath::TypeRelative(qself, segment) => {
|
hir::QPath::TypeRelative(qself, segment) => {
|
||||||
let ty = hir_ty_to_ty(cx.tcx, hir_ty);
|
let ty = hir_ty_to_ty(cx.tcx, hir_ty);
|
||||||
let res = match ty.kind() {
|
let self_type = clean_ty(qself, cx);
|
||||||
|
|
||||||
|
let (trait_, should_show_cast) = match ty.kind() {
|
||||||
ty::Alias(ty::Projection, proj) => {
|
ty::Alias(ty::Projection, proj) => {
|
||||||
Res::Def(DefKind::Trait, proj.trait_ref(cx.tcx).def_id)
|
let res = Res::Def(DefKind::Trait, proj.trait_ref(cx.tcx).def_id);
|
||||||
|
let trait_ = clean_path(&hir::Path { span, res, segments: &[] }, cx);
|
||||||
|
register_res(cx, trait_.res);
|
||||||
|
let self_def_id = res.opt_def_id();
|
||||||
|
let should_show_cast =
|
||||||
|
compute_should_show_cast(self_def_id, &trait_, &self_type);
|
||||||
|
|
||||||
|
(Some(trait_), should_show_cast)
|
||||||
}
|
}
|
||||||
|
ty::Alias(ty::Inherent, _) => (None, false),
|
||||||
// Rustdoc handles `ty::Error`s by turning them into `Type::Infer`s.
|
// Rustdoc handles `ty::Error`s by turning them into `Type::Infer`s.
|
||||||
ty::Error(_) => return Type::Infer,
|
ty::Error(_) => return Type::Infer,
|
||||||
// Otherwise, this is an inherent associated type.
|
_ => bug!("clean: expected associated type, found `{ty:?}`"),
|
||||||
_ => return clean_middle_ty(ty::Binder::dummy(ty), cx, None),
|
|
||||||
};
|
};
|
||||||
let trait_ = clean_path(&hir::Path { span, res, segments: &[] }, cx);
|
|
||||||
register_res(cx, trait_.res);
|
|
||||||
let self_def_id = res.opt_def_id();
|
|
||||||
let self_type = clean_ty(qself, cx);
|
|
||||||
let should_show_cast = compute_should_show_cast(self_def_id, &trait_, &self_type);
|
|
||||||
Type::QPath(Box::new(QPathData {
|
Type::QPath(Box::new(QPathData {
|
||||||
assoc: clean_path_segment(segment, cx),
|
assoc: clean_path_segment(segment, cx),
|
||||||
should_show_cast,
|
should_show_cast,
|
||||||
@ -1836,6 +1847,29 @@ pub(crate) fn clean_middle_ty<'tcx>(
|
|||||||
clean_projection(bound_ty.rebind(*data), cx, parent_def_id)
|
clean_projection(bound_ty.rebind(*data), cx, parent_def_id)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ty::Alias(ty::Inherent, alias_ty) => {
|
||||||
|
let alias_ty = bound_ty.rebind(alias_ty);
|
||||||
|
let self_type = clean_middle_ty(alias_ty.map_bound(|ty| ty.self_ty()), cx, None);
|
||||||
|
|
||||||
|
Type::QPath(Box::new(QPathData {
|
||||||
|
assoc: PathSegment {
|
||||||
|
name: cx.tcx.associated_item(alias_ty.skip_binder().def_id).name,
|
||||||
|
args: GenericArgs::AngleBracketed {
|
||||||
|
args: substs_to_args(
|
||||||
|
cx,
|
||||||
|
alias_ty.map_bound(|ty| ty.substs.as_slice()),
|
||||||
|
true,
|
||||||
|
)
|
||||||
|
.into(),
|
||||||
|
bindings: Default::default(),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
should_show_cast: false,
|
||||||
|
self_type,
|
||||||
|
trait_: None,
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
|
||||||
ty::Param(ref p) => {
|
ty::Param(ref p) => {
|
||||||
if let Some(bounds) = cx.impl_trait_bounds.remove(&p.index.into()) {
|
if let Some(bounds) = cx.impl_trait_bounds.remove(&p.index.into()) {
|
||||||
ImplTrait(bounds)
|
ImplTrait(bounds)
|
||||||
|
@ -1660,7 +1660,7 @@ impl Type {
|
|||||||
|
|
||||||
pub(crate) fn projection(&self) -> Option<(&Type, DefId, PathSegment)> {
|
pub(crate) fn projection(&self) -> Option<(&Type, DefId, PathSegment)> {
|
||||||
if let QPath(box QPathData { self_type, trait_, assoc, .. }) = self {
|
if let QPath(box QPathData { self_type, trait_, assoc, .. }) = self {
|
||||||
Some((self_type, trait_.def_id(), assoc.clone()))
|
Some((self_type, trait_.as_ref()?.def_id(), assoc.clone()))
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
@ -1704,7 +1704,7 @@ pub(crate) struct QPathData {
|
|||||||
pub self_type: Type,
|
pub self_type: Type,
|
||||||
/// FIXME: compute this field on demand.
|
/// FIXME: compute this field on demand.
|
||||||
pub should_show_cast: bool,
|
pub should_show_cast: bool,
|
||||||
pub trait_: Path,
|
pub trait_: Option<Path>,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A primitive (aka, builtin) type.
|
/// A primitive (aka, builtin) type.
|
||||||
|
@ -1116,14 +1116,17 @@ fn fmt_type<'cx>(
|
|||||||
ref trait_,
|
ref trait_,
|
||||||
should_show_cast,
|
should_show_cast,
|
||||||
}) => {
|
}) => {
|
||||||
|
// FIXME(inherent_associated_types): Once we support non-ADT self-types (#106719),
|
||||||
|
// we need to surround them with angle brackets in some cases (e.g. `<dyn …>::P`).
|
||||||
|
|
||||||
if f.alternate() {
|
if f.alternate() {
|
||||||
if should_show_cast {
|
if let Some(trait_) = trait_ && should_show_cast {
|
||||||
write!(f, "<{:#} as {:#}>::", self_type.print(cx), trait_.print(cx))?
|
write!(f, "<{:#} as {:#}>::", self_type.print(cx), trait_.print(cx))?
|
||||||
} else {
|
} else {
|
||||||
write!(f, "{:#}::", self_type.print(cx))?
|
write!(f, "{:#}::", self_type.print(cx))?
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if should_show_cast {
|
if let Some(trait_) = trait_ && should_show_cast {
|
||||||
write!(f, "<{} as {}>::", self_type.print(cx), trait_.print(cx))?
|
write!(f, "<{} as {}>::", self_type.print(cx), trait_.print(cx))?
|
||||||
} else {
|
} else {
|
||||||
write!(f, "{}::", self_type.print(cx))?
|
write!(f, "{}::", self_type.print(cx))?
|
||||||
@ -1139,15 +1142,36 @@ fn fmt_type<'cx>(
|
|||||||
// the ugliness comes from inlining across crates where
|
// the ugliness comes from inlining across crates where
|
||||||
// everything comes in as a fully resolved QPath (hard to
|
// everything comes in as a fully resolved QPath (hard to
|
||||||
// look at).
|
// look at).
|
||||||
if !f.alternate() && let Ok((url, _, path)) = href(trait_.def_id(), cx) {
|
if !f.alternate() {
|
||||||
write!(
|
// FIXME(inherent_associated_types): We always link to the very first associated
|
||||||
f,
|
// type (in respect to source order) that bears the given name (`assoc.name`) and that is
|
||||||
"<a class=\"associatedtype\" href=\"{url}#{shortty}.{name}\" \
|
// affiliated with the computed `DefId`. This is obviously incorrect when we have
|
||||||
title=\"type {path}::{name}\">{name}</a>",
|
// multiple impl blocks. Ideally, we would thread the `DefId` of the assoc ty itself
|
||||||
shortty = ItemType::AssocType,
|
// through here and map it to the corresponding HTML ID that was generated by
|
||||||
name = assoc.name,
|
// `render::Context::derive_id` when the impl blocks were rendered.
|
||||||
path = join_with_double_colon(&path),
|
// There is no such mapping unfortunately.
|
||||||
)
|
// As a hack, we could badly imitate `derive_id` here by keeping *count* when looking
|
||||||
|
// for the assoc ty `DefId` in `tcx.associated_items(self_ty_did).in_definition_order()`
|
||||||
|
// considering privacy, `doc(hidden)`, etc.
|
||||||
|
// I don't feel like that right now :cold_sweat:.
|
||||||
|
|
||||||
|
let parent_href = match trait_ {
|
||||||
|
Some(trait_) => href(trait_.def_id(), cx).ok(),
|
||||||
|
None => self_type.def_id(cx.cache()).and_then(|did| href(did, cx).ok()),
|
||||||
|
};
|
||||||
|
|
||||||
|
if let Some((url, _, path)) = parent_href {
|
||||||
|
write!(
|
||||||
|
f,
|
||||||
|
"<a class=\"associatedtype\" href=\"{url}#{shortty}.{name}\" \
|
||||||
|
title=\"type {path}::{name}\">{name}</a>",
|
||||||
|
shortty = ItemType::AssocType,
|
||||||
|
name = assoc.name,
|
||||||
|
path = join_with_double_colon(&path),
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
write!(f, "{}", assoc.name)
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
write!(f, "{}", assoc.name)
|
write!(f, "{}", assoc.name)
|
||||||
}?;
|
}?;
|
||||||
|
@ -2202,7 +2202,9 @@ fn collect_paths_for_type(first_ty: clean::Type, cache: &Cache) -> Vec<String> {
|
|||||||
}
|
}
|
||||||
clean::Type::QPath(box clean::QPathData { self_type, trait_, .. }) => {
|
clean::Type::QPath(box clean::QPathData { self_type, trait_, .. }) => {
|
||||||
work.push_back(self_type);
|
work.push_back(self_type);
|
||||||
process_path(trait_.def_id());
|
if let Some(trait_) = trait_ {
|
||||||
|
process_path(trait_.def_id());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
|
@ -574,7 +574,7 @@ impl FromWithTcx<clean::Type> for Type {
|
|||||||
name: assoc.name.to_string(),
|
name: assoc.name.to_string(),
|
||||||
args: Box::new(assoc.args.into_tcx(tcx)),
|
args: Box::new(assoc.args.into_tcx(tcx)),
|
||||||
self_type: Box::new(self_type.into_tcx(tcx)),
|
self_type: Box::new(self_type.into_tcx(tcx)),
|
||||||
trait_: trait_.into_tcx(tcx),
|
trait_: trait_.map(|trait_| trait_.into_tcx(tcx)),
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -8,7 +8,7 @@ use serde::{Deserialize, Serialize};
|
|||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
|
|
||||||
/// rustdoc format-version.
|
/// rustdoc format-version.
|
||||||
pub const FORMAT_VERSION: u32 = 24;
|
pub const FORMAT_VERSION: u32 = 25;
|
||||||
|
|
||||||
/// A `Crate` is the root of the emitted JSON blob. It contains all type/documentation information
|
/// A `Crate` is the root of the emitted JSON blob. It contains all type/documentation information
|
||||||
/// about the language items in the local crate, as well as info about external items to allow
|
/// about the language items in the local crate, as well as info about external items to allow
|
||||||
@ -581,13 +581,15 @@ pub enum Type {
|
|||||||
#[serde(rename = "type")]
|
#[serde(rename = "type")]
|
||||||
type_: Box<Type>,
|
type_: Box<Type>,
|
||||||
},
|
},
|
||||||
/// `<Type as Trait>::Name` or associated types like `T::Item` where `T: Iterator`
|
/// Associated types like `<Type as Trait>::Name` and `T::Item` where
|
||||||
|
/// `T: Iterator` or inherent associated types like `Struct::Name`.
|
||||||
QualifiedPath {
|
QualifiedPath {
|
||||||
name: String,
|
name: String,
|
||||||
args: Box<GenericArgs>,
|
args: Box<GenericArgs>,
|
||||||
self_type: Box<Type>,
|
self_type: Box<Type>,
|
||||||
|
/// `None` iff this is an *inherent* associated type.
|
||||||
#[serde(rename = "trait")]
|
#[serde(rename = "trait")]
|
||||||
trait_: Path,
|
trait_: Option<Path>,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1424,6 +1424,7 @@ fn ty_auto_deref_stability<'tcx>(
|
|||||||
continue;
|
continue;
|
||||||
},
|
},
|
||||||
ty::Param(_) => TyPosition::new_deref_stable_for_result(precedence, ty),
|
ty::Param(_) => TyPosition::new_deref_stable_for_result(precedence, ty),
|
||||||
|
ty::Alias(ty::Inherent, _) => unreachable!("inherent projection should have been normalized away above"),
|
||||||
ty::Alias(ty::Projection, _) if ty.has_non_region_param() => {
|
ty::Alias(ty::Projection, _) if ty.has_non_region_param() => {
|
||||||
TyPosition::new_deref_stable_for_result(precedence, ty)
|
TyPosition::new_deref_stable_for_result(precedence, ty)
|
||||||
},
|
},
|
||||||
|
@ -273,7 +273,9 @@ impl<'a> Validator<'a> {
|
|||||||
Type::QualifiedPath { name: _, args, self_type, trait_ } => {
|
Type::QualifiedPath { name: _, args, self_type, trait_ } => {
|
||||||
self.check_generic_args(&**args);
|
self.check_generic_args(&**args);
|
||||||
self.check_type(&**self_type);
|
self.check_type(&**self_type);
|
||||||
self.check_path(trait_, PathKind::Trait);
|
if let Some(trait_) = trait_ {
|
||||||
|
self.check_path(trait_, PathKind::Trait);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -25,7 +25,7 @@ pub fn issue71861(vec: Vec<u32>) -> Box<[u32]> {
|
|||||||
|
|
||||||
// Call to panic_cannot_unwind in case of double-panic is expected
|
// Call to panic_cannot_unwind in case of double-panic is expected
|
||||||
// on LLVM 16 and older, but other panics are not.
|
// on LLVM 16 and older, but other panics are not.
|
||||||
// CHECK: cleanup
|
// CHECK: filter
|
||||||
// old-NEXT: ; call core::panicking::panic_cannot_unwind
|
// old-NEXT: ; call core::panicking::panic_cannot_unwind
|
||||||
// old-NEXT: panic_cannot_unwind
|
// old-NEXT: panic_cannot_unwind
|
||||||
|
|
||||||
@ -40,7 +40,7 @@ pub fn issue75636<'a>(iter: &[&'a str]) -> Box<[&'a str]> {
|
|||||||
|
|
||||||
// Call to panic_cannot_unwind in case of double-panic is expected,
|
// Call to panic_cannot_unwind in case of double-panic is expected,
|
||||||
// on LLVM 16 and older, but other panics are not.
|
// on LLVM 16 and older, but other panics are not.
|
||||||
// CHECK: cleanup
|
// CHECK: filter
|
||||||
// old-NEXT: ; call core::panicking::panic_cannot_unwind
|
// old-NEXT: ; call core::panicking::panic_cannot_unwind
|
||||||
// old-NEXT: panic_cannot_unwind
|
// old-NEXT: panic_cannot_unwind
|
||||||
|
|
||||||
|
9
tests/run-make/forced-unwind-terminate-pof/Makefile
Normal file
9
tests/run-make/forced-unwind-terminate-pof/Makefile
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
# ignore-cross-compile
|
||||||
|
# only-linux
|
||||||
|
include ../tools.mk
|
||||||
|
|
||||||
|
all: foo
|
||||||
|
$(call RUN,foo) | $(CGREP) -v "cannot unwind"
|
||||||
|
|
||||||
|
foo: foo.rs
|
||||||
|
$(RUSTC) $<
|
17
tests/run-make/forced-unwind-terminate-pof/foo.rs
Normal file
17
tests/run-make/forced-unwind-terminate-pof/foo.rs
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
// Tests that forced unwind through POF Rust frames wouldn't trigger our terminating guards.
|
||||||
|
|
||||||
|
#![feature(c_unwind)]
|
||||||
|
#![no_main]
|
||||||
|
|
||||||
|
extern "C-unwind" {
|
||||||
|
fn pthread_exit(v: *mut core::ffi::c_void) -> !;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe extern "C" fn call_pthread_exit() {
|
||||||
|
pthread_exit(core::ptr::null_mut());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[no_mangle]
|
||||||
|
unsafe extern "C-unwind" fn main(_argc: core::ffi::c_int, _argv: *mut *mut core::ffi::c_char) {
|
||||||
|
call_pthread_exit();
|
||||||
|
}
|
44
tests/rustdoc/inherent-projections.rs
Normal file
44
tests/rustdoc/inherent-projections.rs
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
#![feature(inherent_associated_types)]
|
||||||
|
#![allow(incomplete_features)]
|
||||||
|
|
||||||
|
// @has 'inherent_projections/fn.create.html'
|
||||||
|
// @has - '//pre[@class="rust item-decl"]' "create() -> Owner::Metadata"
|
||||||
|
// @has - '//pre[@class="rust item-decl"]//a[@class="associatedtype"]/@href' 'struct.Owner.html#associatedtype.Metadata'
|
||||||
|
pub fn create() -> Owner::Metadata {}
|
||||||
|
|
||||||
|
pub struct Owner;
|
||||||
|
|
||||||
|
impl Owner {
|
||||||
|
pub type Metadata = ();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Make sure we handle bound vars correctly.
|
||||||
|
// @has 'inherent_projections/type.User.html' '//pre[@class="rust item-decl"]' "for<'a> fn(_: Carrier<'a>::Focus)"
|
||||||
|
pub type User = for<'a> fn(Carrier<'a>::Focus);
|
||||||
|
|
||||||
|
pub struct Carrier<'a>(&'a ());
|
||||||
|
|
||||||
|
impl<'a> Carrier<'a> {
|
||||||
|
pub type Focus = &'a mut i32;
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////
|
||||||
|
|
||||||
|
// FIXME(inherent_associated_types): Below we link to `Proj` but we should link to `Proj-1`.
|
||||||
|
// The current test checks for the buggy behavior for demonstration purposes.
|
||||||
|
|
||||||
|
// @has 'inherent_projections/type.Test.html'
|
||||||
|
// @has - '//pre[@class="rust item-decl"]' "Parametrized<i32>"
|
||||||
|
// @has - '//pre[@class="rust item-decl"]//a[@class="associatedtype"]/@href' 'struct.Parametrized.html#associatedtype.Proj'
|
||||||
|
// @!has - '//pre[@class="rust item-decl"]//a[@class="associatedtype"]/@href' 'struct.Parametrized.html#associatedtype.Proj-1'
|
||||||
|
pub type Test = Parametrized<i32>::Proj;
|
||||||
|
|
||||||
|
pub struct Parametrized<T>(T);
|
||||||
|
|
||||||
|
impl Parametrized<bool> {
|
||||||
|
pub type Proj = ();
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Parametrized<i32> {
|
||||||
|
pub type Proj = String;
|
||||||
|
}
|
45
tests/rustdoc/intra-doc/inherent-associated-types.rs
Normal file
45
tests/rustdoc/intra-doc/inherent-associated-types.rs
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
#![feature(inherent_associated_types)]
|
||||||
|
|
||||||
|
#![allow(incomplete_features)]
|
||||||
|
#![deny(rustdoc::broken_intra_doc_links)]
|
||||||
|
|
||||||
|
// @has inherent_associated_types/index.html
|
||||||
|
|
||||||
|
// @has - '//a/@href' 'enum.Simple.html#associatedtype.Type'
|
||||||
|
//! [`Simple::Type`]
|
||||||
|
|
||||||
|
pub enum Simple {}
|
||||||
|
|
||||||
|
impl Simple {
|
||||||
|
pub type Type = ();
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////
|
||||||
|
|
||||||
|
// @has 'inherent_associated_types/type.Test0.html' '//a/@href' \
|
||||||
|
// 'struct.Parametrized.html#associatedtype.Proj'
|
||||||
|
/// [`Parametrized<bool>::Proj`]
|
||||||
|
pub type Test0 = ();
|
||||||
|
|
||||||
|
// FIXME(inherent_associated_types): The intra-doc link below should point to `Proj-1` not `Proj`.
|
||||||
|
// The current test checks for the buggy behavior for demonstration purposes.
|
||||||
|
// The same bug happens for inherent associated functions and constants (see #85960, #93398).
|
||||||
|
//
|
||||||
|
// Further, at some point we should reject the intra-doc link `Parametrized::Proj`.
|
||||||
|
// It currently links to `Parametrized<bool>::Proj`.
|
||||||
|
|
||||||
|
// @has 'inherent_associated_types/type.Test1.html'
|
||||||
|
// @has - '//a/@href' 'struct.Parametrized.html#associatedtype.Proj'
|
||||||
|
// @!has - '//a/@href' 'struct.Parametrized.html#associatedtype.Proj-1'
|
||||||
|
/// [`Parametrized<i32>::Proj`]
|
||||||
|
pub type Test1 = ();
|
||||||
|
|
||||||
|
pub struct Parametrized<T>(T);
|
||||||
|
|
||||||
|
impl Parametrized<bool> {
|
||||||
|
pub type Proj = ();
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Parametrized<i32> {
|
||||||
|
pub type Proj = String;
|
||||||
|
}
|
@ -0,0 +1,49 @@
|
|||||||
|
// check-fail
|
||||||
|
// Tests that a doc comment will not preclude a field from being considered a diagnostic argument
|
||||||
|
// normalize-stderr-test "the following other types implement trait `IntoDiagnosticArg`:(?:.*\n){0,9}\s+and \d+ others" -> "normalized in stderr"
|
||||||
|
// normalize-stderr-test "diagnostic_builder\.rs:[0-9]+:[0-9]+" -> "diagnostic_builder.rs:LL:CC"
|
||||||
|
|
||||||
|
// The proc_macro2 crate handles spans differently when on beta/stable release rather than nightly,
|
||||||
|
// changing the output of this test. Since Subdiagnostic is strictly internal to the compiler
|
||||||
|
// the test is just ignored on stable and beta:
|
||||||
|
// ignore-stage1
|
||||||
|
// ignore-beta
|
||||||
|
// ignore-stable
|
||||||
|
|
||||||
|
#![feature(rustc_private)]
|
||||||
|
#![crate_type = "lib"]
|
||||||
|
|
||||||
|
extern crate rustc_errors;
|
||||||
|
extern crate rustc_fluent_macro;
|
||||||
|
extern crate rustc_macros;
|
||||||
|
extern crate rustc_session;
|
||||||
|
extern crate rustc_span;
|
||||||
|
|
||||||
|
use rustc_errors::{Applicability, DiagnosticMessage, SubdiagnosticMessage};
|
||||||
|
use rustc_fluent_macro::fluent_messages;
|
||||||
|
use rustc_macros::{Diagnostic, Subdiagnostic};
|
||||||
|
use rustc_span::Span;
|
||||||
|
|
||||||
|
fluent_messages! { "./example.ftl" }
|
||||||
|
|
||||||
|
struct NotIntoDiagnosticArg;
|
||||||
|
|
||||||
|
#[derive(Diagnostic)]
|
||||||
|
#[diag(no_crate_example)]
|
||||||
|
struct Test {
|
||||||
|
#[primary_span]
|
||||||
|
span: Span,
|
||||||
|
/// A doc comment
|
||||||
|
arg: NotIntoDiagnosticArg,
|
||||||
|
//~^ ERROR the trait bound `NotIntoDiagnosticArg: IntoDiagnosticArg` is not satisfied
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Subdiagnostic)]
|
||||||
|
#[label(no_crate_example)]
|
||||||
|
struct SubTest {
|
||||||
|
#[primary_span]
|
||||||
|
span: Span,
|
||||||
|
/// A doc comment
|
||||||
|
arg: NotIntoDiagnosticArg,
|
||||||
|
//~^ ERROR the trait bound `NotIntoDiagnosticArg: IntoDiagnosticArg` is not satisfied
|
||||||
|
}
|
@ -0,0 +1,30 @@
|
|||||||
|
error[E0277]: the trait bound `NotIntoDiagnosticArg: IntoDiagnosticArg` is not satisfied
|
||||||
|
--> $DIR/diagnostic-derive-doc-comment-field.rs:37:10
|
||||||
|
|
|
||||||
|
LL | #[derive(Diagnostic)]
|
||||||
|
| ---------- required by a bound introduced by this call
|
||||||
|
...
|
||||||
|
LL | arg: NotIntoDiagnosticArg,
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^ the trait `IntoDiagnosticArg` is not implemented for `NotIntoDiagnosticArg`
|
||||||
|
|
|
||||||
|
= help: normalized in stderr
|
||||||
|
note: required by a bound in `DiagnosticBuilder::<'a, G>::set_arg`
|
||||||
|
--> $COMPILER_DIR/rustc_errors/src/diagnostic_builder.rs:LL:CC
|
||||||
|
= note: this error originates in the macro `forward` (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||||
|
|
||||||
|
error[E0277]: the trait bound `NotIntoDiagnosticArg: IntoDiagnosticArg` is not satisfied
|
||||||
|
--> $DIR/diagnostic-derive-doc-comment-field.rs:47:10
|
||||||
|
|
|
||||||
|
LL | #[derive(Subdiagnostic)]
|
||||||
|
| ------------- required by a bound introduced by this call
|
||||||
|
...
|
||||||
|
LL | arg: NotIntoDiagnosticArg,
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^ the trait `IntoDiagnosticArg` is not implemented for `NotIntoDiagnosticArg`
|
||||||
|
|
|
||||||
|
= help: normalized in stderr
|
||||||
|
note: required by a bound in `Diagnostic::set_arg`
|
||||||
|
--> $COMPILER_DIR/rustc_errors/src/diagnostic.rs:964:5
|
||||||
|
|
||||||
|
error: aborting due to 2 previous errors
|
||||||
|
|
||||||
|
For more information about this error, try `rustc --explain E0277`.
|
@ -339,12 +339,12 @@ struct ErrorWithDefaultLabelAttr<'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Diagnostic)]
|
#[derive(Diagnostic)]
|
||||||
//~^ ERROR the trait bound `Hello: IntoDiagnosticArg` is not satisfied
|
|
||||||
#[diag(no_crate_example, code = "E0123")]
|
#[diag(no_crate_example, code = "E0123")]
|
||||||
struct ArgFieldWithoutSkip {
|
struct ArgFieldWithoutSkip {
|
||||||
#[primary_span]
|
#[primary_span]
|
||||||
span: Span,
|
span: Span,
|
||||||
other: Hello,
|
other: Hello,
|
||||||
|
//~^ ERROR the trait bound `Hello: IntoDiagnosticArg` is not satisfied
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Diagnostic)]
|
#[derive(Diagnostic)]
|
||||||
|
@ -641,15 +641,18 @@ LL | #[derive(Diagnostic)]
|
|||||||
= note: this error originates in the derive macro `Diagnostic` (in Nightly builds, run with -Z macro-backtrace for more info)
|
= note: this error originates in the derive macro `Diagnostic` (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||||
|
|
||||||
error[E0277]: the trait bound `Hello: IntoDiagnosticArg` is not satisfied
|
error[E0277]: the trait bound `Hello: IntoDiagnosticArg` is not satisfied
|
||||||
--> $DIR/diagnostic-derive.rs:341:10
|
--> $DIR/diagnostic-derive.rs:346:12
|
||||||
|
|
|
|
||||||
LL | #[derive(Diagnostic)]
|
LL | #[derive(Diagnostic)]
|
||||||
| ^^^^^^^^^^ the trait `IntoDiagnosticArg` is not implemented for `Hello`
|
| ---------- required by a bound introduced by this call
|
||||||
|
...
|
||||||
|
LL | other: Hello,
|
||||||
|
| ^^^^^ the trait `IntoDiagnosticArg` is not implemented for `Hello`
|
||||||
|
|
|
|
||||||
= help: normalized in stderr
|
= help: normalized in stderr
|
||||||
note: required by a bound in `DiagnosticBuilder::<'a, G>::set_arg`
|
note: required by a bound in `DiagnosticBuilder::<'a, G>::set_arg`
|
||||||
--> $COMPILER_DIR/rustc_errors/src/diagnostic_builder.rs:LL:CC
|
--> $COMPILER_DIR/rustc_errors/src/diagnostic_builder.rs:LL:CC
|
||||||
= note: this error originates in the derive macro `Diagnostic` which comes from the expansion of the macro `forward` (in Nightly builds, run with -Z macro-backtrace for more info)
|
= note: this error originates in the macro `forward` (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||||
|
|
||||||
error: aborting due to 84 previous errors
|
error: aborting due to 84 previous errors
|
||||||
|
|
||||||
|
@ -0,0 +1,10 @@
|
|||||||
|
// known-bug: #108491
|
||||||
|
|
||||||
|
// FIXME(inherent_associated_types): This should pass.
|
||||||
|
|
||||||
|
struct Foo {
|
||||||
|
bar: Self::Bar,
|
||||||
|
}
|
||||||
|
impl Foo {
|
||||||
|
pub type Bar = usize;
|
||||||
|
}
|
@ -0,0 +1,49 @@
|
|||||||
|
error[E0601]: `main` function not found in crate `cycle_iat_inside_of_adt`
|
||||||
|
--> $DIR/cycle-iat-inside-of-adt.rs:10:2
|
||||||
|
|
|
||||||
|
LL | }
|
||||||
|
| ^ consider adding a `main` function to `$DIR/cycle-iat-inside-of-adt.rs`
|
||||||
|
|
||||||
|
error[E0391]: cycle detected when computing predicates of `Foo`
|
||||||
|
--> $DIR/cycle-iat-inside-of-adt.rs:5:1
|
||||||
|
|
|
||||||
|
LL | struct Foo {
|
||||||
|
| ^^^^^^^^^^
|
||||||
|
|
|
||||||
|
note: ...which requires computing predicates of `Foo`...
|
||||||
|
--> $DIR/cycle-iat-inside-of-adt.rs:5:1
|
||||||
|
|
|
||||||
|
LL | struct Foo {
|
||||||
|
| ^^^^^^^^^^
|
||||||
|
note: ...which requires computing inferred outlives predicates of `Foo`...
|
||||||
|
--> $DIR/cycle-iat-inside-of-adt.rs:5:1
|
||||||
|
|
|
||||||
|
LL | struct Foo {
|
||||||
|
| ^^^^^^^^^^
|
||||||
|
= note: ...which requires computing the inferred outlives predicates for items in this crate...
|
||||||
|
note: ...which requires computing type of `Foo::bar`...
|
||||||
|
--> $DIR/cycle-iat-inside-of-adt.rs:6:5
|
||||||
|
|
|
||||||
|
LL | bar: Self::Bar,
|
||||||
|
| ^^^^^^^^^^^^^^
|
||||||
|
note: ...which requires computing normalized predicates of `Foo`...
|
||||||
|
--> $DIR/cycle-iat-inside-of-adt.rs:5:1
|
||||||
|
|
|
||||||
|
LL | struct Foo {
|
||||||
|
| ^^^^^^^^^^
|
||||||
|
= note: ...which again requires computing predicates of `Foo`, completing the cycle
|
||||||
|
note: cycle used when collecting item types in top-level module
|
||||||
|
--> $DIR/cycle-iat-inside-of-adt.rs:5:1
|
||||||
|
|
|
||||||
|
LL | / struct Foo {
|
||||||
|
LL | | bar: Self::Bar,
|
||||||
|
LL | | }
|
||||||
|
LL | | impl Foo {
|
||||||
|
LL | | pub type Bar = usize;
|
||||||
|
LL | | }
|
||||||
|
| |_^
|
||||||
|
|
||||||
|
error: aborting due to 2 previous errors
|
||||||
|
|
||||||
|
Some errors have detailed explanations: E0391, E0601.
|
||||||
|
For more information about an error, try `rustc --explain E0391`.
|
@ -0,0 +1,16 @@
|
|||||||
|
// known-bug: unknown
|
||||||
|
|
||||||
|
#![feature(inherent_associated_types)]
|
||||||
|
#![allow(incomplete_features)]
|
||||||
|
|
||||||
|
// FIXME(inherent_associated_types): This shouldn't lead to a cycle error.
|
||||||
|
|
||||||
|
fn user<T>() where S<T>::P: std::fmt::Debug {}
|
||||||
|
|
||||||
|
struct S<T>;
|
||||||
|
|
||||||
|
impl<T: Copy> S<T> {
|
||||||
|
type P = ();
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {}
|
@ -0,0 +1,37 @@
|
|||||||
|
error[E0391]: cycle detected when computing predicates of `user`
|
||||||
|
--> $DIR/cycle-iat-inside-of-where-predicate.rs:8:1
|
||||||
|
|
|
||||||
|
LL | fn user<T>() where S<T>::P: std::fmt::Debug {}
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
|
||||||
|
note: ...which requires computing predicates of `user`...
|
||||||
|
--> $DIR/cycle-iat-inside-of-where-predicate.rs:8:1
|
||||||
|
|
|
||||||
|
LL | fn user<T>() where S<T>::P: std::fmt::Debug {}
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
note: ...which requires computing explicit predicates of `user`...
|
||||||
|
--> $DIR/cycle-iat-inside-of-where-predicate.rs:8:1
|
||||||
|
|
|
||||||
|
LL | fn user<T>() where S<T>::P: std::fmt::Debug {}
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
note: ...which requires computing normalized predicates of `user`...
|
||||||
|
--> $DIR/cycle-iat-inside-of-where-predicate.rs:8:1
|
||||||
|
|
|
||||||
|
LL | fn user<T>() where S<T>::P: std::fmt::Debug {}
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
= note: ...which again requires computing predicates of `user`, completing the cycle
|
||||||
|
note: cycle used when collecting item types in top-level module
|
||||||
|
--> $DIR/cycle-iat-inside-of-where-predicate.rs:3:1
|
||||||
|
|
|
||||||
|
LL | / #![feature(inherent_associated_types)]
|
||||||
|
LL | | #![allow(incomplete_features)]
|
||||||
|
LL | |
|
||||||
|
LL | | // FIXME(inherent_associated_types): This shouldn't lead to a cycle error.
|
||||||
|
... |
|
||||||
|
LL | |
|
||||||
|
LL | | fn main() {}
|
||||||
|
| |____________^
|
||||||
|
|
||||||
|
error: aborting due to previous error
|
||||||
|
|
||||||
|
For more information about this error, try `rustc --explain E0391`.
|
@ -1,23 +0,0 @@
|
|||||||
// known-bug: unknown
|
|
||||||
// failure-status: 101
|
|
||||||
// normalize-stderr-test "note: .*\n\n" -> ""
|
|
||||||
// normalize-stderr-test "thread 'rustc' panicked.*\n" -> ""
|
|
||||||
// rustc-env:RUST_BACKTRACE=0
|
|
||||||
|
|
||||||
// FIXME: I presume a type variable that couldn't be solved by `resolve_vars_if_possible`
|
|
||||||
// escapes the InferCtxt snapshot.
|
|
||||||
|
|
||||||
#![feature(inherent_associated_types)]
|
|
||||||
#![allow(incomplete_features)]
|
|
||||||
|
|
||||||
struct Cont<T>(T);
|
|
||||||
|
|
||||||
impl<T: Copy> Cont<T> {
|
|
||||||
type Out = Vec<T>;
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn weird<T: Copy>(x: T) {
|
|
||||||
let _: Cont<_>::Out = vec![true];
|
|
||||||
}
|
|
||||||
|
|
||||||
fn main() {}
|
|
@ -1,6 +0,0 @@
|
|||||||
error: the compiler unexpectedly panicked. this is a bug.
|
|
||||||
|
|
||||||
query stack during panic:
|
|
||||||
#0 [typeck] type-checking `weird`
|
|
||||||
#1 [used_trait_imports] finding used_trait_imports `weird`
|
|
||||||
end of query stack
|
|
@ -1,15 +0,0 @@
|
|||||||
// known-bug: unknown
|
|
||||||
|
|
||||||
#![feature(inherent_associated_types)]
|
|
||||||
#![allow(incomplete_features)]
|
|
||||||
|
|
||||||
struct S<T>(T);
|
|
||||||
|
|
||||||
impl S<()> {
|
|
||||||
type P = i128;
|
|
||||||
}
|
|
||||||
|
|
||||||
fn main() {
|
|
||||||
// We fail to infer `_ == ()` here.
|
|
||||||
let _: S<_>::P;
|
|
||||||
}
|
|
@ -1,19 +0,0 @@
|
|||||||
// known-bug: unknown
|
|
||||||
// check-pass
|
|
||||||
|
|
||||||
// We currently don't region-check inherent associated type projections at all.
|
|
||||||
|
|
||||||
#![feature(inherent_associated_types)]
|
|
||||||
#![allow(incomplete_features, dead_code)]
|
|
||||||
|
|
||||||
struct S<T>(T);
|
|
||||||
|
|
||||||
impl S<&'static ()> {
|
|
||||||
type T = ();
|
|
||||||
}
|
|
||||||
|
|
||||||
fn usr<'a>() {
|
|
||||||
let _: S::<&'a ()>::T; // this should *fail* but it doesn't!
|
|
||||||
}
|
|
||||||
|
|
||||||
fn main() {}
|
|
15
tests/ui/associated-inherent-types/bugs/wf-check-skipped.rs
Normal file
15
tests/ui/associated-inherent-types/bugs/wf-check-skipped.rs
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
// known-bug: #100041
|
||||||
|
// check-pass
|
||||||
|
|
||||||
|
#![feature(inherent_associated_types)]
|
||||||
|
#![allow(incomplete_features)]
|
||||||
|
|
||||||
|
// FIXME(inherent_associated_types): This should fail.
|
||||||
|
|
||||||
|
struct Foo;
|
||||||
|
|
||||||
|
impl Foo {
|
||||||
|
type Bar<T> = ();
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() -> Foo::Bar::<Vec<[u32]>> {}
|
@ -31,7 +31,7 @@ fn main() {
|
|||||||
let _: Select<u8>::Projection = ();
|
let _: Select<u8>::Projection = ();
|
||||||
|
|
||||||
let _: Choose<NonCopy>::Result = ();
|
let _: Choose<NonCopy>::Result = ();
|
||||||
let _: Choose<bool>::Result = vec![true];
|
let _: Choose<&str>::Result = vec!["…"]; // regression test for issue #108957
|
||||||
}
|
}
|
||||||
|
|
||||||
// Test if we use the correct `ParamEnv` when proving obligations.
|
// Test if we use the correct `ParamEnv` when proving obligations.
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user