Rollup merge of #112232 - fee1-dead-contrib:match-eq-const-msg, r=b-naber
Better error for non const `PartialEq` call generated by `match` Resolves #90237
This commit is contained in:
commit
31d1fbf8d2
35 changed files with 211 additions and 100 deletions
|
@ -14,7 +14,7 @@ use rustc_infer::traits::ObligationCause;
|
||||||
use rustc_middle::hir::nested_filter::OnlyBodies;
|
use rustc_middle::hir::nested_filter::OnlyBodies;
|
||||||
use rustc_middle::mir::tcx::PlaceTy;
|
use rustc_middle::mir::tcx::PlaceTy;
|
||||||
use rustc_middle::mir::{
|
use rustc_middle::mir::{
|
||||||
self, AggregateKind, BindingForm, BorrowKind, ClearCrossCrate, ConstraintCategory,
|
self, AggregateKind, BindingForm, BorrowKind, CallSource, ClearCrossCrate, ConstraintCategory,
|
||||||
FakeReadCause, LocalDecl, LocalInfo, LocalKind, Location, Operand, Place, PlaceRef,
|
FakeReadCause, LocalDecl, LocalInfo, LocalKind, Location, Operand, Place, PlaceRef,
|
||||||
ProjectionElem, Rvalue, Statement, StatementKind, Terminator, TerminatorKind, VarBindingForm,
|
ProjectionElem, Rvalue, Statement, StatementKind, Terminator, TerminatorKind, VarBindingForm,
|
||||||
};
|
};
|
||||||
|
@ -2579,7 +2579,10 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
||||||
fn explain_deref_coercion(&mut self, loan: &BorrowData<'tcx>, err: &mut Diagnostic) {
|
fn explain_deref_coercion(&mut self, loan: &BorrowData<'tcx>, err: &mut Diagnostic) {
|
||||||
let tcx = self.infcx.tcx;
|
let tcx = self.infcx.tcx;
|
||||||
if let (
|
if let (
|
||||||
Some(Terminator { kind: TerminatorKind::Call { from_hir_call: false, .. }, .. }),
|
Some(Terminator {
|
||||||
|
kind: TerminatorKind::Call { call_source: CallSource::OverloadedOperator, .. },
|
||||||
|
..
|
||||||
|
}),
|
||||||
Some((method_did, method_substs)),
|
Some((method_did, method_substs)),
|
||||||
) = (
|
) = (
|
||||||
&self.body[loan.reserve_location.block].terminator,
|
&self.body[loan.reserve_location.block].terminator,
|
||||||
|
|
|
@ -6,8 +6,8 @@ use rustc_hir::intravisit::Visitor;
|
||||||
use rustc_index::IndexSlice;
|
use rustc_index::IndexSlice;
|
||||||
use rustc_infer::infer::NllRegionVariableOrigin;
|
use rustc_infer::infer::NllRegionVariableOrigin;
|
||||||
use rustc_middle::mir::{
|
use rustc_middle::mir::{
|
||||||
Body, CastKind, ConstraintCategory, FakeReadCause, Local, LocalInfo, Location, Operand, Place,
|
Body, CallSource, CastKind, ConstraintCategory, FakeReadCause, Local, LocalInfo, Location,
|
||||||
Rvalue, Statement, StatementKind, TerminatorKind,
|
Operand, Place, Rvalue, Statement, StatementKind, TerminatorKind,
|
||||||
};
|
};
|
||||||
use rustc_middle::ty::adjustment::PointerCast;
|
use rustc_middle::ty::adjustment::PointerCast;
|
||||||
use rustc_middle::ty::{self, RegionVid, TyCtxt};
|
use rustc_middle::ty::{self, RegionVid, TyCtxt};
|
||||||
|
@ -494,7 +494,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
||||||
} else if self.was_captured_by_trait_object(borrow) {
|
} else if self.was_captured_by_trait_object(borrow) {
|
||||||
LaterUseKind::TraitCapture
|
LaterUseKind::TraitCapture
|
||||||
} else if location.statement_index == block.statements.len() {
|
} else if location.statement_index == block.statements.len() {
|
||||||
if let TerminatorKind::Call { func, from_hir_call: true, .. } =
|
if let TerminatorKind::Call { func, call_source: CallSource::Normal, .. } =
|
||||||
&block.terminator().kind
|
&block.terminator().kind
|
||||||
{
|
{
|
||||||
// Just point to the function, to reduce the chance of overlapping spans.
|
// Just point to the function, to reduce the chance of overlapping spans.
|
||||||
|
|
|
@ -13,8 +13,9 @@ use rustc_index::IndexSlice;
|
||||||
use rustc_infer::infer::LateBoundRegionConversionTime;
|
use rustc_infer::infer::LateBoundRegionConversionTime;
|
||||||
use rustc_middle::mir::tcx::PlaceTy;
|
use rustc_middle::mir::tcx::PlaceTy;
|
||||||
use rustc_middle::mir::{
|
use rustc_middle::mir::{
|
||||||
AggregateKind, Constant, FakeReadCause, Local, LocalInfo, LocalKind, Location, Operand, Place,
|
AggregateKind, CallSource, Constant, FakeReadCause, Local, LocalInfo, LocalKind, Location,
|
||||||
PlaceRef, ProjectionElem, Rvalue, Statement, StatementKind, Terminator, TerminatorKind,
|
Operand, Place, PlaceRef, ProjectionElem, Rvalue, Statement, StatementKind, Terminator,
|
||||||
|
TerminatorKind,
|
||||||
};
|
};
|
||||||
use rustc_middle::ty::print::Print;
|
use rustc_middle::ty::print::Print;
|
||||||
use rustc_middle::ty::{self, Instance, Ty, TyCtxt};
|
use rustc_middle::ty::{self, Instance, Ty, TyCtxt};
|
||||||
|
@ -414,7 +415,12 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
||||||
if !is_terminator {
|
if !is_terminator {
|
||||||
continue;
|
continue;
|
||||||
} else if let Some(Terminator {
|
} else if let Some(Terminator {
|
||||||
kind: TerminatorKind::Call { func, from_hir_call: false, .. },
|
kind:
|
||||||
|
TerminatorKind::Call {
|
||||||
|
func,
|
||||||
|
call_source: CallSource::OverloadedOperator,
|
||||||
|
..
|
||||||
|
},
|
||||||
..
|
..
|
||||||
}) = &bbd.terminator
|
}) = &bbd.terminator
|
||||||
{
|
{
|
||||||
|
@ -839,7 +845,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
||||||
debug!("move_spans: target_temp = {:?}", target_temp);
|
debug!("move_spans: target_temp = {:?}", target_temp);
|
||||||
|
|
||||||
if let Some(Terminator {
|
if let Some(Terminator {
|
||||||
kind: TerminatorKind::Call { fn_span, from_hir_call, .. }, ..
|
kind: TerminatorKind::Call { fn_span, call_source, .. }, ..
|
||||||
}) = &self.body[location.block].terminator
|
}) = &self.body[location.block].terminator
|
||||||
{
|
{
|
||||||
let Some((method_did, method_substs)) =
|
let Some((method_did, method_substs)) =
|
||||||
|
@ -859,7 +865,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
||||||
method_did,
|
method_did,
|
||||||
method_substs,
|
method_substs,
|
||||||
*fn_span,
|
*fn_span,
|
||||||
*from_hir_call,
|
call_source.from_hir_call(),
|
||||||
Some(self.infcx.tcx.fn_arg_names(method_did)[0]),
|
Some(self.infcx.tcx.fn_arg_names(method_did)[0]),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
|
@ -128,7 +128,7 @@ impl<'cx, 'tcx> Visitor<'tcx> for InvalidationGenerator<'cx, 'tcx> {
|
||||||
destination,
|
destination,
|
||||||
target: _,
|
target: _,
|
||||||
unwind: _,
|
unwind: _,
|
||||||
from_hir_call: _,
|
call_source: _,
|
||||||
fn_span: _,
|
fn_span: _,
|
||||||
} => {
|
} => {
|
||||||
self.consume_operand(location, func);
|
self.consume_operand(location, func);
|
||||||
|
|
|
@ -710,7 +710,7 @@ impl<'cx, 'tcx, R> rustc_mir_dataflow::ResultsVisitor<'cx, 'tcx, R> for MirBorro
|
||||||
destination,
|
destination,
|
||||||
target: _,
|
target: _,
|
||||||
unwind: _,
|
unwind: _,
|
||||||
from_hir_call: _,
|
call_source: _,
|
||||||
fn_span: _,
|
fn_span: _,
|
||||||
} => {
|
} => {
|
||||||
self.consume_operand(loc, (func, span), flow_state);
|
self.consume_operand(loc, (func, span), flow_state);
|
||||||
|
|
|
@ -1370,7 +1370,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
||||||
}
|
}
|
||||||
// FIXME: check the values
|
// FIXME: check the values
|
||||||
}
|
}
|
||||||
TerminatorKind::Call { func, args, destination, from_hir_call, target, .. } => {
|
TerminatorKind::Call { func, args, destination, call_source, target, .. } => {
|
||||||
self.check_operand(func, term_location);
|
self.check_operand(func, term_location);
|
||||||
for arg in args {
|
for arg in args {
|
||||||
self.check_operand(arg, term_location);
|
self.check_operand(arg, term_location);
|
||||||
|
@ -1446,7 +1446,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
||||||
.add_element(region_vid, term_location);
|
.add_element(region_vid, term_location);
|
||||||
}
|
}
|
||||||
|
|
||||||
self.check_call_inputs(body, term, &sig, args, term_location, *from_hir_call);
|
self.check_call_inputs(body, term, &sig, args, term_location, *call_source);
|
||||||
}
|
}
|
||||||
TerminatorKind::Assert { cond, msg, .. } => {
|
TerminatorKind::Assert { cond, msg, .. } => {
|
||||||
self.check_operand(cond, term_location);
|
self.check_operand(cond, term_location);
|
||||||
|
@ -1573,7 +1573,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
||||||
sig: &ty::FnSig<'tcx>,
|
sig: &ty::FnSig<'tcx>,
|
||||||
args: &[Operand<'tcx>],
|
args: &[Operand<'tcx>],
|
||||||
term_location: Location,
|
term_location: Location,
|
||||||
from_hir_call: bool,
|
call_source: CallSource,
|
||||||
) {
|
) {
|
||||||
debug!("check_call_inputs({:?}, {:?})", sig, args);
|
debug!("check_call_inputs({:?}, {:?})", sig, args);
|
||||||
if args.len() < sig.inputs().len() || (args.len() > sig.inputs().len() && !sig.c_variadic) {
|
if args.len() < sig.inputs().len() || (args.len() > sig.inputs().len() && !sig.c_variadic) {
|
||||||
|
@ -1591,7 +1591,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
||||||
let op_arg_ty = op_arg.ty(body, self.tcx());
|
let op_arg_ty = op_arg.ty(body, self.tcx());
|
||||||
|
|
||||||
let op_arg_ty = self.normalize(op_arg_ty, term_location);
|
let op_arg_ty = self.normalize(op_arg_ty, term_location);
|
||||||
let category = if from_hir_call {
|
let category = if call_source.from_hir_call() {
|
||||||
ConstraintCategory::CallArgument(self.infcx.tcx.erase_regions(func_ty))
|
ConstraintCategory::CallArgument(self.infcx.tcx.erase_regions(func_ty))
|
||||||
} else {
|
} else {
|
||||||
ConstraintCategory::Boring
|
ConstraintCategory::Boring
|
||||||
|
|
|
@ -421,7 +421,7 @@ fn codegen_fn_body(fx: &mut FunctionCx<'_, '_, '_>, start_block: Block) {
|
||||||
target,
|
target,
|
||||||
fn_span,
|
fn_span,
|
||||||
unwind: _,
|
unwind: _,
|
||||||
from_hir_call: _,
|
call_source: _,
|
||||||
} => {
|
} => {
|
||||||
fx.tcx.prof.generic_activity("codegen call").run(|| {
|
fx.tcx.prof.generic_activity("codegen call").run(|| {
|
||||||
crate::abi::codegen_terminator_call(
|
crate::abi::codegen_terminator_call(
|
||||||
|
|
|
@ -1280,7 +1280,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
||||||
destination,
|
destination,
|
||||||
target,
|
target,
|
||||||
unwind,
|
unwind,
|
||||||
from_hir_call: _,
|
call_source: _,
|
||||||
fn_span,
|
fn_span,
|
||||||
} => self.codegen_call_terminator(
|
} => self.codegen_call_terminator(
|
||||||
helper,
|
helper,
|
||||||
|
|
|
@ -210,6 +210,9 @@ const_eval_long_running =
|
||||||
.label = the const evaluator is currently interpreting this expression
|
.label = the const evaluator is currently interpreting this expression
|
||||||
.help = the constant being evaluated
|
.help = the constant being evaluated
|
||||||
|
|
||||||
|
const_eval_match_eq_non_const = cannot match on `{$ty}` in {const_eval_const_context}s
|
||||||
|
.note = `{$ty}` cannot be compared in compile-time, and therefore cannot be used in `match`es
|
||||||
|
|
||||||
const_eval_max_num_nodes_in_const = maximum number of nodes exceeded in constant {$global_const_id}
|
const_eval_max_num_nodes_in_const = maximum number of nodes exceeded in constant {$global_const_id}
|
||||||
|
|
||||||
const_eval_memory_access_test = memory access failed
|
const_eval_memory_access_test = memory access failed
|
||||||
|
|
|
@ -271,6 +271,18 @@ pub struct RawBytesNote {
|
||||||
pub bytes: String,
|
pub bytes: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// FIXME(fee1-dead) do not use stringly typed `ConstContext`
|
||||||
|
|
||||||
|
#[derive(Diagnostic)]
|
||||||
|
#[diag(const_eval_match_eq_non_const, code = "E0015")]
|
||||||
|
#[note]
|
||||||
|
pub struct NonConstMatchEq<'tcx> {
|
||||||
|
#[primary_span]
|
||||||
|
pub span: Span,
|
||||||
|
pub ty: Ty<'tcx>,
|
||||||
|
pub kind: ConstContext,
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Diagnostic)]
|
#[derive(Diagnostic)]
|
||||||
#[diag(const_eval_for_loop_into_iter_non_const, code = "E0015")]
|
#[diag(const_eval_for_loop_into_iter_non_const, code = "E0015")]
|
||||||
pub struct NonConstForLoopIntoIter<'tcx> {
|
pub struct NonConstForLoopIntoIter<'tcx> {
|
||||||
|
|
|
@ -62,7 +62,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
||||||
destination,
|
destination,
|
||||||
target,
|
target,
|
||||||
unwind,
|
unwind,
|
||||||
from_hir_call: _,
|
call_source: _,
|
||||||
fn_span: _,
|
fn_span: _,
|
||||||
} => {
|
} => {
|
||||||
let old_stack = self.frame_idx();
|
let old_stack = self.frame_idx();
|
||||||
|
|
|
@ -702,7 +702,7 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
|
||||||
self.super_terminator(terminator, location);
|
self.super_terminator(terminator, location);
|
||||||
|
|
||||||
match &terminator.kind {
|
match &terminator.kind {
|
||||||
TerminatorKind::Call { func, args, fn_span, from_hir_call, .. } => {
|
TerminatorKind::Call { func, args, fn_span, call_source, .. } => {
|
||||||
let ConstCx { tcx, body, param_env, .. } = *self.ccx;
|
let ConstCx { tcx, body, param_env, .. } = *self.ccx;
|
||||||
let caller = self.def_id();
|
let caller = self.def_id();
|
||||||
|
|
||||||
|
@ -755,7 +755,7 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
|
||||||
callee,
|
callee,
|
||||||
substs,
|
substs,
|
||||||
span: *fn_span,
|
span: *fn_span,
|
||||||
from_hir_call: *from_hir_call,
|
call_source: *call_source,
|
||||||
feature: Some(sym::const_trait_impl),
|
feature: Some(sym::const_trait_impl),
|
||||||
});
|
});
|
||||||
return;
|
return;
|
||||||
|
@ -797,7 +797,7 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
|
||||||
callee,
|
callee,
|
||||||
substs,
|
substs,
|
||||||
span: *fn_span,
|
span: *fn_span,
|
||||||
from_hir_call: *from_hir_call,
|
call_source: *call_source,
|
||||||
feature: None,
|
feature: None,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -823,7 +823,7 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
|
||||||
callee,
|
callee,
|
||||||
substs,
|
substs,
|
||||||
span: *fn_span,
|
span: *fn_span,
|
||||||
from_hir_call: *from_hir_call,
|
call_source: *call_source,
|
||||||
feature: None,
|
feature: None,
|
||||||
});
|
});
|
||||||
return;
|
return;
|
||||||
|
@ -866,7 +866,7 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
|
||||||
callee,
|
callee,
|
||||||
substs,
|
substs,
|
||||||
span: *fn_span,
|
span: *fn_span,
|
||||||
from_hir_call: *from_hir_call,
|
call_source: *call_source,
|
||||||
feature: None,
|
feature: None,
|
||||||
});
|
});
|
||||||
return;
|
return;
|
||||||
|
@ -926,7 +926,7 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
|
||||||
callee,
|
callee,
|
||||||
substs,
|
substs,
|
||||||
span: *fn_span,
|
span: *fn_span,
|
||||||
from_hir_call: *from_hir_call,
|
call_source: *call_source,
|
||||||
feature: None,
|
feature: None,
|
||||||
});
|
});
|
||||||
return;
|
return;
|
||||||
|
|
|
@ -7,7 +7,7 @@ use rustc_hir as hir;
|
||||||
use rustc_hir::def_id::DefId;
|
use rustc_hir::def_id::DefId;
|
||||||
use rustc_infer::infer::TyCtxtInferExt;
|
use rustc_infer::infer::TyCtxtInferExt;
|
||||||
use rustc_infer::traits::{ImplSource, Obligation, ObligationCause};
|
use rustc_infer::traits::{ImplSource, Obligation, ObligationCause};
|
||||||
use rustc_middle::mir;
|
use rustc_middle::mir::{self, CallSource};
|
||||||
use rustc_middle::ty::print::with_no_trimmed_paths;
|
use rustc_middle::ty::print::with_no_trimmed_paths;
|
||||||
use rustc_middle::ty::subst::{GenericArgKind, SubstsRef};
|
use rustc_middle::ty::subst::{GenericArgKind, SubstsRef};
|
||||||
use rustc_middle::ty::{suggest_constraining_type_param, Adt, Closure, FnDef, FnPtr, Param, Ty};
|
use rustc_middle::ty::{suggest_constraining_type_param, Adt, Closure, FnDef, FnPtr, Param, Ty};
|
||||||
|
@ -100,7 +100,7 @@ pub struct FnCallNonConst<'tcx> {
|
||||||
pub callee: DefId,
|
pub callee: DefId,
|
||||||
pub substs: SubstsRef<'tcx>,
|
pub substs: SubstsRef<'tcx>,
|
||||||
pub span: Span,
|
pub span: Span,
|
||||||
pub from_hir_call: bool,
|
pub call_source: CallSource,
|
||||||
pub feature: Option<Symbol>,
|
pub feature: Option<Symbol>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -110,7 +110,7 @@ impl<'tcx> NonConstOp<'tcx> for FnCallNonConst<'tcx> {
|
||||||
ccx: &ConstCx<'_, 'tcx>,
|
ccx: &ConstCx<'_, 'tcx>,
|
||||||
_: Span,
|
_: Span,
|
||||||
) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
|
) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
|
||||||
let FnCallNonConst { caller, callee, substs, span, from_hir_call, feature } = *self;
|
let FnCallNonConst { caller, callee, substs, span, call_source, feature } = *self;
|
||||||
let ConstCx { tcx, param_env, .. } = *ccx;
|
let ConstCx { tcx, param_env, .. } = *ccx;
|
||||||
|
|
||||||
let diag_trait = |err, self_ty: Ty<'_>, trait_id| {
|
let diag_trait = |err, self_ty: Ty<'_>, trait_id| {
|
||||||
|
@ -157,7 +157,8 @@ impl<'tcx> NonConstOp<'tcx> for FnCallNonConst<'tcx> {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
let call_kind = call_kind(tcx, ccx.param_env, callee, substs, span, from_hir_call, None);
|
let call_kind =
|
||||||
|
call_kind(tcx, ccx.param_env, callee, substs, span, call_source.from_hir_call(), None);
|
||||||
|
|
||||||
debug!(?call_kind);
|
debug!(?call_kind);
|
||||||
|
|
||||||
|
@ -219,6 +220,13 @@ impl<'tcx> NonConstOp<'tcx> for FnCallNonConst<'tcx> {
|
||||||
err
|
err
|
||||||
}
|
}
|
||||||
CallKind::Operator { trait_id, self_ty, .. } => {
|
CallKind::Operator { trait_id, self_ty, .. } => {
|
||||||
|
let mut err = if let CallSource::MatchCmp = call_source {
|
||||||
|
tcx.sess.create_err(errors::NonConstMatchEq {
|
||||||
|
span,
|
||||||
|
kind: ccx.const_kind(),
|
||||||
|
ty: self_ty,
|
||||||
|
})
|
||||||
|
} else {
|
||||||
let mut sugg = None;
|
let mut sugg = None;
|
||||||
|
|
||||||
if Some(trait_id) == ccx.tcx.lang_items().eq_trait() {
|
if Some(trait_id) == ccx.tcx.lang_items().eq_trait() {
|
||||||
|
@ -236,13 +244,15 @@ impl<'tcx> NonConstOp<'tcx> for FnCallNonConst<'tcx> {
|
||||||
}
|
}
|
||||||
let deref = "*".repeat(num_refs);
|
let deref = "*".repeat(num_refs);
|
||||||
|
|
||||||
if let Ok(call_str) = ccx.tcx.sess.source_map().span_to_snippet(span) {
|
if let Ok(call_str) =
|
||||||
if let Some(eq_idx) = call_str.find("==") {
|
ccx.tcx.sess.source_map().span_to_snippet(span)
|
||||||
if let Some(rhs_idx) =
|
|
||||||
call_str[(eq_idx + 2)..].find(|c: char| !c.is_whitespace())
|
|
||||||
{
|
{
|
||||||
let rhs_pos =
|
if let Some(eq_idx) = call_str.find("==") {
|
||||||
span.lo() + BytePos::from_usize(eq_idx + 2 + rhs_idx);
|
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);
|
let rhs_span = span.with_lo(rhs_pos).with_hi(rhs_pos);
|
||||||
sugg = Some(errors::ConsiderDereferencing {
|
sugg = Some(errors::ConsiderDereferencing {
|
||||||
deref,
|
deref,
|
||||||
|
@ -256,11 +266,13 @@ impl<'tcx> NonConstOp<'tcx> for FnCallNonConst<'tcx> {
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
let mut err = tcx.sess.create_err(errors::NonConstOperator {
|
tcx.sess.create_err(errors::NonConstOperator {
|
||||||
span,
|
span,
|
||||||
kind: ccx.const_kind(),
|
kind: ccx.const_kind(),
|
||||||
sugg,
|
sugg,
|
||||||
});
|
})
|
||||||
|
};
|
||||||
|
|
||||||
diag_trait(&mut err, self_ty, trait_id);
|
diag_trait(&mut err, self_ty, trait_id);
|
||||||
err
|
err
|
||||||
}
|
}
|
||||||
|
|
|
@ -797,7 +797,9 @@ impl<'a, 'tcx> Promoter<'a, 'tcx> {
|
||||||
};
|
};
|
||||||
|
|
||||||
match terminator.kind {
|
match terminator.kind {
|
||||||
TerminatorKind::Call { mut func, mut args, from_hir_call, fn_span, .. } => {
|
TerminatorKind::Call {
|
||||||
|
mut func, mut args, call_source: desugar, fn_span, ..
|
||||||
|
} => {
|
||||||
self.visit_operand(&mut func, loc);
|
self.visit_operand(&mut func, loc);
|
||||||
for arg in &mut args {
|
for arg in &mut args {
|
||||||
self.visit_operand(arg, loc);
|
self.visit_operand(arg, loc);
|
||||||
|
@ -813,7 +815,7 @@ impl<'a, 'tcx> Promoter<'a, 'tcx> {
|
||||||
unwind: UnwindAction::Continue,
|
unwind: UnwindAction::Continue,
|
||||||
destination: Place::from(new_temp),
|
destination: Place::from(new_temp),
|
||||||
target: Some(new_target),
|
target: Some(new_target),
|
||||||
from_hir_call,
|
call_source: desugar,
|
||||||
fn_span,
|
fn_span,
|
||||||
},
|
},
|
||||||
source_info: SourceInfo::outermost(terminator.source_info.span),
|
source_info: SourceInfo::outermost(terminator.source_info.span),
|
||||||
|
|
|
@ -512,6 +512,31 @@ pub struct CopyNonOverlapping<'tcx> {
|
||||||
pub count: Operand<'tcx>,
|
pub count: Operand<'tcx>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Represents how a `TerminatorKind::Call` was constructed, used for diagnostics
|
||||||
|
#[derive(Clone, Copy, TyEncodable, TyDecodable, Debug, PartialEq, Hash, HashStable)]
|
||||||
|
#[derive(TypeFoldable, TypeVisitable)]
|
||||||
|
pub enum CallSource {
|
||||||
|
/// This came from something such as `a > b` or `a + b`. In THIR, if `from_hir_call`
|
||||||
|
/// is false then this is the desugaring.
|
||||||
|
OverloadedOperator,
|
||||||
|
/// This was from comparison generated by a match, used by const-eval for better errors
|
||||||
|
/// when the comparison cannot be done in compile time.
|
||||||
|
///
|
||||||
|
/// (see <https://github.com/rust-lang/rust/issues/90237>)
|
||||||
|
MatchCmp,
|
||||||
|
/// Other types of desugaring that did not come from the HIR, but we don't care about
|
||||||
|
/// for diagnostics (yet).
|
||||||
|
Misc,
|
||||||
|
/// Normal function call, no special source
|
||||||
|
Normal,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl CallSource {
|
||||||
|
pub fn from_hir_call(self) -> bool {
|
||||||
|
matches!(self, CallSource::Normal)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////
|
||||||
// Terminators
|
// Terminators
|
||||||
|
|
||||||
|
@ -638,11 +663,10 @@ pub enum TerminatorKind<'tcx> {
|
||||||
target: Option<BasicBlock>,
|
target: Option<BasicBlock>,
|
||||||
/// Action to be taken if the call unwinds.
|
/// Action to be taken if the call unwinds.
|
||||||
unwind: UnwindAction,
|
unwind: UnwindAction,
|
||||||
/// `true` if this is from a call in HIR rather than from an overloaded
|
/// Where this call came from in HIR/THIR.
|
||||||
/// operator. True for overloaded function call.
|
call_source: CallSource,
|
||||||
from_hir_call: bool,
|
|
||||||
/// This `Span` is the span of the function, without the dot and receiver
|
/// This `Span` is the span of the function, without the dot and receiver
|
||||||
/// (e.g. `foo(a, b)` in `x.foo(a, b)`
|
/// e.g. `foo(a, b)` in `x.foo(a, b)`
|
||||||
fn_span: Span,
|
fn_span: Span,
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
|
@ -519,7 +519,7 @@ macro_rules! make_mir_visitor {
|
||||||
destination,
|
destination,
|
||||||
target: _,
|
target: _,
|
||||||
unwind: _,
|
unwind: _,
|
||||||
from_hir_call: _,
|
call_source: _,
|
||||||
fn_span: _
|
fn_span: _
|
||||||
} => {
|
} => {
|
||||||
self.visit_operand(func, location);
|
self.visit_operand(func, location);
|
||||||
|
|
|
@ -128,7 +128,9 @@ impl<'tcx, 'body> ParseCtxt<'tcx, 'body> {
|
||||||
destination,
|
destination,
|
||||||
target: Some(target),
|
target: Some(target),
|
||||||
unwind: UnwindAction::Continue,
|
unwind: UnwindAction::Continue,
|
||||||
from_hir_call: *from_hir_call,
|
call_source: if *from_hir_call { CallSource::Normal } else {
|
||||||
|
CallSource::OverloadedOperator
|
||||||
|
},
|
||||||
fn_span: *fn_span,
|
fn_span: *fn_span,
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
|
|
|
@ -173,7 +173,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||||
destination: storage,
|
destination: storage,
|
||||||
target: Some(success),
|
target: Some(success),
|
||||||
unwind: UnwindAction::Continue,
|
unwind: UnwindAction::Continue,
|
||||||
from_hir_call: false,
|
call_source: CallSource::Misc,
|
||||||
fn_span: expr_span,
|
fn_span: expr_span,
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
|
@ -277,7 +277,11 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||||
.ty
|
.ty
|
||||||
.is_inhabited_from(this.tcx, this.parent_module, this.param_env)
|
.is_inhabited_from(this.tcx, this.parent_module, this.param_env)
|
||||||
.then_some(success),
|
.then_some(success),
|
||||||
from_hir_call,
|
call_source: if from_hir_call {
|
||||||
|
CallSource::Normal
|
||||||
|
} else {
|
||||||
|
CallSource::OverloadedOperator
|
||||||
|
},
|
||||||
fn_span,
|
fn_span,
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
|
@ -264,7 +264,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||||
destination: ref_str,
|
destination: ref_str,
|
||||||
target: Some(eq_block),
|
target: Some(eq_block),
|
||||||
unwind: UnwindAction::Continue,
|
unwind: UnwindAction::Continue,
|
||||||
from_hir_call: false,
|
call_source: CallSource::Misc,
|
||||||
fn_span: source_info.span
|
fn_span: source_info.span
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
@ -496,7 +496,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||||
destination: eq_result,
|
destination: eq_result,
|
||||||
target: Some(eq_block),
|
target: Some(eq_block),
|
||||||
unwind: UnwindAction::Continue,
|
unwind: UnwindAction::Continue,
|
||||||
from_hir_call: false,
|
call_source: CallSource::MatchCmp,
|
||||||
fn_span: source_info.span,
|
fn_span: source_info.span,
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
|
@ -654,7 +654,7 @@ where
|
||||||
destination: unit_temp,
|
destination: unit_temp,
|
||||||
target: Some(succ),
|
target: Some(succ),
|
||||||
unwind: unwind.into_action(),
|
unwind: unwind.into_action(),
|
||||||
from_hir_call: true,
|
call_source: CallSource::Misc,
|
||||||
fn_span: self.source_info.span,
|
fn_span: self.source_info.span,
|
||||||
},
|
},
|
||||||
source_info: self.source_info,
|
source_info: self.source_info,
|
||||||
|
|
|
@ -502,15 +502,7 @@ impl Direction for Forward {
|
||||||
propagate(target, exit_state);
|
propagate(target, exit_state);
|
||||||
}
|
}
|
||||||
|
|
||||||
Call {
|
Call { unwind, destination, target, func: _, args: _, call_source: _, fn_span: _ } => {
|
||||||
unwind,
|
|
||||||
destination,
|
|
||||||
target,
|
|
||||||
func: _,
|
|
||||||
args: _,
|
|
||||||
from_hir_call: _,
|
|
||||||
fn_span: _,
|
|
||||||
} => {
|
|
||||||
if let UnwindAction::Cleanup(unwind) = unwind {
|
if let UnwindAction::Cleanup(unwind) = unwind {
|
||||||
propagate(unwind, exit_state);
|
propagate(unwind, exit_state);
|
||||||
}
|
}
|
||||||
|
|
|
@ -40,7 +40,7 @@ fn mock_body<'tcx>() -> mir::Body<'tcx> {
|
||||||
destination: dummy_place.clone(),
|
destination: dummy_place.clone(),
|
||||||
target: Some(mir::START_BLOCK),
|
target: Some(mir::START_BLOCK),
|
||||||
unwind: mir::UnwindAction::Continue,
|
unwind: mir::UnwindAction::Continue,
|
||||||
from_hir_call: false,
|
call_source: mir::CallSource::Misc,
|
||||||
fn_span: DUMMY_SP,
|
fn_span: DUMMY_SP,
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
@ -54,7 +54,7 @@ fn mock_body<'tcx>() -> mir::Body<'tcx> {
|
||||||
destination: dummy_place.clone(),
|
destination: dummy_place.clone(),
|
||||||
target: Some(mir::START_BLOCK),
|
target: Some(mir::START_BLOCK),
|
||||||
unwind: mir::UnwindAction::Continue,
|
unwind: mir::UnwindAction::Continue,
|
||||||
from_hir_call: false,
|
call_source: mir::CallSource::Misc,
|
||||||
fn_span: DUMMY_SP,
|
fn_span: DUMMY_SP,
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
|
@ -399,7 +399,7 @@ impl<'b, 'a, 'tcx> Gatherer<'b, 'a, 'tcx> {
|
||||||
destination,
|
destination,
|
||||||
target,
|
target,
|
||||||
unwind: _,
|
unwind: _,
|
||||||
from_hir_call: _,
|
call_source: _,
|
||||||
fn_span: _,
|
fn_span: _,
|
||||||
} => {
|
} => {
|
||||||
self.gather_operand(func);
|
self.gather_operand(func);
|
||||||
|
|
|
@ -140,7 +140,7 @@ impl<'tcx> MockBlocks<'tcx> {
|
||||||
destination: self.dummy_place.clone(),
|
destination: self.dummy_place.clone(),
|
||||||
target: Some(TEMP_BLOCK),
|
target: Some(TEMP_BLOCK),
|
||||||
unwind: UnwindAction::Continue,
|
unwind: UnwindAction::Continue,
|
||||||
from_hir_call: false,
|
call_source: CallSource::Misc,
|
||||||
fn_span: DUMMY_SP,
|
fn_span: DUMMY_SP,
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|
|
@ -34,7 +34,7 @@ impl<'tcx> Visitor<'tcx> for FunctionItemRefChecker<'_, 'tcx> {
|
||||||
destination: _,
|
destination: _,
|
||||||
target: _,
|
target: _,
|
||||||
unwind: _,
|
unwind: _,
|
||||||
from_hir_call: _,
|
call_source: _,
|
||||||
fn_span: _,
|
fn_span: _,
|
||||||
} = &terminator.kind
|
} = &terminator.kind
|
||||||
{
|
{
|
||||||
|
|
|
@ -1692,7 +1692,7 @@ impl<'tcx> Visitor<'tcx> for EnsureGeneratorFieldAssignmentsNeverAlias<'_> {
|
||||||
destination,
|
destination,
|
||||||
target: Some(_),
|
target: Some(_),
|
||||||
unwind: _,
|
unwind: _,
|
||||||
from_hir_call: _,
|
call_source: _,
|
||||||
fn_span: _,
|
fn_span: _,
|
||||||
} => {
|
} => {
|
||||||
self.check_assigned_place(*destination, |this| {
|
self.check_assigned_place(*destination, |this| {
|
||||||
|
|
|
@ -30,8 +30,8 @@ use rustc_hir::intravisit::{self, Visitor};
|
||||||
use rustc_index::IndexVec;
|
use rustc_index::IndexVec;
|
||||||
use rustc_middle::mir::visit::Visitor as _;
|
use rustc_middle::mir::visit::Visitor as _;
|
||||||
use rustc_middle::mir::{
|
use rustc_middle::mir::{
|
||||||
traversal, AnalysisPhase, Body, ClearCrossCrate, ConstQualifs, Constant, LocalDecl, MirPass,
|
traversal, AnalysisPhase, Body, CallSource, ClearCrossCrate, ConstQualifs, Constant, LocalDecl,
|
||||||
MirPhase, Operand, Place, ProjectionElem, Promoted, RuntimePhase, Rvalue, SourceInfo,
|
MirPass, MirPhase, Operand, Place, ProjectionElem, Promoted, RuntimePhase, Rvalue, SourceInfo,
|
||||||
Statement, StatementKind, TerminatorKind, START_BLOCK,
|
Statement, StatementKind, TerminatorKind, START_BLOCK,
|
||||||
};
|
};
|
||||||
use rustc_middle::query::Providers;
|
use rustc_middle::query::Providers;
|
||||||
|
@ -189,7 +189,7 @@ fn remap_mir_for_const_eval_select<'tcx>(
|
||||||
};
|
};
|
||||||
method(place)
|
method(place)
|
||||||
}).collect();
|
}).collect();
|
||||||
terminator.kind = TerminatorKind::Call { func, args: arguments, destination, target, unwind, from_hir_call: false, fn_span };
|
terminator.kind = TerminatorKind::Call { func, args: arguments, destination, target, unwind, call_source: CallSource::Misc, fn_span };
|
||||||
}
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
|
|
|
@ -54,7 +54,7 @@ fn lower_slice_len_call<'tcx>(
|
||||||
args,
|
args,
|
||||||
destination,
|
destination,
|
||||||
target: Some(bb),
|
target: Some(bb),
|
||||||
from_hir_call: true,
|
call_source: CallSource::Normal,
|
||||||
..
|
..
|
||||||
} => {
|
} => {
|
||||||
// some heuristics for fast rejection
|
// some heuristics for fast rejection
|
||||||
|
|
|
@ -500,7 +500,7 @@ impl<'tcx> CloneShimBuilder<'tcx> {
|
||||||
destination: dest,
|
destination: dest,
|
||||||
target: Some(next),
|
target: Some(next),
|
||||||
unwind: UnwindAction::Cleanup(cleanup),
|
unwind: UnwindAction::Cleanup(cleanup),
|
||||||
from_hir_call: true,
|
call_source: CallSource::Normal,
|
||||||
fn_span: self.span,
|
fn_span: self.span,
|
||||||
},
|
},
|
||||||
false,
|
false,
|
||||||
|
@ -789,7 +789,7 @@ fn build_call_shim<'tcx>(
|
||||||
} else {
|
} else {
|
||||||
UnwindAction::Continue
|
UnwindAction::Continue
|
||||||
},
|
},
|
||||||
from_hir_call: true,
|
call_source: CallSource::Misc,
|
||||||
fn_span: span,
|
fn_span: span,
|
||||||
},
|
},
|
||||||
false,
|
false,
|
||||||
|
|
|
@ -351,7 +351,7 @@ impl<'tcx> Stable for mir::Terminator<'tcx> {
|
||||||
target: target.as_usize(),
|
target: target.as_usize(),
|
||||||
unwind: unwind.stable(),
|
unwind: unwind.stable(),
|
||||||
},
|
},
|
||||||
Call { func, args, destination, target, unwind, from_hir_call: _, fn_span: _ } => {
|
Call { func, args, destination, target, unwind, call_source: _, fn_span: _ } => {
|
||||||
Terminator::Call {
|
Terminator::Call {
|
||||||
func: func.stable(),
|
func: func.stable(),
|
||||||
args: args.iter().map(|arg| arg.stable()).collect(),
|
args: args.iter().map(|arg| arg.stable()).collect(),
|
||||||
|
|
|
@ -317,7 +317,7 @@ fn check_terminator<'tcx>(
|
||||||
TerminatorKind::Call {
|
TerminatorKind::Call {
|
||||||
func,
|
func,
|
||||||
args,
|
args,
|
||||||
from_hir_call: _,
|
call_source: _,
|
||||||
destination: _,
|
destination: _,
|
||||||
target: _,
|
target: _,
|
||||||
unwind: _,
|
unwind: _,
|
||||||
|
|
|
@ -0,0 +1,26 @@
|
||||||
|
error[E0277]: can't compare `str` with `str` in const contexts
|
||||||
|
--> $DIR/match-non-const-eq.rs:6:9
|
||||||
|
|
|
||||||
|
LL | "a" => (),
|
||||||
|
| ^^^ no implementation for `str == str`
|
||||||
|
|
|
||||||
|
= help: the trait `~const PartialEq` is not implemented for `str`
|
||||||
|
note: the trait `PartialEq` is implemented for `str`, but that implementation is not `const`
|
||||||
|
--> $DIR/match-non-const-eq.rs:6:9
|
||||||
|
|
|
||||||
|
LL | "a" => (),
|
||||||
|
| ^^^
|
||||||
|
|
||||||
|
error[E0015]: cannot match on `str` in constant functions
|
||||||
|
--> $DIR/match-non-const-eq.rs:6:9
|
||||||
|
|
|
||||||
|
LL | "a" => (),
|
||||||
|
| ^^^
|
||||||
|
|
|
||||||
|
= note: `str` cannot be compared in compile-time, and therefore cannot be used in `match`es
|
||||||
|
= note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
|
||||||
|
|
||||||
|
error: aborting due to 2 previous errors
|
||||||
|
|
||||||
|
Some errors have detailed explanations: E0015, E0277.
|
||||||
|
For more information about an error, try `rustc --explain E0015`.
|
|
@ -0,0 +1,12 @@
|
||||||
|
// revisions: stock gated
|
||||||
|
#![cfg_attr(gated, feature(const_trait_impl))]
|
||||||
|
|
||||||
|
const fn foo(input: &'static str) {
|
||||||
|
match input {
|
||||||
|
"a" => (), //[gated]~ ERROR can't compare `str` with `str` in const contexts
|
||||||
|
//~^ ERROR cannot match on `str` in constant functions
|
||||||
|
_ => (),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {}
|
|
@ -0,0 +1,13 @@
|
||||||
|
error[E0015]: cannot match on `str` in constant functions
|
||||||
|
--> $DIR/match-non-const-eq.rs:6:9
|
||||||
|
|
|
||||||
|
LL | "a" => (),
|
||||||
|
| ^^^
|
||||||
|
|
|
||||||
|
= note: `str` cannot be compared in compile-time, and therefore cannot be used in `match`es
|
||||||
|
= note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
|
||||||
|
= help: add `#![feature(const_trait_impl)]` to the crate attributes to enable
|
||||||
|
|
||||||
|
error: aborting due to previous error
|
||||||
|
|
||||||
|
For more information about this error, try `rustc --explain E0015`.
|
Loading…
Add table
Add a link
Reference in a new issue