From 05ad6981d08b70632e89663cbe4c4615bbcbc5c9 Mon Sep 17 00:00:00 2001 From: Deadbeef Date: Wed, 3 Nov 2021 17:34:30 +0800 Subject: [PATCH 01/19] More informative error message for E0015 --- .../src/transform/check_consts/check.rs | 6 +- .../src/transform/check_consts/ops.rs | 94 ++++++++++--------- 2 files changed, 51 insertions(+), 49 deletions(-) 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 1d5f463015294..927dfd94ee337 100644 --- a/compiler/rustc_const_eval/src/transform/check_consts/check.rs +++ b/compiler/rustc_const_eval/src/transform/check_consts/check.rs @@ -801,7 +801,7 @@ 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(callee, substs)); return; } @@ -856,7 +856,7 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> { } if !nonconst_call_permission { - self.check_op(ops::FnCallNonConst(None)); + self.check_op(ops::FnCallNonConst(callee, substs)); return; } } @@ -925,7 +925,7 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> { } if !nonconst_call_permission { - self.check_op(ops::FnCallNonConst(None)); + self.check_op(ops::FnCallNonConst(callee, substs)); 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 24c4a4915e5e8..a6da3ebba6ef6 100644 --- a/compiler/rustc_const_eval/src/transform/check_consts/ops.rs +++ b/compiler/rustc_const_eval/src/transform/check_consts/ops.rs @@ -74,65 +74,67 @@ impl NonConstOp for FnCallIndirect { /// A function call where the callee is not marked as `const`. #[derive(Debug)] -pub struct FnCallNonConst<'tcx>(pub Option<(DefId, SubstsRef<'tcx>)>); +pub struct FnCallNonConst<'tcx>(pub DefId, pub SubstsRef<'tcx>); impl<'a> NonConstOp for FnCallNonConst<'a> { fn build_error<'tcx>(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> { + let FnCallNonConst(def_id, substs) = *self; let mut err = struct_span_err!( ccx.tcx.sess, span, E0015, + "cannot call non-const fn `{}` in {}s", + ccx.tcx.def_path_str_with_substs(def_id, substs), + ccx.const_kind() + ); + err.note(&format!( "calls in {}s are limited to constant functions, \ tuple structs and tuple variants", ccx.const_kind(), - ); - - 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); - - 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, - ); - } + )); + + 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); + + 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, + ); } } } - _ => {} } + _ => {} } } } From 75fdc8ac1e248df8ed62b60539b562c07317c5c1 Mon Sep 17 00:00:00 2001 From: Deadbeef Date: Thu, 9 Dec 2021 22:42:17 +0800 Subject: [PATCH 02/19] Improve error messages even more --- .../src/diagnostics/conflict_errors.rs | 23 +- .../rustc_borrowck/src/diagnostics/mod.rs | 115 ++---- .../src/diagnostics/move_errors.rs | 6 +- .../src/transform/check_consts/check.rs | 30 +- .../src/transform/check_consts/ops.rs | 337 +++++++++++------- .../rustc_const_eval/src/util/call_kind.rs | 145 ++++++++ compiler/rustc_const_eval/src/util/mod.rs | 2 + compiler/rustc_hir/src/lang_items.rs | 11 +- compiler/rustc_span/src/symbol.rs | 1 + library/core/src/ops/try_trait.rs | 1 + 10 files changed, 433 insertions(+), 238 deletions(-) create mode 100644 compiler/rustc_const_eval/src/util/call_kind.rs diff --git a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs index a24b7cff9e75c..19f170636dad4 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,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { .map(|n| format!("`{}`", n)) .unwrap_or_else(|| "value".to_owned()); match kind { - FnSelfUseKind::FnOnceCall => { + CallKind::FnCall(once_did) if Some(once_did) == self.infcx.tcx.lang_items().fn_once_trait() => { err.span_label( fn_call_span, &format!( @@ -208,7 +209,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 +237,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 +304,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( @@ -432,7 +431,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 e2eb125981f13..d012847d335e6 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 692c20d7dfe34..0191e3de203f4 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 927dfd94ee337..3b741164dd291 100644 --- a/compiler/rustc_const_eval/src/transform/check_consts/check.rs +++ b/compiler/rustc_const_eval/src/transform/check_consts/check.rs @@ -292,13 +292,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, @@ -777,7 +777,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(); @@ -801,7 +801,13 @@ 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(callee, substs)); + self.check_op(ops::FnCallNonConst { + caller, + callee, + substs, + span: *fn_span, + from_hir_call: *from_hir_call, + }); return; } @@ -856,7 +862,13 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> { } if !nonconst_call_permission { - self.check_op(ops::FnCallNonConst(callee, substs)); + self.check_op(ops::FnCallNonConst { + caller, + callee, + substs, + span: *fn_span, + from_hir_call: *from_hir_call, + }); return; } } @@ -925,7 +937,13 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> { } if !nonconst_call_permission { - self.check_op(ops::FnCallNonConst(callee, substs)); + 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 a6da3ebba6ef6..c26b1e550ba23 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,20 @@ 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, 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 +35,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 +45,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 +59,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,40 +72,120 @@ 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 DefId, pub SubstsRef<'tcx>); -impl<'a> NonConstOp for FnCallNonConst<'a> { - fn build_error<'tcx>(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> { - let FnCallNonConst(def_id, substs) = *self; - let mut err = struct_span_err!( - ccx.tcx.sess, - span, - E0015, - "cannot call non-const fn `{}` in {}s", - ccx.tcx.def_path_str_with_substs(def_id, substs), - ccx.const_kind() - ); - err.note(&format!( - "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 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 { +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; + + 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::ConstIfConst, + 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::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 @@ -137,8 +223,43 @@ impl<'a> NonConstOp for FnCallNonConst<'a> { _ => {} } } + + 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 } @@ -150,8 +271,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( @@ -176,8 +297,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 { @@ -185,7 +306,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, @@ -197,8 +318,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 { @@ -206,7 +327,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) @@ -218,8 +339,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, @@ -242,8 +363,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, @@ -258,8 +379,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, @@ -278,8 +399,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 { @@ -287,7 +408,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, @@ -302,8 +423,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, @@ -339,8 +460,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 } @@ -350,7 +471,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 => "", @@ -384,12 +505,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 => "", @@ -406,8 +527,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) } @@ -416,7 +537,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, @@ -429,8 +550,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`", @@ -443,8 +564,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 @@ -459,12 +580,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, @@ -479,8 +600,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 @@ -496,8 +617,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 { @@ -505,7 +626,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, @@ -530,8 +651,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, @@ -548,8 +669,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) } @@ -562,11 +683,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, @@ -578,7 +695,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, @@ -588,7 +705,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 { @@ -596,11 +713,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, @@ -612,16 +725,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, @@ -633,7 +742,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, @@ -643,7 +752,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 { @@ -651,11 +760,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, @@ -676,7 +781,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, @@ -686,7 +791,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 { @@ -694,11 +799,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, @@ -720,16 +821,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 0000000000000..34925692664be --- /dev/null +++ b/compiler/rustc_const_eval/src/util/call_kind.rs @@ -0,0 +1,145 @@ +//! 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(DefId), + /// 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 = (!from_hir_call) + .then(|| parent) + .flatten() + .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(trait_id)) + } 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 4a406f8bfd088..a1876bed83eca 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 a03c561861e2b..66a1251276adc 100644 --- a/compiler/rustc_hir/src/lang_items.rs +++ b/compiler/rustc_hir/src/lang_items.rs @@ -21,6 +21,7 @@ use std::lazy::SyncLazy; pub enum LangItemGroup { Op, + Fn, } const NUM_GROUPS: usize = 1; @@ -259,9 +260,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; @@ -272,8 +273,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 51a7a2644f695..26bdca4642ffc 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 6a414ae8c4b80..5755abf98ba5f 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. From de2123aaeb6e474ed1a0ee5890d0ef9b82fca8ca Mon Sep 17 00:00:00 2001 From: Deadbeef Date: Fri, 10 Dec 2021 01:10:05 +0800 Subject: [PATCH 03/19] bless you --- src/test/ui/borrowck/issue-64453.rs | 2 +- src/test/ui/borrowck/issue-64453.stderr | 3 ++- src/test/ui/check-static-values-constraints.rs | 2 +- .../ui/check-static-values-constraints.stderr | 8 +++++--- .../ui/const-generics/nested-type.full.stderr | 4 +++- .../ui/const-generics/nested-type.min.stderr | 4 +++- src/test/ui/const-generics/nested-type.rs | 2 +- src/test/ui/consts/const-call.rs | 2 +- src/test/ui/consts/const-call.stderr | 4 +++- .../const-extern-fn-call-extern-fn.rs | 4 ++-- .../const-extern-fn-call-extern-fn.stderr | 8 ++++++-- src/test/ui/consts/const-fn-error.rs | 4 ++-- src/test/ui/consts/const-fn-error.stderr | 13 +++++++++++-- .../ui/consts/const-fn-not-safe-for-const.stderr | 4 +++- src/test/ui/consts/const-for.rs | 4 ++-- src/test/ui/consts/const-for.stderr | 13 +++++++++++-- src/test/ui/consts/control-flow/issue-46843.rs | 2 +- .../ui/consts/control-flow/issue-46843.stderr | 4 +++- .../ui/consts/intrinsic_without_const_stab.rs | 2 +- .../consts/intrinsic_without_const_stab.stderr | 4 +++- .../consts/intrinsic_without_const_stab_fail.rs | 2 +- .../intrinsic_without_const_stab_fail.stderr | 4 +++- src/test/ui/consts/issue-28113.rs | 2 +- src/test/ui/consts/issue-28113.stderr | 4 +++- src/test/ui/consts/issue-32829-2.rs | 6 +++--- src/test/ui/consts/issue-32829-2.stderr | 12 +++++++++--- src/test/ui/consts/issue-43105.rs | 2 +- src/test/ui/consts/issue-43105.stderr | 4 +++- src/test/ui/consts/issue-56164.rs | 2 +- src/test/ui/consts/issue-56164.stderr | 4 +++- .../consts/issue-68542-closure-in-array-len.rs | 2 +- .../issue-68542-closure-in-array-len.stderr | 4 +++- .../consts/min_const_fn/bad_const_fn_body_ice.rs | 2 +- .../min_const_fn/bad_const_fn_body_ice.stderr | 3 ++- src/test/ui/consts/mir_check_nonconst.rs | 2 +- src/test/ui/consts/mir_check_nonconst.stderr | 4 +++- .../consts/unstable-const-fn-in-libcore.stderr | 4 +++- src/test/ui/issues/issue-16538.mir.stderr | 4 +++- src/test/ui/issues/issue-16538.thir.stderr | 4 +++- src/test/ui/issues/issue-25901.rs | 2 +- src/test/ui/issues/issue-25901.stderr | 15 ++++++++++++++- src/test/ui/issues/issue-39559-2.stderr | 8 ++++++-- src/test/ui/never_type/issue-52443.rs | 4 ++-- src/test/ui/never_type/issue-52443.stderr | 13 +++++++++++-- .../call-const-trait-method-fail.rs | 2 +- .../call-const-trait-method-fail.stderr | 8 +++++--- .../call-generic-method-fail.rs | 2 +- .../call-generic-method-fail.stderr | 8 +++++++- .../const-check-fns-in-const-impl.rs | 2 +- .../const-check-fns-in-const-impl.stderr | 4 +++- .../const-default-method-bodies.rs | 2 +- .../const-default-method-bodies.stderr | 8 +++++--- .../cross-crate.gated.stderr | 8 +++++--- .../ui/rfc-2632-const-trait-impl/cross-crate.rs | 4 ++-- .../cross-crate.stock.stderr | 16 ++++++++++------ .../ui/rfc-2632-const-trait-impl/issue-88155.rs | 2 +- .../rfc-2632-const-trait-impl/issue-88155.stderr | 4 +++- .../rfc-2632-const-trait-impl/std-impl-gate.rs | 2 +- .../std-impl-gate.stock.stderr | 4 +++- .../static/static-vec-repeat-not-constant.stderr | 4 +++- 60 files changed, 199 insertions(+), 87 deletions(-) diff --git a/src/test/ui/borrowck/issue-64453.rs b/src/test/ui/borrowck/issue-64453.rs index 9e70a847457c0..33d55be5812e7 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 14e1667038965..f3436fbec66a6 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 3d1b5a0822756..eb4ecd8baca96 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 eb640c88e026f..b28cf0d6bd0f5 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/nested-type.full.stderr b/src/test/ui/const-generics/nested-type.full.stderr index 9d7ca36545c9c..52f1c58825823 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 4f32284ecb1e0..0e3c988ae4d8c 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 039f996de96db..5240f5c3b0b64 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 db642988971e0..28e89559fe538 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 9761348bab824..e46bcad0e1d0e 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 ee07dfae47c38..eccda49db3eb5 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 348387ff5f827..5acf22e4bc66e 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 948c162e8946d..0b813e65621d3 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 E0080 //~| 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 df24585e5551a..81f3c51fc284d 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[E0080]: evaluation of constant value failed --> $DIR/const-fn-error.rs:5:14 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 df793d7dd7ec9..4c7effc0d1586 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 5fc1ee0e36948..58bcb5f74ccf6 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 a35c04b3570b2..b0dc43eb8e850 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 edf62f2326619..ddddc8505c635 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 ea9ea25f9e12d..66227f61e3563 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 810158a295792..d5f694986fc89 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 5a42823a6052a..b32b6398ece62 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 bf2c44169d48b..8b37268b0b205 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 d4a2989e785e0..fcbb3724567fe 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 e5bd7aafe41e6..1d93d454af786 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 fn ; fn main() {} diff --git a/src/test/ui/consts/issue-28113.stderr b/src/test/ui/consts/issue-28113.stderr index 3d274d777b0c7..75fcc010a04f9 100644 --- a/src/test/ui/consts/issue-28113.stderr +++ b/src/test/ui/consts/issue-28113.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 `<[closure@$DIR/issue-28113.rs:4:5: 4:19] as Fn<()>>::call` in constants --> $DIR/issue-28113.rs:4:5 | LL | || -> u8 { 5 }() | ^^^^^^^^^^^^^^^^ + | + = 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 e0fcf27833096..d70b5a8c4e13a 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 1d265875c5c97..b94bdc0e3df11 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 cc6a485085372..cac12b90970fe 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 e508cbdd1dd53..2d1174af71c86 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 90ea217698d65..af65720916cd9 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 fn 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 500af0a40069a..af5d44d4814bf 100644 --- a/src/test/ui/consts/issue-56164.stderr +++ b/src/test/ui/consts/issue-56164.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 `<[closure@$DIR/issue-56164.rs:3:18: 3:24] as Fn<()>>::call` in constant functions --> $DIR/issue-56164.rs:3:18 | LL | const fn foo() { (||{})() } | ^^^^^^^^ + | + = 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 d77fd9aa831be..44f44da234a7c 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 fn } 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 74d70e18a24cb..3787138afc37f 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,10 @@ -error[E0015]: calls in constants are limited to constant functions, tuple structs and tuple variants +error[E0015]: cannot call non-const fn `<[closure@$DIR/issue-68542-closure-in-array-len.rs:6:13: 6:23] as Fn<()>>::call` in constants --> $DIR/issue-68542-closure-in-array-len.rs:6:13 | LL | a: [(); (|| { 0 })()] | ^^^^^^^^^^^^ + | + = 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/min_const_fn/bad_const_fn_body_ice.rs b/src/test/ui/consts/min_const_fn/bad_const_fn_body_ice.rs index 4e1b7bf119c6d..258997597ea9d 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 fee43864e20dc..74234108911dd 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 b8ec0c3c449ff..b6f34b922fae5 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 30f68ba43722d..2bac995eebf09 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 928605356a16e..435141134cb88 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,10 @@ -error[E0015]: calls in constant functions are limited to constant functions, tuple structs and tuple variants +error[E0015]: cannot call non-const fn `>::call_once` 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 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 5a276f27886d2..60a2bf1e2d660 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 8365a1dbf6e5e..2ba9dfa2bc5f8 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 a139ad0d3e323..ba12e1ad0211b 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 d6eb3760cdf40..5c35250bc3f39 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 3d765daa7cdef..ea27e7bd2508f 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 4519833b86486..cebcca944af82 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 216b56f705904..8c1755205f025 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 33e839fd1203d..5f55d61f5fdcd 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,7 @@ 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 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 5a73c4debb481..b5680c04a65a3 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,8 +1,10 @@ -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[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 error: aborting due to previous error 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 e96249ff2fd5a..e3de75ea51943 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,7 @@ pub const fn equals_self(t: &T) -> bool { *t == *t - //~^ ERROR calls in constant functions are limited to constant functions + //~^ ERROR cannot call non-const operator } 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 818c582869631..d50100d033e51 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,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 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 { + | ++++++++++++++++++++++++++++ error: aborting due to previous error 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 3a7074163523b..b3e3dd62be804 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 aaec67161a6af..9e49785c589e1 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 7a0db9c98ea61..4b685b3b2b75a 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,7 @@ 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 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 63e4095af2943..853fa3d64781f 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,8 +1,10 @@ -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[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 error: aborting due to previous error 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 3f553a8ee7079..df960902133f3 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,8 +1,10 @@ -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: aborting due to previous error 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 4bd3359947d94..670d06b85f281 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 @@ -13,9 +13,9 @@ 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 + //~^ ERROR: cannot call non-const fn 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 9908f47a7b288..ea75ad0aeaf8c 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/issue-88155.rs b/src/test/ui/rfc-2632-const-trait-impl/issue-88155.rs index 157005bba7b75..e4fc65e3cb353 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,7 @@ pub trait A { pub const fn foo() -> bool { T::assoc() - //~^ ERROR calls in constant functions are limited + //~^ 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 931baac5389e6..b94d655a9ffa2 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,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 `::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 error: aborting due to previous error 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 c6975da7121f9..2f54c09e31c9e 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 55a0daaaec7bd..0b450a9474282 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 ef98aa546ebdd..84fc638a973cb 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 From c17fda712a0a57290d964d6aa286bf276a833459 Mon Sep 17 00:00:00 2001 From: Deadbeef Date: Wed, 29 Dec 2021 16:29:14 +0800 Subject: [PATCH 04/19] Rebased and improved errors --- .../src/diagnostics/conflict_errors.rs | 4 +++- .../src/transform/check_consts/ops.rs | 2 +- .../rustc_const_eval/src/util/call_kind.rs | 4 +--- compiler/rustc_hir/src/lang_items.rs | 5 +++-- .../ui/const-generics/issues/issue-90318.rs | 4 ++-- .../const-generics/issues/issue-90318.stderr | 20 +++++++++++++++++-- src/test/ui/consts/issue-90870.fixed | 6 +++--- src/test/ui/consts/issue-90870.rs | 6 +++--- src/test/ui/consts/issue-90870.stderr | 9 ++++++--- 9 files changed, 40 insertions(+), 20 deletions(-) diff --git a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs index 19f170636dad4..190028457e4b5 100644 --- a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs @@ -196,7 +196,9 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { .map(|n| format!("`{}`", n)) .unwrap_or_else(|| "value".to_owned()); match kind { - CallKind::FnCall(once_did) if Some(once_did) == self.infcx.tcx.lang_items().fn_once_trait() => { + CallKind::FnCall(once_did) + if Some(once_did) == self.infcx.tcx.lang_items().fn_once_trait() => + { err.span_label( fn_call_span, &format!( 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 c26b1e550ba23..237201c547822 100644 --- a/compiler/rustc_const_eval/src/transform/check_consts/ops.rs +++ b/compiler/rustc_const_eval/src/transform/check_consts/ops.rs @@ -125,7 +125,7 @@ impl<'tcx> NonConstOp<'tcx> for FnCallNonConst<'tcx> { param_env, Binder::dummy(TraitPredicate { trait_ref, - constness: BoundConstness::ConstIfConst, + constness: BoundConstness::NotConst, polarity: ImplPolarity::Positive, }), ); diff --git a/compiler/rustc_const_eval/src/util/call_kind.rs b/compiler/rustc_const_eval/src/util/call_kind.rs index 34925692664be..fe35d94234139 100644 --- a/compiler/rustc_const_eval/src/util/call_kind.rs +++ b/compiler/rustc_const_eval/src/util/call_kind.rs @@ -71,9 +71,7 @@ pub fn call_kind<'tcx>( AssocItemContainer::TraitContainer(trait_did) => Some(trait_did), }); - let fn_call = (!from_hir_call) - .then(|| parent) - .flatten() + let fn_call = parent .and_then(|p| tcx.lang_items().group(LangItemGroup::Fn).iter().find(|did| **did == p)); let operator = (!from_hir_call) diff --git a/compiler/rustc_hir/src/lang_items.rs b/compiler/rustc_hir/src/lang_items.rs index 66a1251276adc..84177cca8f7ab 100644 --- a/compiler/rustc_hir/src/lang_items.rs +++ b/compiler/rustc_hir/src/lang_items.rs @@ -24,7 +24,7 @@ pub enum LangItemGroup { Fn, } -const NUM_GROUPS: usize = 1; +const NUM_GROUPS: usize = 2; macro_rules! expand_group { () => { @@ -99,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], } } diff --git a/src/test/ui/const-generics/issues/issue-90318.rs b/src/test/ui/const-generics/issues/issue-90318.rs index 0c640a5ef7136..bebd0c6ac1202 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 2b8afe2ef09ed..c8690ecd0da7e 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/consts/issue-90870.fixed b/src/test/ui/consts/issue-90870.fixed index e767effcdd06f..0d28e06e53258 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 35b3c8242aa0c..c6bfffd2c5c15 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 0e33e6ebe5a59..478445cfb39c5 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 { From 96e6262ffb7b38254cff27700a93c0c6910e1c14 Mon Sep 17 00:00:00 2001 From: Deadbeef Date: Wed, 29 Dec 2021 17:05:54 +0800 Subject: [PATCH 05/19] Handle Fn family trait call errror --- .../src/diagnostics/conflict_errors.rs | 4 +- .../src/transform/check_consts/ops.rs | 41 ++++++++++++++++++- .../rustc_const_eval/src/util/call_kind.rs | 4 +- src/test/ui/consts/issue-28113.rs | 2 +- src/test/ui/consts/issue-28113.stderr | 3 +- src/test/ui/consts/issue-56164.rs | 2 +- src/test/ui/consts/issue-56164.stderr | 3 +- .../issue-68542-closure-in-array-len.rs | 2 +- .../issue-68542-closure-in-array-len.stderr | 3 +- .../unstable-const-fn-in-libcore.stderr | 6 ++- 10 files changed, 57 insertions(+), 13 deletions(-) diff --git a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs index 190028457e4b5..21fb9b19e2a47 100644 --- a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs @@ -196,8 +196,8 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { .map(|n| format!("`{}`", n)) .unwrap_or_else(|| "value".to_owned()); match kind { - CallKind::FnCall(once_did) - if Some(once_did) == self.infcx.tcx.lang_items().fn_once_trait() => + CallKind::FnCall { fn_trait_id, .. } + if Some(fn_trait_id) == self.infcx.tcx.lang_items().fn_once_trait() => { err.span_label( fn_call_span, 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 237201c547822..519b4c02b61e6 100644 --- a/compiler/rustc_const_eval/src/transform/check_consts/ops.rs +++ b/compiler/rustc_const_eval/src/transform/check_consts/ops.rs @@ -8,7 +8,9 @@ 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::ty::{suggest_constraining_type_param, Adt, Param, TraitPredicate, Ty}; +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; @@ -155,7 +157,7 @@ impl<'tcx> NonConstOp<'tcx> for FnCallNonConst<'tcx> { 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(),) + struct_span_err!(tcx.sess, span, E0015, $fmt, self_ty, ccx.const_kind()) }; } @@ -176,6 +178,41 @@ impl<'tcx> NonConstOp<'tcx> for FnCallNonConst<'tcx> { 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, diff --git a/compiler/rustc_const_eval/src/util/call_kind.rs b/compiler/rustc_const_eval/src/util/call_kind.rs index fe35d94234139..11bb9508a1f86 100644 --- a/compiler/rustc_const_eval/src/util/call_kind.rs +++ b/compiler/rustc_const_eval/src/util/call_kind.rs @@ -44,7 +44,7 @@ pub enum CallKind<'tcx> { is_option_or_result: bool, }, /// A call to `Fn(..)::call(..)`, desugared from `my_closure(a, b, c)` - FnCall(DefId), + 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 { @@ -85,7 +85,7 @@ pub fn call_kind<'tcx>( // an FnOnce call, an operator (e.g. `<<`), or a // deref coercion. let kind = if let Some(&trait_id) = fn_call { - Some(CallKind::FnCall(trait_id)) + 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 { diff --git a/src/test/ui/consts/issue-28113.rs b/src/test/ui/consts/issue-28113.rs index 1d93d454af786..f8131c9f3b717 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 cannot call non-const fn + //~^ 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 75fcc010a04f9..7ad1f752eb085 100644 --- a/src/test/ui/consts/issue-28113.stderr +++ b/src/test/ui/consts/issue-28113.stderr @@ -1,9 +1,10 @@ -error[E0015]: cannot call non-const fn `<[closure@$DIR/issue-28113.rs:4:5: 4:19] as Fn<()>>::call` in constants +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-56164.rs b/src/test/ui/consts/issue-56164.rs index af65720916cd9..9c673d20b2a95 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 cannot call non-const fn +//~^ 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 af5d44d4814bf..62a7c7db6b83a 100644 --- a/src/test/ui/consts/issue-56164.stderr +++ b/src/test/ui/consts/issue-56164.stderr @@ -1,9 +1,10 @@ -error[E0015]: cannot call non-const fn `<[closure@$DIR/issue-56164.rs:3:18: 3:24] as Fn<()>>::call` in constant functions +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 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 44f44da234a7c..37958e7919d64 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 cannot call non-const fn + 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 3787138afc37f..74fbbc680f7e4 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,9 +1,10 @@ -error[E0015]: cannot call non-const fn `<[closure@$DIR/issue-68542-closure-in-array-len.rs:6:13: 6:23] as Fn<()>>::call` in constants +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/unstable-const-fn-in-libcore.stderr b/src/test/ui/consts/unstable-const-fn-in-libcore.stderr index 435141134cb88..4ef25bd1334f3 100644 --- a/src/test/ui/consts/unstable-const-fn-in-libcore.stderr +++ b/src/test/ui/consts/unstable-const-fn-in-libcore.stderr @@ -1,10 +1,14 @@ -error[E0015]: cannot call non-const fn `>::call_once` in constant functions +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 From ea0f26ac345a13901dffcd7bd5bc71f8c4ac942b Mon Sep 17 00:00:00 2001 From: fee1-dead Date: Sat, 1 Jan 2022 01:09:15 +0800 Subject: [PATCH 06/19] fix typo in comment --- compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs index 21fb9b19e2a47..0c8cbfb712a49 100644 --- a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs @@ -306,7 +306,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { ); } } - // Other desugarings takes &self, which cannot cause a move + // Other desugarings take &self, they cannot cause moves _ => unreachable!(), } } else { From 94c300a4522f3386546ba77a21865bb78fe9bba8 Mon Sep 17 00:00:00 2001 From: Rob Pilling Date: Sun, 7 Nov 2021 22:41:35 +0000 Subject: [PATCH 07/19] Suggest tuple-parentheses when passing N arguments to an N-tuple argument --- .../rustc_typeck/src/check/fn_ctxt/checks.rs | 73 +++++++++++++++++-- 1 file changed, 67 insertions(+), 6 deletions(-) diff --git a/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs b/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs index c39199f84b527..5f3507846ba9b 100644 --- a/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs +++ b/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs @@ -28,6 +28,11 @@ use crate::structured_errors::StructuredDiagnostic; use std::iter; use std::slice; +enum FnArgsAsTuple<'hir> { + Single(&'hir hir::Expr<'hir>), + Multi { first: &'hir hir::Expr<'hir>, last: &'hir hir::Expr<'hir> }, +} + impl<'a, 'tcx> FnCtxt<'a, 'tcx> { pub(in super::super) fn check_casts(&self) { let mut deferred_cast_checks = self.deferred_cast_checks.borrow_mut(); @@ -127,8 +132,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let expected_arg_count = formal_input_tys.len(); - // expected_count, arg_count, error_code, sugg_unit - let mut error: Option<(usize, usize, &str, bool)> = None; + // expected_count, arg_count, error_code, sugg_unit, sugg_tuple_wrap_args + let mut error: Option<(usize, usize, &str, bool, Option>)> = None; // If the arguments should be wrapped in a tuple (ex: closures), unwrap them here let (formal_input_tys, expected_input_tys) = if tuple_arguments == TupleArguments { @@ -138,7 +143,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ty::Tuple(arg_types) => { // Argument length differs if arg_types.len() != provided_args.len() { - error = Some((arg_types.len(), provided_args.len(), "E0057", false)); + error = Some((arg_types.len(), provided_args.len(), "E0057", false, None)); } let expected_input_tys = match expected_input_tys.get(0) { Some(&ty) => match ty.kind() { @@ -169,7 +174,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { if supplied_arg_count >= expected_arg_count { (formal_input_tys.to_vec(), expected_input_tys) } else { - error = Some((expected_arg_count, supplied_arg_count, "E0060", false)); + error = Some((expected_arg_count, supplied_arg_count, "E0060", false, None)); (self.err_args(supplied_arg_count), vec![]) } } else { @@ -181,7 +186,43 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } else { false }; - error = Some((expected_arg_count, supplied_arg_count, "E0061", sugg_unit)); + + // are we passing elements of a tuple without the tuple parentheses? + let chosen_arg_tys = if expected_input_tys.is_empty() { + // In most cases we can use expected_arg_tys, but some callers won't have the type + // information, in which case we fall back to the types from the input expressions. + formal_input_tys + } else { + &*expected_input_tys + }; + + let sugg_tuple_wrap_args = chosen_arg_tys + .get(0) + .cloned() + .map(|arg_ty| self.resolve_vars_if_possible(arg_ty)) + .and_then(|arg_ty| match arg_ty.kind() { + ty::Tuple(tup_elems) => Some(tup_elems), + _ => None, + }) + .and_then(|tup_elems| { + if tup_elems.len() == supplied_arg_count && chosen_arg_tys.len() == 1 { + match provided_args { + [] => None, + [single] => Some(FnArgsAsTuple::Single(single)), + [first, .., last] => Some(FnArgsAsTuple::Multi { first, last }), + } + } else { + None + } + }); + + error = Some(( + expected_arg_count, + supplied_arg_count, + "E0061", + sugg_unit, + sugg_tuple_wrap_args, + )); (self.err_args(supplied_arg_count), vec![]) }; @@ -305,7 +346,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } // If there was an error in parameter count, emit that here - if let Some((expected_count, arg_count, err_code, sugg_unit)) = error { + if let Some((expected_count, arg_count, err_code, sugg_unit, sugg_tuple_wrap_args)) = error + { let (span, start_span, args, ctor_of) = match &call_expr.kind { hir::ExprKind::Call( hir::Expr { @@ -408,6 +450,25 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { String::from("()"), Applicability::MachineApplicable, ); + } else if let Some(tuple_fn_arg) = sugg_tuple_wrap_args { + use FnArgsAsTuple::*; + + let spans = match tuple_fn_arg { + Multi { first, last } => vec![ + (first.span.shrink_to_lo(), '('.to_string()), + (last.span.shrink_to_hi(), ')'.to_string()), + ], + Single(single) => vec![ + (single.span.shrink_to_lo(), '('.to_string()), + (single.span.shrink_to_hi(), ",)".to_string()), + ], + }; + + err.multipart_suggestion( + "use parentheses to construct a tuple", + spans, + Applicability::MachineApplicable, + ); } else { err.span_label( span, From 80059f99424c64d10f073ab5c502856d46b1c26d Mon Sep 17 00:00:00 2001 From: Rob Pilling Date: Tue, 9 Nov 2021 23:20:26 +0000 Subject: [PATCH 08/19] Test tuple suggestions, including tuple-as-function-argument --- .../suggestions/args-instead-of-tuple.fixed | 18 +++++++ .../ui/suggestions/args-instead-of-tuple.rs | 18 +++++++ .../suggestions/args-instead-of-tuple.stderr | 52 +++++++++++++++++++ 3 files changed, 88 insertions(+) create mode 100644 src/test/ui/suggestions/args-instead-of-tuple.fixed create mode 100644 src/test/ui/suggestions/args-instead-of-tuple.rs create mode 100644 src/test/ui/suggestions/args-instead-of-tuple.stderr diff --git a/src/test/ui/suggestions/args-instead-of-tuple.fixed b/src/test/ui/suggestions/args-instead-of-tuple.fixed new file mode 100644 index 0000000000000..adb832b8a7b74 --- /dev/null +++ b/src/test/ui/suggestions/args-instead-of-tuple.fixed @@ -0,0 +1,18 @@ +// Test suggesting tuples where bare arguments may have been passed +// See issue #86481 for details. + +// run-rustfix + +fn main() { + let _: Result<(i32, i8), ()> = Ok((1, 2)); + //~^ ERROR this enum variant takes 1 argument but 2 arguments were supplied + let _: Option<(i32, i8, &'static str)> = Some((1, 2, "hi")); + //~^ ERROR this enum variant takes 1 argument but 3 arguments were supplied + let _: Option<()> = Some(()); + //~^ ERROR this enum variant takes 1 argument but 0 arguments were supplied + + f((1, 2)); //~ ERROR this function takes 1 argument +} + +fn f(_: (i32, i32)) { +} diff --git a/src/test/ui/suggestions/args-instead-of-tuple.rs b/src/test/ui/suggestions/args-instead-of-tuple.rs new file mode 100644 index 0000000000000..8dbc58daeb1f5 --- /dev/null +++ b/src/test/ui/suggestions/args-instead-of-tuple.rs @@ -0,0 +1,18 @@ +// Test suggesting tuples where bare arguments may have been passed +// See issue #86481 for details. + +// run-rustfix + +fn main() { + let _: Result<(i32, i8), ()> = Ok(1, 2); + //~^ ERROR this enum variant takes 1 argument but 2 arguments were supplied + let _: Option<(i32, i8, &'static str)> = Some(1, 2, "hi"); + //~^ ERROR this enum variant takes 1 argument but 3 arguments were supplied + let _: Option<()> = Some(); + //~^ ERROR this enum variant takes 1 argument but 0 arguments were supplied + + f(1, 2); //~ ERROR this function takes 1 argument +} + +fn f(_: (i32, i32)) { +} diff --git a/src/test/ui/suggestions/args-instead-of-tuple.stderr b/src/test/ui/suggestions/args-instead-of-tuple.stderr new file mode 100644 index 0000000000000..95bbbdb274964 --- /dev/null +++ b/src/test/ui/suggestions/args-instead-of-tuple.stderr @@ -0,0 +1,52 @@ +error[E0061]: this enum variant takes 1 argument but 2 arguments were supplied + --> $DIR/args-instead-of-tuple.rs:7:36 + | +LL | let _: Result<(i32, i8), ()> = Ok(1, 2); + | ^^ - - supplied 2 arguments + | +help: use parentheses to construct a tuple + | +LL | let _: Result<(i32, i8), ()> = Ok((1, 2)); + | + + + +error[E0061]: this enum variant takes 1 argument but 3 arguments were supplied + --> $DIR/args-instead-of-tuple.rs:9:46 + | +LL | let _: Option<(i32, i8, &'static str)> = Some(1, 2, "hi"); + | ^^^^ - - ---- supplied 3 arguments + | +help: use parentheses to construct a tuple + | +LL | let _: Option<(i32, i8, &'static str)> = Some((1, 2, "hi")); + | + + + +error[E0061]: this enum variant takes 1 argument but 0 arguments were supplied + --> $DIR/args-instead-of-tuple.rs:11:25 + | +LL | let _: Option<()> = Some(); + | ^^^^-- supplied 0 arguments + | +help: expected the unit value `()`; create it with empty parentheses + | +LL | let _: Option<()> = Some(()); + | ++ + +error[E0061]: this function takes 1 argument but 2 arguments were supplied + --> $DIR/args-instead-of-tuple.rs:14:5 + | +LL | f(1, 2); + | ^ - - supplied 2 arguments + | +note: function defined here + --> $DIR/args-instead-of-tuple.rs:17:4 + | +LL | fn f(_: (i32, i32)) { + | ^ ------------- +help: use parentheses to construct a tuple + | +LL | f((1, 2)); + | + + + +error: aborting due to 4 previous errors + +For more information about this error, try `rustc --explain E0061`. From 54d2d30662c2832554bb127f017f7a311bb62b4e Mon Sep 17 00:00:00 2001 From: Rob Pilling Date: Sun, 5 Dec 2021 21:41:33 +0000 Subject: [PATCH 09/19] Compare tuple element & arg types before suggesting a tuple --- .../rustc_typeck/src/check/fn_ctxt/checks.rs | 53 +++++++++++-------- .../args-instead-of-tuple-errors.rs | 13 +++++ .../args-instead-of-tuple-errors.stderr | 25 +++++++++ .../suggestions/args-instead-of-tuple.fixed | 4 +- .../ui/suggestions/args-instead-of-tuple.rs | 4 +- .../suggestions/args-instead-of-tuple.stderr | 12 ++--- 6 files changed, 79 insertions(+), 32 deletions(-) create mode 100644 src/test/ui/suggestions/args-instead-of-tuple-errors.rs create mode 100644 src/test/ui/suggestions/args-instead-of-tuple-errors.stderr diff --git a/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs b/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs index 5f3507846ba9b..a94e6b480d643 100644 --- a/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs +++ b/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs @@ -18,7 +18,7 @@ use rustc_hir::def_id::DefId; use rustc_hir::{ExprKind, Node, QPath}; use rustc_middle::ty::adjustment::AllowTwoPhase; use rustc_middle::ty::fold::TypeFoldable; -use rustc_middle::ty::{self, Ty}; +use rustc_middle::ty::{self, ParamEnv, Ty}; use rustc_session::Session; use rustc_span::symbol::Ident; use rustc_span::{self, MultiSpan, Span}; @@ -188,33 +188,15 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { }; // are we passing elements of a tuple without the tuple parentheses? - let chosen_arg_tys = if expected_input_tys.is_empty() { - // In most cases we can use expected_arg_tys, but some callers won't have the type + let expected_input_tys = if expected_input_tys.is_empty() { + // In most cases we can use expected_input_tys, but some callers won't have the type // information, in which case we fall back to the types from the input expressions. formal_input_tys } else { &*expected_input_tys }; - let sugg_tuple_wrap_args = chosen_arg_tys - .get(0) - .cloned() - .map(|arg_ty| self.resolve_vars_if_possible(arg_ty)) - .and_then(|arg_ty| match arg_ty.kind() { - ty::Tuple(tup_elems) => Some(tup_elems), - _ => None, - }) - .and_then(|tup_elems| { - if tup_elems.len() == supplied_arg_count && chosen_arg_tys.len() == 1 { - match provided_args { - [] => None, - [single] => Some(FnArgsAsTuple::Single(single)), - [first, .., last] => Some(FnArgsAsTuple::Multi { first, last }), - } - } else { - None - } - }); + let sugg_tuple_wrap_args = self.suggested_tuple_wrap(expected_input_tys, provided_args); error = Some(( expected_arg_count, @@ -518,6 +500,33 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } } + fn suggested_tuple_wrap( + &self, + expected_input_tys: &[Ty<'tcx>], + provided_args: &'tcx [hir::Expr<'tcx>], + ) -> Option> { + let [expected_arg_type] = &expected_input_tys[..] else { return None }; + + let ty::Tuple(expected_elems) = self.resolve_vars_if_possible(*expected_arg_type).kind() + else { return None }; + + let expected_types: Vec<_> = expected_elems.iter().map(|k| k.expect_ty()).collect(); + let supplied_types: Vec<_> = provided_args.iter().map(|arg| self.check_expr(arg)).collect(); + + let all_match = iter::zip(expected_types, supplied_types) + .all(|(expected, supplied)| self.can_eq(ParamEnv::empty(), expected, supplied).is_ok()); + + if all_match { + match provided_args { + [] => None, + [single] => Some(FnArgsAsTuple::Single(single)), + [first, .., last] => Some(FnArgsAsTuple::Multi { first, last }), + } + } else { + None + } + } + // AST fragment checking pub(in super::super) fn check_lit( &self, diff --git a/src/test/ui/suggestions/args-instead-of-tuple-errors.rs b/src/test/ui/suggestions/args-instead-of-tuple-errors.rs new file mode 100644 index 0000000000000..c4e9c68e219e6 --- /dev/null +++ b/src/test/ui/suggestions/args-instead-of-tuple-errors.rs @@ -0,0 +1,13 @@ +// Ensure we don't suggest tuple-wrapping when we'd end up with a type error + +fn main() { + // we shouldn't suggest to fix these - `2` isn't a `bool` + + let _: Option<(i32, bool)> = Some(1, 2); + //~^ ERROR this enum variant takes 1 argument but 2 arguments were supplied + int_bool(1, 2); + //~^ ERROR this function takes 1 argument but 2 arguments were supplied +} + +fn int_bool(_: (i32, bool)) { +} diff --git a/src/test/ui/suggestions/args-instead-of-tuple-errors.stderr b/src/test/ui/suggestions/args-instead-of-tuple-errors.stderr new file mode 100644 index 0000000000000..c53c8bbdcc9df --- /dev/null +++ b/src/test/ui/suggestions/args-instead-of-tuple-errors.stderr @@ -0,0 +1,25 @@ +error[E0061]: this enum variant takes 1 argument but 2 arguments were supplied + --> $DIR/args-instead-of-tuple-errors.rs:6:34 + | +LL | let _: Option<(i32, bool)> = Some(1, 2); + | ^^^^ - - supplied 2 arguments + | | + | expected 1 argument + +error[E0061]: this function takes 1 argument but 2 arguments were supplied + --> $DIR/args-instead-of-tuple-errors.rs:8:5 + | +LL | int_bool(1, 2); + | ^^^^^^^^ - - supplied 2 arguments + | | + | expected 1 argument + | +note: function defined here + --> $DIR/args-instead-of-tuple-errors.rs:12:4 + | +LL | fn int_bool(_: (i32, bool)) { + | ^^^^^^^^ -------------- + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0061`. diff --git a/src/test/ui/suggestions/args-instead-of-tuple.fixed b/src/test/ui/suggestions/args-instead-of-tuple.fixed index adb832b8a7b74..095be95f18586 100644 --- a/src/test/ui/suggestions/args-instead-of-tuple.fixed +++ b/src/test/ui/suggestions/args-instead-of-tuple.fixed @@ -11,8 +11,8 @@ fn main() { let _: Option<()> = Some(()); //~^ ERROR this enum variant takes 1 argument but 0 arguments were supplied - f((1, 2)); //~ ERROR this function takes 1 argument + two_ints((1, 2)); //~ ERROR this function takes 1 argument } -fn f(_: (i32, i32)) { +fn two_ints(_: (i32, i32)) { } diff --git a/src/test/ui/suggestions/args-instead-of-tuple.rs b/src/test/ui/suggestions/args-instead-of-tuple.rs index 8dbc58daeb1f5..3466a46df848e 100644 --- a/src/test/ui/suggestions/args-instead-of-tuple.rs +++ b/src/test/ui/suggestions/args-instead-of-tuple.rs @@ -11,8 +11,8 @@ fn main() { let _: Option<()> = Some(); //~^ ERROR this enum variant takes 1 argument but 0 arguments were supplied - f(1, 2); //~ ERROR this function takes 1 argument + two_ints(1, 2); //~ ERROR this function takes 1 argument } -fn f(_: (i32, i32)) { +fn two_ints(_: (i32, i32)) { } diff --git a/src/test/ui/suggestions/args-instead-of-tuple.stderr b/src/test/ui/suggestions/args-instead-of-tuple.stderr index 95bbbdb274964..1bf7e7a8d171b 100644 --- a/src/test/ui/suggestions/args-instead-of-tuple.stderr +++ b/src/test/ui/suggestions/args-instead-of-tuple.stderr @@ -34,18 +34,18 @@ LL | let _: Option<()> = Some(()); error[E0061]: this function takes 1 argument but 2 arguments were supplied --> $DIR/args-instead-of-tuple.rs:14:5 | -LL | f(1, 2); - | ^ - - supplied 2 arguments +LL | two_ints(1, 2); + | ^^^^^^^^ - - supplied 2 arguments | note: function defined here --> $DIR/args-instead-of-tuple.rs:17:4 | -LL | fn f(_: (i32, i32)) { - | ^ ------------- +LL | fn two_ints(_: (i32, i32)) { + | ^^^^^^^^ ------------- help: use parentheses to construct a tuple | -LL | f((1, 2)); - | + + +LL | two_ints((1, 2)); + | + + error: aborting due to 4 previous errors From a129a85144efb67bfd8f380a758ed6be41d3e29b Mon Sep 17 00:00:00 2001 From: Rob Pilling Date: Sun, 16 Jan 2022 21:47:44 +0000 Subject: [PATCH 10/19] Handle generics with ParamEnv --- .../rustc_typeck/src/check/fn_ctxt/checks.rs | 4 +-- .../suggestions/args-instead-of-tuple.fixed | 9 +++++ .../ui/suggestions/args-instead-of-tuple.rs | 9 +++++ .../suggestions/args-instead-of-tuple.stderr | 36 +++++++++++++++++-- 4 files changed, 54 insertions(+), 4 deletions(-) diff --git a/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs b/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs index a94e6b480d643..af0c9e5e5090e 100644 --- a/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs +++ b/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs @@ -18,7 +18,7 @@ use rustc_hir::def_id::DefId; use rustc_hir::{ExprKind, Node, QPath}; use rustc_middle::ty::adjustment::AllowTwoPhase; use rustc_middle::ty::fold::TypeFoldable; -use rustc_middle::ty::{self, ParamEnv, Ty}; +use rustc_middle::ty::{self, Ty}; use rustc_session::Session; use rustc_span::symbol::Ident; use rustc_span::{self, MultiSpan, Span}; @@ -514,7 +514,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let supplied_types: Vec<_> = provided_args.iter().map(|arg| self.check_expr(arg)).collect(); let all_match = iter::zip(expected_types, supplied_types) - .all(|(expected, supplied)| self.can_eq(ParamEnv::empty(), expected, supplied).is_ok()); + .all(|(expected, supplied)| self.can_eq(self.param_env, expected, supplied).is_ok()); if all_match { match provided_args { diff --git a/src/test/ui/suggestions/args-instead-of-tuple.fixed b/src/test/ui/suggestions/args-instead-of-tuple.fixed index 095be95f18586..c9b8a41d469b9 100644 --- a/src/test/ui/suggestions/args-instead-of-tuple.fixed +++ b/src/test/ui/suggestions/args-instead-of-tuple.fixed @@ -12,7 +12,16 @@ fn main() { //~^ ERROR this enum variant takes 1 argument but 0 arguments were supplied two_ints((1, 2)); //~ ERROR this function takes 1 argument + + with_generic((3, 4)); //~ ERROR this function takes 1 argument } fn two_ints(_: (i32, i32)) { } + +fn with_generic((a, b): (i32, T)) { + if false { + // test generics/bound handling + with_generic((a, b)); //~ ERROR this function takes 1 argument + } +} diff --git a/src/test/ui/suggestions/args-instead-of-tuple.rs b/src/test/ui/suggestions/args-instead-of-tuple.rs index 3466a46df848e..d4cc3024dd0d2 100644 --- a/src/test/ui/suggestions/args-instead-of-tuple.rs +++ b/src/test/ui/suggestions/args-instead-of-tuple.rs @@ -12,7 +12,16 @@ fn main() { //~^ ERROR this enum variant takes 1 argument but 0 arguments were supplied two_ints(1, 2); //~ ERROR this function takes 1 argument + + with_generic(3, 4); //~ ERROR this function takes 1 argument } fn two_ints(_: (i32, i32)) { } + +fn with_generic((a, b): (i32, T)) { + if false { + // test generics/bound handling + with_generic(a, b); //~ ERROR this function takes 1 argument + } +} diff --git a/src/test/ui/suggestions/args-instead-of-tuple.stderr b/src/test/ui/suggestions/args-instead-of-tuple.stderr index 1bf7e7a8d171b..172db7ee3df38 100644 --- a/src/test/ui/suggestions/args-instead-of-tuple.stderr +++ b/src/test/ui/suggestions/args-instead-of-tuple.stderr @@ -38,7 +38,7 @@ LL | two_ints(1, 2); | ^^^^^^^^ - - supplied 2 arguments | note: function defined here - --> $DIR/args-instead-of-tuple.rs:17:4 + --> $DIR/args-instead-of-tuple.rs:19:4 | LL | fn two_ints(_: (i32, i32)) { | ^^^^^^^^ ------------- @@ -47,6 +47,38 @@ help: use parentheses to construct a tuple LL | two_ints((1, 2)); | + + -error: aborting due to 4 previous errors +error[E0061]: this function takes 1 argument but 2 arguments were supplied + --> $DIR/args-instead-of-tuple.rs:16:5 + | +LL | with_generic(3, 4); + | ^^^^^^^^^^^^ - - supplied 2 arguments + | +note: function defined here + --> $DIR/args-instead-of-tuple.rs:22:4 + | +LL | fn with_generic((a, b): (i32, T)) { + | ^^^^^^^^^^^^ ---------------- +help: use parentheses to construct a tuple + | +LL | with_generic((3, 4)); + | + + + +error[E0061]: this function takes 1 argument but 2 arguments were supplied + --> $DIR/args-instead-of-tuple.rs:25:9 + | +LL | with_generic(a, b); + | ^^^^^^^^^^^^ - - supplied 2 arguments + | +note: function defined here + --> $DIR/args-instead-of-tuple.rs:22:4 + | +LL | fn with_generic((a, b): (i32, T)) { + | ^^^^^^^^^^^^ ---------------- +help: use parentheses to construct a tuple + | +LL | with_generic((a, b)); + | + + + +error: aborting due to 6 previous errors For more information about this error, try `rustc --explain E0061`. From a8bac9879a36d01c1fc325ed85d6a992deab88fa Mon Sep 17 00:00:00 2001 From: Rob Pilling Date: Sun, 16 Jan 2022 22:47:33 +0000 Subject: [PATCH 11/19] Remove 1-tuple unreachable case --- .../rustc_typeck/src/check/fn_ctxt/checks.rs | 30 +++++++------------ .../args-instead-of-tuple-errors.rs | 3 ++ .../args-instead-of-tuple-errors.stderr | 12 ++++++-- 3 files changed, 24 insertions(+), 21 deletions(-) diff --git a/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs b/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs index af0c9e5e5090e..d7022c27d3984 100644 --- a/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs +++ b/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs @@ -28,9 +28,9 @@ use crate::structured_errors::StructuredDiagnostic; use std::iter; use std::slice; -enum FnArgsAsTuple<'hir> { - Single(&'hir hir::Expr<'hir>), - Multi { first: &'hir hir::Expr<'hir>, last: &'hir hir::Expr<'hir> }, +struct FnArgsAsTuple<'hir> { + first: &'hir hir::Expr<'hir>, + last: &'hir hir::Expr<'hir>, } impl<'a, 'tcx> FnCtxt<'a, 'tcx> { @@ -432,23 +432,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { String::from("()"), Applicability::MachineApplicable, ); - } else if let Some(tuple_fn_arg) = sugg_tuple_wrap_args { - use FnArgsAsTuple::*; - - let spans = match tuple_fn_arg { - Multi { first, last } => vec![ + } else if let Some(FnArgsAsTuple { first, last }) = sugg_tuple_wrap_args { + err.multipart_suggestion( + "use parentheses to construct a tuple", + vec![ (first.span.shrink_to_lo(), '('.to_string()), (last.span.shrink_to_hi(), ')'.to_string()), ], - Single(single) => vec![ - (single.span.shrink_to_lo(), '('.to_string()), - (single.span.shrink_to_hi(), ",)".to_string()), - ], - }; - - err.multipart_suggestion( - "use parentheses to construct a tuple", - spans, Applicability::MachineApplicable, ); } else { @@ -519,8 +509,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { if all_match { match provided_args { [] => None, - [single] => Some(FnArgsAsTuple::Single(single)), - [first, .., last] => Some(FnArgsAsTuple::Multi { first, last }), + [_] => unreachable!( + "shouldn't reach here - need count mismatch between 1-tuple and 1-argument" + ), + [first, .., last] => Some(FnArgsAsTuple { first, last }), } } else { None diff --git a/src/test/ui/suggestions/args-instead-of-tuple-errors.rs b/src/test/ui/suggestions/args-instead-of-tuple-errors.rs index c4e9c68e219e6..2c3ee5fcb8039 100644 --- a/src/test/ui/suggestions/args-instead-of-tuple-errors.rs +++ b/src/test/ui/suggestions/args-instead-of-tuple-errors.rs @@ -7,6 +7,9 @@ fn main() { //~^ ERROR this enum variant takes 1 argument but 2 arguments were supplied int_bool(1, 2); //~^ ERROR this function takes 1 argument but 2 arguments were supplied + + let _: Option<(i8,)> = Some(); + //~^ ERROR this enum variant takes 1 argument but 0 arguments were supplied } fn int_bool(_: (i32, bool)) { diff --git a/src/test/ui/suggestions/args-instead-of-tuple-errors.stderr b/src/test/ui/suggestions/args-instead-of-tuple-errors.stderr index c53c8bbdcc9df..a2ad602dbd47a 100644 --- a/src/test/ui/suggestions/args-instead-of-tuple-errors.stderr +++ b/src/test/ui/suggestions/args-instead-of-tuple-errors.stderr @@ -15,11 +15,19 @@ LL | int_bool(1, 2); | expected 1 argument | note: function defined here - --> $DIR/args-instead-of-tuple-errors.rs:12:4 + --> $DIR/args-instead-of-tuple-errors.rs:15:4 | LL | fn int_bool(_: (i32, bool)) { | ^^^^^^^^ -------------- -error: aborting due to 2 previous errors +error[E0061]: this enum variant takes 1 argument but 0 arguments were supplied + --> $DIR/args-instead-of-tuple-errors.rs:11:28 + | +LL | let _: Option<(i8,)> = Some(); + | ^^^^-- supplied 0 arguments + | | + | expected 1 argument + +error: aborting due to 3 previous errors For more information about this error, try `rustc --explain E0061`. From a6c0a3d9c2ff361a5f76175564b3c72e23cfcd54 Mon Sep 17 00:00:00 2001 From: Michael Watzko Date: Wed, 26 Jan 2022 22:00:26 +0100 Subject: [PATCH 12/19] Unimpl {Add,Sub,Mul,Div,Rem,BitXor,BitOr,BitAnd}<$t> for Saturating<$t> Analog to 9648b313cc8896970a12f45b3bb5c0593c3d510f #93208 --- library/core/src/num/saturating.rs | 130 ++--------------------------- 1 file changed, 8 insertions(+), 122 deletions(-) diff --git a/library/core/src/num/saturating.rs b/library/core/src/num/saturating.rs index 317555034756d..8982473b2dc03 100644 --- a/library/core/src/num/saturating.rs +++ b/library/core/src/num/saturating.rs @@ -217,18 +217,6 @@ macro_rules! saturating_impl { forward_ref_binop! { impl Add, add for Saturating<$t>, Saturating<$t>, #[unstable(feature = "saturating_int_impl", issue = "87920")] } - #[unstable(feature = "saturating_int_assign_impl", issue = "92354")] - impl Add<$t> for Saturating<$t> { - type Output = Saturating<$t>; - - #[inline] - fn add(self, other: $t) -> Saturating<$t> { - Saturating(self.0.saturating_add(other)) - } - } - forward_ref_binop! { impl Add, add for Saturating<$t>, $t, - #[unstable(feature = "saturating_int_assign_impl", issue = "92354")] } - #[unstable(feature = "saturating_int_impl", issue = "87920")] impl AddAssign for Saturating<$t> { #[inline] @@ -242,7 +230,7 @@ macro_rules! saturating_impl { impl AddAssign<$t> for Saturating<$t> { #[inline] fn add_assign(&mut self, other: $t) { - *self = *self + other; + *self = *self + Saturating(other); } } forward_ref_op_assign! { impl AddAssign, add_assign for Saturating<$t>, $t } @@ -259,18 +247,6 @@ macro_rules! saturating_impl { forward_ref_binop! { impl Sub, sub for Saturating<$t>, Saturating<$t>, #[unstable(feature = "saturating_int_impl", issue = "87920")] } - #[unstable(feature = "saturating_int_assign_impl", issue = "92354")] - impl Sub<$t> for Saturating<$t> { - type Output = Saturating<$t>; - - #[inline] - fn sub(self, other: $t) -> Saturating<$t> { - Saturating(self.0.saturating_sub(other)) - } - } - forward_ref_binop! { impl Sub, sub for Saturating<$t>, $t, - #[unstable(feature = "saturating_int_assign_impl", issue = "92354")] } - #[unstable(feature = "saturating_int_impl", issue = "87920")] impl SubAssign for Saturating<$t> { #[inline] @@ -284,7 +260,7 @@ macro_rules! saturating_impl { impl SubAssign<$t> for Saturating<$t> { #[inline] fn sub_assign(&mut self, other: $t) { - *self = *self - other; + *self = *self - Saturating(other); } } forward_ref_op_assign! { impl SubAssign, sub_assign for Saturating<$t>, $t } @@ -301,18 +277,6 @@ macro_rules! saturating_impl { forward_ref_binop! { impl Mul, mul for Saturating<$t>, Saturating<$t>, #[unstable(feature = "saturating_int_impl", issue = "87920")] } - #[unstable(feature = "saturating_int_assign_impl", issue = "92354")] - impl Mul<$t> for Saturating<$t> { - type Output = Saturating<$t>; - - #[inline] - fn mul(self, other: $t) -> Saturating<$t> { - Saturating(self.0.saturating_mul(other)) - } - } - forward_ref_binop! { impl Mul, mul for Saturating<$t>, $t, - #[unstable(feature = "saturating_int_assign_impl", issue = "92354")] } - #[unstable(feature = "saturating_int_impl", issue = "87920")] impl MulAssign for Saturating<$t> { #[inline] @@ -326,7 +290,7 @@ macro_rules! saturating_impl { impl MulAssign<$t> for Saturating<$t> { #[inline] fn mul_assign(&mut self, other: $t) { - *self = *self * other; + *self = *self * Saturating(other); } } forward_ref_op_assign! { impl MulAssign, mul_assign for Saturating<$t>, $t } @@ -362,36 +326,6 @@ macro_rules! saturating_impl { forward_ref_binop! { impl Div, div for Saturating<$t>, Saturating<$t>, #[unstable(feature = "saturating_int_impl", issue = "87920")] } - /// # Examples - /// - /// Basic usage: - /// - /// ``` - /// #![feature(saturating_int_impl, saturating_int_assign_impl)] - /// use std::num::Saturating; - /// - #[doc = concat!("assert_eq!(Saturating(2", stringify!($t), "), Saturating(5", stringify!($t), ") / 2);")] - #[doc = concat!("assert_eq!(Saturating(", stringify!($t), "::MAX), Saturating(", stringify!($t), "::MAX) / 1);")] - #[doc = concat!("assert_eq!(Saturating(", stringify!($t), "::MIN), Saturating(", stringify!($t), "::MIN) / 1);")] - /// ``` - /// - /// ```should_panic - /// #![feature(saturating_int_impl, saturating_int_assign_impl)] - /// use std::num::Saturating; - /// - #[doc = concat!("let _ = Saturating(0", stringify!($t), ") / 0;")] - /// ``` - #[unstable(feature = "saturating_int_assign_impl", issue = "92354")] - impl Div<$t> for Saturating<$t> { - type Output = Saturating<$t>; - - #[inline] - fn div(self, other: $t) -> Saturating<$t> { - Saturating(self.0.saturating_div(other)) - } - } - forward_ref_binop! { impl Div, div for Saturating<$t>, $t, - #[unstable(feature = "saturating_int_assign_impl", issue = "92354")] } #[unstable(feature = "saturating_int_impl", issue = "87920")] impl DivAssign for Saturating<$t> { @@ -406,7 +340,7 @@ macro_rules! saturating_impl { impl DivAssign<$t> for Saturating<$t> { #[inline] fn div_assign(&mut self, other: $t) { - *self = *self / other; + *self = *self / Saturating(other); } } forward_ref_op_assign! { impl DivAssign, div_assign for Saturating<$t>, $t } @@ -423,18 +357,6 @@ macro_rules! saturating_impl { forward_ref_binop! { impl Rem, rem for Saturating<$t>, Saturating<$t>, #[unstable(feature = "saturating_int_impl", issue = "87920")] } - #[unstable(feature = "saturating_int_assign_impl", issue = "92354")] - impl Rem<$t> for Saturating<$t> { - type Output = Saturating<$t>; - - #[inline] - fn rem(self, other: $t) -> Saturating<$t> { - Saturating(self.0.rem(other)) - } - } - forward_ref_binop! { impl Rem, rem for Saturating<$t>, $t, - #[unstable(feature = "saturating_int_assign_impl", issue = "92354")] } - #[unstable(feature = "saturating_int_impl", issue = "87920")] impl RemAssign for Saturating<$t> { #[inline] @@ -448,7 +370,7 @@ macro_rules! saturating_impl { impl RemAssign<$t> for Saturating<$t> { #[inline] fn rem_assign(&mut self, other: $t) { - *self = *self % other; + *self = *self % Saturating(other); } } forward_ref_op_assign! { impl RemAssign, rem_assign for Saturating<$t>, $t } @@ -477,18 +399,6 @@ macro_rules! saturating_impl { forward_ref_binop! { impl BitXor, bitxor for Saturating<$t>, Saturating<$t>, #[unstable(feature = "saturating_int_impl", issue = "87920")] } - #[unstable(feature = "saturating_int_assign_impl", issue = "92354")] - impl BitXor<$t> for Saturating<$t> { - type Output = Saturating<$t>; - - #[inline] - fn bitxor(self, other: $t) -> Saturating<$t> { - Saturating(self.0 ^ other) - } - } - forward_ref_binop! { impl BitXor, bitxor for Saturating<$t>, $t, - #[unstable(feature = "saturating_int_assign_impl", issue = "92354")] } - #[unstable(feature = "saturating_int_impl", issue = "87920")] impl BitXorAssign for Saturating<$t> { #[inline] @@ -502,7 +412,7 @@ macro_rules! saturating_impl { impl BitXorAssign<$t> for Saturating<$t> { #[inline] fn bitxor_assign(&mut self, other: $t) { - *self = *self ^ other; + *self = *self ^ Saturating(other); } } forward_ref_op_assign! { impl BitXorAssign, bitxor_assign for Saturating<$t>, $t } @@ -519,18 +429,6 @@ macro_rules! saturating_impl { forward_ref_binop! { impl BitOr, bitor for Saturating<$t>, Saturating<$t>, #[unstable(feature = "saturating_int_impl", issue = "87920")] } - #[unstable(feature = "saturating_int_assign_impl", issue = "92354")] - impl BitOr<$t> for Saturating<$t> { - type Output = Saturating<$t>; - - #[inline] - fn bitor(self, other: $t) -> Saturating<$t> { - Saturating(self.0 | other) - } - } - forward_ref_binop! { impl BitOr, bitor for Saturating<$t>, $t, - #[unstable(feature = "saturating_int_assign_impl", issue = "92354")] } - #[unstable(feature = "saturating_int_impl", issue = "87920")] impl BitOrAssign for Saturating<$t> { #[inline] @@ -544,7 +442,7 @@ macro_rules! saturating_impl { impl BitOrAssign<$t> for Saturating<$t> { #[inline] fn bitor_assign(&mut self, other: $t) { - *self = *self | other; + *self = *self | Saturating(other); } } forward_ref_op_assign! { impl BitOrAssign, bitor_assign for Saturating<$t>, $t } @@ -561,18 +459,6 @@ macro_rules! saturating_impl { forward_ref_binop! { impl BitAnd, bitand for Saturating<$t>, Saturating<$t>, #[unstable(feature = "saturating_int_impl", issue = "87920")] } - #[unstable(feature = "saturating_int_assign_impl", issue = "92354")] - impl BitAnd<$t> for Saturating<$t> { - type Output = Saturating<$t>; - - #[inline] - fn bitand(self, other: $t) -> Saturating<$t> { - Saturating(self.0 & other) - } - } - forward_ref_binop! { impl BitAnd, bitand for Saturating<$t>, $t, - #[unstable(feature = "saturating_int_assign_impl", issue = "92354")] } - #[unstable(feature = "saturating_int_impl", issue = "87920")] impl BitAndAssign for Saturating<$t> { #[inline] @@ -586,7 +472,7 @@ macro_rules! saturating_impl { impl BitAndAssign<$t> for Saturating<$t> { #[inline] fn bitand_assign(&mut self, other: $t) { - *self = *self & other; + *self = *self & Saturating(other); } } forward_ref_op_assign! { impl BitAndAssign, bitand_assign for Saturating<$t>, $t } From 1ab97dbc52b76fa5b4bc01a110f366d81560b81d Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Wed, 26 Jan 2022 19:09:44 -0800 Subject: [PATCH 13/19] add note suggesting that predicate is satisfied but is not const --- compiler/rustc_middle/src/ty/mod.rs | 9 ++++++++ .../src/traits/error_reporting/mod.rs | 22 +++++++++++++++++++ .../intrinsics/const-eval-select-bad.stderr | 5 +++++ .../assoc-type.stderr | 5 +++++ .../call-generic-method-nonconst.stderr | 5 +++++ .../const-drop-fail.precise.stderr | 5 +++++ .../const-drop-fail.stock.stderr | 5 +++++ ...-method-body-is-const-body-checking.stderr | 5 +++++ .../trait-where-clause.stderr | 10 +++++++++ 9 files changed, 71 insertions(+) diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index 6174c922e2d06..2d8ee549f48dd 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -803,6 +803,10 @@ impl<'tcx> PolyTraitPredicate<'tcx> { p }); } + + pub fn is_const(self) -> bool { + self.skip_binder().constness == BoundConstness::ConstIfConst + } } #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, TyEncodable, TyDecodable)] @@ -1388,6 +1392,10 @@ impl<'tcx> ParamEnv<'tcx> { self.packed.tag().constness } + pub fn is_const(self) -> bool { + self.packed.tag().constness == hir::Constness::Const + } + /// Construct a trait environment with no where-clauses in scope /// where the values of all `impl Trait` and other hidden types /// are revealed. This is suitable for monomorphized, post-typeck @@ -1503,6 +1511,7 @@ impl<'tcx> PolyTraitRef<'tcx> { polarity: ty::ImplPolarity::Positive, }) } + #[inline] pub fn without_const(self) -> PolyTraitPredicate<'tcx> { self.with_constness(BoundConstness::NotConst) diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs index 37cf41a0ec2e2..081f823f851c6 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs @@ -439,6 +439,28 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { } else { err.span_label(span, explanation); } + + if trait_predicate.is_const() && obligation.param_env.is_const() { + let non_const_predicate = trait_ref.without_const(); + let non_const_obligation = Obligation { + cause: obligation.cause.clone(), + param_env: obligation.param_env.without_const(), + predicate: non_const_predicate.to_predicate(tcx), + recursion_depth: obligation.recursion_depth, + }; + if self.predicate_may_hold(&non_const_obligation) { + err.span_note( + span, + &format!( + "the trait `{}` is implemented for `{}`, \ + but that implementation is not `const`", + non_const_predicate.print_modifiers_and_trait_path(), + trait_ref.skip_binder().self_ty(), + ), + ); + } + } + if let Some((msg, span)) = type_def { err.span_label(span, &msg); } diff --git a/src/test/ui/intrinsics/const-eval-select-bad.stderr b/src/test/ui/intrinsics/const-eval-select-bad.stderr index 083b00645388e..06a7a2f63cf5a 100644 --- a/src/test/ui/intrinsics/const-eval-select-bad.stderr +++ b/src/test/ui/intrinsics/const-eval-select-bad.stderr @@ -7,6 +7,11 @@ LL | const_eval_select((), || {}, || {}); | required by a bound introduced by this call | = help: the trait `~const FnOnce<()>` is not implemented for `[closure@$DIR/const-eval-select-bad.rs:6:27: 6:32]` +note: the trait `FnOnce<()>` is implemented for `[closure@$DIR/const-eval-select-bad.rs:6:27: 6:32]`, but that implementation is not `const` + --> $DIR/const-eval-select-bad.rs:6:27 + | +LL | const_eval_select((), || {}, || {}); + | ^^^^^ = note: wrap the `[closure@$DIR/const-eval-select-bad.rs:6:27: 6:32]` in a closure with no arguments: `|| { /* code */ }` note: required by a bound in `const_eval_select` --> $SRC_DIR/core/src/intrinsics.rs:LL:COL diff --git a/src/test/ui/rfc-2632-const-trait-impl/assoc-type.stderr b/src/test/ui/rfc-2632-const-trait-impl/assoc-type.stderr index 429b9f3364be1..0788b17a1c032 100644 --- a/src/test/ui/rfc-2632-const-trait-impl/assoc-type.stderr +++ b/src/test/ui/rfc-2632-const-trait-impl/assoc-type.stderr @@ -5,6 +5,11 @@ LL | type Bar = NonConstAdd; | ^^^^^^^^^^^ no implementation for `NonConstAdd + NonConstAdd` | = help: the trait `~const Add` is not implemented for `NonConstAdd` +note: the trait `Add` is implemented for `NonConstAdd`, but that implementation is not `const` + --> $DIR/assoc-type.rs:18:16 + | +LL | type Bar = NonConstAdd; + | ^^^^^^^^^^^ note: required by a bound in `Foo::Bar` --> $DIR/assoc-type.rs:14:15 | diff --git a/src/test/ui/rfc-2632-const-trait-impl/call-generic-method-nonconst.stderr b/src/test/ui/rfc-2632-const-trait-impl/call-generic-method-nonconst.stderr index 13cffaba91a1d..35b7fe8e401c3 100644 --- a/src/test/ui/rfc-2632-const-trait-impl/call-generic-method-nonconst.stderr +++ b/src/test/ui/rfc-2632-const-trait-impl/call-generic-method-nonconst.stderr @@ -7,6 +7,11 @@ LL | pub const EQ: bool = equals_self(&S); | required by a bound introduced by this call | = help: the trait `~const PartialEq` is not implemented for `S` +note: the trait `PartialEq` is implemented for `S`, but that implementation is not `const` + --> $DIR/call-generic-method-nonconst.rs:19:34 + | +LL | pub const EQ: bool = equals_self(&S); + | ^^ note: required by a bound in `equals_self` --> $DIR/call-generic-method-nonconst.rs:12:25 | diff --git a/src/test/ui/rfc-2632-const-trait-impl/const-drop-fail.precise.stderr b/src/test/ui/rfc-2632-const-trait-impl/const-drop-fail.precise.stderr index df776908a0365..d280cd2556f06 100644 --- a/src/test/ui/rfc-2632-const-trait-impl/const-drop-fail.precise.stderr +++ b/src/test/ui/rfc-2632-const-trait-impl/const-drop-fail.precise.stderr @@ -28,6 +28,11 @@ LL | const _: () = check($exp); LL | ConstImplWithDropGlue(NonTrivialDrop), | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ within `ConstImplWithDropGlue`, the trait `~const Drop` is not implemented for `NonTrivialDrop` | +note: the trait `Drop` is implemented for `NonTrivialDrop`, but that implementation is not `const` + --> $DIR/const-drop-fail.rs:46:5 + | +LL | ConstImplWithDropGlue(NonTrivialDrop), + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ note: required because it appears within the type `ConstImplWithDropGlue` --> $DIR/const-drop-fail.rs:17:8 | diff --git a/src/test/ui/rfc-2632-const-trait-impl/const-drop-fail.stock.stderr b/src/test/ui/rfc-2632-const-trait-impl/const-drop-fail.stock.stderr index df776908a0365..d280cd2556f06 100644 --- a/src/test/ui/rfc-2632-const-trait-impl/const-drop-fail.stock.stderr +++ b/src/test/ui/rfc-2632-const-trait-impl/const-drop-fail.stock.stderr @@ -28,6 +28,11 @@ LL | const _: () = check($exp); LL | ConstImplWithDropGlue(NonTrivialDrop), | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ within `ConstImplWithDropGlue`, the trait `~const Drop` is not implemented for `NonTrivialDrop` | +note: the trait `Drop` is implemented for `NonTrivialDrop`, but that implementation is not `const` + --> $DIR/const-drop-fail.rs:46:5 + | +LL | ConstImplWithDropGlue(NonTrivialDrop), + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ note: required because it appears within the type `ConstImplWithDropGlue` --> $DIR/const-drop-fail.rs:17:8 | diff --git a/src/test/ui/rfc-2632-const-trait-impl/default-method-body-is-const-body-checking.stderr b/src/test/ui/rfc-2632-const-trait-impl/default-method-body-is-const-body-checking.stderr index 05a74757b94f1..bc807507fd668 100644 --- a/src/test/ui/rfc-2632-const-trait-impl/default-method-body-is-const-body-checking.stderr +++ b/src/test/ui/rfc-2632-const-trait-impl/default-method-body-is-const-body-checking.stderr @@ -4,6 +4,11 @@ error[E0277]: the trait bound `(): ~const Tr` is not satisfied LL | foo::<()>(); | ^^ 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-body-checking.rs:12:15 + | +LL | foo::<()>(); + | ^^ note: required by a bound in `foo` --> $DIR/default-method-body-is-const-body-checking.rs:7:28 | diff --git a/src/test/ui/rfc-2632-const-trait-impl/trait-where-clause.stderr b/src/test/ui/rfc-2632-const-trait-impl/trait-where-clause.stderr index 903cd924ca55b..f9b5d81c63b85 100644 --- a/src/test/ui/rfc-2632-const-trait-impl/trait-where-clause.stderr +++ b/src/test/ui/rfc-2632-const-trait-impl/trait-where-clause.stderr @@ -4,6 +4,11 @@ error[E0277]: the trait bound `T: ~const Bar` is not satisfied LL | T::b(); | ^^^^ the trait `~const Bar` is not implemented for `T` | +note: the trait `Bar` is implemented for `T`, but that implementation is not `const` + --> $DIR/trait-where-clause.rs:14:5 + | +LL | T::b(); + | ^^^^ note: required by a bound in `Foo::b` --> $DIR/trait-where-clause.rs:8:24 | @@ -20,6 +25,11 @@ error[E0277]: the trait bound `T: ~const Bar` is not satisfied LL | T::c::(); | ^^^^^^^^^ the trait `~const Bar` is not implemented for `T` | +note: the trait `Bar` is implemented for `T`, but that implementation is not `const` + --> $DIR/trait-where-clause.rs:16:5 + | +LL | T::c::(); + | ^^^^^^^^^ note: required by a bound in `Foo::c` --> $DIR/trait-where-clause.rs:9:13 | From c6de4d55aab6d06f040202cbe39dc5c32809aac2 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Wed, 26 Jan 2022 19:24:01 -0800 Subject: [PATCH 14/19] drive-by: use is_const and is_const_if_const --- .../rustc_const_eval/src/const_eval/eval_queries.rs | 5 ++--- compiler/rustc_lint/src/traits.rs | 3 +-- compiler/rustc_middle/src/ty/mod.rs | 11 +++++++++-- .../src/traits/error_reporting/mod.rs | 2 +- .../src/traits/select/candidate_assembly.rs | 2 +- .../src/traits/select/confirmation.rs | 4 +--- .../rustc_trait_selection/src/traits/select/mod.rs | 4 +--- 7 files changed, 16 insertions(+), 15 deletions(-) diff --git a/compiler/rustc_const_eval/src/const_eval/eval_queries.rs b/compiler/rustc_const_eval/src/const_eval/eval_queries.rs index 3ec9f3ca3b8c2..9dc34260de766 100644 --- a/compiler/rustc_const_eval/src/const_eval/eval_queries.rs +++ b/compiler/rustc_const_eval/src/const_eval/eval_queries.rs @@ -7,7 +7,6 @@ use crate::interpret::{ }; use rustc_errors::ErrorReported; -use rustc_hir as hir; use rustc_hir::def::DefKind; use rustc_middle::mir; use rustc_middle::mir::interpret::ErrorHandled; @@ -216,7 +215,7 @@ pub fn eval_to_const_value_raw_provider<'tcx>( tcx: TyCtxt<'tcx>, key: ty::ParamEnvAnd<'tcx, GlobalId<'tcx>>, ) -> ::rustc_middle::mir::interpret::EvalToConstValueResult<'tcx> { - assert!(key.param_env.constness() == hir::Constness::Const); + assert!(key.param_env.is_const()); // see comment in eval_to_allocation_raw_provider for what we're doing here if key.param_env.reveal() == Reveal::All { let mut key = key; @@ -251,7 +250,7 @@ pub fn eval_to_allocation_raw_provider<'tcx>( tcx: TyCtxt<'tcx>, key: ty::ParamEnvAnd<'tcx, GlobalId<'tcx>>, ) -> ::rustc_middle::mir::interpret::EvalToAllocationRawResult<'tcx> { - assert!(key.param_env.constness() == hir::Constness::Const); + assert!(key.param_env.is_const()); // Because the constant is computed twice (once per value of `Reveal`), we are at risk of // reporting the same error twice here. To resolve this, we check whether we can evaluate the // constant in the more restrictive `Reveal::UserFacing`, which most likely already was diff --git a/compiler/rustc_lint/src/traits.rs b/compiler/rustc_lint/src/traits.rs index dafff640b36ef..4c7f3482776d7 100644 --- a/compiler/rustc_lint/src/traits.rs +++ b/compiler/rustc_lint/src/traits.rs @@ -86,7 +86,6 @@ declare_lint_pass!( impl<'tcx> LateLintPass<'tcx> for DropTraitConstraints { fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::Item<'tcx>) { - use rustc_middle::ty; use rustc_middle::ty::PredicateKind::*; let predicates = cx.tcx.explicit_predicates_of(item.def_id); @@ -94,7 +93,7 @@ impl<'tcx> LateLintPass<'tcx> for DropTraitConstraints { let Trait(trait_predicate) = predicate.kind().skip_binder() else { continue }; - if trait_predicate.constness == ty::BoundConstness::ConstIfConst { + if trait_predicate.is_const_if_const() { // `~const Drop` definitely have meanings so avoid linting here. continue; } diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index 2d8ee549f48dd..e7a8e71ce71b0 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -784,6 +784,11 @@ impl<'tcx> TraitPredicate<'tcx> { pub fn self_ty(self) -> Ty<'tcx> { self.trait_ref.self_ty() } + + #[inline] + pub fn is_const_if_const(self) -> bool { + self.constness == BoundConstness::ConstIfConst + } } impl<'tcx> PolyTraitPredicate<'tcx> { @@ -804,8 +809,9 @@ impl<'tcx> PolyTraitPredicate<'tcx> { }); } - pub fn is_const(self) -> bool { - self.skip_binder().constness == BoundConstness::ConstIfConst + #[inline] + pub fn is_const_if_const(self) -> bool { + self.skip_binder().is_const_if_const() } } @@ -1392,6 +1398,7 @@ impl<'tcx> ParamEnv<'tcx> { self.packed.tag().constness } + #[inline] pub fn is_const(self) -> bool { self.packed.tag().constness == hir::Constness::Const } diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs index 081f823f851c6..687bd16ba30f4 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs @@ -440,7 +440,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { err.span_label(span, explanation); } - if trait_predicate.is_const() && obligation.param_env.is_const() { + if trait_predicate.is_const_if_const() && obligation.param_env.is_const() { let non_const_predicate = trait_ref.without_const(); let non_const_obligation = Obligation { cause: obligation.cause.clone(), diff --git a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs index 0099fba920042..db86041f6180b 100644 --- a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs +++ b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs @@ -305,7 +305,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { } else if lang_items.unsize_trait() == Some(def_id) { self.assemble_candidates_for_unsizing(obligation, &mut candidates); } else if lang_items.drop_trait() == Some(def_id) - && obligation.predicate.skip_binder().constness == ty::BoundConstness::ConstIfConst + && obligation.predicate.is_const_if_const() { self.assemble_const_drop_candidates(obligation, &mut candidates); } else { diff --git a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs index 2e20ea34e10ef..639884844b25d 100644 --- a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs +++ b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs @@ -72,9 +72,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { // CheckPredicate(&A: Super) // CheckPredicate(A: ~const Super) // <- still const env, failure // ``` - if obligation.param_env.constness() == Constness::Const - && obligation.predicate.skip_binder().constness == ty::BoundConstness::NotConst - { + if obligation.param_env.is_const() && !obligation.predicate.is_const_if_const() { new_obligation = TraitObligation { cause: obligation.cause.clone(), param_env: obligation.param_env.without_const(), diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs index ae53690548375..47427395b93b3 100644 --- a/compiler/rustc_trait_selection/src/traits/select/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs @@ -1173,9 +1173,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { ImplCandidate(def_id) if tcx.impl_constness(def_id) == hir::Constness::Const => {} // const param - ParamCandidate(trait_pred) - if trait_pred.skip_binder().constness - == ty::BoundConstness::ConstIfConst => {} + ParamCandidate(trait_pred) if trait_pred.is_const_if_const() => {} // auto trait impl AutoImplCandidate(..) => {} // generator, this will raise error in other places From c6f6e3e0e98dad9578df472a33a71d6bdf104666 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Wed, 26 Jan 2022 22:43:07 -0800 Subject: [PATCH 15/19] do not register infer var for GAT projection in opaque --- .../rustc_infer/src/infer/opaque_types.rs | 16 ++++++++------- .../generic-associated-types/issue-93340.rs | 20 +++++++++++++++++++ 2 files changed, 29 insertions(+), 7 deletions(-) create mode 100644 src/test/ui/generic-associated-types/issue-93340.rs diff --git a/compiler/rustc_infer/src/infer/opaque_types.rs b/compiler/rustc_infer/src/infer/opaque_types.rs index 4851e637d3a62..e7dca94806cb7 100644 --- a/compiler/rustc_infer/src/infer/opaque_types.rs +++ b/compiler/rustc_infer/src/infer/opaque_types.rs @@ -569,13 +569,15 @@ impl<'a, 'tcx> Instantiator<'a, 'tcx> { let predicate = predicate.fold_with(&mut BottomUpFolder { tcx, ty_op: |ty| match ty.kind() { - ty::Projection(projection_ty) => infcx.infer_projection( - self.param_env, - *projection_ty, - traits::ObligationCause::misc(self.value_span, self.body_id), - 0, - &mut self.obligations, - ), + ty::Projection(projection_ty) if !projection_ty.has_escaping_bound_vars() => { + infcx.infer_projection( + self.param_env, + *projection_ty, + traits::ObligationCause::misc(self.value_span, self.body_id), + 0, + &mut self.obligations, + ) + } _ => ty, }, lt_op: |lt| lt, diff --git a/src/test/ui/generic-associated-types/issue-93340.rs b/src/test/ui/generic-associated-types/issue-93340.rs new file mode 100644 index 0000000000000..d065bde88c414 --- /dev/null +++ b/src/test/ui/generic-associated-types/issue-93340.rs @@ -0,0 +1,20 @@ +// check-pass + +#![feature(generic_associated_types)] + +pub trait Scalar: 'static { + type RefType<'a>: ScalarRef<'a>; +} + +pub trait ScalarRef<'a>: 'a {} + +fn cmp_eq<'a, 'b, A: Scalar, B: Scalar, O: Scalar>(a: A::RefType<'a>, b: B::RefType<'b>) -> O { + todo!() +} + +fn build_expression( +) -> impl Fn(A::RefType<'_>, B::RefType<'_>) -> O { + cmp_eq +} + +fn main() {} From db097f308af6b6ec219a460385159985256e2193 Mon Sep 17 00:00:00 2001 From: Kvicii Date: Thu, 27 Jan 2022 22:07:17 +0800 Subject: [PATCH 16/19] fix typo `documenation` --- src/doc/rustdoc/src/references.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/doc/rustdoc/src/references.md b/src/doc/rustdoc/src/references.md index b0e2437392c95..bccc2f8e8fa90 100644 --- a/src/doc/rustdoc/src/references.md +++ b/src/doc/rustdoc/src/references.md @@ -16,7 +16,7 @@ If you know of other great resources, please submit a pull request! - [Github tagged RFCs] - [Github tagged issues] - [RFC (stalled) front page styleguide] -- [Guide on how to write documenation for a Rust crate] +- [Guide on how to write documentation for a Rust crate] [API Guidelines]: https://rust-lang.github.io/api-guidelines/documentation.html From 38f59a3188f44f066105ce58661fd98fbe88e3f3 Mon Sep 17 00:00:00 2001 From: Eric Huss Date: Thu, 27 Jan 2022 15:57:38 -0800 Subject: [PATCH 17/19] rustbuild: Fix compiletest warning when building outside of root. --- src/bootstrap/util.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/bootstrap/util.rs b/src/bootstrap/util.rs index ee58bedcc8735..2c78ceb1e5bec 100644 --- a/src/bootstrap/util.rs +++ b/src/bootstrap/util.rs @@ -282,9 +282,10 @@ pub fn is_valid_test_suite_arg<'a, P: AsRef>( if !path.starts_with(suite_path) { return None; } - let exists = path.is_dir() || path.is_file(); + let abs_path = builder.src.join(path); + let exists = abs_path.is_dir() || abs_path.is_file(); if !exists { - if let Some(p) = path.to_str() { + if let Some(p) = abs_path.to_str() { builder.info(&format!("Warning: Skipping \"{}\": not a regular file or directory", p)); } return None; From 81b4e51c412f9a476d1407005e6de09566179aaa Mon Sep 17 00:00:00 2001 From: scottmcm Date: Fri, 28 Jan 2022 01:35:33 +0000 Subject: [PATCH 18/19] Fix a typo from #92899 Just happened to notice this in passing --- library/core/src/iter/traits/iterator.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/core/src/iter/traits/iterator.rs b/library/core/src/iter/traits/iterator.rs index 65cadcb6c5a4f..a8fe5f59bae01 100644 --- a/library/core/src/iter/traits/iterator.rs +++ b/library/core/src/iter/traits/iterator.rs @@ -515,7 +515,7 @@ pub trait Iterator { /// assert_eq!((2, 'o'), zipper[2]); /// ``` /// - /// If both iterators have roughly equivalent syntax, it may me more readable to use [`zip`]: + /// If both iterators have roughly equivalent syntax, it may be more readable to use [`zip`]: /// /// ``` /// use std::iter::zip; From ff79ce7e6fa0d65a208245d92857bf2c2a14599e Mon Sep 17 00:00:00 2001 From: Kvicii Date: Fri, 28 Jan 2022 10:26:49 +0800 Subject: [PATCH 19/19] fix typo `documenation` --- src/doc/rustdoc/src/references.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/doc/rustdoc/src/references.md b/src/doc/rustdoc/src/references.md index bccc2f8e8fa90..45cf4e88eef6b 100644 --- a/src/doc/rustdoc/src/references.md +++ b/src/doc/rustdoc/src/references.md @@ -22,7 +22,7 @@ If you know of other great resources, please submit a pull request! [API Guidelines]: https://rust-lang.github.io/api-guidelines/documentation.html [Github tagged RFCs]: https://github.com/rust-lang/rfcs/issues?q=label%3AT-rustdoc [Github tagged issues]: https://github.com/rust-lang/rust/issues?q=is%3Aissue+is%3Aopen+label%3AT-rustdoc -[Guide on how to write documenation for a Rust crate]: https://blog.guillaume-gomez.fr/articles/2020-03-12+Guide+on+how+to+write+documentation+for+a+Rust+crate +[Guide on how to write documentation for a Rust crate]: https://blog.guillaume-gomez.fr/articles/2020-03-12+Guide+on+how+to+write+documentation+for+a+Rust+crate [Learn Rust]: https://doc.rust-lang.org/book/ch14-02-publishing-to-crates-io.html#making-useful-documentation-comments [RFC 1574: More API Documentation Conventions]: https://rust-lang.github.io/rfcs/1574-more-api-documentation-conventions.html [RFC 1946: Intra Rustdoc Links]: https://rust-lang.github.io/rfcs/1946-intra-rustdoc-links.html