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

Directly using constant from default specialisation of type causes "erroneous constant used" error #89353

Closed
LAK132 opened this issue Sep 29, 2021 · 5 comments
Labels
A-associated-items Area: Associated items such as associated types and consts. A-specialization Area: Trait impl specialization C-bug Category: This is a bug. F-specialization `#![feature(specialization)]` T-compiler Relevant to the compiler team, which will review and decide on the PR/issue.

Comments

@LAK132
Copy link

LAK132 commented Sep 29, 2021

This works:

#![allow(incomplete_features)]
#![feature(specialization)]
trait ThingImpl {
    const VALUE: i32;
}

struct ThingDefault {
}

impl ThingImpl for ThingDefault {
    const VALUE: i32 = -100;
}

trait ThingTrait {
    type Type: ThingImpl;
}

struct Thing<const T: u32>;

impl<const T: u32> ThingTrait for Thing<T> {
    default type Type = ThingDefault;
}

//

fn main() {
    println!("{}", value::<Thing<0>>());
    println!("{}", value::<Thing<1>>());
    println!("{}", value::<Thing<2>>());
    println!("{}", value::<Thing<3>>());
    println!("{}", value2::<<Thing<3> as ThingTrait>::Type>());
}

fn value<T: ThingTrait>() -> i32 {
    T::Type::VALUE
}

fn value2<T: ThingImpl>() -> i32 {
    T::VALUE
}

// Thing<0>

struct Thing0 {
}

impl ThingImpl for Thing0 {
    const VALUE: i32 = 0;
}

impl ThingTrait for Thing<0> {
    type Type = Thing0;
}

This fails:

#![allow(incomplete_features)]
#![feature(specialization)]

//

trait ThingImpl {
    const VALUE: i32;
}

struct ThingDefault {
}

impl ThingImpl for ThingDefault {
    const VALUE: i32 = -100;
}

trait ThingTrait {
    type Type: ThingImpl;
}

struct Thing<const T: u32>;

impl<const T: u32> ThingTrait for Thing<T> {
    default type Type = ThingDefault;
}

//

fn main() {
    println!("{}", <Thing<0> as ThingTrait>::Type::VALUE);
    println!("{}", <Thing<1> as ThingTrait>::Type::VALUE);
}

// Thing<0>

struct Thing0 {
}

impl ThingImpl for Thing0 {
    const VALUE: i32 = 0;
}

impl ThingTrait for Thing<0> {
    type Type = Thing0;
}

with this error

error: erroneous constant used
  --> src/main.rs:31:20
   |
31 |     println!("{}", <Thing<1> as ThingTrait>::Type::VALUE);
   |                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ referenced constant has errors
   |
   = note: `#[deny(const_err)]` on by default
   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
   = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>

Meta

Build using the Nightly version: 1.57.0-nightly (2021-09-28 8f8092c) (rust playground)

@LAK132 LAK132 added the C-bug Category: This is a bug. label Sep 29, 2021
@estebank estebank added A-associated-items Area: Associated items such as associated types and consts. A-specialization Area: Trait impl specialization F-specialization `#![feature(specialization)]` T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. labels Sep 29, 2021
@LAK132
Copy link
Author

LAK132 commented Oct 1, 2021

more details now that I have a local copy of the compiler:

error: internal compiler error: Encountered error `Unimplemented` selecting `Binder(<<Thing<1_u32> as ThingTrait>::Type as ThingImpl>, [])` during codegen

