diff --git a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs index 7b8b5974fe7..f6d21f879ff 100644 --- a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs @@ -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 { diff --git a/compiler/rustc_borrowck/src/diagnostics/mod.rs b/compiler/rustc_borrowck/src/diagnostics/mod.rs index 84acfbf941d..4400fed13b7 100644 --- a/compiler/rustc_borrowck/src/diagnostics/mod.rs +++ b/compiler/rustc_borrowck/src/diagnostics/mod.rs @@ -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 diff --git a/compiler/rustc_borrowck/src/diagnostics/move_errors.rs b/compiler/rustc_borrowck/src/diagnostics/move_errors.rs index 2934d921868..b33b779edda 100644 --- a/compiler/rustc_borrowck/src/diagnostics/move_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/move_errors.rs @@ -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 { diff --git a/compiler/rustc_const_eval/src/transform/check_consts/check.rs b/compiler/rustc_const_eval/src/transform/check_consts/check.rs index 12a8b8c6d77..095c8f84f41 100644 --- a/compiler/rustc_const_eval/src/transform/check_consts/check.rs +++ b/compiler/rustc_const_eval/src/transform/check_consts/check.rs @@ -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(&mut self, op: O, span: Span) { + pub fn check_op_spanned>(&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 `::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; } } diff --git a/compiler/rustc_const_eval/src/transform/check_consts/ops.rs b/compiler/rustc_const_eval/src/transform/check_consts/ops.rs index 24c4a4915e5..519b4c02b61 100644 --- a/compiler/rustc_const_eval/src/transform/check_consts/ops.rs +++ b/compiler/rustc_const_eval/src/transform/check_consts/ops.rs @@ -3,14 +3,22 @@ use rustc_errors::{struct_span_err, Applicability, DiagnosticBuilder}; use rustc_hir as hir; use rustc_hir::def_id::DefId; +use rustc_infer::infer::TyCtxtInferExt; +use rustc_infer::traits::{ImplSource, Obligation, ObligationCause}; +use rustc_middle::mir; +use rustc_middle::ty::print::with_no_trimmed_paths; use rustc_middle::ty::subst::{GenericArgKind, SubstsRef}; -use rustc_middle::{mir, ty::AssocKind}; +use rustc_middle::ty::{ + suggest_constraining_type_param, Adt, Closure, FnDef, FnPtr, Param, TraitPredicate, Ty, +}; +use rustc_middle::ty::{Binder, BoundConstness, ImplPolarity, TraitRef}; use rustc_session::parse::feature_err; use rustc_span::symbol::sym; -use rustc_span::{symbol::Ident, Span, Symbol}; -use rustc_span::{BytePos, Pos}; +use rustc_span::{BytePos, Pos, Span, Symbol}; +use rustc_trait_selection::traits::SelectionContext; use super::ConstCx; +use crate::util::{call_kind, CallDesugaringKind, CallKind}; #[derive(Clone, Copy, Debug, PartialEq, Eq)] pub enum Status { @@ -29,9 +37,9 @@ pub enum DiagnosticImportance { } /// An operation that is not *always* allowed in a const context. -pub trait NonConstOp: std::fmt::Debug { +pub trait NonConstOp<'tcx>: std::fmt::Debug { /// Returns an enum indicating whether this operation is allowed within the given item. - fn status_in_item(&self, _ccx: &ConstCx<'_, '_>) -> Status { + fn status_in_item(&self, _ccx: &ConstCx<'_, 'tcx>) -> Status { Status::Forbidden } @@ -39,13 +47,13 @@ pub trait NonConstOp: std::fmt::Debug { DiagnosticImportance::Primary } - fn build_error<'tcx>(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx>; + fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx>; } #[derive(Debug)] pub struct FloatingPointOp; -impl NonConstOp for FloatingPointOp { - fn status_in_item(&self, ccx: &ConstCx<'_, '_>) -> Status { +impl<'tcx> NonConstOp<'tcx> for FloatingPointOp { + fn status_in_item(&self, ccx: &ConstCx<'_, 'tcx>) -> Status { if ccx.const_kind() == hir::ConstContext::ConstFn { Status::Unstable(sym::const_fn_floating_point_arithmetic) } else { @@ -53,7 +61,7 @@ impl NonConstOp for FloatingPointOp { } } - fn build_error<'tcx>(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> { + fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> { feature_err( &ccx.tcx.sess.parse_sess, sym::const_fn_floating_point_arithmetic, @@ -66,77 +74,229 @@ impl NonConstOp for FloatingPointOp { /// A function call where the callee is a pointer. #[derive(Debug)] pub struct FnCallIndirect; -impl NonConstOp for FnCallIndirect { - fn build_error<'tcx>(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> { +impl<'tcx> NonConstOp<'tcx> for FnCallIndirect { + fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> { ccx.tcx.sess.struct_span_err(span, "function pointers are not allowed in const fn") } } /// A function call where the callee is not marked as `const`. -#[derive(Debug)] -pub struct FnCallNonConst<'tcx>(pub Option<(DefId, SubstsRef<'tcx>)>); -impl<'a> NonConstOp for FnCallNonConst<'a> { - fn build_error<'tcx>(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> { - let mut err = struct_span_err!( - ccx.tcx.sess, - span, - E0015, - "calls in {}s are limited to constant functions, \ - tuple structs and tuple variants", - ccx.const_kind(), - ); +#[derive(Debug, Clone, Copy)] +pub struct FnCallNonConst<'tcx> { + pub caller: DefId, + pub callee: DefId, + pub substs: SubstsRef<'tcx>, + pub span: Span, + pub from_hir_call: bool, +} - if let FnCallNonConst(Some((callee, substs))) = *self { - if let Some(trait_def_id) = ccx.tcx.lang_items().eq_trait() { - if let Some(eq_item) = ccx.tcx.associated_items(trait_def_id).find_by_name_and_kind( - ccx.tcx, - Ident::with_dummy_span(sym::eq), - AssocKind::Fn, - trait_def_id, - ) { - if callee == eq_item.def_id && substs.len() == 2 { - match (substs[0].unpack(), substs[1].unpack()) { - (GenericArgKind::Type(self_ty), GenericArgKind::Type(rhs_ty)) - if self_ty == rhs_ty - && self_ty.is_ref() - && self_ty.peel_refs().is_primitive() => - { - let mut num_refs = 0; - let mut tmp_ty = self_ty; - while let rustc_middle::ty::Ref(_, inner_ty, _) = tmp_ty.kind() { - num_refs += 1; - tmp_ty = inner_ty; - } - let deref = "*".repeat(num_refs); +impl<'tcx> NonConstOp<'tcx> for FnCallNonConst<'tcx> { + fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, _: Span) -> DiagnosticBuilder<'tcx> { + let FnCallNonConst { caller, callee, substs, span, from_hir_call } = *self; + let ConstCx { tcx, param_env, .. } = *ccx; - if let Ok(call_str) = - ccx.tcx.sess.source_map().span_to_snippet(span) - { - if let Some(eq_idx) = call_str.find("==") { - if let Some(rhs_idx) = call_str[(eq_idx + 2)..] - .find(|c: char| !c.is_whitespace()) - { - let rhs_pos = span.lo() - + BytePos::from_usize(eq_idx + 2 + rhs_idx); - let rhs_span = span.with_lo(rhs_pos).with_hi(rhs_pos); - err.multipart_suggestion( - "consider dereferencing here", - vec![ - (span.shrink_to_lo(), deref.clone()), - (rhs_span, deref), - ], - Applicability::MachineApplicable, - ); - } + let diag_trait = |mut err, self_ty: Ty<'_>, trait_id| { + let trait_ref = TraitRef::from_method(tcx, trait_id, substs); + + match self_ty.kind() { + Param(param_ty) => { + debug!(?param_ty); + if let Some(generics) = caller + .as_local() + .map(|id| tcx.hir().local_def_id_to_hir_id(id)) + .map(|id| tcx.hir().get(id)) + .as_ref() + .and_then(|node| node.generics()) + { + let constraint = with_no_trimmed_paths(|| { + format!("~const {}", trait_ref.print_only_trait_path()) + }); + suggest_constraining_type_param( + tcx, + generics, + &mut err, + ¶m_ty.name.as_str(), + &constraint, + None, + ); + } + } + Adt(..) => { + let obligation = Obligation::new( + ObligationCause::dummy(), + param_env, + Binder::dummy(TraitPredicate { + trait_ref, + constness: BoundConstness::NotConst, + polarity: ImplPolarity::Positive, + }), + ); + + let implsrc = tcx.infer_ctxt().enter(|infcx| { + let mut selcx = SelectionContext::new(&infcx); + selcx.select(&obligation) + }); + + if let Ok(Some(ImplSource::UserDefined(data))) = implsrc { + let span = + tcx.sess.source_map().guess_head_span(tcx.def_span(data.impl_def_id)); + err.span_note(span, "impl defined here, but it is not `const`"); + } + } + _ => {} + } + + err + }; + + let call_kind = call_kind(tcx, ccx.param_env, callee, substs, span, from_hir_call, None); + + debug!(?call_kind); + + let mut err = match call_kind { + CallKind::Normal { desugaring: Some((kind, self_ty)), .. } => { + macro_rules! error { + ($fmt:literal) => { + struct_span_err!(tcx.sess, span, E0015, $fmt, self_ty, ccx.const_kind()) + }; + } + + let err = match kind { + CallDesugaringKind::ForLoopIntoIter => { + error!("cannot convert `{}` into an iterator in {}s") + } + CallDesugaringKind::QuestionBranch => { + error!("`?` cannot determine the branch of `{}` in {}s") + } + CallDesugaringKind::QuestionFromResidual => { + error!("`?` cannot convert from residual of `{}` in {}s") + } + CallDesugaringKind::TryBlockFromOutput => { + error!("`try` block cannot convert `{}` to the result in {}s") + } + }; + + diag_trait(err, self_ty, kind.trait_def_id(tcx)) + } + CallKind::FnCall { fn_trait_id, self_ty } => { + let mut err = struct_span_err!( + tcx.sess, + span, + E0015, + "cannot call non-const closure in {}s", + ccx.const_kind(), + ); + + match self_ty.kind() { + FnDef(def_id, ..) => { + let span = tcx.sess.source_map().guess_head_span(tcx.def_span(*def_id)); + if ccx.tcx.is_const_fn_raw(*def_id) { + span_bug!(span, "calling const FnDef errored when it shouldn't"); + } + + err.span_note(span, "function defined here, but it is not `const`"); + } + FnPtr(..) => { + err.note(&format!( + "function pointers need an RFC before allowed to be called in {}s", + ccx.const_kind() + )); + } + Closure(..) => { + err.note(&format!( + "closures need an RFC before allowed to be called in {}s", + ccx.const_kind() + )); + } + _ => {} + } + + diag_trait(err, self_ty, fn_trait_id) + } + CallKind::Operator { trait_id, self_ty, .. } => { + let mut err = struct_span_err!( + tcx.sess, + span, + E0015, + "cannot call non-const operator in {}s", + ccx.const_kind() + ); + + if Some(trait_id) == ccx.tcx.lang_items().eq_trait() { + match (substs[0].unpack(), substs[1].unpack()) { + (GenericArgKind::Type(self_ty), GenericArgKind::Type(rhs_ty)) + if self_ty == rhs_ty + && self_ty.is_ref() + && self_ty.peel_refs().is_primitive() => + { + let mut num_refs = 0; + let mut tmp_ty = self_ty; + while let rustc_middle::ty::Ref(_, inner_ty, _) = tmp_ty.kind() { + num_refs += 1; + tmp_ty = inner_ty; + } + let deref = "*".repeat(num_refs); + + if let Ok(call_str) = ccx.tcx.sess.source_map().span_to_snippet(span) { + if let Some(eq_idx) = call_str.find("==") { + if let Some(rhs_idx) = + call_str[(eq_idx + 2)..].find(|c: char| !c.is_whitespace()) + { + let rhs_pos = + span.lo() + BytePos::from_usize(eq_idx + 2 + rhs_idx); + let rhs_span = span.with_lo(rhs_pos).with_hi(rhs_pos); + err.multipart_suggestion( + "consider dereferencing here", + vec![ + (span.shrink_to_lo(), deref.clone()), + (rhs_span, deref), + ], + Applicability::MachineApplicable, + ); } } } - _ => {} } + _ => {} } } + + diag_trait(err, self_ty, trait_id) } - } + CallKind::DerefCoercion { deref_target, deref_target_ty, self_ty } => { + let mut err = struct_span_err!( + tcx.sess, + span, + E0015, + "cannot perform deref coercion on `{}` in {}s", + self_ty, + ccx.const_kind() + ); + + err.note(&format!("attempting to deref into `{}`", deref_target_ty)); + + // Check first whether the source is accessible (issue #87060) + if tcx.sess.source_map().span_to_snippet(deref_target).is_ok() { + err.span_note(deref_target, "deref defined here"); + } + + diag_trait(err, self_ty, tcx.lang_items().deref_trait().unwrap()) + } + _ => struct_span_err!( + ccx.tcx.sess, + span, + E0015, + "cannot call non-const fn `{}` in {}s", + ccx.tcx.def_path_str_with_substs(callee, substs), + ccx.const_kind(), + ), + }; + + err.note(&format!( + "calls in {}s are limited to constant functions, \ + tuple structs and tuple variants", + ccx.const_kind(), + )); err } @@ -148,8 +308,8 @@ impl<'a> NonConstOp for FnCallNonConst<'a> { #[derive(Debug)] pub struct FnCallUnstable(pub DefId, pub Option); -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, } -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, diff --git a/compiler/rustc_const_eval/src/util/call_kind.rs b/compiler/rustc_const_eval/src/util/call_kind.rs new file mode 100644 index 00000000000..11bb9508a1f --- /dev/null +++ b/compiler/rustc_const_eval/src/util/call_kind.rs @@ -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, + 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, 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, +) -> 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 } + }) +} diff --git a/compiler/rustc_const_eval/src/util/mod.rs b/compiler/rustc_const_eval/src/util/mod.rs index 4a406f8bfd0..a1876bed83e 100644 --- a/compiler/rustc_const_eval/src/util/mod.rs +++ b/compiler/rustc_const_eval/src/util/mod.rs @@ -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; diff --git a/compiler/rustc_hir/src/lang_items.rs b/compiler/rustc_hir/src/lang_items.rs index 603971a6a91..b299e71c9c4 100644 --- a/compiler/rustc_hir/src/lang_items.rs +++ b/compiler/rustc_hir/src/lang_items.rs @@ -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 { None } + const EMPTY: Vec = 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. diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index cab1d4e21c9..2e451502263 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -184,6 +184,7 @@ symbols! { Formatter, From, FromIterator, + FromResidual, Future, FxHashMap, FxHashSet, diff --git a/library/core/src/ops/try_trait.rs b/library/core/src/ops/try_trait.rs index eac426ad311..ba369e7f3aa 100644 --- a/library/core/src/ops/try_trait.rs +++ b/library/core/src/ops/try_trait.rs @@ -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::Residual> { /// Constructs the type from a compatible `Residual` type. diff --git a/src/test/ui/borrowck/issue-64453.rs b/src/test/ui/borrowck/issue-64453.rs index 9e70a847457..33d55be5812 100644 --- a/src/test/ui/borrowck/issue-64453.rs +++ b/src/test/ui/borrowck/issue-64453.rs @@ -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 { diff --git a/src/test/ui/borrowck/issue-64453.stderr b/src/test/ui/borrowck/issue-64453.stderr index 14e16670389..f3436fbec66 100644 --- a/src/test/ui/borrowck/issue-64453.stderr +++ b/src/test/ui/borrowck/issue-64453.stderr @@ -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` diff --git a/src/test/ui/check-static-values-constraints.rs b/src/test/ui/check-static-values-constraints.rs index 3d1b5a08227..eb4ecd8baca 100644 --- a/src/test/ui/check-static-values-constraints.rs +++ b/src/test/ui/check-static-values-constraints.rs @@ -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] = &[ diff --git a/src/test/ui/check-static-values-constraints.stderr b/src/test/ui/check-static-values-constraints.stderr index eb640c88e02..b28cf0d6bd0 100644 --- a/src/test/ui/check-static-values-constraints.stderr +++ b/src/test/ui/check-static-values-constraints.stderr @@ -15,11 +15,13 @@ error[E0010]: allocations are not allowed in statics LL | static STATIC11: Box = 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 `::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 diff --git a/src/test/ui/const-generics/issue-93647.rs b/src/test/ui/const-generics/issue-93647.rs index 6a8fe64d187..c1a6bf6e34d 100644 --- a/src/test/ui/const-generics/issue-93647.rs +++ b/src/test/ui/const-generics/issue-93647.rs @@ -1,6 +1,6 @@ struct X; fn main() {} diff --git a/src/test/ui/const-generics/issue-93647.stderr b/src/test/ui/const-generics/issue-93647.stderr index 0fe54e7de41..e2048ecd60f 100644 --- a/src/test/ui/const-generics/issue-93647.stderr +++ b/src/test/ui/const-generics/issue-93647.stderr @@ -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 diff --git a/src/test/ui/const-generics/issues/issue-90318.rs b/src/test/ui/const-generics/issues/issue-90318.rs index 0c640a5ef71..bebd0c6ac12 100644 --- a/src/test/ui/const-generics/issues/issue-90318.rs +++ b/src/test/ui/const-generics/issues/issue-90318.rs @@ -13,7 +13,7 @@ fn consume(_val: T) where If<{ TypeId::of::() != 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() where If<{ TypeId::of::() != 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 { } diff --git a/src/test/ui/const-generics/issues/issue-90318.stderr b/src/test/ui/const-generics/issues/issue-90318.stderr index 2b8afe2ef09..c8690ecd0da 100644 --- a/src/test/ui/const-generics/issues/issue-90318.stderr +++ b/src/test/ui/const-generics/issues/issue-90318.stderr @@ -9,11 +9,19 @@ LL | If<{ TypeId::of::() != 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::() != 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::() != 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::() != 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 diff --git a/src/test/ui/const-generics/nested-type.full.stderr b/src/test/ui/const-generics/nested-type.full.stderr index 9d7ca36545c..52f1c588258 100644 --- a/src/test/ui/const-generics/nested-type.full.stderr +++ b/src/test/ui/const-generics/nested-type.full.stderr @@ -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 diff --git a/src/test/ui/const-generics/nested-type.min.stderr b/src/test/ui/const-generics/nested-type.min.stderr index 4f32284ecb1..0e3c988ae4d 100644 --- a/src/test/ui/const-generics/nested-type.min.stderr +++ b/src/test/ui/const-generics/nested-type.min.stderr @@ -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 diff --git a/src/test/ui/const-generics/nested-type.rs b/src/test/ui/const-generics/nested-type.rs index 039f996de96..5240f5c3b0b 100644 --- a/src/test/ui/const-generics/nested-type.rs +++ b/src/test/ui/const-generics/nested-type.rs @@ -13,7 +13,7 @@ struct Foo::value() - //~^ ERROR calls in constants are limited to constant functions + //~^ ERROR cannot call non-const fn }]>; fn main() {} diff --git a/src/test/ui/consts/const-call.rs b/src/test/ui/consts/const-call.rs index db642988971..28e89559fe5 100644 --- a/src/test/ui/consts/const-call.rs +++ b/src/test/ui/consts/const-call.rs @@ -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 } diff --git a/src/test/ui/consts/const-call.stderr b/src/test/ui/consts/const-call.stderr index 9761348bab8..e46bcad0e1d 100644 --- a/src/test/ui/consts/const-call.stderr +++ b/src/test/ui/consts/const-call.stderr @@ -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 diff --git a/src/test/ui/consts/const-extern-fn/const-extern-fn-call-extern-fn.rs b/src/test/ui/consts/const-extern-fn/const-extern-fn-call-extern-fn.rs index ee07dfae47c..eccda49db3e 100644 --- a/src/test/ui/consts/const-extern-fn/const-extern-fn-call-extern-fn.rs +++ b/src/test/ui/consts/const-extern-fn/const-extern-fn-call-extern-fn.rs @@ -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 } } diff --git a/src/test/ui/consts/const-extern-fn/const-extern-fn-call-extern-fn.stderr b/src/test/ui/consts/const-extern-fn/const-extern-fn-call-extern-fn.stderr index 348387ff5f8..5acf22e4bc6 100644 --- a/src/test/ui/consts/const-extern-fn/const-extern-fn-call-extern-fn.stderr +++ b/src/test/ui/consts/const-extern-fn/const-extern-fn-call-extern-fn.stderr @@ -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 diff --git a/src/test/ui/consts/const-fn-error.rs b/src/test/ui/consts/const-fn-error.rs index 065944ea7ea..abe68c17a0d 100644 --- a/src/test/ui/consts/const-fn-error.rs +++ b/src/test/ui/consts/const-fn-error.rs @@ -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; } diff --git a/src/test/ui/consts/const-fn-error.stderr b/src/test/ui/consts/const-fn-error.stderr index e4b62f20a33..4d53cfc35e1 100644 --- a/src/test/ui/consts/const-fn-error.stderr +++ b/src/test/ui/consts/const-fn-error.stderr @@ -13,11 +13,18 @@ LL | | } = note: see issue #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` 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 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 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 ` 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 diff --git a/src/test/ui/consts/const-fn-not-safe-for-const.stderr b/src/test/ui/consts/const-fn-not-safe-for-const.stderr index df793d7dd7e..4c7effc0d15 100644 --- a/src/test/ui/consts/const-fn-not-safe-for-const.stderr +++ b/src/test/ui/consts/const-fn-not-safe-for-const.stderr @@ -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 diff --git a/src/test/ui/consts/const-for.rs b/src/test/ui/consts/const-for.rs index 5fc1ee0e369..58bcb5f74cc 100644 --- a/src/test/ui/consts/const-for.rs +++ b/src/test/ui/consts/const-for.rs @@ -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() {} diff --git a/src/test/ui/consts/const-for.stderr b/src/test/ui/consts/const-for.stderr index a35c04b3570..b0dc43eb8e8 100644 --- a/src/test/ui/consts/const-for.stderr +++ b/src/test/ui/consts/const-for.stderr @@ -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` 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 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 ` 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 diff --git a/src/test/ui/consts/control-flow/issue-46843.rs b/src/test/ui/consts/control-flow/issue-46843.rs index edf62f23266..ddddc8505c6 100644 --- a/src/test/ui/consts/control-flow/issue-46843.rs +++ b/src/test/ui/consts/control-flow/issue-46843.rs @@ -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 }; diff --git a/src/test/ui/consts/control-flow/issue-46843.stderr b/src/test/ui/consts/control-flow/issue-46843.stderr index ea9ea25f9e1..66227f61e35 100644 --- a/src/test/ui/consts/control-flow/issue-46843.stderr +++ b/src/test/ui/consts/control-flow/issue-46843.stderr @@ -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 diff --git a/src/test/ui/consts/intrinsic_without_const_stab.rs b/src/test/ui/consts/intrinsic_without_const_stab.rs index 810158a2957..d5f694986fc 100644 --- a/src/test/ui/consts/intrinsic_without_const_stab.rs +++ b/src/test/ui/consts/intrinsic_without_const_stab.rs @@ -11,7 +11,7 @@ pub const unsafe fn copy(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() {} diff --git a/src/test/ui/consts/intrinsic_without_const_stab.stderr b/src/test/ui/consts/intrinsic_without_const_stab.stderr index 5a42823a605..b32b6398ece 100644 --- a/src/test/ui/consts/intrinsic_without_const_stab.stderr +++ b/src/test/ui/consts/intrinsic_without_const_stab.stderr @@ -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::` 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 diff --git a/src/test/ui/consts/intrinsic_without_const_stab_fail.rs b/src/test/ui/consts/intrinsic_without_const_stab_fail.rs index bf2c44169d4..8b37268b0b2 100644 --- a/src/test/ui/consts/intrinsic_without_const_stab_fail.rs +++ b/src/test/ui/consts/intrinsic_without_const_stab_fail.rs @@ -9,7 +9,7 @@ extern "rust-intrinsic" { #[rustc_const_unstable(feature = "const_intrinsic_copy", issue = "80697")] #[inline] pub const unsafe fn stuff(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() {} diff --git a/src/test/ui/consts/intrinsic_without_const_stab_fail.stderr b/src/test/ui/consts/intrinsic_without_const_stab_fail.stderr index d4a2989e785..fcbb3724567 100644 --- a/src/test/ui/consts/intrinsic_without_const_stab_fail.stderr +++ b/src/test/ui/consts/intrinsic_without_const_stab_fail.stderr @@ -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::` 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 diff --git a/src/test/ui/consts/issue-28113.rs b/src/test/ui/consts/issue-28113.rs index e5bd7aafe41..f8131c9f3b7 100644 --- a/src/test/ui/consts/issue-28113.rs +++ b/src/test/ui/consts/issue-28113.rs @@ -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() {} diff --git a/src/test/ui/consts/issue-28113.stderr b/src/test/ui/consts/issue-28113.stderr index 3d274d777b0..7ad1f752eb0 100644 --- a/src/test/ui/consts/issue-28113.stderr +++ b/src/test/ui/consts/issue-28113.stderr @@ -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 diff --git a/src/test/ui/consts/issue-32829-2.rs b/src/test/ui/consts/issue-32829-2.rs index e0fcf278330..d70b5a8c4e1 100644 --- a/src/test/ui/consts/issue-32829-2.rs +++ b/src/test/ui/consts/issue-32829-2.rs @@ -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 } }; diff --git a/src/test/ui/consts/issue-32829-2.stderr b/src/test/ui/consts/issue-32829-2.stderr index 1d265875c5c..b94bdc0e3df 100644 --- a/src/test/ui/consts/issue-32829-2.stderr +++ b/src/test/ui/consts/issue-32829-2.stderr @@ -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 diff --git a/src/test/ui/consts/issue-43105.rs b/src/test/ui/consts/issue-43105.rs index cc6a4850853..cac12b90970 100644 --- a/src/test/ui/consts/issue-43105.rs +++ b/src/test/ui/consts/issue-43105.rs @@ -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 { diff --git a/src/test/ui/consts/issue-43105.stderr b/src/test/ui/consts/issue-43105.stderr index e508cbdd1dd..2d1174af71c 100644 --- a/src/test/ui/consts/issue-43105.stderr +++ b/src/test/ui/consts/issue-43105.stderr @@ -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 diff --git a/src/test/ui/consts/issue-56164.rs b/src/test/ui/consts/issue-56164.rs index 90ea217698d..9c673d20b2a 100644 --- a/src/test/ui/consts/issue-56164.rs +++ b/src/test/ui/consts/issue-56164.rs @@ -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() diff --git a/src/test/ui/consts/issue-56164.stderr b/src/test/ui/consts/issue-56164.stderr index 500af0a4006..62a7c7db6b8 100644 --- a/src/test/ui/consts/issue-56164.stderr +++ b/src/test/ui/consts/issue-56164.stderr @@ -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 diff --git a/src/test/ui/consts/issue-68542-closure-in-array-len.rs b/src/test/ui/consts/issue-68542-closure-in-array-len.rs index d77fd9aa831..37958e7919d 100644 --- a/src/test/ui/consts/issue-68542-closure-in-array-len.rs +++ b/src/test/ui/consts/issue-68542-closure-in-array-len.rs @@ -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() {} diff --git a/src/test/ui/consts/issue-68542-closure-in-array-len.stderr b/src/test/ui/consts/issue-68542-closure-in-array-len.stderr index 74d70e18a24..74fbbc680f7 100644 --- a/src/test/ui/consts/issue-68542-closure-in-array-len.stderr +++ b/src/test/ui/consts/issue-68542-closure-in-array-len.stderr @@ -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 diff --git a/src/test/ui/consts/issue-90870.fixed b/src/test/ui/consts/issue-90870.fixed index e767effcdd0..0d28e06e532 100644 --- a/src/test/ui/consts/issue-90870.fixed +++ b/src/test/ui/consts/issue-90870.fixed @@ -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; diff --git a/src/test/ui/consts/issue-90870.rs b/src/test/ui/consts/issue-90870.rs index 35b3c8242aa..c6bfffd2c5c 100644 --- a/src/test/ui/consts/issue-90870.rs +++ b/src/test/ui/consts/issue-90870.rs @@ -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; diff --git a/src/test/ui/consts/issue-90870.stderr b/src/test/ui/consts/issue-90870.stderr index 0e33e6ebe5a..478445cfb39 100644 --- a/src/test/ui/consts/issue-90870.stderr +++ b/src/test/ui/consts/issue-90870.stderr @@ -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 { diff --git a/src/test/ui/consts/min_const_fn/bad_const_fn_body_ice.rs b/src/test/ui/consts/min_const_fn/bad_const_fn_body_ice.rs index 4e1b7bf119c..258997597ea 100644 --- a/src/test/ui/consts/min_const_fn/bad_const_fn_body_ice.rs +++ b/src/test/ui/consts/min_const_fn/bad_const_fn_body_ice.rs @@ -1,7 +1,7 @@ const fn foo(a: i32) -> Vec { vec![1, 2, 3] //~^ ERROR allocations are not allowed - //~| ERROR calls in constant functions + //~| ERROR cannot call non-const fn } fn main() {} diff --git a/src/test/ui/consts/min_const_fn/bad_const_fn_body_ice.stderr b/src/test/ui/consts/min_const_fn/bad_const_fn_body_ice.stderr index fee43864e20..74234108911 100644 --- a/src/test/ui/consts/min_const_fn/bad_const_fn_body_ice.stderr +++ b/src/test/ui/consts/min_const_fn/bad_const_fn_body_ice.stderr @@ -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::::into_vec::` 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 diff --git a/src/test/ui/consts/mir_check_nonconst.rs b/src/test/ui/consts/mir_check_nonconst.rs index b8ec0c3c449..b6f34b922fa 100644 --- a/src/test/ui/consts/mir_check_nonconst.rs +++ b/src/test/ui/consts/mir_check_nonconst.rs @@ -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() {} diff --git a/src/test/ui/consts/mir_check_nonconst.stderr b/src/test/ui/consts/mir_check_nonconst.stderr index 30f68ba4372..2bac995eebf 100644 --- a/src/test/ui/consts/mir_check_nonconst.stderr +++ b/src/test/ui/consts/mir_check_nonconst.stderr @@ -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 diff --git a/src/test/ui/consts/unstable-const-fn-in-libcore.stderr b/src/test/ui/consts/unstable-const-fn-in-libcore.stderr index 928605356a1..4ef25bd1334 100644 --- a/src/test/ui/consts/unstable-const-fn-in-libcore.stderr +++ b/src/test/ui/consts/unstable-const-fn-in-libcore.stderr @@ -1,8 +1,14 @@ -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/unstable-const-fn-in-libcore.rs:24:26 | LL | Opt::None => f(), | ^^^ + | + = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants +help: consider further restricting this bound + | +LL | const fn unwrap_or_else T + ~const std::ops::FnOnce<()>>(self, f: F) -> T { + | +++++++++++++++++++++++++++++ error[E0493]: destructors cannot be evaluated at compile-time --> $DIR/unstable-const-fn-in-libcore.rs:19:53 diff --git a/src/test/ui/issues/issue-16538.mir.stderr b/src/test/ui/issues/issue-16538.mir.stderr index 5a276f27886..60a2bf1e2d6 100644 --- a/src/test/ui/issues/issue-16538.mir.stderr +++ b/src/test/ui/issues/issue-16538.mir.stderr @@ -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 `Y::foo` in statics --> $DIR/issue-16538.rs:15:23 | LL | static foo: &Y::X = &*Y::foo(Y::x as *const Y::X); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: calls in statics are limited to constant functions, tuple structs and tuple variants error[E0133]: use of extern static is unsafe and requires unsafe function or block --> $DIR/issue-16538.rs:15:30 diff --git a/src/test/ui/issues/issue-16538.thir.stderr b/src/test/ui/issues/issue-16538.thir.stderr index 8365a1dbf6e..2ba9dfa2bc5 100644 --- a/src/test/ui/issues/issue-16538.thir.stderr +++ b/src/test/ui/issues/issue-16538.thir.stderr @@ -14,11 +14,13 @@ LL | static foo: &Y::X = &*Y::foo(Y::x as *const Y::X); | = note: extern statics are not controlled by the Rust type system: invalid data, aliasing violations or data races will cause undefined behavior -error[E0015]: calls in statics are limited to constant functions, tuple structs and tuple variants +error[E0015]: cannot call non-const fn `Y::foo` in statics --> $DIR/issue-16538.rs:15:23 | LL | static foo: &Y::X = &*Y::foo(Y::x as *const Y::X); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: calls in statics are limited to constant functions, tuple structs and tuple variants error: aborting due to 3 previous errors diff --git a/src/test/ui/issues/issue-25901.rs b/src/test/ui/issues/issue-25901.rs index a139ad0d3e3..ba12e1ad021 100644 --- a/src/test/ui/issues/issue-25901.rs +++ b/src/test/ui/issues/issue-25901.rs @@ -2,7 +2,7 @@ struct A; struct B; static S: &'static B = &A; -//~^ ERROR calls in statics are limited to constant functions +//~^ ERROR cannot perform deref coercion on `A` in statics use std::ops::Deref; diff --git a/src/test/ui/issues/issue-25901.stderr b/src/test/ui/issues/issue-25901.stderr index d6eb3760cdf..5c35250bc3f 100644 --- a/src/test/ui/issues/issue-25901.stderr +++ b/src/test/ui/issues/issue-25901.stderr @@ -1,8 +1,21 @@ -error[E0015]: calls in statics are limited to constant functions, tuple structs and tuple variants +error[E0015]: cannot perform deref coercion on `A` in statics --> $DIR/issue-25901.rs:4:24 | LL | static S: &'static B = &A; | ^^ + | + = note: attempting to deref into `B` +note: deref defined here + --> $DIR/issue-25901.rs:10:5 + | +LL | type Target = B; + | ^^^^^^^^^^^^^^^^ +note: impl defined here, but it is not `const` + --> $DIR/issue-25901.rs:9:1 + | +LL | impl Deref for A { + | ^^^^^^^^^^^^^^^^ + = note: calls in statics are limited to constant functions, tuple structs and tuple variants error: aborting due to previous error diff --git a/src/test/ui/issues/issue-39559-2.stderr b/src/test/ui/issues/issue-39559-2.stderr index 3d765daa7cd..ea27e7bd250 100644 --- a/src/test/ui/issues/issue-39559-2.stderr +++ b/src/test/ui/issues/issue-39559-2.stderr @@ -1,14 +1,18 @@ -error[E0015]: calls in constants are limited to constant functions, tuple structs and tuple variants +error[E0015]: cannot call non-const fn `::dim` in constants --> $DIR/issue-39559-2.rs:14:24 | LL | let array: [usize; Dim3::dim()] | ^^^^^^^^^^^ + | + = 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 `::dim` in constants --> $DIR/issue-39559-2.rs:16:15 | LL | = [0; Dim3::dim()]; | ^^^^^^^^^^^ + | + = note: calls in constants are limited to constant functions, tuple structs and tuple variants error: aborting due to 2 previous errors diff --git a/src/test/ui/never_type/issue-52443.rs b/src/test/ui/never_type/issue-52443.rs index 4519833b864..cebcca944af 100644 --- a/src/test/ui/never_type/issue-52443.rs +++ b/src/test/ui/never_type/issue-52443.rs @@ -8,7 +8,7 @@ fn main() { [(); { for _ in 0usize.. {}; 0}]; //~^ ERROR `for` is not allowed in a `const` - //~| ERROR calls in constants are limited to constant functions + //~| ERROR cannot convert //~| ERROR mutable references are not allowed in constants - //~| ERROR calls in constants are limited to constant functions + //~| ERROR cannot call non-const fn } diff --git a/src/test/ui/never_type/issue-52443.stderr b/src/test/ui/never_type/issue-52443.stderr index 216b56f7059..8c1755205f0 100644 --- a/src/test/ui/never_type/issue-52443.stderr +++ b/src/test/ui/never_type/issue-52443.stderr @@ -38,11 +38,18 @@ LL | [(); loop { break }]; | expected `usize`, found `()` | help: give it a value of the expected type: `break 42` -error[E0015]: calls in constants are limited to constant functions, tuple structs and tuple variants +error[E0015]: cannot convert `RangeFrom` into an iterator in constants --> $DIR/issue-52443.rs:9:21 | LL | [(); { for _ in 0usize.. {}; 0}]; | ^^^^^^^^ + | +note: impl defined here, but it is not `const` + --> $SRC_DIR/core/src/iter/traits/collect.rs:LL:COL + | +LL | impl IntoIterator for I { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: calls in constants are limited to constant functions, tuple structs and tuple variants error[E0658]: mutable references are not allowed in constants --> $DIR/issue-52443.rs:9:21 @@ -53,11 +60,13 @@ LL | [(); { for _ in 0usize.. {}; 0}]; = note: see issue #57349 for more information = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable -error[E0015]: calls in constants are limited to constant functions, tuple structs and tuple variants +error[E0015]: cannot call non-const fn ` as Iterator>::next` in constants --> $DIR/issue-52443.rs:9:21 | LL | [(); { for _ in 0usize.. {}; 0}]; | ^^^^^^^^ + | + = note: calls in constants are limited to constant functions, tuple structs and tuple variants error: aborting due to 6 previous errors; 1 warning emitted diff --git a/src/test/ui/rfc-2632-const-trait-impl/call-const-trait-method-fail.rs b/src/test/ui/rfc-2632-const-trait-impl/call-const-trait-method-fail.rs index 33e839fd120..24b9235bb9a 100644 --- a/src/test/ui/rfc-2632-const-trait-impl/call-const-trait-method-fail.rs +++ b/src/test/ui/rfc-2632-const-trait-impl/call-const-trait-method-fail.rs @@ -22,7 +22,8 @@ pub const fn add_i32(a: i32, b: i32) -> i32 { pub const fn add_u32(a: u32, b: u32) -> u32 { a.plus(b) - //~^ ERROR calls in constant functions are limited to constant functions + //~^ ERROR the trait bound + //~| ERROR cannot call non-const fn } fn main() {} diff --git a/src/test/ui/rfc-2632-const-trait-impl/call-const-trait-method-fail.stderr b/src/test/ui/rfc-2632-const-trait-impl/call-const-trait-method-fail.stderr index 5a73c4debb4..1fc9db27761 100644 --- a/src/test/ui/rfc-2632-const-trait-impl/call-const-trait-method-fail.stderr +++ b/src/test/ui/rfc-2632-const-trait-impl/call-const-trait-method-fail.stderr @@ -1,9 +1,24 @@ -error[E0015]: calls in constant functions are limited to constant functions, tuple structs and tuple variants - --> $DIR/call-const-trait-method-fail.rs:24:5 +error[E0277]: the trait bound `u32: ~const Plus` is not satisfied + --> $DIR/call-const-trait-method-fail.rs:24:7 | LL | a.plus(b) - | ^^^^^^^^^ + | ^^^^^^^ the trait `~const Plus` is not implemented for `u32` + | +note: the trait `Plus` is implemented for `u32`, but that implementation is not `const` + --> $DIR/call-const-trait-method-fail.rs:24:7 + | +LL | a.plus(b) + | ^^^^^^^ -error: aborting due to previous error +error[E0015]: cannot call non-const fn `::plus` in constant functions + --> $DIR/call-const-trait-method-fail.rs:24:7 + | +LL | a.plus(b) + | ^^^^^^^ + | + = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants -For more information about this error, try `rustc --explain E0015`. +error: aborting due to 2 previous errors + +Some errors have detailed explanations: E0015, E0277. +For more information about an error, try `rustc --explain E0015`. diff --git a/src/test/ui/rfc-2632-const-trait-impl/call-generic-method-fail.rs b/src/test/ui/rfc-2632-const-trait-impl/call-generic-method-fail.rs index e96249ff2fd..e81e0d1e571 100644 --- a/src/test/ui/rfc-2632-const-trait-impl/call-generic-method-fail.rs +++ b/src/test/ui/rfc-2632-const-trait-impl/call-generic-method-fail.rs @@ -3,7 +3,8 @@ pub const fn equals_self(t: &T) -> bool { *t == *t - //~^ ERROR calls in constant functions are limited to constant functions + //~^ ERROR can't compare + //~| ERROR cannot call non-const } fn main() {} diff --git a/src/test/ui/rfc-2632-const-trait-impl/call-generic-method-fail.stderr b/src/test/ui/rfc-2632-const-trait-impl/call-generic-method-fail.stderr index 818c5828696..3963f64ad32 100644 --- a/src/test/ui/rfc-2632-const-trait-impl/call-generic-method-fail.stderr +++ b/src/test/ui/rfc-2632-const-trait-impl/call-generic-method-fail.stderr @@ -1,9 +1,28 @@ -error[E0015]: calls in constant functions are limited to constant functions, tuple structs and tuple variants +error[E0277]: can't compare `T` with `T` in const contexts + --> $DIR/call-generic-method-fail.rs:5:5 + | +LL | *t == *t + | ^^^^^^^^ no implementation for `T == T` + | +note: the trait `PartialEq` is implemented for `T`, but that implementation is not `const` --> $DIR/call-generic-method-fail.rs:5:5 | LL | *t == *t | ^^^^^^^^ -error: aborting due to previous error +error[E0015]: cannot call non-const operator in constant functions + --> $DIR/call-generic-method-fail.rs:5:5 + | +LL | *t == *t + | ^^^^^^^^ + | + = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants +help: consider further restricting this bound + | +LL | pub const fn equals_self(t: &T) -> bool { + | ++++++++++++++++++++++++++++ -For more information about this error, try `rustc --explain E0015`. +error: aborting due to 2 previous errors + +Some errors have detailed explanations: E0015, E0277. +For more information about an error, try `rustc --explain E0015`. diff --git a/src/test/ui/rfc-2632-const-trait-impl/const-check-fns-in-const-impl.rs b/src/test/ui/rfc-2632-const-trait-impl/const-check-fns-in-const-impl.rs index 3a707416352..b3e3dd62be8 100644 --- a/src/test/ui/rfc-2632-const-trait-impl/const-check-fns-in-const-impl.rs +++ b/src/test/ui/rfc-2632-const-trait-impl/const-check-fns-in-const-impl.rs @@ -9,7 +9,7 @@ fn non_const() {} impl const T for S { fn foo() { non_const() } - //~^ ERROR calls in constant functions + //~^ ERROR cannot call non-const fn } fn main() {} diff --git a/src/test/ui/rfc-2632-const-trait-impl/const-check-fns-in-const-impl.stderr b/src/test/ui/rfc-2632-const-trait-impl/const-check-fns-in-const-impl.stderr index aaec67161a6..9e49785c589 100644 --- a/src/test/ui/rfc-2632-const-trait-impl/const-check-fns-in-const-impl.stderr +++ b/src/test/ui/rfc-2632-const-trait-impl/const-check-fns-in-const-impl.stderr @@ -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 `non_const` in constant functions --> $DIR/const-check-fns-in-const-impl.rs:11:16 | LL | fn foo() { non_const() } | ^^^^^^^^^^^ + | + = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants error: aborting due to previous error diff --git a/src/test/ui/rfc-2632-const-trait-impl/const-default-method-bodies.rs b/src/test/ui/rfc-2632-const-trait-impl/const-default-method-bodies.rs index 7a0db9c98ea..3e87787a091 100644 --- a/src/test/ui/rfc-2632-const-trait-impl/const-default-method-bodies.rs +++ b/src/test/ui/rfc-2632-const-trait-impl/const-default-method-bodies.rs @@ -23,7 +23,8 @@ impl const ConstDefaultFn for ConstImpl { const fn test() { NonConstImpl.a(); - //~^ ERROR calls in constant functions are limited to constant functions, tuple structs and tuple variants + //~^ ERROR the trait bound + //~| ERROR cannot call non-const fn ConstImpl.a(); } diff --git a/src/test/ui/rfc-2632-const-trait-impl/const-default-method-bodies.stderr b/src/test/ui/rfc-2632-const-trait-impl/const-default-method-bodies.stderr index 63e4095af29..948830d6def 100644 --- a/src/test/ui/rfc-2632-const-trait-impl/const-default-method-bodies.stderr +++ b/src/test/ui/rfc-2632-const-trait-impl/const-default-method-bodies.stderr @@ -1,9 +1,24 @@ -error[E0015]: calls in constant functions are limited to constant functions, tuple structs and tuple variants - --> $DIR/const-default-method-bodies.rs:25:5 +error[E0277]: the trait bound `NonConstImpl: ~const ConstDefaultFn` is not satisfied + --> $DIR/const-default-method-bodies.rs:25:18 | LL | NonConstImpl.a(); - | ^^^^^^^^^^^^^^^^ + | ^^^ the trait `~const ConstDefaultFn` is not implemented for `NonConstImpl` + | +note: the trait `ConstDefaultFn` is implemented for `NonConstImpl`, but that implementation is not `const` + --> $DIR/const-default-method-bodies.rs:25:18 + | +LL | NonConstImpl.a(); + | ^^^ -error: aborting due to previous error +error[E0015]: cannot call non-const fn `::a` in constant functions + --> $DIR/const-default-method-bodies.rs:25:18 + | +LL | NonConstImpl.a(); + | ^^^ + | + = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants -For more information about this error, try `rustc --explain E0015`. +error: aborting due to 2 previous errors + +Some errors have detailed explanations: E0015, E0277. +For more information about an error, try `rustc --explain E0015`. diff --git a/src/test/ui/rfc-2632-const-trait-impl/cross-crate.gated.stderr b/src/test/ui/rfc-2632-const-trait-impl/cross-crate.gated.stderr index 3f553a8ee70..3ca9abb139b 100644 --- a/src/test/ui/rfc-2632-const-trait-impl/cross-crate.gated.stderr +++ b/src/test/ui/rfc-2632-const-trait-impl/cross-crate.gated.stderr @@ -1,9 +1,24 @@ -error[E0015]: calls in constant functions are limited to constant functions, tuple structs and tuple variants - --> $DIR/cross-crate.rs:15:5 +error[E0277]: the trait bound `cross_crate::NonConst: ~const cross_crate::MyTrait` is not satisfied + --> $DIR/cross-crate.rs:15:14 | LL | NonConst.func(); - | ^^^^^^^^^^^^^^^ + | ^^^^^^ the trait `~const cross_crate::MyTrait` is not implemented for `cross_crate::NonConst` + | +note: the trait `cross_crate::MyTrait` is implemented for `cross_crate::NonConst`, but that implementation is not `const` + --> $DIR/cross-crate.rs:15:14 + | +LL | NonConst.func(); + | ^^^^^^ -error: aborting due to previous error +error[E0015]: cannot call non-const fn `::func` in constant functions + --> $DIR/cross-crate.rs:15:14 + | +LL | NonConst.func(); + | ^^^^^^ + | + = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants -For more information about this error, try `rustc --explain E0015`. +error: aborting due to 2 previous errors + +Some errors have detailed explanations: E0015, E0277. +For more information about an error, try `rustc --explain E0015`. diff --git a/src/test/ui/rfc-2632-const-trait-impl/cross-crate.rs b/src/test/ui/rfc-2632-const-trait-impl/cross-crate.rs index 4bd3359947d..fa049ab86ff 100644 --- a/src/test/ui/rfc-2632-const-trait-impl/cross-crate.rs +++ b/src/test/ui/rfc-2632-const-trait-impl/cross-crate.rs @@ -12,10 +12,10 @@ fn non_const_context() { } const fn const_context() { - NonConst.func(); - //~^ ERROR: calls in constant functions are limited to constant functions, tuple structs and tuple variants + NonConst.func(); //~ ERROR: cannot call non-const fn + //[gated]~^ ERROR: the trait bound Const.func(); - //[stock]~^ ERROR: calls in constant functions are limited to constant functions, tuple structs and tuple variants + //[stock]~^ ERROR: cannot call non-const fn } fn main() {} diff --git a/src/test/ui/rfc-2632-const-trait-impl/cross-crate.stock.stderr b/src/test/ui/rfc-2632-const-trait-impl/cross-crate.stock.stderr index 9908f47a7b2..ea75ad0aeaf 100644 --- a/src/test/ui/rfc-2632-const-trait-impl/cross-crate.stock.stderr +++ b/src/test/ui/rfc-2632-const-trait-impl/cross-crate.stock.stderr @@ -1,14 +1,18 @@ -error[E0015]: calls in constant functions are limited to constant functions, tuple structs and tuple variants - --> $DIR/cross-crate.rs:15:5 +error[E0015]: cannot call non-const fn `::func` in constant functions + --> $DIR/cross-crate.rs:15:14 | LL | NonConst.func(); - | ^^^^^^^^^^^^^^^ + | ^^^^^^ + | + = 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 - --> $DIR/cross-crate.rs:17:5 +error[E0015]: cannot call non-const fn `::func` in constant functions + --> $DIR/cross-crate.rs:17:11 | LL | Const.func(); - | ^^^^^^^^^^^^ + | ^^^^^^ + | + = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants error: aborting due to 2 previous errors diff --git a/src/test/ui/rfc-2632-const-trait-impl/default-method-body-is-const-same-trait-ck.rs b/src/test/ui/rfc-2632-const-trait-impl/default-method-body-is-const-same-trait-ck.rs index cccb856c2f6..4d087b5180b 100644 --- a/src/test/ui/rfc-2632-const-trait-impl/default-method-body-is-const-same-trait-ck.rs +++ b/src/test/ui/rfc-2632-const-trait-impl/default-method-body-is-const-same-trait-ck.rs @@ -8,7 +8,8 @@ pub trait Tr { #[default_method_body_is_const] fn b(&self) { ().a() - //~^ ERROR calls in constant functions are limited + //~^ ERROR the trait bound + //~| ERROR cannot call } } diff --git a/src/test/ui/rfc-2632-const-trait-impl/default-method-body-is-const-same-trait-ck.stderr b/src/test/ui/rfc-2632-const-trait-impl/default-method-body-is-const-same-trait-ck.stderr index 91f4d2fd4b0..db4d61f88ab 100644 --- a/src/test/ui/rfc-2632-const-trait-impl/default-method-body-is-const-same-trait-ck.stderr +++ b/src/test/ui/rfc-2632-const-trait-impl/default-method-body-is-const-same-trait-ck.stderr @@ -1,9 +1,24 @@ -error[E0015]: calls in constant functions are limited to constant functions, tuple structs and tuple variants - --> $DIR/default-method-body-is-const-same-trait-ck.rs:10:9 +error[E0277]: the trait bound `(): ~const Tr` is not satisfied + --> $DIR/default-method-body-is-const-same-trait-ck.rs:10:12 | LL | ().a() - | ^^^^^^ + | ^^^ the trait `~const Tr` is not implemented for `()` + | +note: the trait `Tr` is implemented for `()`, but that implementation is not `const` + --> $DIR/default-method-body-is-const-same-trait-ck.rs:10:12 + | +LL | ().a() + | ^^^ -error: aborting due to previous error +error[E0015]: cannot call non-const fn `<() as Tr>::a` in constant functions + --> $DIR/default-method-body-is-const-same-trait-ck.rs:10:12 + | +LL | ().a() + | ^^^ + | + = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants -For more information about this error, try `rustc --explain E0015`. +error: aborting due to 2 previous errors + +Some errors have detailed explanations: E0015, E0277. +For more information about an error, try `rustc --explain E0015`. diff --git a/src/test/ui/rfc-2632-const-trait-impl/issue-88155.rs b/src/test/ui/rfc-2632-const-trait-impl/issue-88155.rs index 157005bba7b..cbe3fe0ce5f 100644 --- a/src/test/ui/rfc-2632-const-trait-impl/issue-88155.rs +++ b/src/test/ui/rfc-2632-const-trait-impl/issue-88155.rs @@ -7,7 +7,8 @@ pub trait A { pub const fn foo() -> bool { T::assoc() - //~^ ERROR calls in constant functions are limited + //~^ ERROR the trait bound + //~| ERROR cannot call non-const fn } fn main() {} diff --git a/src/test/ui/rfc-2632-const-trait-impl/issue-88155.stderr b/src/test/ui/rfc-2632-const-trait-impl/issue-88155.stderr index 931baac5389..931c0b3658f 100644 --- a/src/test/ui/rfc-2632-const-trait-impl/issue-88155.stderr +++ b/src/test/ui/rfc-2632-const-trait-impl/issue-88155.stderr @@ -1,9 +1,24 @@ -error[E0015]: calls in constant functions are limited to constant functions, tuple structs and tuple variants +error[E0277]: the trait bound `T: ~const A` is not satisfied + --> $DIR/issue-88155.rs:9:5 + | +LL | T::assoc() + | ^^^^^^^^^^ the trait `~const A` is not implemented for `T` + | +note: the trait `A` is implemented for `T`, but that implementation is not `const` --> $DIR/issue-88155.rs:9:5 | LL | T::assoc() | ^^^^^^^^^^ -error: aborting due to previous error +error[E0015]: cannot call non-const fn `::assoc` in constant functions + --> $DIR/issue-88155.rs:9:5 + | +LL | T::assoc() + | ^^^^^^^^^^ + | + = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants -For more information about this error, try `rustc --explain E0015`. +error: aborting due to 2 previous errors + +Some errors have detailed explanations: E0015, E0277. +For more information about an error, try `rustc --explain E0015`. diff --git a/src/test/ui/rfc-2632-const-trait-impl/std-impl-gate.rs b/src/test/ui/rfc-2632-const-trait-impl/std-impl-gate.rs index c6975da7121..2f54c09e31c 100644 --- a/src/test/ui/rfc-2632-const-trait-impl/std-impl-gate.rs +++ b/src/test/ui/rfc-2632-const-trait-impl/std-impl-gate.rs @@ -11,7 +11,7 @@ fn non_const_context() -> Vec { const fn const_context() -> Vec { Default::default() - //[stock]~^ ERROR calls in constant functions are limited + //[stock]~^ ERROR cannot call non-const fn } fn main() { diff --git a/src/test/ui/rfc-2632-const-trait-impl/std-impl-gate.stock.stderr b/src/test/ui/rfc-2632-const-trait-impl/std-impl-gate.stock.stderr index 55a0daaaec7..0b450a94742 100644 --- a/src/test/ui/rfc-2632-const-trait-impl/std-impl-gate.stock.stderr +++ b/src/test/ui/rfc-2632-const-trait-impl/std-impl-gate.stock.stderr @@ -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 ` as Default>::default` in constant functions --> $DIR/std-impl-gate.rs:13:5 | LL | Default::default() | ^^^^^^^^^^^^^^^^^^ + | + = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants error: aborting due to previous error diff --git a/src/test/ui/static/static-vec-repeat-not-constant.stderr b/src/test/ui/static/static-vec-repeat-not-constant.stderr index ef98aa546eb..84fc638a973 100644 --- a/src/test/ui/static/static-vec-repeat-not-constant.stderr +++ b/src/test/ui/static/static-vec-repeat-not-constant.stderr @@ -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 `foo` in statics --> $DIR/static-vec-repeat-not-constant.rs:3:25 | LL | static a: [isize; 2] = [foo(); 2]; | ^^^^^ + | + = note: calls in statics are limited to constant functions, tuple structs and tuple variants error: aborting due to previous error