Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

const_eval: do not try to resolve instances containing bound vars #77540

Closed
wants to merge 2 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 19 additions & 2 deletions compiler/rustc_middle/src/ty/consts/kind.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ use crate::mir::interpret::Scalar;
use crate::mir::Promoted;
use crate::ty::subst::{InternalSubsts, SubstsRef};
use crate::ty::ParamEnv;
use crate::ty::{self, TyCtxt, TypeFoldable};
use crate::ty::{self, Ty, TyCtxt, TypeFoldable};
use rustc_errors::ErrorReported;
use rustc_hir::def_id::DefId;
use rustc_macros::HashStable;
Expand Down Expand Up @@ -107,12 +107,29 @@ impl<'tcx> ConstKind<'tcx> {
.with_reveal_all_normalized(tcx)
.and(tcx.erase_regions(&substs));

struct Meh;
impl<'tcx> ty::fold::TypeVisitor<'tcx> for Meh {
fn visit_ty(&mut self, ty: Ty<'tcx>) -> bool {
if matches!(ty.kind, ty::Bound(..)) { true } else { ty.super_visit_with(self) }
}

fn visit_const(&mut self, ct: &'tcx ty::Const<'tcx>) -> bool {
if matches!(ct.val, ConstKind::Bound(..)) {
true
} else {
ct.super_visit_with(self)
}
}
}

// HACK(eddyb) when the query key would contain inference variables,
// attempt using identity substs and `ParamEnv` instead, that will succeed
// when the expression doesn't depend on any parameters.
// FIXME(eddyb, skinny121) pass `InferCtxt` into here when it's available, so that
// we can call `infcx.const_eval_resolve` which handles inference variables.
let param_env_and_substs = if param_env_and_substs.needs_infer() {
let param_env_and_substs = if param_env_and_substs.needs_infer()
|| param_env_and_substs.visit_with(&mut Meh)
{
tcx.param_env(def.did).and(InternalSubsts::identity_for_item(tcx, def.did))
} else {
param_env_and_substs
Expand Down
17 changes: 17 additions & 0 deletions compiler/rustc_mir/src/interpret/eval_context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -527,6 +527,23 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
trace!("resolve: {:?}, {:#?}", def, substs);
trace!("param_env: {:#?}", self.param_env);
trace!("substs: {:#?}", substs);
struct Meh;
impl<'tcx> ty::fold::TypeVisitor<'tcx> for Meh {
fn visit_ty(&mut self, ty: Ty<'tcx>) -> bool {
if matches!(ty.kind(), ty::Bound(..)) { true } else { ty.super_visit_with(self) }
}

fn visit_const(&mut self, ct: &'tcx ty::Const<'tcx>) -> bool {
if matches!(ct.val, ty::ConstKind::Bound(..)) {
true
} else {
ct.super_visit_with(self)
}
}
}
if self.param_env.and(substs).visit_with(&mut Meh) {
throw_inval!(TooGeneric)
}
match ty::Instance::resolve_opt_const_arg(*self.tcx, self.param_env, def, substs) {
Ok(Some(instance)) => Ok(instance),
Ok(None) => throw_inval!(TooGeneric),
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
// run-pass
#![feature(const_generics, const_evaluatable_checked)]
#![allow(incomplete_features)]

trait FromBytesLittleEndian {
const N: usize;
fn from_bytes_le(other: &[u8; Self::N]) -> Self;
}

impl FromBytesLittleEndian for u32 {
const N: usize = 4;
fn from_bytes_le(other: &[u8; 4]) -> Self {
Self::from_le_bytes(*other)
}
}

#[derive(Debug, PartialEq, Eq)]
struct Header(u32);

impl FromBytesLittleEndian for Header {
const N: usize = 4;
fn from_bytes_le(r: &[u8; 4]) -> Self {
Self(FromBytesLittleEndian::from_bytes_le(r))
// This previously caused an ICE in the above line.
}
}

fn main() {
let data = [1, 2, 3, 4];
let h = Header::from_bytes_le(&data);
assert_eq!(h, Header(0x04030201));
}
20 changes: 7 additions & 13 deletions src/test/ui/const-generics/issues/issue-64494.full.stderr
Original file line number Diff line number Diff line change
@@ -1,18 +1,12 @@
error: constant expression depends on a generic parameter
--> $DIR/issue-64494.rs:16:53
error[E0119]: conflicting implementations of trait `MyTrait`:
--> $DIR/issue-64494.rs:18:1
|
LL | impl<T: Foo> MyTrait for T where Is<{T::VAL == 5}>: True {}
| ^^^^
|
= note: this may fail depending on what value the parameter takes

error: constant expression depends on a generic parameter
--> $DIR/issue-64494.rs:19:53
|
| ------------------------------------ first implementation here
LL |
LL | impl<T: Foo> MyTrait for T where Is<{T::VAL == 6}>: True {}
| ^^^^
|
= note: this may fail depending on what value the parameter takes
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation

error: aborting due to 2 previous errors
error: aborting due to previous error

For more information about this error, try `rustc --explain E0119`.
6 changes: 3 additions & 3 deletions src/test/ui/const-generics/issues/issue-64494.min.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -7,19 +7,19 @@ LL | impl<T: Foo> MyTrait for T where Is<{T::VAL == 5}>: True {}
= note: type parameters are currently not permitted in anonymous constants

error: generic parameters must not be used inside of non trivial constant values
--> $DIR/issue-64494.rs:19:38
--> $DIR/issue-64494.rs:18:38
|
LL | impl<T: Foo> MyTrait for T where Is<{T::VAL == 6}>: True {}
| ^^^^^^ non-trivial anonymous constants must not depend on the parameter `T`
|
= note: type parameters are currently not permitted in anonymous constants

error[E0119]: conflicting implementations of trait `MyTrait`:
--> $DIR/issue-64494.rs:19:1
--> $DIR/issue-64494.rs:18:1
|
LL | impl<T: Foo> MyTrait for T where Is<{T::VAL == 5}>: True {}
| ------------------------------------ first implementation here
...
LL |
LL | impl<T: Foo> MyTrait for T where Is<{T::VAL == 6}>: True {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation

Expand Down
8 changes: 3 additions & 5 deletions src/test/ui/const-generics/issues/issue-64494.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,9 @@ struct Is<const T: bool>;
impl True for Is<{true}> {}

impl<T: Foo> MyTrait for T where Is<{T::VAL == 5}>: True {}
//[full]~^ ERROR constant expression depends on a generic parameter
//[min]~^^ ERROR generic parameters must not be used inside of non trivial constant values
//[min]~^ ERROR generic parameters must not be used inside of non trivial constant values
impl<T: Foo> MyTrait for T where Is<{T::VAL == 6}>: True {}
//[full]~^ ERROR constant expression depends on a generic parameter
//[min]~^^ ERROR generic parameters must not be used inside of non trivial constant values
//[min]~| ERROR conflicting implementations of trait `MyTrait`
//[min]~^ ERROR generic parameters must not be used inside of non trivial constant values
//~^^ ERROR conflicting implementations of trait

fn main() {}