thread 'rustc' panicked at 'aborting due to `-Z treat-err-as-bug=1`', compiler/rustc_errors/src/lib.rs:1181:27
stack backtrace:
   0: rust_begin_unwind
   1: core::panicking::panic_fmt
   2: rustc_errors::HandlerInner::emit_diagnostic
   3: rustc_errors::HandlerInner::emit_diag_at_span
   4: rustc_errors::HandlerInner::span_bug
   5: rustc_session::session::Session::delay_span_bug
   6: rustc_infer::infer::InferCtxtBuilder::enter
   7: rustc_trait_selection::traits::codegen::codegen_fulfill_obligation
   8: rustc_middle::dep_graph::<impl rustc_query_system::dep_graph::DepKind for rustc_middle::dep_graph::dep_node::DepKind>::with_deps
   9: rustc_query_system::dep_graph::graph::DepGraph<K>::with_task
  10: rustc_data_structures::stack::ensure_sufficient_stack
  11: rustc_query_system::query::plumbing::get_query
  12: <rustc_query_impl::Queries as rustc_middle::ty::query::QueryEngine>::codegen_fulfill_obligation
  13: rustc_ty_utils::instance::inner_resolve_instance
  14: rustc_ty_utils::instance::resolve_instance
  15: rustc_middle::dep_graph::<impl rustc_query_system::dep_graph::DepKind for rustc_middle::dep_graph::dep_node::DepKind>::with_deps
  16: rustc_query_system::dep_graph::graph::DepGraph<K>::with_task
  17: rustc_data_structures::stack::ensure_sufficient_stack
  18: rustc_query_system::query::plumbing::get_query
  19: <rustc_query_impl::Queries as rustc_middle::ty::query::QueryEngine>::resolve_instance
  20: rustc_middle::ty::instance::Instance::resolve_opt_const_arg
  21: rustc_middle::mir::interpret::queries::<impl rustc_middle::ty::context::TyCtxt>::const_eval_resolve
  22: <rustc_trait_selection::traits::query::normalize::QueryNormalizer as rustc_middle::ty::fold::TypeFolder>::fold_const
  23: <rustc_trait_selection::traits::query::normalize::QueryNormalizer as rustc_middle::ty::fold::TypeFolder>::fold_mir_const
  24: <rustc_infer::infer::at::At as rustc_trait_selection::traits::query::normalize::AtExt>::normalize
  25: rustc_infer::infer::InferCtxtBuilder::enter
  26: core::ops::function::FnOnce::call_once
  27: rustc_middle::dep_graph::<impl rustc_query_system::dep_graph::DepKind for rustc_middle::dep_graph::dep_node::DepKind>::with_deps
  28: rustc_query_system::dep_graph::graph::DepGraph<K>::with_task
  29: rustc_data_structures::stack::ensure_sufficient_stack
  30: rustc_query_system::query::plumbing::get_query
  31: <rustc_query_impl::Queries as rustc_middle::ty::query::QueryEngine>::normalize_mir_const_after_erasing_regions
  32: rustc_middle::ty::normalize_erasing_regions::<impl rustc_middle::ty::context::TyCtxt>::normalize_erasing_regions
  33: rustc_const_eval::interpret::operand::<impl rustc_const_eval::interpret::eval_context::InterpCx<M>>::eval_operand
  34: rustc_const_eval::interpret::step::<impl rustc_const_eval::interpret::eval_context::InterpCx<M>>::run
  35: rustc_const_eval::const_eval::eval_queries::eval_to_allocation_raw_provider
  36: rustc_middle::dep_graph::<impl rustc_query_system::dep_graph::DepKind for rustc_middle::dep_graph::dep_node::DepKind>::with_deps
  37: rustc_query_system::dep_graph::graph::DepGraph<K>::with_task
  38: rustc_data_structures::stack::ensure_sufficient_stack
  39: rustc_query_system::query::plumbing::get_query
  40: <rustc_query_impl::Queries as rustc_middle::ty::query::QueryEngine>::eval_to_allocation_raw
  41: rustc_const_eval::const_eval::eval_queries::eval_to_const_value_raw_provider
  42: rustc_middle::dep_graph::<impl rustc_query_system::dep_graph::DepKind for rustc_middle::dep_graph::dep_node::DepKind>::with_deps
  43: rustc_query_system::dep_graph::graph::DepGraph<K>::with_task
  44: rustc_data_structures::stack::ensure_sufficient_stack
  45: rustc_query_system::query::plumbing::get_query
  46: <rustc_query_impl::Queries as rustc_middle::ty::query::QueryEngine>::eval_to_const_value_raw
  47: rustc_const_eval::const_eval::eval_queries::eval_to_const_value_raw_provider
  48: rustc_middle::dep_graph::<impl rustc_query_system::dep_graph::DepKind for rustc_middle::dep_graph::dep_node::DepKind>::with_deps
  49: rustc_query_system::dep_graph::graph::DepGraph<K>::with_task
  50: rustc_data_structures::stack::ensure_sufficient_stack
  51: rustc_query_system::query::plumbing::get_query
  52: <rustc_query_impl::Queries as rustc_middle::ty::query::QueryEngine>::eval_to_const_value_raw
  53: rustc_middle::mir::interpret::queries::<impl rustc_middle::ty::context::TyCtxt>::const_eval_global_id
  54: rustc_middle::mir::interpret::queries::<impl rustc_middle::ty::context::TyCtxt>::const_eval_resolve
  55: <rustc_trait_selection::traits::query::normalize::QueryNormalizer as rustc_middle::ty::fold::TypeFolder>::fold_const
  56: <rustc_trait_selection::traits::query::normalize::QueryNormalizer as rustc_middle::ty::fold::TypeFolder>::fold_mir_const
  57: <rustc_infer::infer::at::At as rustc_trait_selection::traits::query::normalize::AtExt>::normalize
  58: rustc_infer::infer::InferCtxtBuilder::enter
  59: core::ops::function::FnOnce::call_once
  60: rustc_middle::dep_graph::<impl rustc_query_system::dep_graph::DepKind for rustc_middle::dep_graph::dep_node::DepKind>::with_deps
  61: rustc_query_system::dep_graph::graph::DepGraph<K>::with_task
  62: rustc_data_structures::stack::ensure_sufficient_stack
  63: rustc_query_system::query::plumbing::get_query
  64: <rustc_query_impl::Queries as rustc_middle::ty::query::QueryEngine>::normalize_mir_const_after_erasing_regions
  65: rustc_middle::ty::normalize_erasing_regions::<impl rustc_middle::ty::context::TyCtxt>::normalize_erasing_regions
  66: rustc_const_eval::interpret::operand::<impl rustc_const_eval::interpret::eval_context::InterpCx<M>>::eval_operand
  67: rustc_const_eval::interpret::step::<impl rustc_const_eval::interpret::eval_context::InterpCx<M>>::eval_rvalue_into_place
  68: <rustc_mir_transform::const_prop::ConstPropagator as rustc_middle::mir::visit::MutVisitor>::visit_statement
  69: <rustc_mir_transform::const_prop::ConstPropagator as rustc_middle::mir::visit::MutVisitor>::visit_body
  70: <rustc_mir_transform::const_prop::ConstProp as rustc_middle::mir::MirPass>::run_pass
  71: rustc_mir_transform::run_passes
  72: rustc_mir_transform::optimized_mir
  73: rustc_query_system::dep_graph::graph::DepGraph<K>::with_task
  74: rustc_data_structures::stack::ensure_sufficient_stack
  75: rustc_query_system::query::plumbing::try_execute_query
  76: rustc_query_system::query::plumbing::get_query
  77: rustc_middle::ty::<impl rustc_middle::ty::context::TyCtxt>::instance_mir
  78: rustc_monomorphize::collector::collect_neighbours
  79: rustc_monomorphize::collector::collect_items_rec
  80: rustc_session::utils::<impl rustc_session::session::Session>::time
  81: rustc_monomorphize::collector::collect_crate_mono_items
  82: rustc_monomorphize::partitioning::collect_and_partition_mono_items
  83: rustc_query_system::dep_graph::graph::DepGraph<K>::with_task
  84: rustc_data_structures::stack::ensure_sufficient_stack
  85: rustc_query_system::query::plumbing::try_execute_query
  86: rustc_query_system::query::plumbing::get_query
  87: <rustc_query_impl::Queries as rustc_middle::ty::query::QueryEngine>::collect_and_partition_mono_items
  88: rustc_codegen_ssa::base::codegen_crate
  89: <rustc_codegen_llvm::LlvmCodegenBackend as rustc_codegen_ssa::traits::backend::CodegenBackend>::codegen_crate
  90: rustc_session::utils::<impl rustc_session::session::Session>::time
  91: rustc_interface::queries::Queries::ongoing_codegen

