mirror of
https://github.com/rust-lang/rust.git
synced 2025-04-28 02:57:37 +00:00
Auto merge of #93956 - matthiaskrgr:rollup-zfk35hb, r=matthiaskrgr
Rollup of 9 pull requests Successful merges: - #89926 (make `Instant::{duration_since, elapsed, sub}` saturating and remove workarounds) - #90532 (More informative error message for E0015) - #93810 (Improve chalk integration) - #93851 (More practical examples for `Option::and_then` & `Result::and_then`) - #93885 (bootstrap.py: Suggest disabling download-ci-llvm option if url fails to download) - #93886 (Stabilise inherent_ascii_escape (FCP in #77174)) - #93930 (add link to format_args! when mention it in docs) - #93936 (Couple of driver cleanups) - #93944 (Don't relabel to a team if there is already a team label) Failed merges: r? `@ghost` `@rustbot` modify labels: rollup
This commit is contained in:
commit
9a60099cc4
@ -1,4 +1,5 @@
|
||||
use either::Either;
|
||||
use rustc_const_eval::util::{CallDesugaringKind, CallKind};
|
||||
use rustc_data_structures::fx::FxHashSet;
|
||||
use rustc_errors::{Applicability, DiagnosticBuilder};
|
||||
use rustc_hir as hir;
|
||||
@ -26,7 +27,7 @@ use crate::{
|
||||
|
||||
use super::{
|
||||
explain_borrow::{BorrowExplanation, LaterUseKind},
|
||||
FnSelfUseKind, IncludingDowncast, RegionName, RegionNameSource, UseSpans,
|
||||
IncludingDowncast, RegionName, RegionNameSource, UseSpans,
|
||||
};
|
||||
|
||||
#[derive(Debug)]
|
||||
@ -195,7 +196,9 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
||||
.map(|n| format!("`{}`", n))
|
||||
.unwrap_or_else(|| "value".to_owned());
|
||||
match kind {
|
||||
FnSelfUseKind::FnOnceCall => {
|
||||
CallKind::FnCall { fn_trait_id, .. }
|
||||
if Some(fn_trait_id) == self.infcx.tcx.lang_items().fn_once_trait() =>
|
||||
{
|
||||
err.span_label(
|
||||
fn_call_span,
|
||||
&format!(
|
||||
@ -208,7 +211,8 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
||||
"this value implements `FnOnce`, which causes it to be moved when called",
|
||||
);
|
||||
}
|
||||
FnSelfUseKind::Operator { self_arg } => {
|
||||
CallKind::Operator { self_arg, .. } => {
|
||||
let self_arg = self_arg.unwrap();
|
||||
err.span_label(
|
||||
fn_call_span,
|
||||
&format!(
|
||||
@ -235,12 +239,9 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
||||
);
|
||||
}
|
||||
}
|
||||
FnSelfUseKind::Normal {
|
||||
self_arg,
|
||||
implicit_into_iter,
|
||||
is_option_or_result,
|
||||
} => {
|
||||
if implicit_into_iter {
|
||||
CallKind::Normal { self_arg, desugaring, is_option_or_result } => {
|
||||
let self_arg = self_arg.unwrap();
|
||||
if let Some((CallDesugaringKind::ForLoopIntoIter, _)) = desugaring {
|
||||
err.span_label(
|
||||
fn_call_span,
|
||||
&format!(
|
||||
@ -305,8 +306,8 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
||||
);
|
||||
}
|
||||
}
|
||||
// Deref::deref takes &self, which cannot cause a move
|
||||
FnSelfUseKind::DerefCoercion { .. } => unreachable!(),
|
||||
// Other desugarings takes &self, which cannot cause a move
|
||||
_ => unreachable!(),
|
||||
}
|
||||
} else {
|
||||
err.span_label(
|
||||
@ -433,7 +434,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
||||
}
|
||||
|
||||
if let UseSpans::FnSelfUse {
|
||||
kind: FnSelfUseKind::DerefCoercion { deref_target, deref_target_ty },
|
||||
kind: CallKind::DerefCoercion { deref_target, deref_target_ty, .. },
|
||||
..
|
||||
} = use_spans
|
||||
{
|
||||
|
@ -1,10 +1,10 @@
|
||||
//! Borrow checker diagnostics.
|
||||
|
||||
use rustc_const_eval::util::call_kind;
|
||||
use rustc_errors::DiagnosticBuilder;
|
||||
use rustc_hir as hir;
|
||||
use rustc_hir::def::Namespace;
|
||||
use rustc_hir::def_id::DefId;
|
||||
use rustc_hir::lang_items::LangItemGroup;
|
||||
use rustc_hir::GeneratorKind;
|
||||
use rustc_middle::mir::{
|
||||
AggregateKind, Constant, FakeReadCause, Field, Local, LocalInfo, LocalKind, Location, Operand,
|
||||
@ -13,7 +13,7 @@ use rustc_middle::mir::{
|
||||
use rustc_middle::ty::print::Print;
|
||||
use rustc_middle::ty::{self, DefIdTree, Instance, Ty, TyCtxt};
|
||||
use rustc_mir_dataflow::move_paths::{InitLocation, LookupResult};
|
||||
use rustc_span::{hygiene::DesugaringKind, symbol::sym, Span};
|
||||
use rustc_span::{symbol::sym, Span};
|
||||
use rustc_target::abi::VariantIdx;
|
||||
|
||||
use super::borrow_set::BorrowData;
|
||||
@ -37,7 +37,7 @@ crate use mutability_errors::AccessKind;
|
||||
crate use outlives_suggestion::OutlivesSuggestionBuilder;
|
||||
crate use region_errors::{ErrorConstraintInfo, RegionErrorKind, RegionErrors};
|
||||
crate use region_name::{RegionName, RegionNameSource};
|
||||
use rustc_span::symbol::Ident;
|
||||
crate use rustc_const_eval::util::CallKind;
|
||||
|
||||
pub(super) struct IncludingDowncast(pub(super) bool);
|
||||
|
||||
@ -563,7 +563,7 @@ pub(super) enum UseSpans<'tcx> {
|
||||
fn_call_span: Span,
|
||||
/// The definition span of the method being called
|
||||
fn_span: Span,
|
||||
kind: FnSelfUseKind<'tcx>,
|
||||
kind: CallKind<'tcx>,
|
||||
},
|
||||
/// This access is caused by a `match` or `if let` pattern.
|
||||
PatUse(Span),
|
||||
@ -571,38 +571,15 @@ pub(super) enum UseSpans<'tcx> {
|
||||
OtherUse(Span),
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
|
||||
pub(super) enum FnSelfUseKind<'tcx> {
|
||||
/// A normal method call of the form `receiver.foo(a, b, c)`
|
||||
Normal {
|
||||
self_arg: Ident,
|
||||
implicit_into_iter: bool,
|
||||
/// Whether the self type of the method call has an `.as_ref()` method.
|
||||
/// Used for better diagnostics.
|
||||
is_option_or_result: bool,
|
||||
},
|
||||
/// A call to `FnOnce::call_once`, desugared from `my_closure(a, b, c)`
|
||||
FnOnceCall,
|
||||
/// A call to an operator trait, desuraged from operator syntax (e.g. `a << b`)
|
||||
Operator { self_arg: Ident },
|
||||
DerefCoercion {
|
||||
/// The `Span` of the `Target` associated type
|
||||
/// in the `Deref` impl we are using.
|
||||
deref_target: Span,
|
||||
/// The type `T::Deref` we are dereferencing to
|
||||
deref_target_ty: Ty<'tcx>,
|
||||
},
|
||||
}
|
||||
|
||||
impl UseSpans<'_> {
|
||||
pub(super) fn args_or_use(self) -> Span {
|
||||
match self {
|
||||
UseSpans::ClosureUse { args_span: span, .. }
|
||||
| UseSpans::PatUse(span)
|
||||
| UseSpans::OtherUse(span) => span,
|
||||
UseSpans::FnSelfUse {
|
||||
fn_call_span, kind: FnSelfUseKind::DerefCoercion { .. }, ..
|
||||
} => fn_call_span,
|
||||
UseSpans::FnSelfUse { fn_call_span, kind: CallKind::DerefCoercion { .. }, .. } => {
|
||||
fn_call_span
|
||||
}
|
||||
UseSpans::FnSelfUse { var_span, .. } => var_span,
|
||||
}
|
||||
}
|
||||
@ -613,9 +590,9 @@ impl UseSpans<'_> {
|
||||
UseSpans::ClosureUse { path_span: span, .. }
|
||||
| UseSpans::PatUse(span)
|
||||
| UseSpans::OtherUse(span) => span,
|
||||
UseSpans::FnSelfUse {
|
||||
fn_call_span, kind: FnSelfUseKind::DerefCoercion { .. }, ..
|
||||
} => fn_call_span,
|
||||
UseSpans::FnSelfUse { fn_call_span, kind: CallKind::DerefCoercion { .. }, .. } => {
|
||||
fn_call_span
|
||||
}
|
||||
UseSpans::FnSelfUse { var_span, .. } => var_span,
|
||||
}
|
||||
}
|
||||
@ -626,9 +603,9 @@ impl UseSpans<'_> {
|
||||
UseSpans::ClosureUse { capture_kind_span: span, .. }
|
||||
| UseSpans::PatUse(span)
|
||||
| UseSpans::OtherUse(span) => span,
|
||||
UseSpans::FnSelfUse {
|
||||
fn_call_span, kind: FnSelfUseKind::DerefCoercion { .. }, ..
|
||||
} => fn_call_span,
|
||||
UseSpans::FnSelfUse { fn_call_span, kind: CallKind::DerefCoercion { .. }, .. } => {
|
||||
fn_call_span
|
||||
}
|
||||
UseSpans::FnSelfUse { var_span, .. } => var_span,
|
||||
}
|
||||
}
|
||||
@ -904,67 +881,19 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
||||
return normal_ret;
|
||||
};
|
||||
|
||||
let tcx = self.infcx.tcx;
|
||||
let parent = tcx.parent(method_did);
|
||||
let is_fn_once = parent == tcx.lang_items().fn_once_trait();
|
||||
let is_operator = !from_hir_call
|
||||
&& parent.map_or(false, |p| tcx.lang_items().group(LangItemGroup::Op).contains(&p));
|
||||
let is_deref = !from_hir_call && tcx.is_diagnostic_item(sym::deref_method, method_did);
|
||||
let fn_call_span = *fn_span;
|
||||
|
||||
let self_arg = tcx.fn_arg_names(method_did)[0];
|
||||
|
||||
debug!(
|
||||
"terminator = {:?} from_hir_call={:?}",
|
||||
self.body[location.block].terminator, from_hir_call
|
||||
let kind = call_kind(
|
||||
self.infcx.tcx,
|
||||
self.param_env,
|
||||
method_did,
|
||||
method_substs,
|
||||
*fn_span,
|
||||
*from_hir_call,
|
||||
Some(self.infcx.tcx.fn_arg_names(method_did)[0]),
|
||||
);
|
||||
|
||||
// Check for a 'special' use of 'self' -
|
||||
// an FnOnce call, an operator (e.g. `<<`), or a
|
||||
// deref coercion.
|
||||
let kind = if is_fn_once {
|
||||
Some(FnSelfUseKind::FnOnceCall)
|
||||
} else if is_operator {
|
||||
Some(FnSelfUseKind::Operator { self_arg })
|
||||
} else if is_deref {
|
||||
let deref_target =
|
||||
tcx.get_diagnostic_item(sym::deref_target).and_then(|deref_target| {
|
||||
Instance::resolve(tcx, self.param_env, deref_target, method_substs)
|
||||
.transpose()
|
||||
});
|
||||
if let Some(Ok(instance)) = deref_target {
|
||||
let deref_target_ty = instance.ty(tcx, self.param_env);
|
||||
Some(FnSelfUseKind::DerefCoercion {
|
||||
deref_target: tcx.def_span(instance.def_id()),
|
||||
deref_target_ty,
|
||||
})
|
||||
} else {
|
||||
None
|
||||
}
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
let kind = kind.unwrap_or_else(|| {
|
||||
// This isn't a 'special' use of `self`
|
||||
debug!("move_spans: method_did={:?}, fn_call_span={:?}", method_did, fn_call_span);
|
||||
let implicit_into_iter = Some(method_did) == tcx.lang_items().into_iter_fn()
|
||||
&& fn_call_span.desugaring_kind() == Some(DesugaringKind::ForLoop);
|
||||
let parent_self_ty = parent
|
||||
.filter(|did| tcx.def_kind(*did) == rustc_hir::def::DefKind::Impl)
|
||||
.and_then(|did| match tcx.type_of(did).kind() {
|
||||
ty::Adt(def, ..) => Some(def.did),
|
||||
_ => None,
|
||||
});
|
||||
let is_option_or_result = parent_self_ty.map_or(false, |def_id| {
|
||||
matches!(tcx.get_diagnostic_name(def_id), Some(sym::Option | sym::Result))
|
||||
});
|
||||
FnSelfUseKind::Normal { self_arg, implicit_into_iter, is_option_or_result }
|
||||
});
|
||||
|
||||
return FnSelfUse {
|
||||
var_span: stmt.source_info.span,
|
||||
fn_call_span,
|
||||
fn_call_span: *fn_span,
|
||||
fn_span: self
|
||||
.infcx
|
||||
.tcx
|
||||
|
@ -1,3 +1,4 @@
|
||||
use rustc_const_eval::util::CallDesugaringKind;
|
||||
use rustc_errors::{Applicability, DiagnosticBuilder};
|
||||
use rustc_infer::infer::TyCtxtInferExt;
|
||||
use rustc_middle::mir::*;
|
||||
@ -8,7 +9,7 @@ use rustc_mir_dataflow::move_paths::{
|
||||
use rustc_span::{sym, Span, DUMMY_SP};
|
||||
use rustc_trait_selection::traits::type_known_to_meet_bound_modulo_regions;
|
||||
|
||||
use crate::diagnostics::{FnSelfUseKind, UseSpans};
|
||||
use crate::diagnostics::{CallKind, UseSpans};
|
||||
use crate::prefixes::PrefixSet;
|
||||
use crate::MirBorrowckCtxt;
|
||||
|
||||
@ -410,7 +411,8 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
|
||||
Applicability::MaybeIncorrect,
|
||||
);
|
||||
} else if let Some(UseSpans::FnSelfUse {
|
||||
kind: FnSelfUseKind::Normal { implicit_into_iter: true, .. },
|
||||
kind:
|
||||
CallKind::Normal { desugaring: Some((CallDesugaringKind::ForLoopIntoIter, _)), .. },
|
||||
..
|
||||
}) = use_spans
|
||||
{
|
||||
|
@ -14,6 +14,7 @@ use rustc_middle::ty::{self, adjustment::PointerCast, Instance, InstanceDef, Ty,
|
||||
use rustc_middle::ty::{Binder, TraitPredicate, TraitRef};
|
||||
use rustc_mir_dataflow::{self, Analysis};
|
||||
use rustc_span::{sym, Span, Symbol};
|
||||
use rustc_trait_selection::traits::error_reporting::InferCtxtExt;
|
||||
use rustc_trait_selection::traits::SelectionContext;
|
||||
|
||||
use std::mem;
|
||||
@ -293,13 +294,13 @@ impl<'mir, 'tcx> Checker<'mir, 'tcx> {
|
||||
}
|
||||
|
||||
/// Emits an error if an expression cannot be evaluated in the current context.
|
||||
pub fn check_op(&mut self, op: impl NonConstOp) {
|
||||
pub fn check_op(&mut self, op: impl NonConstOp<'tcx>) {
|
||||
self.check_op_spanned(op, self.span);
|
||||
}
|
||||
|
||||
/// Emits an error at the given `span` if an expression cannot be evaluated in the current
|
||||
/// context.
|
||||
pub fn check_op_spanned<O: NonConstOp>(&mut self, op: O, span: Span) {
|
||||
pub fn check_op_spanned<O: NonConstOp<'tcx>>(&mut self, op: O, span: Span) {
|
||||
let gate = match op.status_in_item(self.ccx) {
|
||||
Status::Allowed => return,
|
||||
|
||||
@ -773,7 +774,7 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
|
||||
self.super_terminator(terminator, location);
|
||||
|
||||
match &terminator.kind {
|
||||
TerminatorKind::Call { func, args, .. } => {
|
||||
TerminatorKind::Call { func, args, fn_span, from_hir_call, .. } => {
|
||||
let ConstCx { tcx, body, param_env, .. } = *self.ccx;
|
||||
let caller = self.def_id().to_def_id();
|
||||
|
||||
@ -797,20 +798,24 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
|
||||
if let Some(trait_id) = tcx.trait_of_item(callee) {
|
||||
trace!("attempting to call a trait method");
|
||||
if !self.tcx.features().const_trait_impl {
|
||||
self.check_op(ops::FnCallNonConst(Some((callee, substs))));
|
||||
self.check_op(ops::FnCallNonConst {
|
||||
caller,
|
||||
callee,
|
||||
substs,
|
||||
span: *fn_span,
|
||||
from_hir_call: *from_hir_call,
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
let trait_ref = TraitRef::from_method(tcx, trait_id, substs);
|
||||
let obligation = Obligation::new(
|
||||
ObligationCause::dummy(),
|
||||
param_env,
|
||||
Binder::dummy(TraitPredicate {
|
||||
trait_ref,
|
||||
constness: ty::BoundConstness::NotConst,
|
||||
polarity: ty::ImplPolarity::Positive,
|
||||
}),
|
||||
);
|
||||
let poly_trait_pred = Binder::dummy(TraitPredicate {
|
||||
trait_ref,
|
||||
constness: ty::BoundConstness::ConstIfConst,
|
||||
polarity: ty::ImplPolarity::Positive,
|
||||
});
|
||||
let obligation =
|
||||
Obligation::new(ObligationCause::dummy(), param_env, poly_trait_pred);
|
||||
|
||||
let implsrc = tcx.infer_ctxt().enter(|infcx| {
|
||||
let mut selcx = SelectionContext::new(&infcx);
|
||||
@ -826,10 +831,6 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
|
||||
return;
|
||||
}
|
||||
Ok(Some(ImplSource::UserDefined(data))) => {
|
||||
if let hir::Constness::NotConst = tcx.impl_constness(data.impl_def_id) {
|
||||
self.check_op(ops::FnCallNonConst(None));
|
||||
return;
|
||||
}
|
||||
let callee_name = tcx.item_name(callee);
|
||||
if let Some(&did) = tcx
|
||||
.associated_item_def_ids(data.impl_def_id)
|
||||
@ -841,22 +842,61 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
|
||||
substs = InternalSubsts::identity_for_item(tcx, did);
|
||||
callee = did;
|
||||
}
|
||||
|
||||
if let hir::Constness::NotConst = tcx.impl_constness(data.impl_def_id) {
|
||||
self.check_op(ops::FnCallNonConst {
|
||||
caller,
|
||||
callee,
|
||||
substs,
|
||||
span: *fn_span,
|
||||
from_hir_call: *from_hir_call,
|
||||
});
|
||||
return;
|
||||
}
|
||||
}
|
||||
_ if !tcx.is_const_fn_raw(callee) => {
|
||||
// At this point, it is only legal when the caller is marked with
|
||||
// #[default_method_body_is_const], and the callee is in the same
|
||||
// trait.
|
||||
let callee_trait = tcx.trait_of_item(callee);
|
||||
if callee_trait.is_some() {
|
||||
if tcx.has_attr(caller, sym::default_method_body_is_const) {
|
||||
if tcx.trait_of_item(caller) == callee_trait {
|
||||
nonconst_call_permission = true;
|
||||
}
|
||||
}
|
||||
if callee_trait.is_some()
|
||||
&& tcx.has_attr(caller, sym::default_method_body_is_const)
|
||||
&& callee_trait == tcx.trait_of_item(caller)
|
||||
// Can only call methods when it's `<Self as TheTrait>::f`.
|
||||
&& tcx.types.self_param == substs.type_at(0)
|
||||
{
|
||||
nonconst_call_permission = true;
|
||||
}
|
||||
|
||||
if !nonconst_call_permission {
|
||||
self.check_op(ops::FnCallNonConst(None));
|
||||
let obligation = Obligation::new(
|
||||
ObligationCause::dummy_with_span(*fn_span),
|
||||
param_env,
|
||||
tcx.mk_predicate(
|
||||
poly_trait_pred.map_bound(ty::PredicateKind::Trait),
|
||||
),
|
||||
);
|
||||
|
||||
// improve diagnostics by showing what failed. Our requirements are stricter this time
|
||||
// as we are going to error again anyways.
|
||||
tcx.infer_ctxt().enter(|infcx| {
|
||||
if let Err(e) = implsrc {
|
||||
infcx.report_selection_error(
|
||||
obligation.clone(),
|
||||
&obligation,
|
||||
&e,
|
||||
false,
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
self.check_op(ops::FnCallNonConst {
|
||||
caller,
|
||||
callee,
|
||||
substs,
|
||||
span: *fn_span,
|
||||
from_hir_call: *from_hir_call,
|
||||
});
|
||||
return;
|
||||
}
|
||||
}
|
||||
@ -925,7 +965,13 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
|
||||
}
|
||||
|
||||
if !nonconst_call_permission {
|
||||
self.check_op(ops::FnCallNonConst(None));
|
||||
self.check_op(ops::FnCallNonConst {
|
||||
caller,
|
||||
callee,
|
||||
substs,
|
||||
span: *fn_span,
|
||||
from_hir_call: *from_hir_call,
|
||||
});
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
@ -3,14 +3,22 @@
|
||||
use rustc_errors::{struct_span_err, Applicability, DiagnosticBuilder};
|
||||
use rustc_hir as hir;
|
||||
use rustc_hir::def_id::DefId;
|
||||
use rustc_infer::infer::TyCtxtInferExt;
|
||||
use rustc_infer::traits::{ImplSource, Obligation, ObligationCause};
|
||||
use rustc_middle::mir;
|
||||
use rustc_middle::ty::print::with_no_trimmed_paths;
|
||||
use rustc_middle::ty::subst::{GenericArgKind, SubstsRef};
|
||||
use rustc_middle::{mir, ty::AssocKind};
|
||||
use rustc_middle::ty::{
|
||||
suggest_constraining_type_param, Adt, Closure, FnDef, FnPtr, Param, TraitPredicate, Ty,
|
||||
};
|
||||
use rustc_middle::ty::{Binder, BoundConstness, ImplPolarity, TraitRef};
|
||||
use rustc_session::parse::feature_err;
|
||||
use rustc_span::symbol::sym;
|
||||
use rustc_span::{symbol::Ident, Span, Symbol};
|
||||
use rustc_span::{BytePos, Pos};
|
||||
use rustc_span::{BytePos, Pos, Span, Symbol};
|
||||
use rustc_trait_selection::traits::SelectionContext;
|
||||
|
||||
use super::ConstCx;
|
||||
use crate::util::{call_kind, CallDesugaringKind, CallKind};
|
||||
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
||||
pub enum Status {
|
||||
@ -29,9 +37,9 @@ pub enum DiagnosticImportance {
|
||||
}
|
||||
|
||||
/// An operation that is not *always* allowed in a const context.
|
||||
pub trait NonConstOp: std::fmt::Debug {
|
||||
pub trait NonConstOp<'tcx>: std::fmt::Debug {
|
||||
/// Returns an enum indicating whether this operation is allowed within the given item.
|
||||
fn status_in_item(&self, _ccx: &ConstCx<'_, '_>) -> Status {
|
||||
fn status_in_item(&self, _ccx: &ConstCx<'_, 'tcx>) -> Status {
|
||||
Status::Forbidden
|
||||
}
|
||||
|
||||
@ -39,13 +47,13 @@ pub trait NonConstOp: std::fmt::Debug {
|
||||
DiagnosticImportance::Primary
|
||||
}
|
||||
|
||||
fn build_error<'tcx>(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx>;
|
||||
fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx>;
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct FloatingPointOp;
|
||||
impl NonConstOp for FloatingPointOp {
|
||||
fn status_in_item(&self, ccx: &ConstCx<'_, '_>) -> Status {
|
||||
impl<'tcx> NonConstOp<'tcx> for FloatingPointOp {
|
||||
fn status_in_item(&self, ccx: &ConstCx<'_, 'tcx>) -> Status {
|
||||
if ccx.const_kind() == hir::ConstContext::ConstFn {
|
||||
Status::Unstable(sym::const_fn_floating_point_arithmetic)
|
||||
} else {
|
||||
@ -53,7 +61,7 @@ impl NonConstOp for FloatingPointOp {
|
||||
}
|
||||
}
|
||||
|
||||
fn build_error<'tcx>(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
|
||||
fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
|
||||
feature_err(
|
||||
&ccx.tcx.sess.parse_sess,
|
||||
sym::const_fn_floating_point_arithmetic,
|
||||
@ -66,77 +74,229 @@ impl NonConstOp for FloatingPointOp {
|
||||
/// A function call where the callee is a pointer.
|
||||
#[derive(Debug)]
|
||||
pub struct FnCallIndirect;
|
||||
impl NonConstOp for FnCallIndirect {
|
||||
fn build_error<'tcx>(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
|
||||
impl<'tcx> NonConstOp<'tcx> for FnCallIndirect {
|
||||
fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
|
||||
ccx.tcx.sess.struct_span_err(span, "function pointers are not allowed in const fn")
|
||||
}
|
||||
}
|
||||
|
||||
/// A function call where the callee is not marked as `const`.
|
||||
#[derive(Debug)]
|
||||
pub struct FnCallNonConst<'tcx>(pub Option<(DefId, SubstsRef<'tcx>)>);
|
||||
impl<'a> NonConstOp for FnCallNonConst<'a> {
|
||||
fn build_error<'tcx>(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
|
||||
let mut err = struct_span_err!(
|
||||
ccx.tcx.sess,
|
||||
span,
|
||||
E0015,
|
||||
"calls in {}s are limited to constant functions, \
|
||||
tuple structs and tuple variants",
|
||||
ccx.const_kind(),
|
||||
);
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub struct FnCallNonConst<'tcx> {
|
||||
pub caller: DefId,
|
||||
pub callee: DefId,
|
||||
pub substs: SubstsRef<'tcx>,
|
||||
pub span: Span,
|
||||
pub from_hir_call: bool,
|
||||
}
|
||||
|
||||
if let FnCallNonConst(Some((callee, substs))) = *self {
|
||||
if let Some(trait_def_id) = ccx.tcx.lang_items().eq_trait() {
|
||||
if let Some(eq_item) = ccx.tcx.associated_items(trait_def_id).find_by_name_and_kind(
|
||||
ccx.tcx,
|
||||
Ident::with_dummy_span(sym::eq),
|
||||
AssocKind::Fn,
|
||||
trait_def_id,
|
||||
) {
|
||||
if callee == eq_item.def_id && substs.len() == 2 {
|
||||
match (substs[0].unpack(), substs[1].unpack()) {
|
||||
(GenericArgKind::Type(self_ty), GenericArgKind::Type(rhs_ty))
|
||||
if self_ty == rhs_ty
|
||||
&& self_ty.is_ref()
|
||||
&& self_ty.peel_refs().is_primitive() =>
|
||||
{
|
||||
let mut num_refs = 0;
|
||||
let mut tmp_ty = self_ty;
|
||||
while let rustc_middle::ty::Ref(_, inner_ty, _) = tmp_ty.kind() {
|
||||
num_refs += 1;
|
||||
tmp_ty = inner_ty;
|
||||
}
|
||||
let deref = "*".repeat(num_refs);
|
||||
impl<'tcx> NonConstOp<'tcx> for FnCallNonConst<'tcx> {
|
||||
fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, _: Span) -> DiagnosticBuilder<'tcx> {
|
||||
let FnCallNonConst { caller, callee, substs, span, from_hir_call } = *self;
|
||||
let ConstCx { tcx, param_env, .. } = *ccx;
|
||||
|
||||
if let Ok(call_str) =
|
||||
ccx.tcx.sess.source_map().span_to_snippet(span)
|
||||
{
|
||||
if let Some(eq_idx) = call_str.find("==") {
|
||||
if let Some(rhs_idx) = call_str[(eq_idx + 2)..]
|
||||
.find(|c: char| !c.is_whitespace())
|
||||
{
|
||||
let rhs_pos = span.lo()
|
||||
+ BytePos::from_usize(eq_idx + 2 + rhs_idx);
|
||||
let rhs_span = span.with_lo(rhs_pos).with_hi(rhs_pos);
|
||||
err.multipart_suggestion(
|
||||
"consider dereferencing here",
|
||||
vec![
|
||||
(span.shrink_to_lo(), deref.clone()),
|
||||
(rhs_span, deref),
|
||||
],
|
||||
Applicability::MachineApplicable,
|
||||
);
|
||||
}
|
||||
let diag_trait = |mut err, self_ty: Ty<'_>, trait_id| {
|
||||
let trait_ref = TraitRef::from_method(tcx, trait_id, substs);
|
||||
|
||||
match self_ty.kind() {
|
||||
Param(param_ty) => {
|
||||
debug!(?param_ty);
|
||||
if let Some(generics) = caller
|
||||
.as_local()
|
||||
.map(|id| tcx.hir().local_def_id_to_hir_id(id))
|
||||
.map(|id| tcx.hir().get(id))
|
||||
.as_ref()
|
||||
.and_then(|node| node.generics())
|
||||
{
|
||||
let constraint = with_no_trimmed_paths(|| {
|
||||
format!("~const {}", trait_ref.print_only_trait_path())
|
||||
});
|
||||
suggest_constraining_type_param(
|
||||
tcx,
|
||||
generics,
|
||||
&mut err,
|
||||
¶m_ty.name.as_str(),
|
||||
&constraint,
|
||||
None,
|
||||
);
|
||||
}
|
||||
}
|
||||
Adt(..) => {
|
||||
let obligation = Obligation::new(
|
||||
ObligationCause::dummy(),
|
||||
param_env,
|
||||
Binder::dummy(TraitPredicate {
|
||||
trait_ref,
|
||||
constness: BoundConstness::NotConst,
|
||||
polarity: ImplPolarity::Positive,
|
||||
}),
|
||||
);
|
||||
|
||||
let implsrc = tcx.infer_ctxt().enter(|infcx| {
|
||||
let mut selcx = SelectionContext::new(&infcx);
|
||||
selcx.select(&obligation)
|
||||
});
|
||||
|
||||
if let Ok(Some(ImplSource::UserDefined(data))) = implsrc {
|
||||
let span =
|
||||
tcx.sess.source_map().guess_head_span(tcx.def_span(data.impl_def_id));
|
||||
err.span_note(span, "impl defined here, but it is not `const`");
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
|
||||
err
|
||||
};
|
||||
|
||||
let call_kind = call_kind(tcx, ccx.param_env, callee, substs, span, from_hir_call, None);
|
||||
|
||||
debug!(?call_kind);
|
||||
|
||||
let mut err = match call_kind {
|
||||
CallKind::Normal { desugaring: Some((kind, self_ty)), .. } => {
|
||||
macro_rules! error {
|
||||
($fmt:literal) => {
|
||||
struct_span_err!(tcx.sess, span, E0015, $fmt, self_ty, ccx.const_kind())
|
||||
};
|
||||
}
|
||||
|
||||
let err = match kind {
|
||||
CallDesugaringKind::ForLoopIntoIter => {
|
||||
error!("cannot convert `{}` into an iterator in {}s")
|
||||
}
|
||||
CallDesugaringKind::QuestionBranch => {
|
||||
error!("`?` cannot determine the branch of `{}` in {}s")
|
||||
}
|
||||
CallDesugaringKind::QuestionFromResidual => {
|
||||
error!("`?` cannot convert from residual of `{}` in {}s")
|
||||
}
|
||||
CallDesugaringKind::TryBlockFromOutput => {
|
||||
error!("`try` block cannot convert `{}` to the result in {}s")
|
||||
}
|
||||
};
|
||||
|
||||
diag_trait(err, self_ty, kind.trait_def_id(tcx))
|
||||
}
|
||||
CallKind::FnCall { fn_trait_id, self_ty } => {
|
||||
let mut err = struct_span_err!(
|
||||
tcx.sess,
|
||||
span,
|
||||
E0015,
|
||||
"cannot call non-const closure in {}s",
|
||||
ccx.const_kind(),
|
||||
);
|
||||
|
||||
match self_ty.kind() {
|
||||
FnDef(def_id, ..) => {
|
||||
let span = tcx.sess.source_map().guess_head_span(tcx.def_span(*def_id));
|
||||
if ccx.tcx.is_const_fn_raw(*def_id) {
|
||||
span_bug!(span, "calling const FnDef errored when it shouldn't");
|
||||
}
|
||||
|
||||
err.span_note(span, "function defined here, but it is not `const`");
|
||||
}
|
||||
FnPtr(..) => {
|
||||
err.note(&format!(
|
||||
"function pointers need an RFC before allowed to be called in {}s",
|
||||
ccx.const_kind()
|
||||
));
|
||||
}
|
||||
Closure(..) => {
|
||||
err.note(&format!(
|
||||
"closures need an RFC before allowed to be called in {}s",
|
||||
ccx.const_kind()
|
||||
));
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
|
||||
diag_trait(err, self_ty, fn_trait_id)
|
||||
}
|
||||
CallKind::Operator { trait_id, self_ty, .. } => {
|
||||
let mut err = struct_span_err!(
|
||||
tcx.sess,
|
||||
span,
|
||||
E0015,
|
||||
"cannot call non-const operator in {}s",
|
||||
ccx.const_kind()
|
||||
);
|
||||
|
||||
if Some(trait_id) == ccx.tcx.lang_items().eq_trait() {
|
||||
match (substs[0].unpack(), substs[1].unpack()) {
|
||||
(GenericArgKind::Type(self_ty), GenericArgKind::Type(rhs_ty))
|
||||
if self_ty == rhs_ty
|
||||
&& self_ty.is_ref()
|
||||
&& self_ty.peel_refs().is_primitive() =>
|
||||
{
|
||||
let mut num_refs = 0;
|
||||
let mut tmp_ty = self_ty;
|
||||
while let rustc_middle::ty::Ref(_, inner_ty, _) = tmp_ty.kind() {
|
||||
num_refs += 1;
|
||||
tmp_ty = inner_ty;
|
||||
}
|
||||
let deref = "*".repeat(num_refs);
|
||||
|
||||
if let Ok(call_str) = ccx.tcx.sess.source_map().span_to_snippet(span) {
|
||||
if let Some(eq_idx) = call_str.find("==") {
|
||||
if let Some(rhs_idx) =
|
||||
call_str[(eq_idx + 2)..].find(|c: char| !c.is_whitespace())
|
||||
{
|
||||
let rhs_pos =
|
||||
span.lo() + BytePos::from_usize(eq_idx + 2 + rhs_idx);
|
||||
let rhs_span = span.with_lo(rhs_pos).with_hi(rhs_pos);
|
||||
err.multipart_suggestion(
|
||||
"consider dereferencing here",
|
||||
vec![
|
||||
(span.shrink_to_lo(), deref.clone()),
|
||||
(rhs_span, deref),
|
||||
],
|
||||
Applicability::MachineApplicable,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
diag_trait(err, self_ty, trait_id)
|
||||
}
|
||||
}
|
||||
CallKind::DerefCoercion { deref_target, deref_target_ty, self_ty } => {
|
||||
let mut err = struct_span_err!(
|
||||
tcx.sess,
|
||||
span,
|
||||
E0015,
|
||||
"cannot perform deref coercion on `{}` in {}s",
|
||||
self_ty,
|
||||
ccx.const_kind()
|
||||
);
|
||||
|
||||
err.note(&format!("attempting to deref into `{}`", deref_target_ty));
|
||||
|
||||
// Check first whether the source is accessible (issue #87060)
|
||||
if tcx.sess.source_map().span_to_snippet(deref_target).is_ok() {
|
||||
err.span_note(deref_target, "deref defined here");
|
||||
}
|
||||
|
||||
diag_trait(err, self_ty, tcx.lang_items().deref_trait().unwrap())
|
||||
}
|
||||
_ => struct_span_err!(
|
||||
ccx.tcx.sess,
|
||||
span,
|
||||
E0015,
|
||||
"cannot call non-const fn `{}` in {}s",
|
||||
ccx.tcx.def_path_str_with_substs(callee, substs),
|
||||
ccx.const_kind(),
|
||||
),
|
||||
};
|
||||
|
||||
err.note(&format!(
|
||||
"calls in {}s are limited to constant functions, \
|
||||
tuple structs and tuple variants",
|
||||
ccx.const_kind(),
|
||||
));
|
||||
|
||||
err
|
||||
}
|
||||
@ -148,8 +308,8 @@ impl<'a> NonConstOp for FnCallNonConst<'a> {
|
||||
#[derive(Debug)]
|
||||
pub struct FnCallUnstable(pub DefId, pub Option<Symbol>);
|
||||
|
||||
impl NonConstOp for FnCallUnstable {
|
||||
fn build_error<'tcx>(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
|
||||
impl<'tcx> NonConstOp<'tcx> for FnCallUnstable {
|
||||
fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
|
||||
let FnCallUnstable(def_id, feature) = *self;
|
||||
|
||||
let mut err = ccx.tcx.sess.struct_span_err(
|
||||
@ -174,8 +334,8 @@ impl NonConstOp for FnCallUnstable {
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct FnPtrCast;
|
||||
impl NonConstOp for FnPtrCast {
|
||||
fn status_in_item(&self, ccx: &ConstCx<'_, '_>) -> Status {
|
||||
impl<'tcx> NonConstOp<'tcx> for FnPtrCast {
|
||||
fn status_in_item(&self, ccx: &ConstCx<'_, 'tcx>) -> Status {
|
||||
if ccx.const_kind() != hir::ConstContext::ConstFn {
|
||||
Status::Allowed
|
||||
} else {
|
||||
@ -183,7 +343,7 @@ impl NonConstOp for FnPtrCast {
|
||||
}
|
||||
}
|
||||
|
||||
fn build_error<'tcx>(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
|
||||
fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
|
||||
feature_err(
|
||||
&ccx.tcx.sess.parse_sess,
|
||||
sym::const_fn_fn_ptr_basics,
|
||||
@ -195,8 +355,8 @@ impl NonConstOp for FnPtrCast {
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Generator(pub hir::GeneratorKind);
|
||||
impl NonConstOp for Generator {
|
||||
fn status_in_item(&self, _: &ConstCx<'_, '_>) -> Status {
|
||||
impl<'tcx> NonConstOp<'tcx> for Generator {
|
||||
fn status_in_item(&self, _: &ConstCx<'_, 'tcx>) -> Status {
|
||||
if let hir::GeneratorKind::Async(hir::AsyncGeneratorKind::Block) = self.0 {
|
||||
Status::Unstable(sym::const_async_blocks)
|
||||
} else {
|
||||
@ -204,7 +364,7 @@ impl NonConstOp for Generator {
|
||||
}
|
||||
}
|
||||
|
||||
fn build_error<'tcx>(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
|
||||
fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
|
||||
let msg = format!("{}s are not allowed in {}s", self.0, ccx.const_kind());
|
||||
if let hir::GeneratorKind::Async(hir::AsyncGeneratorKind::Block) = self.0 {
|
||||
feature_err(&ccx.tcx.sess.parse_sess, sym::const_async_blocks, span, &msg)
|
||||
@ -216,8 +376,8 @@ impl NonConstOp for Generator {
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct HeapAllocation;
|
||||
impl NonConstOp for HeapAllocation {
|
||||
fn build_error<'tcx>(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
|
||||
impl<'tcx> NonConstOp<'tcx> for HeapAllocation {
|
||||
fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
|
||||
let mut err = struct_span_err!(
|
||||
ccx.tcx.sess,
|
||||
span,
|
||||
@ -240,8 +400,8 @@ impl NonConstOp for HeapAllocation {
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct InlineAsm;
|
||||
impl NonConstOp for InlineAsm {
|
||||
fn build_error<'tcx>(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
|
||||
impl<'tcx> NonConstOp<'tcx> for InlineAsm {
|
||||
fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
|
||||
struct_span_err!(
|
||||
ccx.tcx.sess,
|
||||
span,
|
||||
@ -256,8 +416,8 @@ impl NonConstOp for InlineAsm {
|
||||
pub struct LiveDrop {
|
||||
pub dropped_at: Option<Span>,
|
||||
}
|
||||
impl NonConstOp for LiveDrop {
|
||||
fn build_error<'tcx>(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
|
||||
impl<'tcx> NonConstOp<'tcx> for LiveDrop {
|
||||
fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
|
||||
let mut err = struct_span_err!(
|
||||
ccx.tcx.sess,
|
||||
span,
|
||||
@ -276,8 +436,8 @@ impl NonConstOp for LiveDrop {
|
||||
/// A borrow of a type that contains an `UnsafeCell` somewhere. The borrow never escapes to
|
||||
/// the final value of the constant.
|
||||
pub struct TransientCellBorrow;
|
||||
impl NonConstOp for TransientCellBorrow {
|
||||
fn status_in_item(&self, _: &ConstCx<'_, '_>) -> Status {
|
||||
impl<'tcx> NonConstOp<'tcx> for TransientCellBorrow {
|
||||
fn status_in_item(&self, _: &ConstCx<'_, 'tcx>) -> Status {
|
||||
Status::Unstable(sym::const_refs_to_cell)
|
||||
}
|
||||
fn importance(&self) -> DiagnosticImportance {
|
||||
@ -285,7 +445,7 @@ impl NonConstOp for TransientCellBorrow {
|
||||
// not additionally emit a feature gate error if activating the feature gate won't work.
|
||||
DiagnosticImportance::Secondary
|
||||
}
|
||||
fn build_error<'tcx>(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
|
||||
fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
|
||||
feature_err(
|
||||
&ccx.tcx.sess.parse_sess,
|
||||
sym::const_refs_to_cell,
|
||||
@ -300,8 +460,8 @@ impl NonConstOp for TransientCellBorrow {
|
||||
/// the final value of the constant, and thus we cannot allow this (for now). We may allow
|
||||
/// it in the future for static items.
|
||||
pub struct CellBorrow;
|
||||
impl NonConstOp for CellBorrow {
|
||||
fn build_error<'tcx>(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
|
||||
impl<'tcx> NonConstOp<'tcx> for CellBorrow {
|
||||
fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
|
||||
let mut err = struct_span_err!(
|
||||
ccx.tcx.sess,
|
||||
span,
|
||||
@ -337,8 +497,8 @@ impl NonConstOp for CellBorrow {
|
||||
/// static or const items.
|
||||
pub struct MutBorrow(pub hir::BorrowKind);
|
||||
|
||||
impl NonConstOp for MutBorrow {
|
||||
fn status_in_item(&self, _ccx: &ConstCx<'_, '_>) -> Status {
|
||||
impl<'tcx> NonConstOp<'tcx> for MutBorrow {
|
||||
fn status_in_item(&self, _ccx: &ConstCx<'_, 'tcx>) -> Status {
|
||||
Status::Forbidden
|
||||
}
|
||||
|
||||
@ -348,7 +508,7 @@ impl NonConstOp for MutBorrow {
|
||||
DiagnosticImportance::Secondary
|
||||
}
|
||||
|
||||
fn build_error<'tcx>(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
|
||||
fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
|
||||
let raw = match self.0 {
|
||||
hir::BorrowKind::Raw => "raw ",
|
||||
hir::BorrowKind::Ref => "",
|
||||
@ -382,12 +542,12 @@ impl NonConstOp for MutBorrow {
|
||||
#[derive(Debug)]
|
||||
pub struct TransientMutBorrow(pub hir::BorrowKind);
|
||||
|
||||
impl NonConstOp for TransientMutBorrow {
|
||||
fn status_in_item(&self, _: &ConstCx<'_, '_>) -> Status {
|
||||
impl<'tcx> NonConstOp<'tcx> for TransientMutBorrow {
|
||||
fn status_in_item(&self, _: &ConstCx<'_, 'tcx>) -> Status {
|
||||
Status::Unstable(sym::const_mut_refs)
|
||||
}
|
||||
|
||||
fn build_error<'tcx>(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
|
||||
fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
|
||||
let raw = match self.0 {
|
||||
hir::BorrowKind::Raw => "raw ",
|
||||
hir::BorrowKind::Ref => "",
|
||||
@ -404,8 +564,8 @@ impl NonConstOp for TransientMutBorrow {
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct MutDeref;
|
||||
impl NonConstOp for MutDeref {
|
||||
fn status_in_item(&self, _: &ConstCx<'_, '_>) -> Status {
|
||||
impl<'tcx> NonConstOp<'tcx> for MutDeref {
|
||||
fn status_in_item(&self, _: &ConstCx<'_, 'tcx>) -> Status {
|
||||
Status::Unstable(sym::const_mut_refs)
|
||||
}
|
||||
|
||||
@ -414,7 +574,7 @@ impl NonConstOp for MutDeref {
|
||||
DiagnosticImportance::Secondary
|
||||
}
|
||||
|
||||
fn build_error<'tcx>(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
|
||||
fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
|
||||
feature_err(
|
||||
&ccx.tcx.sess.parse_sess,
|
||||
sym::const_mut_refs,
|
||||
@ -427,8 +587,8 @@ impl NonConstOp for MutDeref {
|
||||
/// A call to a `panic()` lang item where the first argument is _not_ a `&str`.
|
||||
#[derive(Debug)]
|
||||
pub struct PanicNonStr;
|
||||
impl NonConstOp for PanicNonStr {
|
||||
fn build_error<'tcx>(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
|
||||
impl<'tcx> NonConstOp<'tcx> for PanicNonStr {
|
||||
fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
|
||||
ccx.tcx.sess.struct_span_err(
|
||||
span,
|
||||
"argument to `panic!()` in a const context must have type `&str`",
|
||||
@ -441,8 +601,8 @@ impl NonConstOp for PanicNonStr {
|
||||
/// allocation base addresses that are not known at compile-time.
|
||||
#[derive(Debug)]
|
||||
pub struct RawPtrComparison;
|
||||
impl NonConstOp for RawPtrComparison {
|
||||
fn build_error<'tcx>(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
|
||||
impl<'tcx> NonConstOp<'tcx> for RawPtrComparison {
|
||||
fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
|
||||
let mut err = ccx
|
||||
.tcx
|
||||
.sess
|
||||
@ -457,12 +617,12 @@ impl NonConstOp for RawPtrComparison {
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct RawMutPtrDeref;
|
||||
impl NonConstOp for RawMutPtrDeref {
|
||||
impl<'tcx> NonConstOp<'tcx> for RawMutPtrDeref {
|
||||
fn status_in_item(&self, _: &ConstCx<'_, '_>) -> Status {
|
||||
Status::Unstable(sym::const_mut_refs)
|
||||
}
|
||||
|
||||
fn build_error<'tcx>(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
|
||||
fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
|
||||
feature_err(
|
||||
&ccx.tcx.sess.parse_sess,
|
||||
sym::const_mut_refs,
|
||||
@ -477,8 +637,8 @@ impl NonConstOp for RawMutPtrDeref {
|
||||
/// allocation base addresses that are not known at compile-time.
|
||||
#[derive(Debug)]
|
||||
pub struct RawPtrToIntCast;
|
||||
impl NonConstOp for RawPtrToIntCast {
|
||||
fn build_error<'tcx>(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
|
||||
impl<'tcx> NonConstOp<'tcx> for RawPtrToIntCast {
|
||||
fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
|
||||
let mut err = ccx
|
||||
.tcx
|
||||
.sess
|
||||
@ -494,8 +654,8 @@ impl NonConstOp for RawPtrToIntCast {
|
||||
/// An access to a (non-thread-local) `static`.
|
||||
#[derive(Debug)]
|
||||
pub struct StaticAccess;
|
||||
impl NonConstOp for StaticAccess {
|
||||
fn status_in_item(&self, ccx: &ConstCx<'_, '_>) -> Status {
|
||||
impl<'tcx> NonConstOp<'tcx> for StaticAccess {
|
||||
fn status_in_item(&self, ccx: &ConstCx<'_, 'tcx>) -> Status {
|
||||
if let hir::ConstContext::Static(_) = ccx.const_kind() {
|
||||
Status::Allowed
|
||||
} else {
|
||||
@ -503,7 +663,7 @@ impl NonConstOp for StaticAccess {
|
||||
}
|
||||
}
|
||||
|
||||
fn build_error<'tcx>(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
|
||||
fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
|
||||
let mut err = struct_span_err!(
|
||||
ccx.tcx.sess,
|
||||
span,
|
||||
@ -528,8 +688,8 @@ impl NonConstOp for StaticAccess {
|
||||
/// An access to a thread-local `static`.
|
||||
#[derive(Debug)]
|
||||
pub struct ThreadLocalAccess;
|
||||
impl NonConstOp for ThreadLocalAccess {
|
||||
fn build_error<'tcx>(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
|
||||
impl<'tcx> NonConstOp<'tcx> for ThreadLocalAccess {
|
||||
fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
|
||||
struct_span_err!(
|
||||
ccx.tcx.sess,
|
||||
span,
|
||||
@ -546,8 +706,8 @@ pub mod ty {
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct MutRef(pub mir::LocalKind);
|
||||
impl NonConstOp for MutRef {
|
||||
fn status_in_item(&self, _ccx: &ConstCx<'_, '_>) -> Status {
|
||||
impl<'tcx> NonConstOp<'tcx> for MutRef {
|
||||
fn status_in_item(&self, _ccx: &ConstCx<'_, 'tcx>) -> Status {
|
||||
Status::Unstable(sym::const_mut_refs)
|
||||
}
|
||||
|
||||
@ -560,11 +720,7 @@ pub mod ty {
|
||||
}
|
||||
}
|
||||
|
||||
fn build_error<'tcx>(
|
||||
&self,
|
||||
ccx: &ConstCx<'_, 'tcx>,
|
||||
span: Span,
|
||||
) -> DiagnosticBuilder<'tcx> {
|
||||
fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
|
||||
feature_err(
|
||||
&ccx.tcx.sess.parse_sess,
|
||||
sym::const_mut_refs,
|
||||
@ -576,7 +732,7 @@ pub mod ty {
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct FnPtr(pub mir::LocalKind);
|
||||
impl NonConstOp for FnPtr {
|
||||
impl<'tcx> NonConstOp<'tcx> for FnPtr {
|
||||
fn importance(&self) -> DiagnosticImportance {
|
||||
match self.0 {
|
||||
mir::LocalKind::Var | mir::LocalKind::Temp => DiagnosticImportance::Secondary,
|
||||
@ -586,7 +742,7 @@ pub mod ty {
|
||||
}
|
||||
}
|
||||
|
||||
fn status_in_item(&self, ccx: &ConstCx<'_, '_>) -> Status {
|
||||
fn status_in_item(&self, ccx: &ConstCx<'_, 'tcx>) -> Status {
|
||||
if ccx.const_kind() != hir::ConstContext::ConstFn {
|
||||
Status::Allowed
|
||||
} else {
|
||||
@ -594,11 +750,7 @@ pub mod ty {
|
||||
}
|
||||
}
|
||||
|
||||
fn build_error<'tcx>(
|
||||
&self,
|
||||
ccx: &ConstCx<'_, 'tcx>,
|
||||
span: Span,
|
||||
) -> DiagnosticBuilder<'tcx> {
|
||||
fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
|
||||
feature_err(
|
||||
&ccx.tcx.sess.parse_sess,
|
||||
sym::const_fn_fn_ptr_basics,
|
||||
@ -610,16 +762,12 @@ pub mod ty {
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct ImplTrait;
|
||||
impl NonConstOp for ImplTrait {
|
||||
impl<'tcx> NonConstOp<'tcx> for ImplTrait {
|
||||
fn status_in_item(&self, _: &ConstCx<'_, '_>) -> Status {
|
||||
Status::Unstable(sym::const_impl_trait)
|
||||
}
|
||||
|
||||
fn build_error<'tcx>(
|
||||
&self,
|
||||
ccx: &ConstCx<'_, 'tcx>,
|
||||
span: Span,
|
||||
) -> DiagnosticBuilder<'tcx> {
|
||||
fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
|
||||
feature_err(
|
||||
&ccx.tcx.sess.parse_sess,
|
||||
sym::const_impl_trait,
|
||||
@ -631,7 +779,7 @@ pub mod ty {
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct TraitBound(pub mir::LocalKind);
|
||||
impl NonConstOp for TraitBound {
|
||||
impl<'tcx> NonConstOp<'tcx> for TraitBound {
|
||||
fn importance(&self) -> DiagnosticImportance {
|
||||
match self.0 {
|
||||
mir::LocalKind::Var | mir::LocalKind::Temp => DiagnosticImportance::Secondary,
|
||||
@ -641,7 +789,7 @@ pub mod ty {
|
||||
}
|
||||
}
|
||||
|
||||
fn status_in_item(&self, ccx: &ConstCx<'_, '_>) -> Status {
|
||||
fn status_in_item(&self, ccx: &ConstCx<'_, 'tcx>) -> Status {
|
||||
if ccx.const_kind() != hir::ConstContext::ConstFn {
|
||||
Status::Allowed
|
||||
} else {
|
||||
@ -649,11 +797,7 @@ pub mod ty {
|
||||
}
|
||||
}
|
||||
|
||||
fn build_error<'tcx>(
|
||||
&self,
|
||||
ccx: &ConstCx<'_, 'tcx>,
|
||||
span: Span,
|
||||
) -> DiagnosticBuilder<'tcx> {
|
||||
fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
|
||||
let mut err = feature_err(
|
||||
&ccx.tcx.sess.parse_sess,
|
||||
sym::const_fn_trait_bound,
|
||||
@ -674,7 +818,7 @@ pub mod ty {
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct DynTrait(pub mir::LocalKind);
|
||||
impl NonConstOp for DynTrait {
|
||||
impl<'tcx> NonConstOp<'tcx> for DynTrait {
|
||||
fn importance(&self) -> DiagnosticImportance {
|
||||
match self.0 {
|
||||
mir::LocalKind::Var | mir::LocalKind::Temp => DiagnosticImportance::Secondary,
|
||||
@ -684,7 +828,7 @@ pub mod ty {
|
||||
}
|
||||
}
|
||||
|
||||
fn status_in_item(&self, ccx: &ConstCx<'_, '_>) -> Status {
|
||||
fn status_in_item(&self, ccx: &ConstCx<'_, 'tcx>) -> Status {
|
||||
if ccx.const_kind() != hir::ConstContext::ConstFn {
|
||||
Status::Allowed
|
||||
} else {
|
||||
@ -692,11 +836,7 @@ pub mod ty {
|
||||
}
|
||||
}
|
||||
|
||||
fn build_error<'tcx>(
|
||||
&self,
|
||||
ccx: &ConstCx<'_, 'tcx>,
|
||||
span: Span,
|
||||
) -> DiagnosticBuilder<'tcx> {
|
||||
fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
|
||||
let mut err = feature_err(
|
||||
&ccx.tcx.sess.parse_sess,
|
||||
sym::const_fn_trait_bound,
|
||||
@ -718,16 +858,12 @@ pub mod ty {
|
||||
/// A trait bound with the `?const Trait` opt-out
|
||||
#[derive(Debug)]
|
||||
pub struct TraitBoundNotConst;
|
||||
impl NonConstOp for TraitBoundNotConst {
|
||||
fn status_in_item(&self, _: &ConstCx<'_, '_>) -> Status {
|
||||
impl<'tcx> NonConstOp<'tcx> for TraitBoundNotConst {
|
||||
fn status_in_item(&self, _: &ConstCx<'_, 'tcx>) -> Status {
|
||||
Status::Unstable(sym::const_trait_bound_opt_out)
|
||||
}
|
||||
|
||||
fn build_error<'tcx>(
|
||||
&self,
|
||||
ccx: &ConstCx<'_, 'tcx>,
|
||||
span: Span,
|
||||
) -> DiagnosticBuilder<'tcx> {
|
||||
fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
|
||||
feature_err(
|
||||
&ccx.tcx.sess.parse_sess,
|
||||
sym::const_trait_bound_opt_out,
|
||||
|
143
compiler/rustc_const_eval/src/util/call_kind.rs
Normal file
143
compiler/rustc_const_eval/src/util/call_kind.rs
Normal file
@ -0,0 +1,143 @@
|
||||
//! Common logic for borrowck use-after-move errors when moved into a `fn(self)`,
|
||||
//! as well as errors when attempting to call a non-const function in a const
|
||||
//! context.
|
||||
|
||||
use rustc_hir::def_id::DefId;
|
||||
use rustc_hir::lang_items::LangItemGroup;
|
||||
use rustc_middle::ty::subst::SubstsRef;
|
||||
use rustc_middle::ty::{self, AssocItemContainer, DefIdTree, Instance, ParamEnv, Ty, TyCtxt};
|
||||
use rustc_span::symbol::Ident;
|
||||
use rustc_span::{sym, DesugaringKind, Span};
|
||||
|
||||
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
|
||||
pub enum CallDesugaringKind {
|
||||
/// for _ in x {} calls x.into_iter()
|
||||
ForLoopIntoIter,
|
||||
/// x? calls x.branch()
|
||||
QuestionBranch,
|
||||
/// x? calls type_of(x)::from_residual()
|
||||
QuestionFromResidual,
|
||||
/// try { ..; x } calls type_of(x)::from_output(x)
|
||||
TryBlockFromOutput,
|
||||
}
|
||||
|
||||
impl CallDesugaringKind {
|
||||
pub fn trait_def_id(self, tcx: TyCtxt<'_>) -> DefId {
|
||||
match self {
|
||||
Self::ForLoopIntoIter => tcx.get_diagnostic_item(sym::IntoIterator).unwrap(),
|
||||
Self::QuestionBranch | Self::TryBlockFromOutput => {
|
||||
tcx.lang_items().try_trait().unwrap()
|
||||
}
|
||||
Self::QuestionFromResidual => tcx.get_diagnostic_item(sym::FromResidual).unwrap(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
|
||||
pub enum CallKind<'tcx> {
|
||||
/// A normal method call of the form `receiver.foo(a, b, c)`
|
||||
Normal {
|
||||
self_arg: Option<Ident>,
|
||||
desugaring: Option<(CallDesugaringKind, Ty<'tcx>)>,
|
||||
/// Whether the self type of the method call has an `.as_ref()` method.
|
||||
/// Used for better diagnostics.
|
||||
is_option_or_result: bool,
|
||||
},
|
||||
/// A call to `Fn(..)::call(..)`, desugared from `my_closure(a, b, c)`
|
||||
FnCall { fn_trait_id: DefId, self_ty: Ty<'tcx> },
|
||||
/// A call to an operator trait, desuraged from operator syntax (e.g. `a << b`)
|
||||
Operator { self_arg: Option<Ident>, trait_id: DefId, self_ty: Ty<'tcx> },
|
||||
DerefCoercion {
|
||||
/// The `Span` of the `Target` associated type
|
||||
/// in the `Deref` impl we are using.
|
||||
deref_target: Span,
|
||||
/// The type `T::Deref` we are dereferencing to
|
||||
deref_target_ty: Ty<'tcx>,
|
||||
self_ty: Ty<'tcx>,
|
||||
},
|
||||
}
|
||||
|
||||
pub fn call_kind<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
param_env: ParamEnv<'tcx>,
|
||||
method_did: DefId,
|
||||
method_substs: SubstsRef<'tcx>,
|
||||
fn_call_span: Span,
|
||||
from_hir_call: bool,
|
||||
self_arg: Option<Ident>,
|
||||
) -> CallKind<'tcx> {
|
||||
let parent = tcx.opt_associated_item(method_did).and_then(|assoc| match assoc.container {
|
||||
AssocItemContainer::ImplContainer(impl_did) => tcx.trait_id_of_impl(impl_did),
|
||||
AssocItemContainer::TraitContainer(trait_did) => Some(trait_did),
|
||||
});
|
||||
|
||||
let fn_call = parent
|
||||
.and_then(|p| tcx.lang_items().group(LangItemGroup::Fn).iter().find(|did| **did == p));
|
||||
|
||||
let operator = (!from_hir_call)
|
||||
.then(|| parent)
|
||||
.flatten()
|
||||
.and_then(|p| tcx.lang_items().group(LangItemGroup::Op).iter().find(|did| **did == p));
|
||||
|
||||
let is_deref = !from_hir_call && tcx.is_diagnostic_item(sym::deref_method, method_did);
|
||||
|
||||
// Check for a 'special' use of 'self' -
|
||||
// an FnOnce call, an operator (e.g. `<<`), or a
|
||||
// deref coercion.
|
||||
let kind = if let Some(&trait_id) = fn_call {
|
||||
Some(CallKind::FnCall { fn_trait_id: trait_id, self_ty: method_substs.type_at(0) })
|
||||
} else if let Some(&trait_id) = operator {
|
||||
Some(CallKind::Operator { self_arg, trait_id, self_ty: method_substs.type_at(0) })
|
||||
} else if is_deref {
|
||||
let deref_target = tcx.get_diagnostic_item(sym::deref_target).and_then(|deref_target| {
|
||||
Instance::resolve(tcx, param_env, deref_target, method_substs).transpose()
|
||||
});
|
||||
if let Some(Ok(instance)) = deref_target {
|
||||
let deref_target_ty = instance.ty(tcx, param_env);
|
||||
Some(CallKind::DerefCoercion {
|
||||
deref_target: tcx.def_span(instance.def_id()),
|
||||
deref_target_ty,
|
||||
self_ty: method_substs.type_at(0),
|
||||
})
|
||||
} else {
|
||||
None
|
||||
}
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
kind.unwrap_or_else(|| {
|
||||
// This isn't a 'special' use of `self`
|
||||
debug!(?method_did, ?fn_call_span);
|
||||
let desugaring = if Some(method_did) == tcx.lang_items().into_iter_fn()
|
||||
&& fn_call_span.desugaring_kind() == Some(DesugaringKind::ForLoop)
|
||||
{
|
||||
Some((CallDesugaringKind::ForLoopIntoIter, method_substs.type_at(0)))
|
||||
} else if fn_call_span.desugaring_kind() == Some(DesugaringKind::QuestionMark) {
|
||||
if Some(method_did) == tcx.lang_items().branch_fn() {
|
||||
Some((CallDesugaringKind::QuestionBranch, method_substs.type_at(0)))
|
||||
} else if Some(method_did) == tcx.lang_items().from_residual_fn() {
|
||||
Some((CallDesugaringKind::QuestionFromResidual, method_substs.type_at(0)))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
} else if Some(method_did) == tcx.lang_items().from_output_fn()
|
||||
&& fn_call_span.desugaring_kind() == Some(DesugaringKind::TryBlock)
|
||||
{
|
||||
Some((CallDesugaringKind::TryBlockFromOutput, method_substs.type_at(0)))
|
||||
} else {
|
||||
None
|
||||
};
|
||||
let parent_self_ty = tcx
|
||||
.parent(method_did)
|
||||
.filter(|did| tcx.def_kind(*did) == rustc_hir::def::DefKind::Impl)
|
||||
.and_then(|did| match tcx.type_of(did).kind() {
|
||||
ty::Adt(def, ..) => Some(def.did),
|
||||
_ => None,
|
||||
});
|
||||
let is_option_or_result = parent_self_ty.map_or(false, |def_id| {
|
||||
matches!(tcx.get_diagnostic_name(def_id), Some(sym::Option | sym::Result))
|
||||
});
|
||||
CallKind::Normal { self_arg, desugaring, is_option_or_result }
|
||||
})
|
||||
}
|
@ -1,8 +1,10 @@
|
||||
pub mod aggregate;
|
||||
mod alignment;
|
||||
mod call_kind;
|
||||
pub mod collect_writes;
|
||||
mod find_self_call;
|
||||
|
||||
pub use self::aggregate::expand_aggregate;
|
||||
pub use self::alignment::is_disaligned;
|
||||
pub use self::call_kind::{call_kind, CallDesugaringKind, CallKind};
|
||||
pub use self::find_self_call::find_self_call;
|
||||
|
@ -263,7 +263,7 @@ fn run_compiler(
|
||||
describe_lints(compiler.session(), &lint_store, registered_lints);
|
||||
return;
|
||||
}
|
||||
let should_stop = RustcDefaultCalls::print_crate_info(
|
||||
let should_stop = print_crate_info(
|
||||
&***compiler.codegen_backend(),
|
||||
compiler.session(),
|
||||
None,
|
||||
@ -292,7 +292,7 @@ fn run_compiler(
|
||||
|
||||
interface::run_compiler(config, |compiler| {
|
||||
let sess = compiler.session();
|
||||
let should_stop = RustcDefaultCalls::print_crate_info(
|
||||
let should_stop = print_crate_info(
|
||||
&***compiler.codegen_backend(),
|
||||
sess,
|
||||
Some(compiler.input()),
|
||||
@ -301,13 +301,9 @@ fn run_compiler(
|
||||
compiler.temps_dir(),
|
||||
)
|
||||
.and_then(|| {
|
||||
RustcDefaultCalls::list_metadata(
|
||||
sess,
|
||||
&*compiler.codegen_backend().metadata_loader(),
|
||||
compiler.input(),
|
||||
)
|
||||
list_metadata(sess, &*compiler.codegen_backend().metadata_loader(), compiler.input())
|
||||
})
|
||||
.and_then(|| RustcDefaultCalls::try_process_rlink(sess, compiler));
|
||||
.and_then(|| try_process_rlink(sess, compiler));
|
||||
|
||||
if should_stop == Compilation::Stop {
|
||||
return sess.compile_status();
|
||||
@ -512,10 +508,6 @@ impl Compilation {
|
||||
}
|
||||
}
|
||||
|
||||
/// CompilerCalls instance for a regular rustc build.
|
||||
#[derive(Copy, Clone)]
|
||||
pub struct RustcDefaultCalls;
|
||||
|
||||
fn handle_explain(registry: Registry, code: &str, output: ErrorOutputType) {
|
||||
let upper_cased_code = code.to_ascii_uppercase();
|
||||
let normalised = if upper_cased_code.starts_with('E') {
|
||||
@ -588,164 +580,159 @@ fn show_content_with_pager(content: &str) {
|
||||
}
|
||||
}
|
||||
|
||||
impl RustcDefaultCalls {
|
||||
pub fn try_process_rlink(sess: &Session, compiler: &interface::Compiler) -> Compilation {
|
||||
if sess.opts.debugging_opts.link_only {
|
||||
if let Input::File(file) = compiler.input() {
|
||||
// FIXME: #![crate_type] and #![crate_name] support not implemented yet
|
||||
sess.init_crate_types(collect_crate_types(sess, &[]));
|
||||
let outputs = compiler.build_output_filenames(sess, &[]);
|
||||
let rlink_data = fs::read(file).unwrap_or_else(|err| {
|
||||
sess.fatal(&format!("failed to read rlink file: {}", err));
|
||||
});
|
||||
let mut decoder = rustc_serialize::opaque::Decoder::new(&rlink_data, 0);
|
||||
let codegen_results: CodegenResults =
|
||||
rustc_serialize::Decodable::decode(&mut decoder);
|
||||
let result = compiler.codegen_backend().link(sess, codegen_results, &outputs);
|
||||
abort_on_err(result, sess);
|
||||
} else {
|
||||
sess.fatal("rlink must be a file")
|
||||
}
|
||||
Compilation::Stop
|
||||
pub fn try_process_rlink(sess: &Session, compiler: &interface::Compiler) -> Compilation {
|
||||
if sess.opts.debugging_opts.link_only {
|
||||
if let Input::File(file) = compiler.input() {
|
||||
// FIXME: #![crate_type] and #![crate_name] support not implemented yet
|
||||
sess.init_crate_types(collect_crate_types(sess, &[]));
|
||||
let outputs = compiler.build_output_filenames(sess, &[]);
|
||||
let rlink_data = fs::read(file).unwrap_or_else(|err| {
|
||||
sess.fatal(&format!("failed to read rlink file: {}", err));
|
||||
});
|
||||
let mut decoder = rustc_serialize::opaque::Decoder::new(&rlink_data, 0);
|
||||
let codegen_results: CodegenResults = rustc_serialize::Decodable::decode(&mut decoder);
|
||||
let result = compiler.codegen_backend().link(sess, codegen_results, &outputs);
|
||||
abort_on_err(result, sess);
|
||||
} else {
|
||||
Compilation::Continue
|
||||
}
|
||||
}
|
||||
|
||||
pub fn list_metadata(
|
||||
sess: &Session,
|
||||
metadata_loader: &dyn MetadataLoader,
|
||||
input: &Input,
|
||||
) -> Compilation {
|
||||
if sess.opts.debugging_opts.ls {
|
||||
match *input {
|
||||
Input::File(ref ifile) => {
|
||||
let path = &(*ifile);
|
||||
let mut v = Vec::new();
|
||||
locator::list_file_metadata(&sess.target, path, metadata_loader, &mut v)
|
||||
.unwrap();
|
||||
println!("{}", String::from_utf8(v).unwrap());
|
||||
}
|
||||
Input::Str { .. } => {
|
||||
early_error(ErrorOutputType::default(), "cannot list metadata for stdin");
|
||||
}
|
||||
}
|
||||
return Compilation::Stop;
|
||||
}
|
||||
|
||||
Compilation::Continue
|
||||
}
|
||||
|
||||
fn print_crate_info(
|
||||
codegen_backend: &dyn CodegenBackend,
|
||||
sess: &Session,
|
||||
input: Option<&Input>,
|
||||
odir: &Option<PathBuf>,
|
||||
ofile: &Option<PathBuf>,
|
||||
temps_dir: &Option<PathBuf>,
|
||||
) -> Compilation {
|
||||
use rustc_session::config::PrintRequest::*;
|
||||
// NativeStaticLibs and LinkArgs are special - printed during linking
|
||||
// (empty iterator returns true)
|
||||
if sess.opts.prints.iter().all(|&p| p == NativeStaticLibs || p == LinkArgs) {
|
||||
return Compilation::Continue;
|
||||
}
|
||||
|
||||
let attrs = match input {
|
||||
None => None,
|
||||
Some(input) => {
|
||||
let result = parse_crate_attrs(sess, input);
|
||||
match result {
|
||||
Ok(attrs) => Some(attrs),
|
||||
Err(mut parse_error) => {
|
||||
parse_error.emit();
|
||||
return Compilation::Stop;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
for req in &sess.opts.prints {
|
||||
match *req {
|
||||
TargetList => {
|
||||
let mut targets =
|
||||
rustc_target::spec::TARGETS.iter().copied().collect::<Vec<_>>();
|
||||
targets.sort_unstable();
|
||||
println!("{}", targets.join("\n"));
|
||||
}
|
||||
Sysroot => println!("{}", sess.sysroot.display()),
|
||||
TargetLibdir => println!("{}", sess.target_tlib_path.dir.display()),
|
||||
TargetSpec => println!("{}", sess.target.to_json().pretty()),
|
||||
FileNames | CrateName => {
|
||||
let input = input.unwrap_or_else(|| {
|
||||
early_error(ErrorOutputType::default(), "no input file provided")
|
||||
});
|
||||
let attrs = attrs.as_ref().unwrap();
|
||||
let t_outputs = rustc_interface::util::build_output_filenames(
|
||||
input, odir, ofile, temps_dir, attrs, sess,
|
||||
);
|
||||
let id = rustc_session::output::find_crate_name(sess, attrs, input);
|
||||
if *req == PrintRequest::CrateName {
|
||||
println!("{}", id);
|
||||
continue;
|
||||
}
|
||||
let crate_types = collect_crate_types(sess, attrs);
|
||||
for &style in &crate_types {
|
||||
let fname =
|
||||
rustc_session::output::filename_for_input(sess, style, &id, &t_outputs);
|
||||
println!("{}", fname.file_name().unwrap().to_string_lossy());
|
||||
}
|
||||
}
|
||||
Cfg => {
|
||||
let mut cfgs = sess
|
||||
.parse_sess
|
||||
.config
|
||||
.iter()
|
||||
.filter_map(|&(name, value)| {
|
||||
// Note that crt-static is a specially recognized cfg
|
||||
// directive that's printed out here as part of
|
||||
// rust-lang/rust#37406, but in general the
|
||||
// `target_feature` cfg is gated under
|
||||
// rust-lang/rust#29717. For now this is just
|
||||
// specifically allowing the crt-static cfg and that's
|
||||
// it, this is intended to get into Cargo and then go
|
||||
// through to build scripts.
|
||||
if (name != sym::target_feature || value != Some(sym::crt_dash_static))
|
||||
&& !sess.is_nightly_build()
|
||||
&& find_gated_cfg(|cfg_sym| cfg_sym == name).is_some()
|
||||
{
|
||||
return None;
|
||||
}
|
||||
|
||||
if let Some(value) = value {
|
||||
Some(format!("{}=\"{}\"", name, value))
|
||||
} else {
|
||||
Some(name.to_string())
|
||||
}
|
||||
})
|
||||
.collect::<Vec<String>>();
|
||||
|
||||
cfgs.sort();
|
||||
for cfg in cfgs {
|
||||
println!("{}", cfg);
|
||||
}
|
||||
}
|
||||
RelocationModels
|
||||
| CodeModels
|
||||
| TlsModels
|
||||
| TargetCPUs
|
||||
| StackProtectorStrategies
|
||||
| TargetFeatures => {
|
||||
codegen_backend.print(*req, sess);
|
||||
}
|
||||
// Any output here interferes with Cargo's parsing of other printed output
|
||||
NativeStaticLibs => {}
|
||||
LinkArgs => {}
|
||||
}
|
||||
sess.fatal("rlink must be a file")
|
||||
}
|
||||
Compilation::Stop
|
||||
} else {
|
||||
Compilation::Continue
|
||||
}
|
||||
}
|
||||
|
||||
pub fn list_metadata(
|
||||
sess: &Session,
|
||||
metadata_loader: &dyn MetadataLoader,
|
||||
input: &Input,
|
||||
) -> Compilation {
|
||||
if sess.opts.debugging_opts.ls {
|
||||
match *input {
|
||||
Input::File(ref ifile) => {
|
||||
let path = &(*ifile);
|
||||
let mut v = Vec::new();
|
||||
locator::list_file_metadata(&sess.target, path, metadata_loader, &mut v).unwrap();
|
||||
println!("{}", String::from_utf8(v).unwrap());
|
||||
}
|
||||
Input::Str { .. } => {
|
||||
early_error(ErrorOutputType::default(), "cannot list metadata for stdin");
|
||||
}
|
||||
}
|
||||
return Compilation::Stop;
|
||||
}
|
||||
|
||||
Compilation::Continue
|
||||
}
|
||||
|
||||
fn print_crate_info(
|
||||
codegen_backend: &dyn CodegenBackend,
|
||||
sess: &Session,
|
||||
input: Option<&Input>,
|
||||
odir: &Option<PathBuf>,
|
||||
ofile: &Option<PathBuf>,
|
||||
temps_dir: &Option<PathBuf>,
|
||||
) -> Compilation {
|
||||
use rustc_session::config::PrintRequest::*;
|
||||
// NativeStaticLibs and LinkArgs are special - printed during linking
|
||||
// (empty iterator returns true)
|
||||
if sess.opts.prints.iter().all(|&p| p == NativeStaticLibs || p == LinkArgs) {
|
||||
return Compilation::Continue;
|
||||
}
|
||||
|
||||
let attrs = match input {
|
||||
None => None,
|
||||
Some(input) => {
|
||||
let result = parse_crate_attrs(sess, input);
|
||||
match result {
|
||||
Ok(attrs) => Some(attrs),
|
||||
Err(mut parse_error) => {
|
||||
parse_error.emit();
|
||||
return Compilation::Stop;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
for req in &sess.opts.prints {
|
||||
match *req {
|
||||
TargetList => {
|
||||
let mut targets = rustc_target::spec::TARGETS.iter().copied().collect::<Vec<_>>();
|
||||
targets.sort_unstable();
|
||||
println!("{}", targets.join("\n"));
|
||||
}
|
||||
Sysroot => println!("{}", sess.sysroot.display()),
|
||||
TargetLibdir => println!("{}", sess.target_tlib_path.dir.display()),
|
||||
TargetSpec => println!("{}", sess.target.to_json().pretty()),
|
||||
FileNames | CrateName => {
|
||||
let input = input.unwrap_or_else(|| {
|
||||
early_error(ErrorOutputType::default(), "no input file provided")
|
||||
});
|
||||
let attrs = attrs.as_ref().unwrap();
|
||||
let t_outputs = rustc_interface::util::build_output_filenames(
|
||||
input, odir, ofile, temps_dir, attrs, sess,
|
||||
);
|
||||
let id = rustc_session::output::find_crate_name(sess, attrs, input);
|
||||
if *req == PrintRequest::CrateName {
|
||||
println!("{}", id);
|
||||
continue;
|
||||
}
|
||||
let crate_types = collect_crate_types(sess, attrs);
|
||||
for &style in &crate_types {
|
||||
let fname =
|
||||
rustc_session::output::filename_for_input(sess, style, &id, &t_outputs);
|
||||
println!("{}", fname.file_name().unwrap().to_string_lossy());
|
||||
}
|
||||
}
|
||||
Cfg => {
|
||||
let mut cfgs = sess
|
||||
.parse_sess
|
||||
.config
|
||||
.iter()
|
||||
.filter_map(|&(name, value)| {
|
||||
// Note that crt-static is a specially recognized cfg
|
||||
// directive that's printed out here as part of
|
||||
// rust-lang/rust#37406, but in general the
|
||||
// `target_feature` cfg is gated under
|
||||
// rust-lang/rust#29717. For now this is just
|
||||
// specifically allowing the crt-static cfg and that's
|
||||
// it, this is intended to get into Cargo and then go
|
||||
// through to build scripts.
|
||||
if (name != sym::target_feature || value != Some(sym::crt_dash_static))
|
||||
&& !sess.is_nightly_build()
|
||||
&& find_gated_cfg(|cfg_sym| cfg_sym == name).is_some()
|
||||
{
|
||||
return None;
|
||||
}
|
||||
|
||||
if let Some(value) = value {
|
||||
Some(format!("{}=\"{}\"", name, value))
|
||||
} else {
|
||||
Some(name.to_string())
|
||||
}
|
||||
})
|
||||
.collect::<Vec<String>>();
|
||||
|
||||
cfgs.sort();
|
||||
for cfg in cfgs {
|
||||
println!("{}", cfg);
|
||||
}
|
||||
}
|
||||
RelocationModels
|
||||
| CodeModels
|
||||
| TlsModels
|
||||
| TargetCPUs
|
||||
| StackProtectorStrategies
|
||||
| TargetFeatures => {
|
||||
codegen_backend.print(*req, sess);
|
||||
}
|
||||
// Any output here interferes with Cargo's parsing of other printed output
|
||||
NativeStaticLibs => {}
|
||||
LinkArgs => {}
|
||||
}
|
||||
}
|
||||
Compilation::Stop
|
||||
}
|
||||
|
||||
/// Prints version information
|
||||
pub fn version(binary: &str, matches: &getopts::Matches) {
|
||||
let verbose = matches.opt_present("verbose");
|
||||
|
@ -21,9 +21,10 @@ use std::lazy::SyncLazy;
|
||||
|
||||
pub enum LangItemGroup {
|
||||
Op,
|
||||
Fn,
|
||||
}
|
||||
|
||||
const NUM_GROUPS: usize = 1;
|
||||
const NUM_GROUPS: usize = 2;
|
||||
|
||||
macro_rules! expand_group {
|
||||
() => {
|
||||
@ -98,11 +99,12 @@ macro_rules! language_item_table {
|
||||
/// Construct an empty collection of lang items and no missing ones.
|
||||
pub fn new() -> Self {
|
||||
fn init_none(_: LangItem) -> Option<DefId> { None }
|
||||
const EMPTY: Vec<DefId> = Vec::new();
|
||||
|
||||
Self {
|
||||
items: vec![$(init_none(LangItem::$variant)),*],
|
||||
missing: Vec::new(),
|
||||
groups: [vec![]; NUM_GROUPS],
|
||||
groups: [EMPTY; NUM_GROUPS],
|
||||
}
|
||||
}
|
||||
|
||||
@ -251,9 +253,9 @@ language_item_table! {
|
||||
DerefTarget, sym::deref_target, deref_target, Target::AssocTy, GenericRequirement::None;
|
||||
Receiver, sym::receiver, receiver_trait, Target::Trait, GenericRequirement::None;
|
||||
|
||||
Fn, kw::Fn, fn_trait, Target::Trait, GenericRequirement::Exact(1);
|
||||
FnMut, sym::fn_mut, fn_mut_trait, Target::Trait, GenericRequirement::Exact(1);
|
||||
FnOnce, sym::fn_once, fn_once_trait, Target::Trait, GenericRequirement::Exact(1);
|
||||
Fn(Fn), kw::Fn, fn_trait, Target::Trait, GenericRequirement::Exact(1);
|
||||
FnMut(Fn), sym::fn_mut, fn_mut_trait, Target::Trait, GenericRequirement::Exact(1);
|
||||
FnOnce(Fn), sym::fn_once, fn_once_trait, Target::Trait, GenericRequirement::Exact(1);
|
||||
|
||||
FnOnceOutput, sym::fn_once_output, fn_once_output, Target::AssocTy, GenericRequirement::None;
|
||||
|
||||
@ -264,8 +266,8 @@ language_item_table! {
|
||||
Unpin, sym::unpin, unpin_trait, Target::Trait, GenericRequirement::None;
|
||||
Pin, sym::pin, pin_type, Target::Struct, GenericRequirement::None;
|
||||
|
||||
PartialEq, sym::eq, eq_trait, Target::Trait, GenericRequirement::Exact(1);
|
||||
PartialOrd, sym::partial_ord, partial_ord_trait, Target::Trait, GenericRequirement::Exact(1);
|
||||
PartialEq(Op), sym::eq, eq_trait, Target::Trait, GenericRequirement::Exact(1);
|
||||
PartialOrd(Op), sym::partial_ord, partial_ord_trait, Target::Trait, GenericRequirement::Exact(1);
|
||||
|
||||
// A number of panic-related lang items. The `panic` item corresponds to divide-by-zero and
|
||||
// various panic cases with `match`. The `panic_bounds_check` item is for indexing arrays.
|
||||
|
@ -49,6 +49,31 @@ impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> {
|
||||
Canonicalizer::canonicalize(value, self, self.tcx, &CanonicalizeAllFreeRegions, query_state)
|
||||
}
|
||||
|
||||
/// Like [Self::canonicalize_query], but preserves distinct universes. For
|
||||
/// example, canonicalizing `&'?0: Trait<'?1>`, where `'?0` is in `U1` and
|
||||
/// `'?1` is in `U3` would be canonicalized to have ?0` in `U1` and `'?1`
|
||||
/// in `U2`.
|
||||
///
|
||||
/// This is used for Chalk integration.
|
||||
pub fn canonicalize_query_preserving_universes<V>(
|
||||
&self,
|
||||
value: V,
|
||||
query_state: &mut OriginalQueryValues<'tcx>,
|
||||
) -> Canonicalized<'tcx, V>
|
||||
where
|
||||
V: TypeFoldable<'tcx>,
|
||||
{
|
||||
self.tcx.sess.perf_stats.queries_canonicalized.fetch_add(1, Ordering::Relaxed);
|
||||
|
||||
Canonicalizer::canonicalize(
|
||||
value,
|
||||
self,
|
||||
self.tcx,
|
||||
&CanonicalizeAllFreeRegionsPreservingUniverses,
|
||||
query_state,
|
||||
)
|
||||
}
|
||||
|
||||
/// Canonicalizes a query *response* `V`. When we canonicalize a
|
||||
/// query response, we only canonicalize unbound inference
|
||||
/// variables, and we leave other free regions alone. So,
|
||||
@ -133,7 +158,7 @@ impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> {
|
||||
/// maximally general query. But if we are canonicalizing a *query
|
||||
/// response*, then we don't typically replace free regions, as they
|
||||
/// must have been introduced from other parts of the system.
|
||||
trait CanonicalizeRegionMode {
|
||||
trait CanonicalizeMode {
|
||||
fn canonicalize_free_region<'tcx>(
|
||||
&self,
|
||||
canonicalizer: &mut Canonicalizer<'_, 'tcx>,
|
||||
@ -141,11 +166,14 @@ trait CanonicalizeRegionMode {
|
||||
) -> ty::Region<'tcx>;
|
||||
|
||||
fn any(&self) -> bool;
|
||||
|
||||
// Do we preserve universe of variables.
|
||||
fn preserve_universes(&self) -> bool;
|
||||
}
|
||||
|
||||
struct CanonicalizeQueryResponse;
|
||||
|
||||
impl CanonicalizeRegionMode for CanonicalizeQueryResponse {
|
||||
impl CanonicalizeMode for CanonicalizeQueryResponse {
|
||||
fn canonicalize_free_region<'tcx>(
|
||||
&self,
|
||||
canonicalizer: &mut Canonicalizer<'_, 'tcx>,
|
||||
@ -198,11 +226,15 @@ impl CanonicalizeRegionMode for CanonicalizeQueryResponse {
|
||||
fn any(&self) -> bool {
|
||||
false
|
||||
}
|
||||
|
||||
fn preserve_universes(&self) -> bool {
|
||||
true
|
||||
}
|
||||
}
|
||||
|
||||
struct CanonicalizeUserTypeAnnotation;
|
||||
|
||||
impl CanonicalizeRegionMode for CanonicalizeUserTypeAnnotation {
|
||||
impl CanonicalizeMode for CanonicalizeUserTypeAnnotation {
|
||||
fn canonicalize_free_region<'tcx>(
|
||||
&self,
|
||||
canonicalizer: &mut Canonicalizer<'_, 'tcx>,
|
||||
@ -221,11 +253,15 @@ impl CanonicalizeRegionMode for CanonicalizeUserTypeAnnotation {
|
||||
fn any(&self) -> bool {
|
||||
false
|
||||
}
|
||||
|
||||
fn preserve_universes(&self) -> bool {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
struct CanonicalizeAllFreeRegions;
|
||||
|
||||
impl CanonicalizeRegionMode for CanonicalizeAllFreeRegions {
|
||||
impl CanonicalizeMode for CanonicalizeAllFreeRegions {
|
||||
fn canonicalize_free_region<'tcx>(
|
||||
&self,
|
||||
canonicalizer: &mut Canonicalizer<'_, 'tcx>,
|
||||
@ -237,11 +273,39 @@ impl CanonicalizeRegionMode for CanonicalizeAllFreeRegions {
|
||||
fn any(&self) -> bool {
|
||||
true
|
||||
}
|
||||
|
||||
fn preserve_universes(&self) -> bool {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
struct CanonicalizeAllFreeRegionsPreservingUniverses;
|
||||
|
||||
impl CanonicalizeMode for CanonicalizeAllFreeRegionsPreservingUniverses {
|
||||
fn canonicalize_free_region<'tcx>(
|
||||
&self,
|
||||
canonicalizer: &mut Canonicalizer<'_, 'tcx>,
|
||||
r: ty::Region<'tcx>,
|
||||
) -> ty::Region<'tcx> {
|
||||
let universe = canonicalizer.infcx.universe_of_region(r);
|
||||
canonicalizer.canonical_var_for_region(
|
||||
CanonicalVarInfo { kind: CanonicalVarKind::Region(universe) },
|
||||
r,
|
||||
)
|
||||
}
|
||||
|
||||
fn any(&self) -> bool {
|
||||
true
|
||||
}
|
||||
|
||||
fn preserve_universes(&self) -> bool {
|
||||
true
|
||||
}
|
||||
}
|
||||
|
||||
struct CanonicalizeFreeRegionsOtherThanStatic;
|
||||
|
||||
impl CanonicalizeRegionMode for CanonicalizeFreeRegionsOtherThanStatic {
|
||||
impl CanonicalizeMode for CanonicalizeFreeRegionsOtherThanStatic {
|
||||
fn canonicalize_free_region<'tcx>(
|
||||
&self,
|
||||
canonicalizer: &mut Canonicalizer<'_, 'tcx>,
|
||||
@ -257,6 +321,10 @@ impl CanonicalizeRegionMode for CanonicalizeFreeRegionsOtherThanStatic {
|
||||
fn any(&self) -> bool {
|
||||
true
|
||||
}
|
||||
|
||||
fn preserve_universes(&self) -> bool {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
struct Canonicalizer<'cx, 'tcx> {
|
||||
@ -267,7 +335,7 @@ struct Canonicalizer<'cx, 'tcx> {
|
||||
// Note that indices is only used once `var_values` is big enough to be
|
||||
// heap-allocated.
|
||||
indices: FxHashMap<GenericArg<'tcx>, BoundVar>,
|
||||
canonicalize_region_mode: &'cx dyn CanonicalizeRegionMode,
|
||||
canonicalize_mode: &'cx dyn CanonicalizeMode,
|
||||
needs_canonical_flags: TypeFlags,
|
||||
|
||||
binder_index: ty::DebruijnIndex,
|
||||
@ -311,7 +379,7 @@ impl<'cx, 'tcx> TypeFolder<'tcx> for Canonicalizer<'cx, 'tcx> {
|
||||
vid, r
|
||||
);
|
||||
let r = self.tcx.reuse_or_mk_region(r, ty::ReVar(resolved_vid));
|
||||
self.canonicalize_region_mode.canonicalize_free_region(self, r)
|
||||
self.canonicalize_mode.canonicalize_free_region(self, r)
|
||||
}
|
||||
|
||||
ty::ReStatic
|
||||
@ -319,7 +387,7 @@ impl<'cx, 'tcx> TypeFolder<'tcx> for Canonicalizer<'cx, 'tcx> {
|
||||
| ty::ReFree(_)
|
||||
| ty::ReEmpty(_)
|
||||
| ty::RePlaceholder(..)
|
||||
| ty::ReErased => self.canonicalize_region_mode.canonicalize_free_region(self, r),
|
||||
| ty::ReErased => self.canonicalize_mode.canonicalize_free_region(self, r),
|
||||
}
|
||||
}
|
||||
|
||||
@ -337,8 +405,10 @@ impl<'cx, 'tcx> TypeFolder<'tcx> for Canonicalizer<'cx, 'tcx> {
|
||||
// `TyVar(vid)` is unresolved, track its universe index in the canonicalized
|
||||
// result.
|
||||
Err(mut ui) => {
|
||||
// FIXME: perf problem described in #55921.
|
||||
ui = ty::UniverseIndex::ROOT;
|
||||
if !self.canonicalize_mode.preserve_universes() {
|
||||
// FIXME: perf problem described in #55921.
|
||||
ui = ty::UniverseIndex::ROOT;
|
||||
}
|
||||
self.canonicalize_ty_var(
|
||||
CanonicalVarInfo {
|
||||
kind: CanonicalVarKind::Ty(CanonicalTyVarKind::General(ui)),
|
||||
@ -422,8 +492,10 @@ impl<'cx, 'tcx> TypeFolder<'tcx> for Canonicalizer<'cx, 'tcx> {
|
||||
// `ConstVar(vid)` is unresolved, track its universe index in the
|
||||
// canonicalized result
|
||||
Err(mut ui) => {
|
||||
// FIXME: perf problem described in #55921.
|
||||
ui = ty::UniverseIndex::ROOT;
|
||||
if !self.canonicalize_mode.preserve_universes() {
|
||||
// FIXME: perf problem described in #55921.
|
||||
ui = ty::UniverseIndex::ROOT;
|
||||
}
|
||||
return self.canonicalize_const_var(
|
||||
CanonicalVarInfo { kind: CanonicalVarKind::Const(ui, ct.ty) },
|
||||
ct,
|
||||
@ -462,7 +534,7 @@ impl<'cx, 'tcx> Canonicalizer<'cx, 'tcx> {
|
||||
value: V,
|
||||
infcx: &InferCtxt<'_, 'tcx>,
|
||||
tcx: TyCtxt<'tcx>,
|
||||
canonicalize_region_mode: &dyn CanonicalizeRegionMode,
|
||||
canonicalize_region_mode: &dyn CanonicalizeMode,
|
||||
query_state: &mut OriginalQueryValues<'tcx>,
|
||||
) -> Canonicalized<'tcx, V>
|
||||
where
|
||||
@ -493,7 +565,7 @@ impl<'cx, 'tcx> Canonicalizer<'cx, 'tcx> {
|
||||
let mut canonicalizer = Canonicalizer {
|
||||
infcx,
|
||||
tcx,
|
||||
canonicalize_region_mode,
|
||||
canonicalize_mode: canonicalize_region_mode,
|
||||
needs_canonical_flags,
|
||||
variables: SmallVec::new(),
|
||||
query_state,
|
||||
@ -504,10 +576,11 @@ impl<'cx, 'tcx> Canonicalizer<'cx, 'tcx> {
|
||||
|
||||
// Once we have canonicalized `out_value`, it should not
|
||||
// contain anything that ties it to this inference context
|
||||
// anymore, so it should live in the global arena.
|
||||
debug_assert!(!out_value.needs_infer());
|
||||
// anymore.
|
||||
debug_assert!(!out_value.needs_infer() && !out_value.has_placeholders());
|
||||
|
||||
let canonical_variables = tcx.intern_canonical_var_infos(&canonicalizer.variables);
|
||||
let canonical_variables =
|
||||
tcx.intern_canonical_var_infos(&canonicalizer.universe_canonicalized_variables());
|
||||
|
||||
let max_universe = canonical_variables
|
||||
.iter()
|
||||
@ -527,6 +600,19 @@ impl<'cx, 'tcx> Canonicalizer<'cx, 'tcx> {
|
||||
|
||||
let var_values = &mut query_state.var_values;
|
||||
|
||||
let universe = info.universe();
|
||||
if universe != ty::UniverseIndex::ROOT {
|
||||
assert!(self.canonicalize_mode.preserve_universes());
|
||||
|
||||
// Insert universe into the universe map. To preserve the order of the
|
||||
// universes in the value being canonicalized, we don't update the
|
||||
// universe in `info` until we have finished canonicalizing.
|
||||
match query_state.universe_map.binary_search(&universe) {
|
||||
Err(idx) => query_state.universe_map.insert(idx, universe),
|
||||
Ok(_) => {}
|
||||
}
|
||||
}
|
||||
|
||||
// This code is hot. `variables` and `var_values` are usually small
|
||||
// (fewer than 8 elements ~95% of the time). They are SmallVec's to
|
||||
// avoid allocations in those cases. We also don't use `indices` to
|
||||
@ -569,6 +655,61 @@ impl<'cx, 'tcx> Canonicalizer<'cx, 'tcx> {
|
||||
}
|
||||
}
|
||||
|
||||
/// Replaces the universe indexes used in `var_values` with their index in
|
||||
/// `query_state.universe_map`. This minimizes the maximum universe used in
|
||||
/// the canonicalized value.
|
||||
fn universe_canonicalized_variables(self) -> SmallVec<[CanonicalVarInfo<'tcx>; 8]> {
|
||||
if self.query_state.universe_map.len() == 1 {
|
||||
return self.variables;
|
||||
}
|
||||
|
||||
let reverse_universe_map: FxHashMap<ty::UniverseIndex, ty::UniverseIndex> = self
|
||||
.query_state
|
||||
.universe_map
|
||||
.iter()
|
||||
.enumerate()
|
||||
.map(|(idx, universe)| (*universe, ty::UniverseIndex::from_usize(idx)))
|
||||
.collect();
|
||||
|
||||
self.variables
|
||||
.iter()
|
||||
.map(|v| CanonicalVarInfo {
|
||||
kind: match v.kind {
|
||||
CanonicalVarKind::Ty(CanonicalTyVarKind::Int | CanonicalTyVarKind::Float) => {
|
||||
return *v;
|
||||
}
|
||||
CanonicalVarKind::Ty(CanonicalTyVarKind::General(u)) => {
|
||||
CanonicalVarKind::Ty(CanonicalTyVarKind::General(reverse_universe_map[&u]))
|
||||
}
|
||||
CanonicalVarKind::Region(u) => {
|
||||
CanonicalVarKind::Region(reverse_universe_map[&u])
|
||||
}
|
||||
CanonicalVarKind::Const(u, t) => {
|
||||
CanonicalVarKind::Const(reverse_universe_map[&u], t)
|
||||
}
|
||||
CanonicalVarKind::PlaceholderTy(placeholder) => {
|
||||
CanonicalVarKind::PlaceholderTy(ty::Placeholder {
|
||||
universe: reverse_universe_map[&placeholder.universe],
|
||||
..placeholder
|
||||
})
|
||||
}
|
||||
CanonicalVarKind::PlaceholderRegion(placeholder) => {
|
||||
CanonicalVarKind::PlaceholderRegion(ty::Placeholder {
|
||||
universe: reverse_universe_map[&placeholder.universe],
|
||||
..placeholder
|
||||
})
|
||||
}
|
||||
CanonicalVarKind::PlaceholderConst(placeholder) => {
|
||||
CanonicalVarKind::PlaceholderConst(ty::Placeholder {
|
||||
universe: reverse_universe_map[&placeholder.universe],
|
||||
..placeholder
|
||||
})
|
||||
}
|
||||
},
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
|
||||
/// Shorthand helper that creates a canonical region variable for
|
||||
/// `r` (always in the root universe). The reason that we always
|
||||
/// put these variables into the root universe is because this
|
||||
|
@ -4,7 +4,7 @@
|
||||
//! `rustc_data_structures::AtomicRef` type, which allows us to setup a global
|
||||
//! static which can then be set in this file at program startup.
|
||||
//!
|
||||
//! See `SPAN_DEBUG` for an example of how to set things up.
|
||||
//! See `SPAN_TRACK` for an example of how to set things up.
|
||||
//!
|
||||
//! The functions in this file should fall back to the default set in their
|
||||
//! origin crate when the `TyCtxt` is not present in TLS.
|
||||
@ -13,18 +13,6 @@ use rustc_errors::{Diagnostic, TRACK_DIAGNOSTICS};
|
||||
use rustc_middle::ty::tls;
|
||||
use std::fmt;
|
||||
|
||||
/// This is a callback from `rustc_ast` as it cannot access the implicit state
|
||||
/// in `rustc_middle` otherwise.
|
||||
fn span_debug(span: rustc_span::Span, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
tls::with_opt(|tcx| {
|
||||
if let Some(tcx) = tcx {
|
||||
rustc_span::debug_with_source_map(span, f, tcx.sess.source_map())
|
||||
} else {
|
||||
rustc_span::default_span_debug(span, f)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
fn track_span_parent(def_id: rustc_span::def_id::LocalDefId) {
|
||||
tls::with_opt(|tcx| {
|
||||
if let Some(tcx) = tcx {
|
||||
@ -65,7 +53,6 @@ fn def_id_debug(def_id: rustc_hir::def_id::DefId, f: &mut fmt::Formatter<'_>) ->
|
||||
/// Sets up the callbacks in prior crates which we want to refer to the
|
||||
/// TyCtxt in.
|
||||
pub fn setup_callbacks() {
|
||||
rustc_span::SPAN_DEBUG.swap(&(span_debug as fn(_, &mut fmt::Formatter<'_>) -> _));
|
||||
rustc_span::SPAN_TRACK.swap(&(track_span_parent as fn(_)));
|
||||
rustc_hir::def_id::DEF_ID_DEBUG.swap(&(def_id_debug as fn(_, &mut fmt::Formatter<'_>) -> _));
|
||||
TRACK_DIAGNOSTICS.swap(&(track_diagnostic as fn(&_)));
|
||||
|
@ -186,6 +186,8 @@ pub struct Config {
|
||||
}
|
||||
|
||||
pub fn create_compiler_and_run<R>(config: Config, f: impl FnOnce(&Compiler) -> R) -> R {
|
||||
crate::callbacks::setup_callbacks();
|
||||
|
||||
let registry = &config.registry;
|
||||
let (mut sess, codegen_backend) = util::create_session(
|
||||
config.opts,
|
||||
@ -238,7 +240,7 @@ pub fn create_compiler_and_run<R>(config: Config, f: impl FnOnce(&Compiler) -> R
|
||||
pub fn run_compiler<R: Send>(mut config: Config, f: impl FnOnce(&Compiler) -> R + Send) -> R {
|
||||
tracing::trace!("run_compiler");
|
||||
let stderr = config.stderr.take();
|
||||
util::setup_callbacks_and_run_in_thread_pool_with_globals(
|
||||
util::run_in_thread_pool_with_globals(
|
||||
config.opts.edition,
|
||||
config.opts.debugging_opts.threads,
|
||||
&stderr,
|
||||
|
@ -15,6 +15,7 @@ mod proc_macro_decls;
|
||||
mod queries;
|
||||
pub mod util;
|
||||
|
||||
pub use callbacks::setup_callbacks;
|
||||
pub use interface::{run_compiler, Config};
|
||||
pub use passes::{DEFAULT_EXTERN_QUERY_PROVIDERS, DEFAULT_QUERY_PROVIDERS};
|
||||
pub use queries::Queries;
|
||||
|
@ -128,7 +128,7 @@ fn scoped_thread<F: FnOnce() -> R + Send, R: Send>(cfg: thread::Builder, f: F) -
|
||||
}
|
||||
|
||||
#[cfg(not(parallel_compiler))]
|
||||
pub fn setup_callbacks_and_run_in_thread_pool_with_globals<F: FnOnce() -> R + Send, R: Send>(
|
||||
pub fn run_in_thread_pool_with_globals<F: FnOnce() -> R + Send, R: Send>(
|
||||
edition: Edition,
|
||||
_threads: usize,
|
||||
stderr: &Option<Arc<Mutex<Vec<u8>>>>,
|
||||
@ -140,8 +140,6 @@ pub fn setup_callbacks_and_run_in_thread_pool_with_globals<F: FnOnce() -> R + Se
|
||||
cfg = cfg.stack_size(size);
|
||||
}
|
||||
|
||||
crate::callbacks::setup_callbacks();
|
||||
|
||||
let main_handler = move || {
|
||||
rustc_span::create_session_globals_then(edition, || {
|
||||
io::set_output_capture(stderr.clone());
|
||||
@ -176,14 +174,12 @@ unsafe fn handle_deadlock() {
|
||||
}
|
||||
|
||||
#[cfg(parallel_compiler)]
|
||||
pub fn setup_callbacks_and_run_in_thread_pool_with_globals<F: FnOnce() -> R + Send, R: Send>(
|
||||
pub fn run_in_thread_pool_with_globals<F: FnOnce() -> R + Send, R: Send>(
|
||||
edition: Edition,
|
||||
threads: usize,
|
||||
stderr: &Option<Arc<Mutex<Vec<u8>>>>,
|
||||
f: F,
|
||||
) -> R {
|
||||
crate::callbacks::setup_callbacks();
|
||||
|
||||
let mut config = rayon::ThreadPoolBuilder::new()
|
||||
.thread_name(|_| "rustc".to_string())
|
||||
.acquire_thread_handler(jobserver::acquire_thread)
|
||||
|
@ -64,9 +64,9 @@ pub struct CanonicalVarValues<'tcx> {
|
||||
/// result.
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct OriginalQueryValues<'tcx> {
|
||||
/// Map from the universes that appear in the query to the
|
||||
/// universes in the caller context. For the time being, we only
|
||||
/// ever put ROOT values into the query, so this map is very
|
||||
/// Map from the universes that appear in the query to the universes in the
|
||||
/// caller context. For all queries except `evaluate_goal` (used by Chalk),
|
||||
/// we only ever put ROOT values into the query, so this map is very
|
||||
/// simple.
|
||||
pub universe_map: SmallVec<[ty::UniverseIndex; 4]>,
|
||||
|
||||
|
@ -1013,37 +1013,25 @@ pub fn with_source_map<T, F: FnOnce() -> T>(source_map: Lrc<SourceMap>, f: F) ->
|
||||
f()
|
||||
}
|
||||
|
||||
pub fn debug_with_source_map(
|
||||
span: Span,
|
||||
f: &mut fmt::Formatter<'_>,
|
||||
source_map: &SourceMap,
|
||||
) -> fmt::Result {
|
||||
write!(f, "{} ({:?})", source_map.span_to_diagnostic_string(span), span.ctxt())
|
||||
}
|
||||
|
||||
pub fn default_span_debug(span: Span, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
with_session_globals(|session_globals| {
|
||||
if let Some(source_map) = &*session_globals.source_map.borrow() {
|
||||
debug_with_source_map(span, f, source_map)
|
||||
} else {
|
||||
f.debug_struct("Span")
|
||||
.field("lo", &span.lo())
|
||||
.field("hi", &span.hi())
|
||||
.field("ctxt", &span.ctxt())
|
||||
.finish()
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
impl fmt::Debug for Span {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
(*SPAN_DEBUG)(*self, f)
|
||||
with_session_globals(|session_globals| {
|
||||
if let Some(source_map) = &*session_globals.source_map.borrow() {
|
||||
write!(f, "{} ({:?})", source_map.span_to_diagnostic_string(*self), self.ctxt())
|
||||
} else {
|
||||
f.debug_struct("Span")
|
||||
.field("lo", &self.lo())
|
||||
.field("hi", &self.hi())
|
||||
.field("ctxt", &self.ctxt())
|
||||
.finish()
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Debug for SpanData {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
(*SPAN_DEBUG)(Span::new(self.lo, self.hi, self.ctxt, self.parent), f)
|
||||
fmt::Debug::fmt(&Span::new(self.lo, self.hi, self.ctxt, self.parent), f)
|
||||
}
|
||||
}
|
||||
|
||||
@ -2003,8 +1991,6 @@ pub struct FileLines {
|
||||
pub lines: Vec<LineInfo>,
|
||||
}
|
||||
|
||||
pub static SPAN_DEBUG: AtomicRef<fn(Span, &mut fmt::Formatter<'_>) -> fmt::Result> =
|
||||
AtomicRef::new(&(default_span_debug as fn(_, &mut fmt::Formatter<'_>) -> _));
|
||||
pub static SPAN_TRACK: AtomicRef<fn(LocalDefId)> = AtomicRef::new(&((|_| {}) as fn(_)));
|
||||
|
||||
// _____________________________________________________________________________
|
||||
|
@ -184,6 +184,7 @@ symbols! {
|
||||
Formatter,
|
||||
From,
|
||||
FromIterator,
|
||||
FromResidual,
|
||||
Future,
|
||||
FxHashMap,
|
||||
FxHashSet,
|
||||
|
@ -8,7 +8,7 @@ use crate::traits::{
|
||||
PredicateObligation, SelectionError, TraitEngine,
|
||||
};
|
||||
use rustc_data_structures::fx::{FxHashMap, FxIndexSet};
|
||||
use rustc_middle::ty::{self, Ty};
|
||||
use rustc_middle::ty::{self, Ty, TypeFoldable};
|
||||
|
||||
pub struct FulfillmentContext<'tcx> {
|
||||
obligations: FxIndexSet<PredicateObligation<'tcx>>,
|
||||
@ -91,7 +91,12 @@ impl<'tcx> TraitEngine<'tcx> for FulfillmentContext<'tcx> {
|
||||
let environment = obligation.param_env.caller_bounds();
|
||||
let goal = ChalkEnvironmentAndGoal { environment, goal: obligation.predicate };
|
||||
let mut orig_values = OriginalQueryValues::default();
|
||||
let canonical_goal = infcx.canonicalize_query(goal, &mut orig_values);
|
||||
if goal.references_error() {
|
||||
continue;
|
||||
}
|
||||
|
||||
let canonical_goal =
|
||||
infcx.canonicalize_query_preserving_universes(goal, &mut orig_values);
|
||||
|
||||
match infcx.tcx.evaluate_goal(canonical_goal) {
|
||||
Ok(response) => {
|
||||
|
@ -20,11 +20,10 @@ use rustc_span::symbol::sym;
|
||||
use std::fmt;
|
||||
use std::sync::Arc;
|
||||
|
||||
use crate::chalk::lowering::{self, LowerInto};
|
||||
use crate::chalk::lowering::LowerInto;
|
||||
|
||||
pub struct RustIrDatabase<'tcx> {
|
||||
pub(crate) interner: RustInterner<'tcx>,
|
||||
pub(crate) reempty_placeholder: ty::Region<'tcx>,
|
||||
}
|
||||
|
||||
impl fmt::Debug for RustIrDatabase<'_> {
|
||||
@ -40,12 +39,9 @@ impl<'tcx> RustIrDatabase<'tcx> {
|
||||
bound_vars: SubstsRef<'tcx>,
|
||||
) -> Vec<chalk_ir::QuantifiedWhereClause<RustInterner<'tcx>>> {
|
||||
let predicates = self.interner.tcx.predicates_defined_on(def_id).predicates;
|
||||
let mut regions_substitutor =
|
||||
lowering::RegionsSubstitutor::new(self.interner.tcx, self.reempty_placeholder);
|
||||
predicates
|
||||
.iter()
|
||||
.map(|(wc, _)| wc.subst(self.interner.tcx, bound_vars))
|
||||
.map(|wc| wc.fold_with(&mut regions_substitutor))
|
||||
.filter_map(|wc| LowerInto::<
|
||||
Option<chalk_ir::QuantifiedWhereClause<RustInterner<'tcx>>>
|
||||
>::lower_into(wc, self.interner)).collect()
|
||||
@ -287,9 +283,6 @@ impl<'tcx> chalk_solve::RustIrDatabase<RustInterner<'tcx>> for RustIrDatabase<'t
|
||||
|
||||
let trait_ref = self.interner.tcx.impl_trait_ref(def_id).expect("not an impl");
|
||||
let trait_ref = trait_ref.subst(self.interner.tcx, bound_vars);
|
||||
let mut regions_substitutor =
|
||||
lowering::RegionsSubstitutor::new(self.interner.tcx, self.reempty_placeholder);
|
||||
let trait_ref = trait_ref.fold_with(&mut regions_substitutor);
|
||||
|
||||
let where_clauses = self.where_clauses_for(def_id, bound_vars);
|
||||
|
||||
@ -335,9 +328,6 @@ impl<'tcx> chalk_solve::RustIrDatabase<RustInterner<'tcx>> for RustIrDatabase<'t
|
||||
|
||||
let self_ty = trait_ref.self_ty();
|
||||
let self_ty = self_ty.subst(self.interner.tcx, bound_vars);
|
||||
let mut regions_substitutor =
|
||||
lowering::RegionsSubstitutor::new(self.interner.tcx, self.reempty_placeholder);
|
||||
let self_ty = self_ty.fold_with(&mut regions_substitutor);
|
||||
let lowered_ty = self_ty.lower_into(self.interner);
|
||||
|
||||
parameters[0].assert_ty_ref(self.interner).could_match(
|
||||
@ -556,11 +546,11 @@ impl<'tcx> chalk_solve::RustIrDatabase<RustInterner<'tcx>> for RustIrDatabase<'t
|
||||
Fn => lang_items.fn_trait(),
|
||||
FnMut => lang_items.fn_mut_trait(),
|
||||
FnOnce => lang_items.fn_once_trait(),
|
||||
Generator => lang_items.gen_trait(),
|
||||
Unsize => lang_items.unsize_trait(),
|
||||
Unpin => lang_items.unpin_trait(),
|
||||
CoerceUnsized => lang_items.coerce_unsized_trait(),
|
||||
DiscriminantKind => lang_items.discriminant_kind_trait(),
|
||||
Generator => lang_items.generator_return(),
|
||||
};
|
||||
def_id.map(chalk_ir::TraitId)
|
||||
}
|
||||
@ -684,28 +674,18 @@ impl<'tcx> chalk_ir::UnificationDatabase<RustInterner<'tcx>> for RustIrDatabase<
|
||||
let variances = self.interner.tcx.variances_of(def_id.0);
|
||||
chalk_ir::Variances::from_iter(
|
||||
self.interner,
|
||||
variances.iter().map(|v| match v {
|
||||
ty::Variance::Invariant => chalk_ir::Variance::Invariant,
|
||||
ty::Variance::Covariant => chalk_ir::Variance::Covariant,
|
||||
ty::Variance::Contravariant => chalk_ir::Variance::Contravariant,
|
||||
ty::Variance::Bivariant => unimplemented!(),
|
||||
}),
|
||||
variances.iter().map(|v| v.lower_into(self.interner)),
|
||||
)
|
||||
}
|
||||
|
||||
fn adt_variance(
|
||||
&self,
|
||||
def_id: chalk_ir::AdtId<RustInterner<'tcx>>,
|
||||
adt_id: chalk_ir::AdtId<RustInterner<'tcx>>,
|
||||
) -> chalk_ir::Variances<RustInterner<'tcx>> {
|
||||
let variances = self.interner.tcx.variances_of(def_id.0.did);
|
||||
let variances = self.interner.tcx.variances_of(adt_id.0.did);
|
||||
chalk_ir::Variances::from_iter(
|
||||
self.interner,
|
||||
variances.iter().map(|v| match v {
|
||||
ty::Variance::Invariant => chalk_ir::Variance::Invariant,
|
||||
ty::Variance::Covariant => chalk_ir::Variance::Covariant,
|
||||
ty::Variance::Contravariant => chalk_ir::Variance::Contravariant,
|
||||
ty::Variance::Bivariant => unimplemented!(),
|
||||
}),
|
||||
variances.iter().map(|v| v.lower_into(self.interner)),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
@ -188,12 +188,18 @@ impl<'tcx> LowerInto<'tcx, chalk_ir::GoalData<RustInterner<'tcx>>> for ty::Predi
|
||||
chalk_ir::DomainGoal::ObjectSafe(chalk_ir::TraitId(t)),
|
||||
),
|
||||
|
||||
ty::PredicateKind::Subtype(ty::SubtypePredicate { a, b, a_is_expected: _ }) => {
|
||||
chalk_ir::GoalData::SubtypeGoal(chalk_ir::SubtypeGoal {
|
||||
a: a.lower_into(interner),
|
||||
b: b.lower_into(interner),
|
||||
})
|
||||
}
|
||||
|
||||
// FIXME(chalk): other predicates
|
||||
//
|
||||
// We can defer this, but ultimately we'll want to express
|
||||
// some of these in terms of chalk operations.
|
||||
ty::PredicateKind::ClosureKind(..)
|
||||
| ty::PredicateKind::Subtype(..)
|
||||
| ty::PredicateKind::Coerce(..)
|
||||
| ty::PredicateKind::ConstEvaluatable(..)
|
||||
| ty::PredicateKind::ConstEquate(..) => {
|
||||
@ -464,9 +470,11 @@ impl<'tcx> LowerInto<'tcx, chalk_ir::Lifetime<RustInterner<'tcx>>> for Region<'t
|
||||
})
|
||||
.intern(interner)
|
||||
}
|
||||
ReEmpty(_) => unimplemented!(),
|
||||
// FIXME(chalk): need to handle ReErased
|
||||
ReErased => unimplemented!(),
|
||||
ReEmpty(ui) => {
|
||||
chalk_ir::LifetimeData::Empty(chalk_ir::UniverseIndex { counter: ui.index() })
|
||||
.intern(interner)
|
||||
}
|
||||
ReErased => chalk_ir::LifetimeData::Erased.intern(interner),
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -488,12 +496,12 @@ impl<'tcx> LowerInto<'tcx, Region<'tcx>> for &chalk_ir::Lifetime<RustInterner<'t
|
||||
name: ty::BoundRegionKind::BrAnon(p.idx as u32),
|
||||
})
|
||||
}
|
||||
chalk_ir::LifetimeData::Static => ty::RegionKind::ReStatic,
|
||||
chalk_ir::LifetimeData::Phantom(_, _) => unimplemented!(),
|
||||
chalk_ir::LifetimeData::Static => return interner.tcx.lifetimes.re_static,
|
||||
chalk_ir::LifetimeData::Empty(ui) => {
|
||||
ty::RegionKind::ReEmpty(ty::UniverseIndex::from_usize(ui.counter))
|
||||
ty::ReEmpty(ty::UniverseIndex::from_usize(ui.counter))
|
||||
}
|
||||
chalk_ir::LifetimeData::Erased => ty::RegionKind::ReErased,
|
||||
chalk_ir::LifetimeData::Erased => return interner.tcx.lifetimes.re_erased,
|
||||
chalk_ir::LifetimeData::Phantom(void, _) => match *void {},
|
||||
};
|
||||
interner.tcx.mk_region(kind)
|
||||
}
|
||||
@ -788,6 +796,16 @@ impl<'tcx> LowerInto<'tcx, chalk_solve::rust_ir::Polarity> for ty::ImplPolarity
|
||||
}
|
||||
}
|
||||
}
|
||||
impl<'tcx> LowerInto<'tcx, chalk_ir::Variance> for ty::Variance {
|
||||
fn lower_into(self, _interner: RustInterner<'tcx>) -> chalk_ir::Variance {
|
||||
match self {
|
||||
ty::Variance::Covariant => chalk_ir::Variance::Covariant,
|
||||
ty::Variance::Invariant => chalk_ir::Variance::Invariant,
|
||||
ty::Variance::Contravariant => chalk_ir::Variance::Contravariant,
|
||||
ty::Variance::Bivariant => unimplemented!(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> LowerInto<'tcx, chalk_solve::rust_ir::AliasEqBound<RustInterner<'tcx>>>
|
||||
for ty::ProjectionPredicate<'tcx>
|
||||
@ -1016,10 +1034,6 @@ impl<'tcx> TypeFolder<'tcx> for ParamsSubstitutor<'tcx> {
|
||||
|
||||
fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> {
|
||||
match *t.kind() {
|
||||
// FIXME(chalk): currently we convert params to placeholders starting at
|
||||
// index `0`. To support placeholders, we'll actually need to do a
|
||||
// first pass to collect placeholders. Then we can insert params after.
|
||||
ty::Placeholder(_) => unimplemented!(),
|
||||
ty::Param(param) => match self.list.iter().position(|r| r == ¶m) {
|
||||
Some(idx) => self.tcx.mk_ty(ty::Placeholder(ty::PlaceholderType {
|
||||
universe: ty::UniverseIndex::from_usize(0),
|
||||
@ -1035,15 +1049,15 @@ impl<'tcx> TypeFolder<'tcx> for ParamsSubstitutor<'tcx> {
|
||||
}))
|
||||
}
|
||||
},
|
||||
|
||||
_ => t.super_fold_with(self),
|
||||
}
|
||||
}
|
||||
|
||||
fn fold_region(&mut self, r: Region<'tcx>) -> Region<'tcx> {
|
||||
match r {
|
||||
// FIXME(chalk) - jackh726 - this currently isn't hit in any tests.
|
||||
// This covers any region variables in a goal, right?
|
||||
// FIXME(chalk) - jackh726 - this currently isn't hit in any tests,
|
||||
// since canonicalization will already change these to canonical
|
||||
// variables (ty::ReLateBound).
|
||||
ty::ReEarlyBound(_re) => match self.named_regions.get(&_re.def_id) {
|
||||
Some(idx) => {
|
||||
let br = ty::BoundRegion {
|
||||
@ -1066,6 +1080,39 @@ impl<'tcx> TypeFolder<'tcx> for ParamsSubstitutor<'tcx> {
|
||||
}
|
||||
}
|
||||
|
||||
crate struct ReverseParamsSubstitutor<'tcx> {
|
||||
tcx: TyCtxt<'tcx>,
|
||||
params: rustc_data_structures::fx::FxHashMap<usize, rustc_middle::ty::ParamTy>,
|
||||
}
|
||||
|
||||
impl<'tcx> ReverseParamsSubstitutor<'tcx> {
|
||||
crate fn new(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
params: rustc_data_structures::fx::FxHashMap<usize, rustc_middle::ty::ParamTy>,
|
||||
) -> Self {
|
||||
Self { tcx, params }
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> TypeFolder<'tcx> for ReverseParamsSubstitutor<'tcx> {
|
||||
fn tcx<'b>(&'b self) -> TyCtxt<'tcx> {
|
||||
self.tcx
|
||||
}
|
||||
|
||||
fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> {
|
||||
match *t.kind() {
|
||||
ty::Placeholder(ty::PlaceholderType { universe: ty::UniverseIndex::ROOT, name }) => {
|
||||
match self.params.get(&name.as_usize()) {
|
||||
Some(param) => self.tcx.mk_ty(ty::Param(*param)),
|
||||
None => t,
|
||||
}
|
||||
}
|
||||
|
||||
_ => t.super_fold_with(self),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Used to collect `Placeholder`s.
|
||||
crate struct PlaceholdersCollector {
|
||||
universe_index: ty::UniverseIndex,
|
||||
@ -1110,32 +1157,3 @@ impl<'tcx> TypeVisitor<'tcx> for PlaceholdersCollector {
|
||||
r.super_visit_with(self)
|
||||
}
|
||||
}
|
||||
|
||||
/// Used to substitute specific `Regions`s with placeholders.
|
||||
crate struct RegionsSubstitutor<'tcx> {
|
||||
tcx: TyCtxt<'tcx>,
|
||||
reempty_placeholder: ty::Region<'tcx>,
|
||||
}
|
||||
|
||||
impl<'tcx> RegionsSubstitutor<'tcx> {
|
||||
crate fn new(tcx: TyCtxt<'tcx>, reempty_placeholder: ty::Region<'tcx>) -> Self {
|
||||
RegionsSubstitutor { tcx, reempty_placeholder }
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> TypeFolder<'tcx> for RegionsSubstitutor<'tcx> {
|
||||
fn tcx<'b>(&'b self) -> TyCtxt<'tcx> {
|
||||
self.tcx
|
||||
}
|
||||
|
||||
fn fold_region(&mut self, r: Region<'tcx>) -> Region<'tcx> {
|
||||
match r {
|
||||
ty::ReEmpty(ui) => {
|
||||
assert_eq!(ui.as_usize(), 0);
|
||||
self.reempty_placeholder
|
||||
}
|
||||
|
||||
_ => r.super_fold_with(self),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -22,9 +22,8 @@ use rustc_infer::infer::canonical::{
|
||||
use rustc_infer::traits::{self, CanonicalChalkEnvironmentAndGoal};
|
||||
|
||||
use crate::chalk::db::RustIrDatabase as ChalkRustIrDatabase;
|
||||
use crate::chalk::lowering::{
|
||||
LowerInto, ParamsSubstitutor, PlaceholdersCollector, RegionsSubstitutor,
|
||||
};
|
||||
use crate::chalk::lowering::LowerInto;
|
||||
use crate::chalk::lowering::{ParamsSubstitutor, PlaceholdersCollector, ReverseParamsSubstitutor};
|
||||
|
||||
use chalk_solve::Solution;
|
||||
|
||||
@ -42,19 +41,10 @@ crate fn evaluate_goal<'tcx>(
|
||||
let mut placeholders_collector = PlaceholdersCollector::new();
|
||||
obligation.visit_with(&mut placeholders_collector);
|
||||
|
||||
let reempty_placeholder = tcx.mk_region(ty::RegionKind::RePlaceholder(ty::Placeholder {
|
||||
universe: ty::UniverseIndex::ROOT,
|
||||
name: ty::BoundRegionKind::BrAnon(placeholders_collector.next_anon_region_placeholder + 1),
|
||||
}));
|
||||
|
||||
let mut params_substitutor =
|
||||
ParamsSubstitutor::new(tcx, placeholders_collector.next_ty_placeholder);
|
||||
let obligation = obligation.fold_with(&mut params_substitutor);
|
||||
// FIXME(chalk): we really should be substituting these back in the solution
|
||||
let _params: FxHashMap<usize, ParamTy> = params_substitutor.params;
|
||||
|
||||
let mut regions_substitutor = RegionsSubstitutor::new(tcx, reempty_placeholder);
|
||||
let obligation = obligation.fold_with(&mut regions_substitutor);
|
||||
let params: FxHashMap<usize, ParamTy> = params_substitutor.params;
|
||||
|
||||
let max_universe = obligation.max_universe.index();
|
||||
|
||||
@ -96,7 +86,8 @@ crate fn evaluate_goal<'tcx>(
|
||||
|
||||
use chalk_solve::Solver;
|
||||
let mut solver = chalk_engine::solve::SLGSolver::new(32, None);
|
||||
let db = ChalkRustIrDatabase { interner, reempty_placeholder };
|
||||
let db = ChalkRustIrDatabase { interner };
|
||||
debug!(?lowered_goal);
|
||||
let solution = solver.solve(&db, &lowered_goal);
|
||||
debug!(?obligation, ?solution, "evaluate goal");
|
||||
|
||||
@ -110,8 +101,9 @@ crate fn evaluate_goal<'tcx>(
|
||||
use rustc_middle::infer::canonical::CanonicalVarInfo;
|
||||
|
||||
let mut var_values: IndexVec<BoundVar, GenericArg<'tcx>> = IndexVec::new();
|
||||
let mut reverse_param_substitutor = ReverseParamsSubstitutor::new(tcx, params);
|
||||
subst.as_slice(interner).iter().for_each(|p| {
|
||||
var_values.push(p.lower_into(interner));
|
||||
var_values.push(p.lower_into(interner).fold_with(&mut reverse_param_substitutor));
|
||||
});
|
||||
let variables: Vec<_> = binders
|
||||
.iter(interner)
|
||||
|
@ -112,7 +112,6 @@
|
||||
#![feature(extend_one)]
|
||||
#![feature(fmt_internals)]
|
||||
#![feature(fn_traits)]
|
||||
#![feature(inherent_ascii_escape)]
|
||||
#![feature(inplace_iteration)]
|
||||
#![feature(iter_advance_by)]
|
||||
#![feature(layout_for_ptr)]
|
||||
|
@ -108,7 +108,7 @@ pub use core::slice::ArrayChunks;
|
||||
pub use core::slice::ArrayChunksMut;
|
||||
#[unstable(feature = "array_windows", issue = "75027")]
|
||||
pub use core::slice::ArrayWindows;
|
||||
#[unstable(feature = "inherent_ascii_escape", issue = "77174")]
|
||||
#[stable(feature = "inherent_ascii_escape", since = "1.60.0")]
|
||||
pub use core::slice::EscapeAscii;
|
||||
#[stable(feature = "slice_get_slice", since = "1.28.0")]
|
||||
pub use core::slice::SliceIndex;
|
||||
|
@ -872,7 +872,7 @@ pub(crate) mod builtin {
|
||||
($fmt:expr, $($args:tt)*) => {{ /* compiler built-in */ }};
|
||||
}
|
||||
|
||||
/// Same as `format_args`, but can be used in some const contexts.
|
||||
/// Same as [`format_args`], but can be used in some const contexts.
|
||||
///
|
||||
/// This macro is used by the panic macros for the `const_panic` feature.
|
||||
///
|
||||
@ -886,7 +886,7 @@ pub(crate) mod builtin {
|
||||
($fmt:expr, $($args:tt)*) => {{ /* compiler built-in */ }};
|
||||
}
|
||||
|
||||
/// Same as `format_args`, but adds a newline in the end.
|
||||
/// Same as [`format_args`], but adds a newline in the end.
|
||||
#[unstable(
|
||||
feature = "format_args_nl",
|
||||
issue = "none",
|
||||
|
@ -791,7 +791,6 @@ impl u8 {
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// #![feature(inherent_ascii_escape)]
|
||||
///
|
||||
/// assert_eq!("0", b'0'.escape_ascii().to_string());
|
||||
/// assert_eq!("\\t", b'\t'.escape_ascii().to_string());
|
||||
@ -804,10 +803,10 @@ impl u8 {
|
||||
/// ```
|
||||
#[must_use = "this returns the escaped byte as an iterator, \
|
||||
without modifying the original"]
|
||||
#[unstable(feature = "inherent_ascii_escape", issue = "77174")]
|
||||
#[stable(feature = "inherent_ascii_escape", since = "1.60.0")]
|
||||
#[inline]
|
||||
pub fn escape_ascii(&self) -> ascii::EscapeDefault {
|
||||
ascii::escape_default(*self)
|
||||
pub fn escape_ascii(self) -> ascii::EscapeDefault {
|
||||
ascii::escape_default(self)
|
||||
}
|
||||
|
||||
pub(crate) fn is_utf8_char_boundary(self) -> bool {
|
||||
|
@ -302,6 +302,7 @@ pub trait Try: FromResidual {
|
||||
enclosing_scope = "this function should return `Result` or `Option` to accept `?`"
|
||||
),
|
||||
)]
|
||||
#[rustc_diagnostic_item = "FromResidual"]
|
||||
#[unstable(feature = "try_trait_v2", issue = "84277")]
|
||||
pub trait FromResidual<R = <Self as Try>::Residual> {
|
||||
/// Constructs the type from a compatible `Residual` type.
|
||||
|
@ -1207,13 +1207,25 @@ impl<T> Option<T> {
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// fn sq(x: u32) -> Option<u32> { Some(x * x) }
|
||||
/// fn nope(_: u32) -> Option<u32> { None }
|
||||
/// fn sq_then_to_string(x: u32) -> Option<String> {
|
||||
/// x.checked_mul(x).map(|sq| sq.to_string())
|
||||
/// }
|
||||
///
|
||||
/// assert_eq!(Some(2).and_then(sq).and_then(sq), Some(16));
|
||||
/// assert_eq!(Some(2).and_then(sq).and_then(nope), None);
|
||||
/// assert_eq!(Some(2).and_then(nope).and_then(sq), None);
|
||||
/// assert_eq!(None.and_then(sq).and_then(sq), None);
|
||||
/// assert_eq!(Some(2).and_then(sq_then_to_string), Some(4.to_string()));
|
||||
/// assert_eq!(Some(1_000_000).and_then(sq_then_to_string), None); // overflowed!
|
||||
/// assert_eq!(None.and_then(sq_then_to_string), None);
|
||||
/// ```
|
||||
///
|
||||
/// Often used to chain fallible operations that may return [`None`].
|
||||
///
|
||||
/// ```
|
||||
/// let arr_2d = [["A0", "A1"], ["B0", "B1"]];
|
||||
///
|
||||
/// let item_0_1 = arr_2d.get(0).and_then(|row| row.get(1));
|
||||
/// assert_eq!(item_0_1, Some(&"A1"));
|
||||
///
|
||||
/// let item_2_0 = arr_2d.get(2).and_then(|row| row.get(0));
|
||||
/// assert_eq!(item_2_0, None);
|
||||
/// ```
|
||||
#[inline]
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
|
@ -1281,16 +1281,28 @@ impl<T, E> Result<T, E> {
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// Basic usage:
|
||||
/// ```
|
||||
/// fn sq_then_to_string(x: u32) -> Result<String, &'static str> {
|
||||
/// x.checked_mul(x).map(|sq| sq.to_string()).ok_or("overflowed")
|
||||
/// }
|
||||
///
|
||||
/// assert_eq!(Ok(2).and_then(sq_then_to_string), Ok(4.to_string()));
|
||||
/// assert_eq!(Ok(1_000_000).and_then(sq_then_to_string), Err("overflowed"));
|
||||
/// assert_eq!(Err("not a number").and_then(sq_then_to_string), Err("not a number"));
|
||||
/// ```
|
||||
///
|
||||
/// Often used to chain fallible operations that may return [`Err`].
|
||||
///
|
||||
/// ```
|
||||
/// fn sq(x: u32) -> Result<u32, u32> { Ok(x * x) }
|
||||
/// fn err(x: u32) -> Result<u32, u32> { Err(x) }
|
||||
/// use std::{io::ErrorKind, path::Path};
|
||||
///
|
||||
/// assert_eq!(Ok(2).and_then(sq).and_then(sq), Ok(16));
|
||||
/// assert_eq!(Ok(2).and_then(sq).and_then(err), Err(4));
|
||||
/// assert_eq!(Ok(2).and_then(err).and_then(sq), Err(2));
|
||||
/// assert_eq!(Err(3).and_then(sq).and_then(sq), Err(3));
|
||||
/// // Note: on Windows "/" maps to "C:\"
|
||||
/// let root_modified_time = Path::new("/").metadata().and_then(|md| md.modified());
|
||||
/// assert!(root_modified_time.is_ok());
|
||||
///
|
||||
/// let should_fail = Path::new("/bad/path").metadata().and_then(|md| md.modified());
|
||||
/// assert!(should_fail.is_err());
|
||||
/// assert_eq!(should_fail.unwrap_err().kind(), ErrorKind::NotFound);
|
||||
/// ```
|
||||
#[inline]
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
|
@ -68,7 +68,6 @@ impl [u8] {
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// #![feature(inherent_ascii_escape)]
|
||||
///
|
||||
/// let s = b"0\t\r\n'\"\\\x9d";
|
||||
/// let escaped = s.escape_ascii().to_string();
|
||||
@ -76,7 +75,7 @@ impl [u8] {
|
||||
/// ```
|
||||
#[must_use = "this returns the escaped bytes as an iterator, \
|
||||
without modifying the original"]
|
||||
#[unstable(feature = "inherent_ascii_escape", issue = "77174")]
|
||||
#[stable(feature = "inherent_ascii_escape", since = "1.60.0")]
|
||||
pub fn escape_ascii(&self) -> EscapeAscii<'_> {
|
||||
EscapeAscii { inner: self.iter().flat_map(EscapeByte) }
|
||||
}
|
||||
@ -93,13 +92,13 @@ impl_fn_for_zst! {
|
||||
///
|
||||
/// This `struct` is created by the [`slice::escape_ascii`] method. See its
|
||||
/// documentation for more information.
|
||||
#[unstable(feature = "inherent_ascii_escape", issue = "77174")]
|
||||
#[stable(feature = "inherent_ascii_escape", since = "1.60.0")]
|
||||
#[derive(Clone)]
|
||||
pub struct EscapeAscii<'a> {
|
||||
inner: iter::FlatMap<super::Iter<'a, u8>, ascii::EscapeDefault, EscapeByte>,
|
||||
}
|
||||
|
||||
#[unstable(feature = "inherent_ascii_escape", issue = "77174")]
|
||||
#[stable(feature = "inherent_ascii_escape", since = "1.60.0")]
|
||||
impl<'a> iter::Iterator for EscapeAscii<'a> {
|
||||
type Item = u8;
|
||||
#[inline]
|
||||
@ -131,23 +130,23 @@ impl<'a> iter::Iterator for EscapeAscii<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
#[unstable(feature = "inherent_ascii_escape", issue = "77174")]
|
||||
#[stable(feature = "inherent_ascii_escape", since = "1.60.0")]
|
||||
impl<'a> iter::DoubleEndedIterator for EscapeAscii<'a> {
|
||||
fn next_back(&mut self) -> Option<u8> {
|
||||
self.inner.next_back()
|
||||
}
|
||||
}
|
||||
#[unstable(feature = "inherent_ascii_escape", issue = "77174")]
|
||||
#[stable(feature = "inherent_ascii_escape", since = "1.60.0")]
|
||||
impl<'a> iter::ExactSizeIterator for EscapeAscii<'a> {}
|
||||
#[unstable(feature = "inherent_ascii_escape", issue = "77174")]
|
||||
#[stable(feature = "inherent_ascii_escape", since = "1.60.0")]
|
||||
impl<'a> iter::FusedIterator for EscapeAscii<'a> {}
|
||||
#[unstable(feature = "inherent_ascii_escape", issue = "77174")]
|
||||
#[stable(feature = "inherent_ascii_escape", since = "1.60.0")]
|
||||
impl<'a> fmt::Display for EscapeAscii<'a> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
self.clone().try_for_each(|b| f.write_char(b as char))
|
||||
}
|
||||
}
|
||||
#[unstable(feature = "inherent_ascii_escape", issue = "77174")]
|
||||
#[stable(feature = "inherent_ascii_escape", since = "1.60.0")]
|
||||
impl<'a> fmt::Debug for EscapeAscii<'a> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
f.debug_struct("EscapeAscii").finish_non_exhaustive()
|
||||
|
@ -81,7 +81,7 @@ pub use index::SliceIndex;
|
||||
#[unstable(feature = "slice_range", issue = "76393")]
|
||||
pub use index::range;
|
||||
|
||||
#[unstable(feature = "inherent_ascii_escape", issue = "77174")]
|
||||
#[stable(feature = "inherent_ascii_escape", since = "1.60.0")]
|
||||
pub use ascii::EscapeAscii;
|
||||
|
||||
/// Calculates the direction and split point of a one-sided range.
|
||||
|
@ -115,14 +115,6 @@ impl Instant {
|
||||
Instant { t: time }
|
||||
}
|
||||
|
||||
pub const fn zero() -> Instant {
|
||||
Instant { t: Timespec::zero() }
|
||||
}
|
||||
|
||||
pub fn actually_monotonic() -> bool {
|
||||
true
|
||||
}
|
||||
|
||||
pub fn checked_sub_instant(&self, other: &Instant) -> Option<Duration> {
|
||||
self.t.sub_timespec(&other.t).ok()
|
||||
}
|
||||
|
@ -14,15 +14,6 @@ impl Instant {
|
||||
}
|
||||
}
|
||||
|
||||
pub const fn zero() -> Instant {
|
||||
Instant(0)
|
||||
}
|
||||
|
||||
pub fn actually_monotonic() -> bool {
|
||||
// There are ways to change the system time
|
||||
false
|
||||
}
|
||||
|
||||
pub fn checked_sub_instant(&self, other: &Instant) -> Option<Duration> {
|
||||
self.0.checked_sub(other.0).map(|ticks| {
|
||||
// `SYSTIM` is measured in microseconds
|
||||
|
@ -25,14 +25,6 @@ impl Instant {
|
||||
pub fn checked_sub_duration(&self, other: &Duration) -> Option<Instant> {
|
||||
Some(Instant(self.0.checked_sub(*other)?))
|
||||
}
|
||||
|
||||
pub fn actually_monotonic() -> bool {
|
||||
false
|
||||
}
|
||||
|
||||
pub const fn zero() -> Instant {
|
||||
Instant(Duration::from_secs(0))
|
||||
}
|
||||
}
|
||||
|
||||
impl SystemTime {
|
||||
|
@ -154,14 +154,6 @@ mod inner {
|
||||
Instant { t: unsafe { mach_absolute_time() } }
|
||||
}
|
||||
|
||||
pub const fn zero() -> Instant {
|
||||
Instant { t: 0 }
|
||||
}
|
||||
|
||||
pub fn actually_monotonic() -> bool {
|
||||
true
|
||||
}
|
||||
|
||||
pub fn checked_sub_instant(&self, other: &Instant) -> Option<Duration> {
|
||||
let diff = self.t.checked_sub(other.t)?;
|
||||
let info = info();
|
||||
@ -296,17 +288,6 @@ mod inner {
|
||||
Instant { t: now(libc::CLOCK_MONOTONIC) }
|
||||
}
|
||||
|
||||
pub const fn zero() -> Instant {
|
||||
Instant { t: Timespec::zero() }
|
||||
}
|
||||
|
||||
pub fn actually_monotonic() -> bool {
|
||||
(cfg!(target_os = "linux") && cfg!(target_arch = "x86_64"))
|
||||
|| (cfg!(target_os = "linux") && cfg!(target_arch = "x86"))
|
||||
|| (cfg!(target_os = "linux") && cfg!(target_arch = "aarch64"))
|
||||
|| cfg!(target_os = "fuchsia")
|
||||
}
|
||||
|
||||
pub fn checked_sub_instant(&self, other: &Instant) -> Option<Duration> {
|
||||
self.t.sub_timespec(&other.t).ok()
|
||||
}
|
||||
|
@ -13,14 +13,6 @@ impl Instant {
|
||||
panic!("time not implemented on this platform")
|
||||
}
|
||||
|
||||
pub const fn zero() -> Instant {
|
||||
Instant(Duration::from_secs(0))
|
||||
}
|
||||
|
||||
pub fn actually_monotonic() -> bool {
|
||||
false
|
||||
}
|
||||
|
||||
pub fn checked_sub_instant(&self, other: &Instant) -> Option<Duration> {
|
||||
self.0.checked_sub(other.0)
|
||||
}
|
||||
|
@ -25,14 +25,6 @@ impl Instant {
|
||||
Instant(current_time(wasi::CLOCKID_MONOTONIC))
|
||||
}
|
||||
|
||||
pub const fn zero() -> Instant {
|
||||
Instant(Duration::from_secs(0))
|
||||
}
|
||||
|
||||
pub fn actually_monotonic() -> bool {
|
||||
true
|
||||
}
|
||||
|
||||
pub fn checked_sub_instant(&self, other: &Instant) -> Option<Duration> {
|
||||
self.0.checked_sub(other.0)
|
||||
}
|
||||
|
@ -41,14 +41,6 @@ impl Instant {
|
||||
perf_counter::PerformanceCounterInstant::now().into()
|
||||
}
|
||||
|
||||
pub fn actually_monotonic() -> bool {
|
||||
false
|
||||
}
|
||||
|
||||
pub const fn zero() -> Instant {
|
||||
Instant { t: Duration::from_secs(0) }
|
||||
}
|
||||
|
||||
pub fn checked_sub_instant(&self, other: &Instant) -> Option<Duration> {
|
||||
// On windows there's a threshold below which we consider two timestamps
|
||||
// equivalent due to measurement error. For more details + doc link,
|
||||
|
@ -31,7 +31,6 @@
|
||||
|
||||
#![stable(feature = "time", since = "1.3.0")]
|
||||
|
||||
mod monotonic;
|
||||
#[cfg(test)]
|
||||
mod tests;
|
||||
|
||||
@ -50,8 +49,8 @@ pub use core::time::FromFloatSecsError;
|
||||
/// A measurement of a monotonically nondecreasing clock.
|
||||
/// Opaque and useful only with [`Duration`].
|
||||
///
|
||||
/// Instants are always guaranteed to be no less than any previously measured
|
||||
/// instant when created, and are often useful for tasks such as measuring
|
||||
/// Instants are always guaranteed, barring [platform bugs], to be no less than any previously
|
||||
/// measured instant when created, and are often useful for tasks such as measuring
|
||||
/// benchmarks or timing how long an operation takes.
|
||||
///
|
||||
/// Note, however, that instants are **not** guaranteed to be **steady**. In other
|
||||
@ -84,6 +83,8 @@ pub use core::time::FromFloatSecsError;
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// [platform bugs]: Instant#monotonicity
|
||||
///
|
||||
/// # OS-specific behaviors
|
||||
///
|
||||
/// An `Instant` is a wrapper around system-specific types and it may behave
|
||||
@ -125,6 +126,26 @@ pub use core::time::FromFloatSecsError;
|
||||
/// > structure cannot represent the new point in time.
|
||||
///
|
||||
/// [`add`]: Instant::add
|
||||
///
|
||||
/// ## Monotonicity
|
||||
///
|
||||
/// On all platforms `Instant` will try to use an OS API that guarantees monotonic behavior
|
||||
/// if available, which is the case for all [tier 1] platforms.
|
||||
/// In practice such guarantees are – under rare circumstances – broken by hardware, virtualization
|
||||
/// or operating system bugs. To work around these bugs and platforms not offering monotonic clocks
|
||||
/// [`duration_since`], [`elapsed`] and [`sub`] saturate to zero. In older Rust versions this
|
||||
/// lead to a panic instead. [`checked_duration_since`] can be used to detect and handle situations
|
||||
/// where monotonicity is violated, or `Instant`s are subtracted in the wrong order.
|
||||
///
|
||||
/// This workaround obscures programming errors where earlier and later instants are accidentally
|
||||
/// swapped. For this reason future rust versions may reintroduce panics.
|
||||
///
|
||||
/// [tier 1]: https://doc.rust-lang.org/rustc/platform-support.html
|
||||
/// [`duration_since`]: Instant::duration_since
|
||||
/// [`elapsed`]: Instant::elapsed
|
||||
/// [`sub`]: Instant::sub
|
||||
/// [`checked_duration_since`]: Instant::checked_duration_since
|
||||
///
|
||||
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
||||
#[stable(feature = "time2", since = "1.8.0")]
|
||||
pub struct Instant(time::Instant);
|
||||
@ -247,59 +268,19 @@ impl Instant {
|
||||
#[must_use]
|
||||
#[stable(feature = "time2", since = "1.8.0")]
|
||||
pub fn now() -> Instant {
|
||||
let os_now = time::Instant::now();
|
||||
|
||||
// And here we come upon a sad state of affairs. The whole point of
|
||||
// `Instant` is that it's monotonically increasing. We've found in the
|
||||
// wild, however, that it's not actually monotonically increasing for
|
||||
// one reason or another. These appear to be OS and hardware level bugs,
|
||||
// and there's not really a whole lot we can do about them. Here's a
|
||||
// taste of what we've found:
|
||||
//
|
||||
// * #48514 - OpenBSD, x86_64
|
||||
// * #49281 - linux arm64 and s390x
|
||||
// * #51648 - windows, x86
|
||||
// * #56560 - windows, x86_64, AWS
|
||||
// * #56612 - windows, x86, vm (?)
|
||||
// * #56940 - linux, arm64
|
||||
// * https://bugzilla.mozilla.org/show_bug.cgi?id=1487778 - a similar
|
||||
// Firefox bug
|
||||
//
|
||||
// It seems that this just happens a lot in the wild.
|
||||
// We're seeing panics across various platforms where consecutive calls
|
||||
// to `Instant::now`, such as via the `elapsed` function, are panicking
|
||||
// as they're going backwards. Placed here is a last-ditch effort to try
|
||||
// to fix things up. We keep a global "latest now" instance which is
|
||||
// returned instead of what the OS says if the OS goes backwards.
|
||||
//
|
||||
// To hopefully mitigate the impact of this, a few platforms are
|
||||
// excluded as "these at least haven't gone backwards yet".
|
||||
//
|
||||
// While issues have been seen on arm64 platforms the Arm architecture
|
||||
// requires that the counter monotonically increases and that it must
|
||||
// provide a uniform view of system time (e.g. it must not be possible
|
||||
// for a core to receive a message from another core with a time stamp
|
||||
// and observe time going backwards (ARM DDI 0487G.b D11.1.2). While
|
||||
// there have been a few 64bit SoCs that have bugs which cause time to
|
||||
// not monoticially increase, these have been fixed in the Linux kernel
|
||||
// and we shouldn't penalize all Arm SoCs for those who refuse to
|
||||
// update their kernels:
|
||||
// SUN50I_ERRATUM_UNKNOWN1 - Allwinner A64 / Pine A64 - fixed in 5.1
|
||||
// FSL_ERRATUM_A008585 - Freescale LS2080A/LS1043A - fixed in 4.10
|
||||
// HISILICON_ERRATUM_161010101 - Hisilicon 1610 - fixed in 4.11
|
||||
// ARM64_ERRATUM_858921 - Cortex A73 - fixed in 4.12
|
||||
if time::Instant::actually_monotonic() {
|
||||
return Instant(os_now);
|
||||
}
|
||||
|
||||
Instant(monotonic::monotonize(os_now))
|
||||
Instant(time::Instant::now())
|
||||
}
|
||||
|
||||
/// Returns the amount of time elapsed from another instant to this one.
|
||||
/// Returns the amount of time elapsed from another instant to this one,
|
||||
/// or zero duration if that instant is later than this one.
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
/// This function will panic if `earlier` is later than `self`.
|
||||
/// Previous rust versions panicked when `earlier` was later than `self`. Currently this
|
||||
/// method saturates. Future versions may reintroduce the panic in some circumstances.
|
||||
/// See [Monotonicity].
|
||||
///
|
||||
/// [Monotonicity]: Instant#monotonicity
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
@ -311,16 +292,22 @@ impl Instant {
|
||||
/// sleep(Duration::new(1, 0));
|
||||
/// let new_now = Instant::now();
|
||||
/// println!("{:?}", new_now.duration_since(now));
|
||||
/// println!("{:?}", now.duration_since(new_now)); // 0ns
|
||||
/// ```
|
||||
#[must_use]
|
||||
#[stable(feature = "time2", since = "1.8.0")]
|
||||
pub fn duration_since(&self, earlier: Instant) -> Duration {
|
||||
self.0.checked_sub_instant(&earlier.0).expect("supplied instant is later than self")
|
||||
self.checked_duration_since(earlier).unwrap_or_default()
|
||||
}
|
||||
|
||||
/// Returns the amount of time elapsed from another instant to this one,
|
||||
/// or None if that instant is later than this one.
|
||||
///
|
||||
/// Due to [monotonicity bugs], even under correct logical ordering of the passed `Instant`s,
|
||||
/// this method can return `None`.
|
||||
///
|
||||
/// [monotonicity bugs]: Instant#monotonicity
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```no_run
|
||||
@ -364,9 +351,11 @@ impl Instant {
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
/// This function may panic if the current time is earlier than this
|
||||
/// instant, which is something that can happen if an `Instant` is
|
||||
/// produced synthetically.
|
||||
/// Previous rust versions panicked when self was earlier than the current time. Currently this
|
||||
/// method returns a Duration of zero in that case. Future versions may reintroduce the panic.
|
||||
/// See [Monotonicity].
|
||||
///
|
||||
/// [Monotonicity]: Instant#monotonicity
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
@ -442,6 +431,16 @@ impl SubAssign<Duration> for Instant {
|
||||
impl Sub<Instant> for Instant {
|
||||
type Output = Duration;
|
||||
|
||||
/// Returns the amount of time elapsed from another instant to this one,
|
||||
/// or zero duration if that instant is later than this one.
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
/// Previous rust versions panicked when `other` was later than `self`. Currently this
|
||||
/// method saturates. Future versions may reintroduce the panic in some circumstances.
|
||||
/// See [Monotonicity].
|
||||
///
|
||||
/// [Monotonicity]: Instant#monotonicity
|
||||
fn sub(self, other: Instant) -> Duration {
|
||||
self.duration_since(other)
|
||||
}
|
||||
|
@ -1,116 +0,0 @@
|
||||
use crate::sys::time;
|
||||
|
||||
#[inline]
|
||||
pub(super) fn monotonize(raw: time::Instant) -> time::Instant {
|
||||
inner::monotonize(raw)
|
||||
}
|
||||
|
||||
#[cfg(any(all(target_has_atomic = "64", not(target_has_atomic = "128")), target_arch = "aarch64"))]
|
||||
pub mod inner {
|
||||
use crate::sync::atomic::AtomicU64;
|
||||
use crate::sync::atomic::Ordering::*;
|
||||
use crate::sys::time;
|
||||
use crate::time::Duration;
|
||||
|
||||
pub(in crate::time) const ZERO: time::Instant = time::Instant::zero();
|
||||
|
||||
// bits 30 and 31 are never used since the nanoseconds part never exceeds 10^9
|
||||
const UNINITIALIZED: u64 = 0b11 << 30;
|
||||
static MONO: AtomicU64 = AtomicU64::new(UNINITIALIZED);
|
||||
|
||||
#[inline]
|
||||
pub(super) fn monotonize(raw: time::Instant) -> time::Instant {
|
||||
monotonize_impl(&MONO, raw)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub(in crate::time) fn monotonize_impl(mono: &AtomicU64, raw: time::Instant) -> time::Instant {
|
||||
let delta = raw.checked_sub_instant(&ZERO).unwrap();
|
||||
let secs = delta.as_secs();
|
||||
// occupies no more than 30 bits (10^9 seconds)
|
||||
let nanos = delta.subsec_nanos() as u64;
|
||||
|
||||
// This wraps around every 136 years (2^32 seconds).
|
||||
// To detect backsliding we use wrapping arithmetic and declare forward steps smaller
|
||||
// than 2^31 seconds as expected and everything else as a backslide which will be
|
||||
// monotonized.
|
||||
// This could be a problem for programs that call instants at intervals greater
|
||||
// than 68 years. Interstellar probes may want to ensure that actually_monotonic() is true.
|
||||
let packed = (secs << 32) | nanos;
|
||||
let updated = mono.fetch_update(Relaxed, Relaxed, |old| {
|
||||
(old == UNINITIALIZED || packed.wrapping_sub(old) < u64::MAX / 2).then_some(packed)
|
||||
});
|
||||
match updated {
|
||||
Ok(_) => raw,
|
||||
Err(newer) => {
|
||||
// Backslide occurred. We reconstruct monotonized time from the upper 32 bit of the
|
||||
// passed in value and the 64bits loaded from the atomic
|
||||
let seconds_lower = newer >> 32;
|
||||
let mut seconds_upper = secs & 0xffff_ffff_0000_0000;
|
||||
if secs & 0xffff_ffff > seconds_lower {
|
||||
// Backslide caused the lower 32bit of the seconds part to wrap.
|
||||
// This must be the case because the seconds part is larger even though
|
||||
// we are in the backslide branch, i.e. the seconds count should be smaller or equal.
|
||||
//
|
||||
// We assume that backslides are smaller than 2^32 seconds
|
||||
// which means we need to add 1 to the upper half to restore it.
|
||||
//
|
||||
// Example:
|
||||
// most recent observed time: 0xA1_0000_0000_0000_0000u128
|
||||
// bits stored in AtomicU64: 0x0000_0000_0000_0000u64
|
||||
// backslide by 1s
|
||||
// caller time is 0xA0_ffff_ffff_0000_0000u128
|
||||
// -> we can fix up the upper half time by adding 1 << 32
|
||||
seconds_upper = seconds_upper.wrapping_add(0x1_0000_0000);
|
||||
}
|
||||
let secs = seconds_upper | seconds_lower;
|
||||
let nanos = newer as u32;
|
||||
ZERO.checked_add_duration(&Duration::new(secs, nanos)).unwrap()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(all(target_has_atomic = "128", not(target_arch = "aarch64")))]
|
||||
pub mod inner {
|
||||
use crate::sync::atomic::AtomicU128;
|
||||
use crate::sync::atomic::Ordering::*;
|
||||
use crate::sys::time;
|
||||
use crate::time::Duration;
|
||||
|
||||
const ZERO: time::Instant = time::Instant::zero();
|
||||
static MONO: AtomicU128 = AtomicU128::new(0);
|
||||
|
||||
#[inline]
|
||||
pub(super) fn monotonize(raw: time::Instant) -> time::Instant {
|
||||
let delta = raw.checked_sub_instant(&ZERO).unwrap();
|
||||
// Split into seconds and nanos since Duration doesn't have a
|
||||
// constructor that takes a u128
|
||||
let secs = delta.as_secs() as u128;
|
||||
let nanos = delta.subsec_nanos() as u128;
|
||||
let timestamp: u128 = secs << 64 | nanos;
|
||||
let timestamp = MONO.fetch_max(timestamp, Relaxed).max(timestamp);
|
||||
let secs = (timestamp >> 64) as u64;
|
||||
let nanos = timestamp as u32;
|
||||
ZERO.checked_add_duration(&Duration::new(secs, nanos)).unwrap()
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(any(target_has_atomic = "64", target_has_atomic = "128")))]
|
||||
pub mod inner {
|
||||
use crate::cmp;
|
||||
use crate::sys::time;
|
||||
use crate::sys_common::mutex::StaticMutex;
|
||||
|
||||
#[inline]
|
||||
pub(super) fn monotonize(os_now: time::Instant) -> time::Instant {
|
||||
static LOCK: StaticMutex = StaticMutex::new();
|
||||
static mut LAST_NOW: time::Instant = time::Instant::zero();
|
||||
unsafe {
|
||||
let _lock = LOCK.lock();
|
||||
let now = cmp::max(LAST_NOW, os_now);
|
||||
LAST_NOW = now;
|
||||
now
|
||||
}
|
||||
}
|
||||
}
|
@ -90,10 +90,9 @@ fn instant_math_is_associative() {
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[should_panic]
|
||||
fn instant_duration_since_panic() {
|
||||
fn instant_duration_since_saturates() {
|
||||
let a = Instant::now();
|
||||
let _ = (a - Duration::SECOND).duration_since(a);
|
||||
assert_eq!((a - Duration::SECOND).duration_since(a), Duration::ZERO);
|
||||
}
|
||||
|
||||
#[test]
|
||||
@ -109,6 +108,7 @@ fn instant_checked_duration_since_nopanic() {
|
||||
#[test]
|
||||
fn instant_saturating_duration_since_nopanic() {
|
||||
let a = Instant::now();
|
||||
#[allow(deprecated, deprecated_in_future)]
|
||||
let ret = (a - Duration::SECOND).saturating_duration_since(a);
|
||||
assert_eq!(ret, Duration::ZERO);
|
||||
}
|
||||
@ -192,31 +192,6 @@ fn since_epoch() {
|
||||
assert!(a < hundred_twenty_years);
|
||||
}
|
||||
|
||||
#[cfg(all(target_has_atomic = "64", not(target_has_atomic = "128")))]
|
||||
#[test]
|
||||
fn monotonizer_wrapping_backslide() {
|
||||
use super::monotonic::inner::{monotonize_impl, ZERO};
|
||||
use core::sync::atomic::AtomicU64;
|
||||
|
||||
let reference = AtomicU64::new(0);
|
||||
|
||||
let time = match ZERO.checked_add_duration(&Duration::from_secs(0xffff_ffff)) {
|
||||
Some(time) => time,
|
||||
None => {
|
||||
// platform cannot represent u32::MAX seconds so it won't have to deal with this kind
|
||||
// of overflow either
|
||||
return;
|
||||
}
|
||||
};
|
||||
|
||||
let monotonized = monotonize_impl(&reference, time);
|
||||
let expected = ZERO.checked_add_duration(&Duration::from_secs(1 << 32)).unwrap();
|
||||
assert_eq!(
|
||||
monotonized, expected,
|
||||
"64bit monotonizer should handle overflows in the seconds part"
|
||||
);
|
||||
}
|
||||
|
||||
macro_rules! bench_instant_threaded {
|
||||
($bench_name:ident, $thread_count:expr) => {
|
||||
#[bench]
|
||||
|
@ -63,7 +63,7 @@ def support_xz():
|
||||
except tarfile.CompressionError:
|
||||
return False
|
||||
|
||||
def get(base, url, path, checksums, verbose=False, do_verify=True):
|
||||
def get(base, url, path, checksums, verbose=False, do_verify=True, help_on_error=None):
|
||||
with tempfile.NamedTemporaryFile(delete=False) as temp_file:
|
||||
temp_path = temp_file.name
|
||||
|
||||
@ -82,7 +82,7 @@ def get(base, url, path, checksums, verbose=False, do_verify=True):
|
||||
print("ignoring already-download file",
|
||||
path, "due to failed verification")
|
||||
os.unlink(path)
|
||||
download(temp_path, "{}/{}".format(base, url), True, verbose)
|
||||
download(temp_path, "{}/{}".format(base, url), True, verbose, help_on_error=help_on_error)
|
||||
if do_verify and not verify(temp_path, sha256, verbose):
|
||||
raise RuntimeError("failed verification")
|
||||
if verbose:
|
||||
@ -95,17 +95,17 @@ def get(base, url, path, checksums, verbose=False, do_verify=True):
|
||||
os.unlink(temp_path)
|
||||
|
||||
|
||||
def download(path, url, probably_big, verbose):
|
||||
def download(path, url, probably_big, verbose, help_on_error=None):
|
||||
for _ in range(0, 4):
|
||||
try:
|
||||
_download(path, url, probably_big, verbose, True)
|
||||
_download(path, url, probably_big, verbose, True, help_on_error=help_on_error)
|
||||
return
|
||||
except RuntimeError:
|
||||
print("\nspurious failure, trying again")
|
||||
_download(path, url, probably_big, verbose, False)
|
||||
_download(path, url, probably_big, verbose, False, help_on_error=help_on_error)
|
||||
|
||||
|
||||
def _download(path, url, probably_big, verbose, exception):
|
||||
def _download(path, url, probably_big, verbose, exception, help_on_error=None):
|
||||
if probably_big or verbose:
|
||||
print("downloading {}".format(url))
|
||||
# see https://serverfault.com/questions/301128/how-to-download
|
||||
@ -126,7 +126,8 @@ def _download(path, url, probably_big, verbose, exception):
|
||||
"--connect-timeout", "30", # timeout if cannot connect within 30 seconds
|
||||
"--retry", "3", "-Sf", "-o", path, url],
|
||||
verbose=verbose,
|
||||
exception=exception)
|
||||
exception=exception,
|
||||
help_on_error=help_on_error)
|
||||
|
||||
|
||||
def verify(path, expected, verbose):
|
||||
@ -167,7 +168,7 @@ def unpack(tarball, tarball_suffix, dst, verbose=False, match=None):
|
||||
shutil.rmtree(os.path.join(dst, fname))
|
||||
|
||||
|
||||
def run(args, verbose=False, exception=False, is_bootstrap=False, **kwargs):
|
||||
def run(args, verbose=False, exception=False, is_bootstrap=False, help_on_error=None, **kwargs):
|
||||
"""Run a child program in a new process"""
|
||||
if verbose:
|
||||
print("running: " + ' '.join(args))
|
||||
@ -178,6 +179,8 @@ def run(args, verbose=False, exception=False, is_bootstrap=False, **kwargs):
|
||||
code = ret.wait()
|
||||
if code != 0:
|
||||
err = "failed to run: " + ' '.join(args)
|
||||
if help_on_error is not None:
|
||||
err += "\n" + help_on_error
|
||||
if verbose or exception:
|
||||
raise RuntimeError(err)
|
||||
# For most failures, we definitely do want to print this error, or the user will have no
|
||||
@ -624,6 +627,14 @@ class RustBuild(object):
|
||||
filename = "rust-dev-nightly-" + self.build + tarball_suffix
|
||||
tarball = os.path.join(rustc_cache, filename)
|
||||
if not os.path.exists(tarball):
|
||||
help_on_error = "error: failed to download llvm from ci"
|
||||
help_on_error += "\nhelp: old builds get deleted after a certain time"
|
||||
help_on_error += "\nhelp: if trying to compile an old commit of rustc,"
|
||||
help_on_error += " disable `download-ci-llvm` in config.toml:"
|
||||
help_on_error += "\n"
|
||||
help_on_error += "\n[llvm]"
|
||||
help_on_error += "\ndownload-ci-llvm = false"
|
||||
help_on_error += "\n"
|
||||
get(
|
||||
base,
|
||||
"{}/{}".format(url, filename),
|
||||
@ -631,6 +642,7 @@ class RustBuild(object):
|
||||
self.checksums_sha256,
|
||||
verbose=self.verbose,
|
||||
do_verify=False,
|
||||
help_on_error=help_on_error,
|
||||
)
|
||||
unpack(tarball, tarball_suffix, self.llvm_root(),
|
||||
match="rust-dev",
|
||||
|
@ -688,7 +688,7 @@ fn main_args(at_args: &[String]) -> MainResult {
|
||||
Ok(opts) => opts,
|
||||
Err(code) => return if code == 0 { Ok(()) } else { Err(ErrorReported) },
|
||||
};
|
||||
rustc_interface::util::setup_callbacks_and_run_in_thread_pool_with_globals(
|
||||
rustc_interface::util::run_in_thread_pool_with_globals(
|
||||
options.edition,
|
||||
1, // this runs single-threaded, even in a parallel compiler
|
||||
&None,
|
||||
|
@ -1,6 +1,5 @@
|
||||
// NOTE: rustc cannot currently handle bounds of the form `for<'a> <Foo as Bar<'a>>::Assoc: Baz`.
|
||||
// This should hopefully be fixed with Chalk.
|
||||
// ignore-compare-mode-chalk
|
||||
|
||||
#![feature(associated_type_bounds)]
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
error[E0277]: `<<Self as Case1>::C as Iterator>::Item` cannot be sent between threads safely
|
||||
--> $DIR/bad-bounds-on-assoc-in-trait.rs:27:36
|
||||
--> $DIR/bad-bounds-on-assoc-in-trait.rs:26:36
|
||||
|
|
||||
LL | type C: Clone + Iterator<Item: Send + Iterator<Item: for<'a> Lam<&'a u8, App: Debug>> + Sync>;
|
||||
| ^^^^ `<<Self as Case1>::C as Iterator>::Item` cannot be sent between threads safely
|
||||
@ -11,7 +11,7 @@ LL | trait Case1 where <<Self as Case1>::C as Iterator>::Item: Send {
|
||||
| ++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||
|
||||
error[E0277]: `<<Self as Case1>::C as Iterator>::Item` is not an iterator
|
||||
--> $DIR/bad-bounds-on-assoc-in-trait.rs:27:43
|
||||
--> $DIR/bad-bounds-on-assoc-in-trait.rs:26:43
|
||||
|
|
||||
LL | type C: Clone + Iterator<Item: Send + Iterator<Item: for<'a> Lam<&'a u8, App: Debug>> + Sync>;
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `<<Self as Case1>::C as Iterator>::Item` is not an iterator
|
||||
@ -23,7 +23,7 @@ LL | trait Case1 where <<Self as Case1>::C as Iterator>::Item: Iterator {
|
||||
| ++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||
|
||||
error[E0277]: `<<Self as Case1>::C as Iterator>::Item` cannot be shared between threads safely
|
||||
--> $DIR/bad-bounds-on-assoc-in-trait.rs:27:93
|
||||
--> $DIR/bad-bounds-on-assoc-in-trait.rs:26:93
|
||||
|
|
||||
LL | type C: Clone + Iterator<Item: Send + Iterator<Item: for<'a> Lam<&'a u8, App: Debug>> + Sync>;
|
||||
| ^^^^ `<<Self as Case1>::C as Iterator>::Item` cannot be shared between threads safely
|
||||
|
@ -1,5 +1,4 @@
|
||||
// build-pass (FIXME(62277): could be check-pass?)
|
||||
// ignore-compare-mode-chalk
|
||||
|
||||
#![feature(associated_type_bounds)]
|
||||
|
||||
|
@ -1,5 +1,4 @@
|
||||
// run-pass
|
||||
// ignore-compare-mode-chalk
|
||||
|
||||
#![feature(associated_type_bounds)]
|
||||
#![feature(untagged_unions)]
|
||||
|
@ -1,8 +1,6 @@
|
||||
// run-pass
|
||||
// Test references to the trait `Stream` in the bounds for associated
|
||||
// types defined on `Stream`. Issue #20551.
|
||||
// ignore-compare-mode-chalk
|
||||
|
||||
|
||||
trait Stream {
|
||||
type Car;
|
||||
|
@ -1,4 +1,3 @@
|
||||
// ignore-compare-mode-chalk
|
||||
trait Z<'a, T: ?Sized>
|
||||
where
|
||||
T: Z<'a, u16>,
|
||||
|
@ -1,11 +1,11 @@
|
||||
error[E0277]: the trait bound `str: Clone` is not satisfied
|
||||
--> $DIR/hr-associated-type-bound-param-2.rs:4:8
|
||||
--> $DIR/hr-associated-type-bound-param-2.rs:3:8
|
||||
|
|
||||
LL | T: Z<'a, u16>,
|
||||
| ^^^^^^^^^^ the trait `Clone` is not implemented for `str`
|
||||
|
|
||||
note: required by a bound in `Z`
|
||||
--> $DIR/hr-associated-type-bound-param-2.rs:7:35
|
||||
--> $DIR/hr-associated-type-bound-param-2.rs:6:35
|
||||
|
|
||||
LL | trait Z<'a, T: ?Sized>
|
||||
| - required by a bound in this
|
||||
@ -14,13 +14,13 @@ LL | for<'b> <T as Z<'b, u16>>::W: Clone,
|
||||
| ^^^^^ required by this bound in `Z`
|
||||
|
||||
error[E0277]: the trait bound `str: Clone` is not satisfied
|
||||
--> $DIR/hr-associated-type-bound-param-2.rs:4:8
|
||||
--> $DIR/hr-associated-type-bound-param-2.rs:3:8
|
||||
|
|
||||
LL | T: Z<'a, u16>,
|
||||
| ^^^^^^^^^^ the trait `Clone` is not implemented for `str`
|
||||
|
|
||||
note: required by a bound in `Z`
|
||||
--> $DIR/hr-associated-type-bound-param-2.rs:7:35
|
||||
--> $DIR/hr-associated-type-bound-param-2.rs:6:35
|
||||
|
|
||||
LL | trait Z<'a, T: ?Sized>
|
||||
| - required by a bound in this
|
||||
@ -29,13 +29,13 @@ LL | for<'b> <T as Z<'b, u16>>::W: Clone,
|
||||
| ^^^^^ required by this bound in `Z`
|
||||
|
||||
error[E0277]: the trait bound `str: Clone` is not satisfied
|
||||
--> $DIR/hr-associated-type-bound-param-2.rs:16:14
|
||||
--> $DIR/hr-associated-type-bound-param-2.rs:15:14
|
||||
|
|
||||
LL | type W = str;
|
||||
| ^^^ the trait `Clone` is not implemented for `str`
|
||||
|
|
||||
note: required by a bound in `Z`
|
||||
--> $DIR/hr-associated-type-bound-param-2.rs:7:35
|
||||
--> $DIR/hr-associated-type-bound-param-2.rs:6:35
|
||||
|
|
||||
LL | trait Z<'a, T: ?Sized>
|
||||
| - required by a bound in this
|
||||
|
@ -1,4 +1,3 @@
|
||||
// ignore-compare-mode-chalk
|
||||
trait Cycle: Sized {
|
||||
type Next: Cycle<Next = Self>;
|
||||
}
|
||||
|
@ -1,11 +1,11 @@
|
||||
error[E0277]: the trait bound `str: Clone` is not satisfied
|
||||
--> $DIR/hr-associated-type-bound-param-5.rs:27:14
|
||||
--> $DIR/hr-associated-type-bound-param-5.rs:26:14
|
||||
|
|
||||
LL | type U = str;
|
||||
| ^^^ the trait `Clone` is not implemented for `str`
|
||||
|
|
||||
note: required by a bound in `X`
|
||||
--> $DIR/hr-associated-type-bound-param-5.rs:18:45
|
||||
--> $DIR/hr-associated-type-bound-param-5.rs:17:45
|
||||
|
|
||||
LL | trait X<'a, T: Cycle + for<'b> X<'b, T>>
|
||||
| - required by a bound in this
|
||||
@ -14,13 +14,13 @@ LL | for<'b> <T::Next as X<'b, T::Next>>::U: Clone,
|
||||
| ^^^^^ required by this bound in `X`
|
||||
|
||||
error[E0277]: the trait bound `str: Clone` is not satisfied
|
||||
--> $DIR/hr-associated-type-bound-param-5.rs:32:14
|
||||
--> $DIR/hr-associated-type-bound-param-5.rs:31:14
|
||||
|
|
||||
LL | type U = str;
|
||||
| ^^^ the trait `Clone` is not implemented for `str`
|
||||
|
|
||||
note: required by a bound in `X`
|
||||
--> $DIR/hr-associated-type-bound-param-5.rs:18:45
|
||||
--> $DIR/hr-associated-type-bound-param-5.rs:17:45
|
||||
|
|
||||
LL | trait X<'a, T: Cycle + for<'b> X<'b, T>>
|
||||
| - required by a bound in this
|
||||
|
@ -1,6 +1,5 @@
|
||||
// Tests that HRTBs are correctly accepted -- https://github.com/rust-lang/rust/issues/50301
|
||||
// check-pass
|
||||
// ignore-compare-mode-chalk
|
||||
trait Trait
|
||||
where
|
||||
for<'a> &'a Self::IntoIter: IntoIterator<Item = u32>,
|
||||
|
@ -2,7 +2,7 @@ struct Project;
|
||||
struct Value;
|
||||
|
||||
static settings_dir: String = format!("");
|
||||
//~^ ERROR calls in statics are limited to constant functions
|
||||
//~^ ERROR cannot call non-const fn
|
||||
//~| ERROR is not yet stable as a const
|
||||
|
||||
fn from_string(_: String) -> Value {
|
||||
|
@ -7,12 +7,13 @@ LL | static settings_dir: String = format!("");
|
||||
= help: add `#![feature(const_fmt_arguments_new)]` to the crate attributes to enable
|
||||
= note: this error originates in the macro `$crate::__export::format_args` (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||
|
||||
error[E0015]: calls in statics are limited to constant functions, tuple structs and tuple variants
|
||||
error[E0015]: cannot call non-const fn `format` in statics
|
||||
--> $DIR/issue-64453.rs:4:31
|
||||
|
|
||||
LL | static settings_dir: String = format!("");
|
||||
| ^^^^^^^^^^^
|
||||
|
|
||||
= note: calls in statics are limited to constant functions, tuple structs and tuple variants
|
||||
= note: this error originates in the macro `format` (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||
|
||||
error[E0507]: cannot move out of static item `settings_dir`
|
||||
|
6
src/test/ui/chalkify/assert.rs
Normal file
6
src/test/ui/chalkify/assert.rs
Normal file
@ -0,0 +1,6 @@
|
||||
// run-pass
|
||||
// compile-flags: -Z chalk
|
||||
|
||||
fn main() {
|
||||
assert_eq!(1, 1);
|
||||
}
|
@ -2,6 +2,5 @@
|
||||
// compile-flags: -Z chalk
|
||||
|
||||
fn main() {
|
||||
// FIXME(chalk): Require `RegionOutlives`/`TypeOutlives`/`Subtype` support
|
||||
//println!("hello");
|
||||
println!("hello");
|
||||
}
|
||||
|
@ -5,8 +5,7 @@ use std::fmt::Display;
|
||||
|
||||
fn main() {
|
||||
let d: &dyn Display = &mut 3;
|
||||
// FIXME(chalk) should be able to call d.to_string() as well, but doing so
|
||||
// requires Chalk to be able to prove trait object well-formed goals.
|
||||
d.to_string();
|
||||
(&d).to_string();
|
||||
let f: &dyn Fn(i32) -> _ = &|x| x + x;
|
||||
f(2);
|
||||
|
@ -87,7 +87,7 @@ static mut STATIC13: SafeStruct = SafeStruct{field1: SafeEnum::Variant1,
|
||||
static mut STATIC14: SafeStruct = SafeStruct {
|
||||
field1: SafeEnum::Variant1,
|
||||
field2: SafeEnum::Variant4("str".to_string())
|
||||
//~^ ERROR calls in statics are limited to constant functions
|
||||
//~^ ERROR cannot call non-const fn
|
||||
};
|
||||
|
||||
static STATIC15: &'static [Box<MyOwned>] = &[
|
||||
|
@ -15,11 +15,13 @@ error[E0010]: allocations are not allowed in statics
|
||||
LL | static STATIC11: Box<MyOwned> = box MyOwned;
|
||||
| ^^^^^^^^^^^ allocation not allowed in statics
|
||||
|
||||
error[E0015]: calls in statics are limited to constant functions, tuple structs and tuple variants
|
||||
--> $DIR/check-static-values-constraints.rs:89:32
|
||||
error[E0015]: cannot call non-const fn `<str as ToString>::to_string` in statics
|
||||
--> $DIR/check-static-values-constraints.rs:89:38
|
||||
|
|
||||
LL | field2: SafeEnum::Variant4("str".to_string())
|
||||
| ^^^^^^^^^^^^^^^^^
|
||||
| ^^^^^^^^^^^
|
||||
|
|
||||
= note: calls in statics are limited to constant functions, tuple structs and tuple variants
|
||||
|
||||
error[E0010]: allocations are not allowed in statics
|
||||
--> $DIR/check-static-values-constraints.rs:94:5
|
||||
|
@ -1,6 +1,6 @@
|
||||
struct X<const N: usize = {
|
||||
(||1usize)()
|
||||
//~^ ERROR calls in constants are limited to
|
||||
//~^ ERROR cannot call
|
||||
}>;
|
||||
|
||||
fn main() {}
|
||||
|
@ -1,8 +1,11 @@
|
||||
error[E0015]: calls in constants are limited to constant functions, tuple structs and tuple variants
|
||||
error[E0015]: cannot call non-const closure in constants
|
||||
--> $DIR/issue-93647.rs:2:5
|
||||
|
|
||||
LL | (||1usize)()
|
||||
| ^^^^^^^^^^^^
|
||||
|
|
||||
= note: closures need an RFC before allowed to be called in constants
|
||||
= note: calls in constants are limited to constant functions, tuple structs and tuple variants
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
|
@ -13,7 +13,7 @@ fn consume<T: 'static>(_val: T)
|
||||
where
|
||||
If<{ TypeId::of::<T>() != TypeId::of::<()>() }>: True,
|
||||
//~^ ERROR: overly complex generic constant
|
||||
//~| ERROR: calls in constants are limited to constant functions
|
||||
//~| ERROR: cannot call non-const operator in constants
|
||||
{
|
||||
}
|
||||
|
||||
@ -21,7 +21,7 @@ fn test<T: 'static>()
|
||||
where
|
||||
If<{ TypeId::of::<T>() != TypeId::of::<()>() }>: True,
|
||||
//~^ ERROR: overly complex generic constant
|
||||
//~| ERROR: calls in constants are limited to constant functions
|
||||
//~| ERROR: cannot call non-const operator in constants
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -9,11 +9,19 @@ LL | If<{ TypeId::of::<T>() != TypeId::of::<()>() }>: True,
|
||||
= help: consider moving this anonymous constant into a `const` function
|
||||
= note: this operation may be supported in the future
|
||||
|
||||
error[E0015]: calls in constants are limited to constant functions, tuple structs and tuple variants
|
||||
error[E0015]: cannot call non-const operator in constants
|
||||
--> $DIR/issue-90318.rs:14:10
|
||||
|
|
||||
LL | If<{ TypeId::of::<T>() != TypeId::of::<()>() }>: True,
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
note: impl defined here, but it is not `const`
|
||||
--> $SRC_DIR/core/src/any.rs:LL:COL
|
||||
|
|
||||
LL | #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Debug, Hash)]
|
||||
| ^^^^^^^^^
|
||||
= note: calls in constants are limited to constant functions, tuple structs and tuple variants
|
||||
= note: this error originates in the derive macro `PartialEq` (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||
|
||||
error: overly complex generic constant
|
||||
--> $DIR/issue-90318.rs:22:8
|
||||
@ -26,11 +34,19 @@ LL | If<{ TypeId::of::<T>() != TypeId::of::<()>() }>: True,
|
||||
= help: consider moving this anonymous constant into a `const` function
|
||||
= note: this operation may be supported in the future
|
||||
|
||||
error[E0015]: calls in constants are limited to constant functions, tuple structs and tuple variants
|
||||
error[E0015]: cannot call non-const operator in constants
|
||||
--> $DIR/issue-90318.rs:22:10
|
||||
|
|
||||
LL | If<{ TypeId::of::<T>() != TypeId::of::<()>() }>: True,
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
note: impl defined here, but it is not `const`
|
||||
--> $SRC_DIR/core/src/any.rs:LL:COL
|
||||
|
|
||||
LL | #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Debug, Hash)]
|
||||
| ^^^^^^^^^
|
||||
= note: calls in constants are limited to constant functions, tuple structs and tuple variants
|
||||
= note: this error originates in the derive macro `PartialEq` (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||
|
||||
error: aborting due to 4 previous errors
|
||||
|
||||
|
@ -1,8 +1,10 @@
|
||||
error[E0015]: calls in constants are limited to constant functions, tuple structs and tuple variants
|
||||
error[E0015]: cannot call non-const fn `Foo::{constant#0}::Foo::<17_usize>::value` in constants
|
||||
--> $DIR/nested-type.rs:15:5
|
||||
|
|
||||
LL | Foo::<17>::value()
|
||||
| ^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= note: calls in constants are limited to constant functions, tuple structs and tuple variants
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
|
@ -14,11 +14,13 @@ LL | | }]>;
|
||||
= note: the only supported types are integers, `bool` and `char`
|
||||
= help: more complex types are supported with `#![feature(adt_const_params)]`
|
||||
|
||||
error[E0015]: calls in constants are limited to constant functions, tuple structs and tuple variants
|
||||
error[E0015]: cannot call non-const fn `Foo::{constant#0}::Foo::<17_usize>::value` in constants
|
||||
--> $DIR/nested-type.rs:15:5
|
||||
|
|
||||
LL | Foo::<17>::value()
|
||||
| ^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= note: calls in constants are limited to constant functions, tuple structs and tuple variants
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
|
||||
|
@ -13,7 +13,7 @@ struct Foo<const N: [u8; { //[min]~ ERROR `[u8; _]` is forbidden
|
||||
}
|
||||
|
||||
Foo::<17>::value()
|
||||
//~^ ERROR calls in constants are limited to constant functions
|
||||
//~^ ERROR cannot call non-const fn
|
||||
}]>;
|
||||
|
||||
fn main() {}
|
||||
|
@ -4,5 +4,5 @@ fn f(x: usize) -> usize {
|
||||
|
||||
fn main() {
|
||||
let _ = [0; f(2)];
|
||||
//~^ ERROR calls in constants are limited to constant functions
|
||||
//~^ ERROR cannot call non-const fn
|
||||
}
|
||||
|
@ -1,8 +1,10 @@
|
||||
error[E0015]: calls in constants are limited to constant functions, tuple structs and tuple variants
|
||||
error[E0015]: cannot call non-const fn `f` in constants
|
||||
--> $DIR/const-call.rs:6:17
|
||||
|
|
||||
LL | let _ = [0; f(2)];
|
||||
| ^^^^
|
||||
|
|
||||
= note: calls in constants are limited to constant functions, tuple structs and tuple variants
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
|
@ -0,0 +1,9 @@
|
||||
error[E0284]: type annotations needed: cannot satisfy `<usize as SliceIndex<[u8]>>::Output == _`
|
||||
--> $DIR/ub-nonnull.rs:19:30
|
||||
|
|
||||
LL | let out_of_bounds_ptr = &ptr[255];
|
||||
| ^^^^^^^^ cannot satisfy `<usize as SliceIndex<[u8]>>::Output == _`
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0284`.
|
@ -0,0 +1,9 @@
|
||||
error[E0282]: type annotations needed
|
||||
--> $DIR/ub-wide-ptr.rs:90:67
|
||||
|
|
||||
LL | const MYSLICE_SUFFIX_BAD: &MySliceBool = &MySlice(true, [unsafe { mem::transmute(3u8) }]);
|
||||
| ^^^^^^^^^^^^^^ cannot infer type for type parameter `U` declared on the function `transmute`
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0282`.
|
@ -7,7 +7,7 @@ extern "C" {
|
||||
const extern "C" fn bar() {
|
||||
unsafe {
|
||||
regular_in_block();
|
||||
//~^ ERROR: calls in constant functions
|
||||
//~^ ERROR: cannot call non-const fn
|
||||
}
|
||||
}
|
||||
|
||||
@ -16,7 +16,7 @@ extern "C" fn regular() {}
|
||||
const extern "C" fn foo() {
|
||||
unsafe {
|
||||
regular();
|
||||
//~^ ERROR: calls in constant functions
|
||||
//~^ ERROR: cannot call non-const fn
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,14 +1,18 @@
|
||||
error[E0015]: calls in constant functions are limited to constant functions, tuple structs and tuple variants
|
||||
error[E0015]: cannot call non-const fn `regular_in_block` in constant functions
|
||||
--> $DIR/const-extern-fn-call-extern-fn.rs:9:9
|
||||
|
|
||||
LL | regular_in_block();
|
||||
| ^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
|
||||
|
||||
error[E0015]: calls in constant functions are limited to constant functions, tuple structs and tuple variants
|
||||
error[E0015]: cannot call non-const fn `regular` in constant functions
|
||||
--> $DIR/const-extern-fn-call-extern-fn.rs:18:9
|
||||
|
|
||||
LL | regular();
|
||||
| ^^^^^^^^^
|
||||
|
|
||||
= note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
|
||||
|
@ -4,8 +4,8 @@ const fn f(x: usize) -> usize {
|
||||
let mut sum = 0;
|
||||
for i in 0..x {
|
||||
//~^ ERROR mutable references
|
||||
//~| ERROR calls in constant functions
|
||||
//~| ERROR calls in constant functions
|
||||
//~| ERROR cannot convert
|
||||
//~| ERROR cannot call non-const fn
|
||||
//~| ERROR `for` is not allowed in a `const fn`
|
||||
sum += i;
|
||||
}
|
||||
|
@ -13,11 +13,18 @@ LL | | }
|
||||
= note: see issue #87575 <https://github.com/rust-lang/rust/issues/87575> for more information
|
||||
= help: add `#![feature(const_for)]` to the crate attributes to enable
|
||||
|
||||
error[E0015]: calls in constant functions are limited to constant functions, tuple structs and tuple variants
|
||||
error[E0015]: cannot convert `std::ops::Range<usize>` into an iterator in constant functions
|
||||
--> $DIR/const-fn-error.rs:5:14
|
||||
|
|
||||
LL | for i in 0..x {
|
||||
| ^^^^
|
||||
|
|
||||
note: impl defined here, but it is not `const`
|
||||
--> $SRC_DIR/core/src/iter/traits/collect.rs:LL:COL
|
||||
|
|
||||
LL | impl<I: Iterator> IntoIterator for I {
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
= note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
|
||||
|
||||
error[E0658]: mutable references are not allowed in constant functions
|
||||
--> $DIR/const-fn-error.rs:5:14
|
||||
@ -28,11 +35,13 @@ LL | for i in 0..x {
|
||||
= note: see issue #57349 <https://github.com/rust-lang/rust/issues/57349> for more information
|
||||
= help: add `#![feature(const_mut_refs)]` to the crate attributes to enable
|
||||
|
||||
error[E0015]: calls in constant functions are limited to constant functions, tuple structs and tuple variants
|
||||
error[E0015]: cannot call non-const fn `<std::ops::Range<usize> as Iterator>::next` in constant functions
|
||||
--> $DIR/const-fn-error.rs:5:14
|
||||
|
|
||||
LL | for i in 0..x {
|
||||
| ^^^^
|
||||
|
|
||||
= note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
|
||||
|
||||
error: aborting due to 4 previous errors
|
||||
|
||||
|
@ -1,8 +1,10 @@
|
||||
error[E0015]: calls in constant functions are limited to constant functions, tuple structs and tuple variants
|
||||
error[E0015]: cannot call non-const fn `random` in constant functions
|
||||
--> $DIR/const-fn-not-safe-for-const.rs:14:5
|
||||
|
|
||||
LL | random()
|
||||
| ^^^^^^^^
|
||||
|
|
||||
= note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
|
||||
|
||||
error[E0013]: constant functions cannot refer to statics
|
||||
--> $DIR/const-fn-not-safe-for-const.rs:20:5
|
||||
|
@ -3,8 +3,8 @@
|
||||
|
||||
const _: () = {
|
||||
for _ in 0..5 {}
|
||||
//~^ error: calls in constants are limited to
|
||||
//~| error: calls in constants are limited to
|
||||
//~^ error: cannot convert
|
||||
//~| error: cannot call non-const fn
|
||||
};
|
||||
|
||||
fn main() {}
|
||||
|
@ -1,14 +1,23 @@
|
||||
error[E0015]: calls in constants are limited to constant functions, tuple structs and tuple variants
|
||||
error[E0015]: cannot convert `std::ops::Range<i32>` into an iterator in constants
|
||||
--> $DIR/const-for.rs:5:14
|
||||
|
|
||||
LL | for _ in 0..5 {}
|
||||
| ^^^^
|
||||
|
|
||||
note: impl defined here, but it is not `const`
|
||||
--> $SRC_DIR/core/src/iter/traits/collect.rs:LL:COL
|
||||
|
|
||||
LL | impl<I: Iterator> IntoIterator for I {
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
= note: calls in constants are limited to constant functions, tuple structs and tuple variants
|
||||
|
||||
error[E0015]: calls in constants are limited to constant functions, tuple structs and tuple variants
|
||||
error[E0015]: cannot call non-const fn `<std::ops::Range<i32> as Iterator>::next` in constants
|
||||
--> $DIR/const-for.rs:5:14
|
||||
|
|
||||
LL | for _ in 0..5 {}
|
||||
| ^^^^
|
||||
|
|
||||
= note: calls in constants are limited to constant functions, tuple structs and tuple variants
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
|
||||
|
@ -8,7 +8,7 @@ fn non_const() -> Thing {
|
||||
}
|
||||
|
||||
pub const Q: i32 = match non_const() {
|
||||
//~^ ERROR calls in constants are limited to constant functions
|
||||
//~^ ERROR cannot call non-const fn
|
||||
Thing::This => 1,
|
||||
Thing::That => 0
|
||||
};
|
||||
|
@ -1,8 +1,10 @@
|
||||
error[E0015]: calls in constants are limited to constant functions, tuple structs and tuple variants
|
||||
error[E0015]: cannot call non-const fn `non_const` in constants
|
||||
--> $DIR/issue-46843.rs:10:26
|
||||
|
|
||||
LL | pub const Q: i32 = match non_const() {
|
||||
| ^^^^^^^^^^^
|
||||
|
|
||||
= note: calls in constants are limited to constant functions, tuple structs and tuple variants
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
|
@ -11,7 +11,7 @@ pub const unsafe fn copy<T>(src: *const T, dst: *mut T, count: usize) {
|
||||
}
|
||||
|
||||
unsafe { copy(src, dst, count) }
|
||||
//~^ ERROR calls in constant functions are limited to constant functions
|
||||
//~^ ERROR cannot call non-const fn
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
|
@ -1,8 +1,10 @@
|
||||
error[E0015]: calls in constant functions are limited to constant functions, tuple structs and tuple variants
|
||||
error[E0015]: cannot call non-const fn `copy::copy::<T>` in constant functions
|
||||
--> $DIR/intrinsic_without_const_stab.rs:13:14
|
||||
|
|
||||
LL | unsafe { copy(src, dst, count) }
|
||||
| ^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
|
@ -9,7 +9,7 @@ extern "rust-intrinsic" {
|
||||
#[rustc_const_unstable(feature = "const_intrinsic_copy", issue = "80697")]
|
||||
#[inline]
|
||||
pub const unsafe fn stuff<T>(src: *const T, dst: *mut T, count: usize) {
|
||||
unsafe { copy(src, dst, count) } //~ ERROR calls in constant functions are limited
|
||||
unsafe { copy(src, dst, count) } //~ ERROR cannot call non-const fn
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
|
@ -1,8 +1,10 @@
|
||||
error[E0015]: calls in constant functions are limited to constant functions, tuple structs and tuple variants
|
||||
error[E0015]: cannot call non-const fn `copy::<T>` in constant functions
|
||||
--> $DIR/intrinsic_without_const_stab_fail.rs:12:14
|
||||
|
|
||||
LL | unsafe { copy(src, dst, count) }
|
||||
| ^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
|
@ -2,7 +2,7 @@
|
||||
|
||||
const X: u8 =
|
||||
|| -> u8 { 5 }()
|
||||
//~^ ERROR calls in constants are limited to constant functions
|
||||
//~^ ERROR cannot call non-const closure
|
||||
;
|
||||
|
||||
fn main() {}
|
||||
|
@ -1,8 +1,11 @@
|
||||
error[E0015]: calls in constants are limited to constant functions, tuple structs and tuple variants
|
||||
error[E0015]: cannot call non-const closure in constants
|
||||
--> $DIR/issue-28113.rs:4:5
|
||||
|
|
||||
LL | || -> u8 { 5 }()
|
||||
| ^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= note: closures need an RFC before allowed to be called in constants
|
||||
= note: calls in constants are limited to constant functions, tuple structs and tuple variants
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
|
@ -8,7 +8,7 @@ const bad : u32 = {
|
||||
const bad_two : u32 = {
|
||||
{
|
||||
invalid();
|
||||
//~^ ERROR: calls in constants are limited to constant functions, tuple structs and tuple variants
|
||||
//~^ ERROR: cannot call non-const fn `invalid`
|
||||
0
|
||||
}
|
||||
};
|
||||
@ -30,7 +30,7 @@ static bad_four : u32 = {
|
||||
static bad_five : u32 = {
|
||||
{
|
||||
invalid();
|
||||
//~^ ERROR: calls in statics are limited to constant functions, tuple structs and tuple variants
|
||||
//~^ ERROR: cannot call non-const fn `invalid`
|
||||
0
|
||||
}
|
||||
};
|
||||
@ -52,7 +52,7 @@ static mut bad_seven : u32 = {
|
||||
static mut bad_eight : u32 = {
|
||||
{
|
||||
invalid();
|
||||
//~^ ERROR: calls in statics are limited to constant functions, tuple structs and tuple variants
|
||||
//~^ ERROR: cannot call non-const fn `invalid`
|
||||
0
|
||||
}
|
||||
};
|
||||
|
@ -1,20 +1,26 @@
|
||||
error[E0015]: calls in constants are limited to constant functions, tuple structs and tuple variants
|
||||
error[E0015]: cannot call non-const fn `invalid` in constants
|
||||
--> $DIR/issue-32829-2.rs:10:9
|
||||
|
|
||||
LL | invalid();
|
||||
| ^^^^^^^^^
|
||||
|
|
||||
= note: calls in constants are limited to constant functions, tuple structs and tuple variants
|
||||
|
||||
error[E0015]: calls in statics are limited to constant functions, tuple structs and tuple variants
|
||||
error[E0015]: cannot call non-const fn `invalid` in statics
|
||||
--> $DIR/issue-32829-2.rs:32:9
|
||||
|
|
||||
LL | invalid();
|
||||
| ^^^^^^^^^
|
||||
|
|
||||
= note: calls in statics are limited to constant functions, tuple structs and tuple variants
|
||||
|
||||
error[E0015]: calls in statics are limited to constant functions, tuple structs and tuple variants
|
||||
error[E0015]: cannot call non-const fn `invalid` in statics
|
||||
--> $DIR/issue-32829-2.rs:54:9
|
||||
|
|
||||
LL | invalid();
|
||||
| ^^^^^^^^^
|
||||
|
|
||||
= note: calls in statics are limited to constant functions, tuple structs and tuple variants
|
||||
|
||||
error: aborting due to 3 previous errors
|
||||
|
||||
|
@ -1,7 +1,7 @@
|
||||
fn xyz() -> u8 { 42 }
|
||||
|
||||
const NUM: u8 = xyz();
|
||||
//~^ ERROR calls in constants are limited to constant functions, tuple structs and tuple variants
|
||||
//~^ ERROR cannot call non-const fn
|
||||
|
||||
fn main() {
|
||||
match 1 {
|
||||
|
@ -1,8 +1,10 @@
|
||||
error[E0015]: calls in constants are limited to constant functions, tuple structs and tuple variants
|
||||
error[E0015]: cannot call non-const fn `xyz` in constants
|
||||
--> $DIR/issue-43105.rs:3:17
|
||||
|
|
||||
LL | const NUM: u8 = xyz();
|
||||
| ^^^^^
|
||||
|
|
||||
= note: calls in constants are limited to constant functions, tuple structs and tuple variants
|
||||
|
||||
error: could not evaluate constant pattern
|
||||
--> $DIR/issue-43105.rs:8:9
|
||||
|
@ -1,7 +1,7 @@
|
||||
#![feature(const_fn_fn_ptr_basics)]
|
||||
|
||||
const fn foo() { (||{})() }
|
||||
//~^ ERROR calls in constant functions
|
||||
//~^ ERROR cannot call non-const closure
|
||||
|
||||
const fn bad(input: fn()) {
|
||||
input()
|
||||
|
@ -1,8 +1,11 @@
|
||||
error[E0015]: calls in constant functions are limited to constant functions, tuple structs and tuple variants
|
||||
error[E0015]: cannot call non-const closure in constant functions
|
||||
--> $DIR/issue-56164.rs:3:18
|
||||
|
|
||||
LL | const fn foo() { (||{})() }
|
||||
| ^^^^^^^^
|
||||
|
|
||||
= note: closures need an RFC before allowed to be called in constant functions
|
||||
= note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
|
||||
|
||||
error: function pointers are not allowed in const fn
|
||||
--> $DIR/issue-56164.rs:7:5
|
||||
|
@ -3,7 +3,7 @@
|
||||
// in the length part of an array.
|
||||
|
||||
struct Bug {
|
||||
a: [(); (|| { 0 })()] //~ ERROR calls in constants are limited to
|
||||
a: [(); (|| { 0 })()] //~ ERROR cannot call non-const closure
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
|
@ -1,8 +1,11 @@
|
||||
error[E0015]: calls in constants are limited to constant functions, tuple structs and tuple variants
|
||||
error[E0015]: cannot call non-const closure in constants
|
||||
--> $DIR/issue-68542-closure-in-array-len.rs:6:13
|
||||
|
|
||||
LL | a: [(); (|| { 0 })()]
|
||||
| ^^^^^^^^^^^^
|
||||
|
|
||||
= note: closures need an RFC before allowed to be called in constants
|
||||
= note: calls in constants are limited to constant functions, tuple structs and tuple variants
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
|
@ -6,20 +6,20 @@
|
||||
|
||||
const fn f(a: &u8, b: &u8) -> bool {
|
||||
*a == *b
|
||||
//~^ ERROR: calls in constant functions are limited to constant functions, tuple structs and tuple variants [E0015]
|
||||
//~^ ERROR: cannot call non-const operator in constant functions [E0015]
|
||||
//~| HELP: consider dereferencing here
|
||||
}
|
||||
|
||||
const fn g(a: &&&&i64, b: &&&&i64) -> bool {
|
||||
****a == ****b
|
||||
//~^ ERROR: calls in constant functions are limited to constant functions, tuple structs and tuple variants [E0015]
|
||||
//~^ ERROR: cannot call non-const operator in constant functions [E0015]
|
||||
//~| HELP: consider dereferencing here
|
||||
}
|
||||
|
||||
const fn h(mut a: &[u8], mut b: &[u8]) -> bool {
|
||||
while let ([l, at @ ..], [r, bt @ ..]) = (a, b) {
|
||||
if *l == *r {
|
||||
//~^ ERROR: calls in constant functions are limited to constant functions, tuple structs and tuple variants [E0015]
|
||||
//~^ ERROR: cannot call non-const operator in constant functions [E0015]
|
||||
//~| HELP: consider dereferencing here
|
||||
a = at;
|
||||
b = bt;
|
||||
|
@ -6,20 +6,20 @@
|
||||
|
||||
const fn f(a: &u8, b: &u8) -> bool {
|
||||
a == b
|
||||
//~^ ERROR: calls in constant functions are limited to constant functions, tuple structs and tuple variants [E0015]
|
||||
//~^ ERROR: cannot call non-const operator in constant functions [E0015]
|
||||
//~| HELP: consider dereferencing here
|
||||
}
|
||||
|
||||
const fn g(a: &&&&i64, b: &&&&i64) -> bool {
|
||||
a == b
|
||||
//~^ ERROR: calls in constant functions are limited to constant functions, tuple structs and tuple variants [E0015]
|
||||
//~^ ERROR: cannot call non-const operator in constant functions [E0015]
|
||||
//~| HELP: consider dereferencing here
|
||||
}
|
||||
|
||||
const fn h(mut a: &[u8], mut b: &[u8]) -> bool {
|
||||
while let ([l, at @ ..], [r, bt @ ..]) = (a, b) {
|
||||
if l == r {
|
||||
//~^ ERROR: calls in constant functions are limited to constant functions, tuple structs and tuple variants [E0015]
|
||||
//~^ ERROR: cannot call non-const operator in constant functions [E0015]
|
||||
//~| HELP: consider dereferencing here
|
||||
a = at;
|
||||
b = bt;
|
||||
|
@ -1,31 +1,34 @@
|
||||
error[E0015]: calls in constant functions are limited to constant functions, tuple structs and tuple variants
|
||||
error[E0015]: cannot call non-const operator in constant functions
|
||||
--> $DIR/issue-90870.rs:8:5
|
||||
|
|
||||
LL | a == b
|
||||
| ^^^^^^
|
||||
|
|
||||
= note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
|
||||
help: consider dereferencing here
|
||||
|
|
||||
LL | *a == *b
|
||||
| + +
|
||||
|
||||
error[E0015]: calls in constant functions are limited to constant functions, tuple structs and tuple variants
|
||||
error[E0015]: cannot call non-const operator in constant functions
|
||||
--> $DIR/issue-90870.rs:14:5
|
||||
|
|
||||
LL | a == b
|
||||
| ^^^^^^
|
||||
|
|
||||
= note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
|
||||
help: consider dereferencing here
|
||||
|
|
||||
LL | ****a == ****b
|
||||
| ++++ ++++
|
||||
|
||||
error[E0015]: calls in constant functions are limited to constant functions, tuple structs and tuple variants
|
||||
error[E0015]: cannot call non-const operator in constant functions
|
||||
--> $DIR/issue-90870.rs:21:12
|
||||
|
|
||||
LL | if l == r {
|
||||
| ^^^^^^
|
||||
|
|
||||
= note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
|
||||
help: consider dereferencing here
|
||||
|
|
||||
LL | if *l == *r {
|
||||
|
@ -1,7 +1,7 @@
|
||||
const fn foo(a: i32) -> Vec<i32> {
|
||||
vec![1, 2, 3]
|
||||
//~^ ERROR allocations are not allowed
|
||||
//~| ERROR calls in constant functions
|
||||
//~| ERROR cannot call non-const fn
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
|
@ -6,12 +6,13 @@ LL | vec![1, 2, 3]
|
||||
|
|
||||
= note: this error originates in the macro `vec` (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||
|
||||
error[E0015]: calls in constant functions are limited to constant functions, tuple structs and tuple variants
|
||||
error[E0015]: cannot call non-const fn `slice::<impl [i32]>::into_vec::<std::alloc::Global>` in constant functions
|
||||
--> $DIR/bad_const_fn_body_ice.rs:2:5
|
||||
|
|
||||
LL | vec![1, 2, 3]
|
||||
| ^^^^^^^^^^^^^
|
||||
|
|
||||
= note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
|
||||
= note: this error originates in the macro `vec` (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
|
@ -6,6 +6,6 @@ fn bar() -> Foo {
|
||||
}
|
||||
|
||||
static foo: Foo = bar();
|
||||
//~^ ERROR calls in statics are limited to constant functions, tuple structs and tuple variants
|
||||
//~^ ERROR cannot call non-const fn
|
||||
|
||||
fn main() {}
|
||||
|
@ -1,8 +1,10 @@
|
||||
error[E0015]: calls in statics are limited to constant functions, tuple structs and tuple variants
|
||||
error[E0015]: cannot call non-const fn `bar` in statics
|
||||
--> $DIR/mir_check_nonconst.rs:8:19
|
||||
|
|
||||
LL | static foo: Foo = bar();
|
||||
| ^^^^^
|
||||
|
|
||||
= note: calls in statics are limited to constant functions, tuple structs and tuple variants
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user