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:
bors 2022-02-13 07:04:56 +00:00
commit 9a60099cc4
157 changed files with 1563 additions and 1143 deletions

View File

@ -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
{

View File

@ -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

View File

@ -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
{

View File

@ -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;
}
}

View File

@ -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,
&param_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,

View 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 }
})
}

View File

@ -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;

View File

@ -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");

View File

@ -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.

View File

@ -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

View File

@ -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(&_)));

View File

@ -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,

View File

@ -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;

View File

@ -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)

View File

@ -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]>,

View File

@ -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(_)));
// _____________________________________________________________________________

View File

@ -184,6 +184,7 @@ symbols! {
Formatter,
From,
FromIterator,
FromResidual,
Future,
FxHashMap,
FxHashSet,

View File

@ -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) => {

View File

@ -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)),
)
}
}

View File

@ -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 == &param) {
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),
}
}
}

View File

@ -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)

View File

@ -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)]

View File

@ -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;

View File

@ -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",

View File

@ -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 {

View File

@ -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.

View File

@ -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")]

View File

@ -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")]

View File

@ -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()

View File

@ -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.

View File

@ -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()
}

View File

@ -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

View File

@ -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 {

View File

@ -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()
}

View File

@ -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)
}

View File

@ -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)
}

View File

@ -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,

View File

@ -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)
}

View File

@ -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
}
}
}

View File

@ -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]

View File

@ -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",

View File

@ -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,

View File

@ -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)]

View File

@ -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

View File

@ -1,5 +1,4 @@
// build-pass (FIXME(62277): could be check-pass?)
// ignore-compare-mode-chalk
#![feature(associated_type_bounds)]

View File

@ -1,5 +1,4 @@
// run-pass
// ignore-compare-mode-chalk
#![feature(associated_type_bounds)]
#![feature(untagged_unions)]

View File

@ -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;

View File

@ -1,4 +1,3 @@
// ignore-compare-mode-chalk
trait Z<'a, T: ?Sized>
where
T: Z<'a, u16>,

View File

@ -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

View File

@ -1,4 +1,3 @@
// ignore-compare-mode-chalk
trait Cycle: Sized {
type Next: Cycle<Next = Self>;
}

View File

@ -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

View File

@ -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>,

View File

@ -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 {

View File

@ -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`

View File

@ -0,0 +1,6 @@
// run-pass
// compile-flags: -Z chalk
fn main() {
assert_eq!(1, 1);
}

View File

@ -2,6 +2,5 @@
// compile-flags: -Z chalk
fn main() {
// FIXME(chalk): Require `RegionOutlives`/`TypeOutlives`/`Subtype` support
//println!("hello");
println!("hello");
}

View File

@ -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);

View File

@ -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>] = &[

View File

@ -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

View File

@ -1,6 +1,6 @@
struct X<const N: usize = {
(||1usize)()
//~^ ERROR calls in constants are limited to
//~^ ERROR cannot call
}>;
fn main() {}

View File

@ -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

View File

@ -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
{
}

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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() {}

View File

@ -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
}

View File

@ -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

View File

@ -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`.

View File

@ -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`.

View File

@ -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
}
}

View File

@ -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

View File

@ -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;
}

View File

@ -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

View File

@ -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

View File

@ -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() {}

View File

@ -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

View File

@ -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
};

View File

@ -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

View File

@ -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() {}

View File

@ -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

View File

@ -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() {}

View File

@ -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

View File

@ -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() {}

View File

@ -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

View File

@ -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
}
};

View File

@ -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

View File

@ -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 {

View File

@ -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

View File

@ -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()

View File

@ -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

View File

@ -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() {}

View File

@ -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

View File

@ -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;

View File

@ -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;

View File

@ -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 {

View File

@ -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() {}

View File

@ -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

View File

@ -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() {}

View File

@ -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