query stack during panic:
#0 [codegen_fulfill_obligation] checking if `ThingImpl` fulfills its obligations
#1 [resolve_instance] resolving instance `<<Thing<1_u32> as ThingTrait>::Type as ThingImpl>::VALUE`
#2 [normalize_mir_const_after_erasing_regions] normalizing `<<Thing<1_u32> as ThingTrait>::Type as ThingImpl>::VALUE`
#3 [eval_to_allocation_raw] const-evaluating + checking `main::promoted[0]`
#4 [eval_to_const_value_raw] simplifying constant for the type system `main::promoted[0]`
#5 [eval_to_const_value_raw] simplifying constant for the type system `main::promoted[0]`
#6 [normalize_mir_const_after_erasing_regions] normalizing `main::promoted[0]`
#7 [optimized_mir] optimizing MIR for `main`
#8 [collect_and_partition_mono_items] collect_and_partition_mono_items
end of query stack

@LAK132
Copy link
Author

LAK132 commented Oct 7, 2021

Debug build of rustc gets me

thread 'rustc' panicked at 'assertion failed: `(left == right)`
  left: `Binder(<<Thing<1_u32> as ThingTrait>::Type as ThingImpl>, [])`,
 right: `Binder(<ThingDefault as ThingImpl>, [])`', compiler/rustc_trait_selection/src/traits/codegen.rs:30:5

