Skip to content

Commit

Permalink
Rollup merge of rust-lang#91272 - FabianWolff:issue-90870-const-fn-eq…
Browse files Browse the repository at this point in the history
…, r=wesleywiser

Print a suggestion when comparing references to primitive types in `const fn`

Fixes rust-lang#90870.
  • Loading branch information
matthiaskrgr committed Dec 8, 2021
2 parents c104236 + b38a540 commit 871cf2b
Show file tree
Hide file tree
Showing 5 changed files with 170 additions and 10 deletions.
6 changes: 3 additions & 3 deletions compiler/rustc_const_eval/src/transform/check_consts/check.rs
Original file line number Diff line number Diff line change
Expand Up @@ -801,7 +801,7 @@ impl Visitor<'tcx> for Checker<'mir, '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);
self.check_op(ops::FnCallNonConst(Some((callee, substs))));
return;
}

Expand Down Expand Up @@ -857,7 +857,7 @@ impl Visitor<'tcx> for Checker<'mir, 'tcx> {
}

if !nonconst_call_permission {
self.check_op(ops::FnCallNonConst);
self.check_op(ops::FnCallNonConst(None));
return;
}
}
Expand Down Expand Up @@ -926,7 +926,7 @@ impl Visitor<'tcx> for Checker<'mir, 'tcx> {
}

if !nonconst_call_permission {
self.check_op(ops::FnCallNonConst);
self.check_op(ops::FnCallNonConst(None));
return;
}
}
Expand Down
70 changes: 63 additions & 7 deletions compiler/rustc_const_eval/src/transform/check_consts/ops.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
//! Concrete error types for all operations which may be invalid in a certain const context.

use rustc_errors::{struct_span_err, DiagnosticBuilder};
use rustc_errors::{struct_span_err, Applicability, DiagnosticBuilder};
use rustc_hir as hir;
use rustc_hir::def_id::DefId;
use rustc_middle::mir;
use rustc_middle::ty::subst::{GenericArgKind, SubstsRef};
use rustc_middle::{mir, ty::AssocKind};
use rustc_session::parse::feature_err;
use rustc_span::symbol::sym;
use rustc_span::{Span, Symbol};
use rustc_span::{symbol::Ident, Span, Symbol};
use rustc_span::{BytePos, Pos};

use super::ConstCx;

Expand Down Expand Up @@ -72,17 +74,71 @@ impl NonConstOp for FnCallIndirect {

/// A function call where the callee is not marked as `const`.
#[derive(Debug)]
pub struct FnCallNonConst;
impl NonConstOp for FnCallNonConst {
pub struct FnCallNonConst<'tcx>(pub Option<(DefId, SubstsRef<'tcx>)>);
impl<'a> NonConstOp for FnCallNonConst<'a> {
fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
struct_span_err!(
let mut err = struct_span_err!(
ccx.tcx.sess,
span,
E0015,
"calls in {}s are limited to constant functions, \
tuple structs and tuple variants",
ccx.const_kind(),
)
);

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,
);
}
}
}
}
_ => {}
}
}
}
}
}

err
}
}

Expand Down
34 changes: 34 additions & 0 deletions src/test/ui/consts/issue-90870.fixed
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
// Regression test for issue #90870.

// run-rustfix

#![allow(dead_code)]

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]
//~| 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]
//~| 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]
//~| HELP: consider dereferencing here
a = at;
b = bt;
} else {
return false;
}
}

a.is_empty() && b.is_empty()
}

fn main() {}
34 changes: 34 additions & 0 deletions src/test/ui/consts/issue-90870.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
// Regression test for issue #90870.

// run-rustfix

#![allow(dead_code)]

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]
//~| 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]
//~| 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]
//~| HELP: consider dereferencing here
a = at;
b = bt;
} else {
return false;
}
}

a.is_empty() && b.is_empty()
}

fn main() {}
36 changes: 36 additions & 0 deletions src/test/ui/consts/issue-90870.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
error[E0015]: calls in constant functions are limited to constant functions, tuple structs and tuple variants
--> $DIR/issue-90870.rs:8:5
|
LL | a == b
| ^^^^^^
|
help: consider dereferencing here
|
LL | *a == *b
| + +

error[E0015]: calls in constant functions are limited to constant functions, tuple structs and tuple variants
--> $DIR/issue-90870.rs:14:5
|
LL | a == b
| ^^^^^^
|
help: consider dereferencing here
|
LL | ****a == ****b
| ++++ ++++

error[E0015]: calls in constant functions are limited to constant functions, tuple structs and tuple variants
--> $DIR/issue-90870.rs:21:12
|
LL | if l == r {
| ^^^^^^
|
help: consider dereferencing here
|
LL | if *l == *r {
| + +

error: aborting due to 3 previous errors

For more information about this error, try `rustc --explain E0015`.

0 comments on commit 871cf2b

Please sign in to comment.