Replacing

debug_assert_eq!(trait_ref, tcx.normalize_erasing_regions(param_env, trait_ref));
with let trait_ref = tcx.normalize_erasing_regions(param_env, trait_ref); seems to stop it from hitting
Err(Unimplemented) => {
// This can trigger when we probe for the source of a `'static` lifetime requirement
// on a trait object: `impl Foo for dyn Trait {}` has an implicit `'static` bound.
infcx.tcx.sess.delay_span_bug(
rustc_span::DUMMY_SP,
&format!(
"Encountered error `Unimplemented` selecting `{:?}` during codegen",
trait_ref
),
);
return Err(ErrorReported);
}
which is what was causing the ICE in the release compiler.

@LAK132
Copy link
Author

LAK132 commented Oct 8, 2021

Would this change be accepted as a PR? It's unclear to me if this assertion was testing a precondition for the argument passed to the function or just a postcondition to protect the code that caused the ICE in release.

@estebank
Copy link
Contributor

estebank commented Nov 11, 2021

I believe that an earlier pass of normalization should have made the assert successful, so the change as is is likely not going to be accepted, but we clearly have a bug that needs fixing (glances at the open issue count... understatement of the century).

CC @rust-lang/compiler

Edit: I think that the problem is in the following:

let trait_ref = ty::TraitRef::from_method(tcx, trait_id, rcvr_substs);
// See FIXME on `BoundVarsCollector`.
let mut bound_vars_collector = BoundVarsCollector::new();
trait_ref.visit_with(&mut bound_vars_collector);
let trait_binder = ty::Binder::bind_with_vars(trait_ref, bound_vars_collector.into_vars(tcx));
let vtbl = tcx.codegen_fulfill_obligation((param_env, trait_binder))?;

I wonder if the following has anything to do with this (but don't know if at all):

// FIXME(#86795): `BoundVarsCollector` here should **NOT** be used
// outside of `resolve_associated_item`. It's just to address #64494,
// #83765, and #85848 which are creating bound types/regions that lose
// their `Binder` *unintentionally*.
// It's ideal to remove `BoundVarsCollector` and just use
// `ty::Binder::*` methods but we use this stopgap until we figure out
// the "real" fix.

Edit 2: as expected (almost tautologically), adding let trait_binder = tcx.normalize_erasing_regions(param_env, trait_binder); before the call to codegen_fulfill_obligation highlighted above makes the repro case compile. From a quick glance it looks like it might be a reasonable patch, but someone with better understanding of why that assert was there in the first place (like @lcnr), will be a better judge of it.

@LAK132
Copy link
Author

LAK132 commented Nov 10, 2022

This appears to be fixed :D

@LAK132 LAK132 closed this as completed Nov 10, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-associated-items Area: Associated items such as associated types and consts. A-specialization Area: Trait impl specialization C-bug Category: This is a bug. F-specialization `#![feature(specialization)]` T-compiler Relevant to the compiler team, which will review and decide on the PR/issue.
Projects
None yet
Development

No branches or pull requests

2 participants