diff --git a/compiler/rustc_metadata/src/rmeta/decoder.rs b/compiler/rustc_metadata/src/rmeta/decoder.rs index cc4b7d08f45..2a0332a1124 100644 --- a/compiler/rustc_metadata/src/rmeta/decoder.rs +++ b/compiler/rustc_metadata/src/rmeta/decoder.rs @@ -26,6 +26,7 @@ use rustc_middle::middle::cstore::{ForeignModule, LinkagePreference, NativeLib}; use rustc_middle::middle::exported_symbols::{ExportedSymbol, SymbolExportLevel}; use rustc_middle::mir::interpret::{AllocDecodingSession, AllocDecodingState}; use rustc_middle::mir::{self, Body, Promoted}; +use rustc_middle::thir; use rustc_middle::ty::codec::TyDecoder; use rustc_middle::ty::{self, Ty, TyCtxt, Visibility}; use rustc_serialize::{opaque, Decodable, Decoder}; @@ -541,7 +542,7 @@ impl<'a, 'tcx> Decodable> for Span { } } -impl<'a, 'tcx> Decodable> for &'tcx [mir::abstract_const::Node<'tcx>] { +impl<'a, 'tcx> Decodable> for &'tcx [thir::abstract_const::Node<'tcx>] { fn decode(d: &mut DecodeContext<'a, 'tcx>) -> Result { ty::codec::RefDecodable::decode(d) } @@ -1196,14 +1197,14 @@ impl<'a, 'tcx> CrateMetadataRef<'a> { .decode((self, tcx)) } - fn get_mir_abstract_const( + fn get_thir_abstract_const( &self, tcx: TyCtxt<'tcx>, id: DefIndex, - ) -> Result]>, ErrorReported> { + ) -> Result]>, ErrorReported> { self.root .tables - .mir_abstract_consts + .thir_abstract_consts .get(self, id) .map_or(Ok(None), |v| Ok(Some(v.decode((self, tcx))))) } diff --git a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs index 80341b16e14..50074803bbe 100644 --- a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs +++ b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs @@ -116,7 +116,7 @@ provide! { <'tcx> tcx, def_id, other, cdata, optimized_mir => { tcx.arena.alloc(cdata.get_optimized_mir(tcx, def_id.index)) } mir_for_ctfe => { tcx.arena.alloc(cdata.get_mir_for_ctfe(tcx, def_id.index)) } promoted_mir => { tcx.arena.alloc(cdata.get_promoted_mir(tcx, def_id.index)) } - mir_abstract_const => { cdata.get_mir_abstract_const(tcx, def_id.index) } + thir_abstract_const => { cdata.get_thir_abstract_const(tcx, def_id.index) } unused_generic_params => { cdata.get_unused_generic_params(def_id.index) } const_param_default => { tcx.mk_const(cdata.get_const_param_default(tcx, def_id.index)) } mir_const_qualif => { cdata.mir_const_qualif(def_id.index) } diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs index 52c6193940d..1b24e5eae98 100644 --- a/compiler/rustc_metadata/src/rmeta/encoder.rs +++ b/compiler/rustc_metadata/src/rmeta/encoder.rs @@ -23,6 +23,7 @@ use rustc_middle::middle::exported_symbols::{ metadata_symbol_name, ExportedSymbol, SymbolExportLevel, }; use rustc_middle::mir::interpret; +use rustc_middle::thir; use rustc_middle::traits::specialization_graph; use rustc_middle::ty::codec::TyEncoder; use rustc_middle::ty::{self, SymbolName, Ty, TyCtxt}; @@ -344,7 +345,7 @@ impl<'a, 'tcx> TyEncoder<'tcx> for EncodeContext<'a, 'tcx> { } } -impl<'a, 'tcx> Encodable> for &'tcx [mir::abstract_const::Node<'tcx>] { +impl<'a, 'tcx> Encodable> for &'tcx [thir::abstract_const::Node<'tcx>] { fn encode(&self, s: &mut EncodeContext<'a, 'tcx>) -> opaque::EncodeResult { (**self).encode(s) } @@ -1297,9 +1298,10 @@ impl EncodeContext<'a, 'tcx> { if encode_const { record!(self.tables.mir_for_ctfe[def_id.to_def_id()] <- self.tcx.mir_for_ctfe(def_id)); - let abstract_const = self.tcx.mir_abstract_const(def_id); + // FIXME(generic_const_exprs): this feels wrong to have in `encode_mir` + let abstract_const = self.tcx.thir_abstract_const(def_id); if let Ok(Some(abstract_const)) = abstract_const { - record!(self.tables.mir_abstract_consts[def_id.to_def_id()] <- abstract_const); + record!(self.tables.thir_abstract_consts[def_id.to_def_id()] <- abstract_const); } } record!(self.tables.promoted_mir[def_id.to_def_id()] <- self.tcx.promoted_mir(def_id)); diff --git a/compiler/rustc_metadata/src/rmeta/mod.rs b/compiler/rustc_metadata/src/rmeta/mod.rs index fe0bf5b64ba..575ab04ab24 100644 --- a/compiler/rustc_metadata/src/rmeta/mod.rs +++ b/compiler/rustc_metadata/src/rmeta/mod.rs @@ -15,6 +15,7 @@ use rustc_middle::hir::exports::Export; use rustc_middle::middle::cstore::{CrateDepKind, ForeignModule, LinkagePreference, NativeLib}; use rustc_middle::middle::exported_symbols::{ExportedSymbol, SymbolExportLevel}; use rustc_middle::mir; +use rustc_middle::thir; use rustc_middle::ty::{self, ReprOptions, Ty}; use rustc_serialize::opaque::Encoder; use rustc_session::config::SymbolManglingVersion; @@ -305,7 +306,7 @@ define_tables! { mir: Table)>, mir_for_ctfe: Table)>, promoted_mir: Table>)>, - mir_abstract_consts: Table])>, + thir_abstract_consts: Table])>, const_defaults: Table>>, unused_generic_params: Table>>, // `def_keys` and `def_path_hashes` represent a lazy version of a diff --git a/compiler/rustc_middle/src/mir/abstract_const.rs b/compiler/rustc_middle/src/mir/abstract_const.rs deleted file mode 100644 index 1ef10241143..00000000000 --- a/compiler/rustc_middle/src/mir/abstract_const.rs +++ /dev/null @@ -1,38 +0,0 @@ -//! A subset of a mir body used for const evaluatability checking. -use crate::mir::{self, CastKind}; -use crate::ty::{self, Ty}; - -rustc_index::newtype_index! { - /// An index into an `AbstractConst`. - pub struct NodeId { - derive [HashStable] - DEBUG_FORMAT = "n{}", - } -} - -/// A node of an `AbstractConst`. -#[derive(Debug, Clone, Copy, PartialEq, Eq, HashStable, TyEncodable, TyDecodable)] -pub enum Node<'tcx> { - Leaf(&'tcx ty::Const<'tcx>), - Binop(mir::BinOp, NodeId, NodeId), - UnaryOp(mir::UnOp, NodeId), - FunctionCall(NodeId, &'tcx [NodeId]), - Cast(CastKind, NodeId, Ty<'tcx>), -} - -#[derive(Debug, Copy, Clone, PartialEq, Eq, HashStable, TyEncodable, TyDecodable)] -pub enum NotConstEvaluatable { - Error(rustc_errors::ErrorReported), - MentionsInfer, - MentionsParam, -} - -impl From for NotConstEvaluatable { - fn from(e: rustc_errors::ErrorReported) -> NotConstEvaluatable { - NotConstEvaluatable::Error(e) - } -} - -TrivialTypeFoldableAndLiftImpls! { - NotConstEvaluatable, -} diff --git a/compiler/rustc_middle/src/mir/mod.rs b/compiler/rustc_middle/src/mir/mod.rs index e40227530cd..ebdf354b905 100644 --- a/compiler/rustc_middle/src/mir/mod.rs +++ b/compiler/rustc_middle/src/mir/mod.rs @@ -40,7 +40,6 @@ use self::graph_cyclic_cache::GraphIsCyclicCache; use self::predecessors::{PredecessorCache, Predecessors}; pub use self::query::*; -pub mod abstract_const; pub mod coverage; mod generic_graph; pub mod generic_graphviz; diff --git a/compiler/rustc_middle/src/mir/query.rs b/compiler/rustc_middle/src/mir/query.rs index 1bdb6ca012b..567f65e83d9 100644 --- a/compiler/rustc_middle/src/mir/query.rs +++ b/compiler/rustc_middle/src/mir/query.rs @@ -1,6 +1,6 @@ //! Values computed by queries that use MIR. -use crate::mir::{abstract_const, Body, Promoted}; +use crate::mir::{Body, Promoted}; use crate::ty::{self, Ty, TyCtxt}; use rustc_data_structures::sync::Lrc; use rustc_data_structures::vec_map::VecMap; @@ -431,16 +431,4 @@ impl<'tcx> TyCtxt<'tcx> { self.mir_for_ctfe(def.did) } } - - #[inline] - pub fn mir_abstract_const_opt_const_arg( - self, - def: ty::WithOptConstParam, - ) -> Result]>, ErrorReported> { - if let Some((did, param_did)) = def.as_const_arg() { - self.mir_abstract_const_of_const_arg((did, param_did)) - } else { - self.mir_abstract_const(def.did) - } - } } diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index 7402a779394..5748e5319e0 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -303,17 +303,17 @@ rustc_queries! { } /// Try to build an abstract representation of the given constant. - query mir_abstract_const( + query thir_abstract_const( key: DefId - ) -> Result]>, ErrorReported> { + ) -> Result]>, ErrorReported> { desc { |tcx| "building an abstract representation for {}", tcx.def_path_str(key), } } /// Try to build an abstract representation of the given constant. - query mir_abstract_const_of_const_arg( + query thir_abstract_const_of_const_arg( key: (LocalDefId, DefId) - ) -> Result]>, ErrorReported> { + ) -> Result]>, ErrorReported> { desc { |tcx| "building an abstract representation for the const argument {}", diff --git a/compiler/rustc_middle/src/thir.rs b/compiler/rustc_middle/src/thir.rs index 91a64e163e7..8d6fd1e729d 100644 --- a/compiler/rustc_middle/src/thir.rs +++ b/compiler/rustc_middle/src/thir.rs @@ -33,6 +33,9 @@ use rustc_target::asm::InlineAsmRegOrRegClass; use std::fmt; use std::ops::Index; +pub mod abstract_const; +pub mod visit; + newtype_index! { /// An index to an [`Arm`] stored in [`Thir::arms`] #[derive(HashStable)] diff --git a/compiler/rustc_middle/src/thir/abstract_const.rs b/compiler/rustc_middle/src/thir/abstract_const.rs new file mode 100644 index 00000000000..f80beadd6e5 --- /dev/null +++ b/compiler/rustc_middle/src/thir/abstract_const.rs @@ -0,0 +1,61 @@ +//! A subset of a mir body used for const evaluatability checking. +use crate::mir; +use crate::ty::{self, Ty, TyCtxt}; +use rustc_errors::ErrorReported; + +rustc_index::newtype_index! { + /// An index into an `AbstractConst`. + pub struct NodeId { + derive [HashStable] + DEBUG_FORMAT = "n{}", + } +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq, HashStable, TyEncodable, TyDecodable)] +pub enum CastKind { + /// thir::ExprKind::As + As, + /// thir::ExprKind::Use + Use, +} + +/// A node of an `AbstractConst`. +#[derive(Debug, Clone, Copy, PartialEq, Eq, HashStable, TyEncodable, TyDecodable)] +pub enum Node<'tcx> { + Leaf(&'tcx ty::Const<'tcx>), + Binop(mir::BinOp, NodeId, NodeId), + UnaryOp(mir::UnOp, NodeId), + FunctionCall(NodeId, &'tcx [NodeId]), + Cast(CastKind, NodeId, Ty<'tcx>), +} + +#[derive(Debug, Copy, Clone, PartialEq, Eq, HashStable, TyEncodable, TyDecodable)] +pub enum NotConstEvaluatable { + Error(ErrorReported), + MentionsInfer, + MentionsParam, +} + +impl From for NotConstEvaluatable { + fn from(e: ErrorReported) -> NotConstEvaluatable { + NotConstEvaluatable::Error(e) + } +} + +TrivialTypeFoldableAndLiftImpls! { + NotConstEvaluatable, +} + +impl<'tcx> TyCtxt<'tcx> { + #[inline] + pub fn thir_abstract_const_opt_const_arg( + self, + def: ty::WithOptConstParam, + ) -> Result]>, ErrorReported> { + if let Some((did, param_did)) = def.as_const_arg() { + self.thir_abstract_const_of_const_arg((did, param_did)) + } else { + self.thir_abstract_const(def.did) + } + } +} diff --git a/compiler/rustc_mir_build/src/thir/visit.rs b/compiler/rustc_middle/src/thir/visit.rs similarity index 98% rename from compiler/rustc_mir_build/src/thir/visit.rs rename to compiler/rustc_middle/src/thir/visit.rs index 51c371b8720..7fc15e02fcd 100644 --- a/compiler/rustc_mir_build/src/thir/visit.rs +++ b/compiler/rustc_middle/src/thir/visit.rs @@ -1,4 +1,6 @@ -use rustc_middle::thir::{self, *}; +use super::{ + Arm, Block, Expr, ExprKind, Guard, InlineAsmOperand, Pat, PatKind, Stmt, StmtKind, Thir, +}; use rustc_middle::ty::Const; pub trait Visitor<'a, 'tcx: 'a>: Sized { @@ -101,7 +103,7 @@ pub fn walk_expr<'a, 'tcx: 'a, V: Visitor<'a, 'tcx>>(visitor: &mut V, expr: &Exp visitor.visit_expr(&visitor.thir()[field]); } } - Adt(box thir::Adt { + Adt(box crate::thir::Adt { ref fields, ref base, adt_def: _, diff --git a/compiler/rustc_middle/src/traits/mod.rs b/compiler/rustc_middle/src/traits/mod.rs index 74edb17fe32..e21a2d1034c 100644 --- a/compiler/rustc_middle/src/traits/mod.rs +++ b/compiler/rustc_middle/src/traits/mod.rs @@ -9,7 +9,7 @@ pub mod specialization_graph; mod structural_impls; use crate::infer::canonical::Canonical; -use crate::mir::abstract_const::NotConstEvaluatable; +use crate::thir::abstract_const::NotConstEvaluatable; use crate::ty::subst::SubstsRef; use crate::ty::{self, AdtKind, Ty, TyCtxt}; diff --git a/compiler/rustc_middle/src/ty/codec.rs b/compiler/rustc_middle/src/ty/codec.rs index 4edb6a327b0..8b70692960d 100644 --- a/compiler/rustc_middle/src/ty/codec.rs +++ b/compiler/rustc_middle/src/ty/codec.rs @@ -12,6 +12,7 @@ use crate::mir::{ self, interpret::{AllocId, Allocation}, }; +use crate::thir; use crate::ty::subst::SubstsRef; use crate::ty::{self, List, Ty, TyCtxt}; use rustc_data_structures::fx::FxHashMap; @@ -362,7 +363,7 @@ impl<'tcx, D: TyDecoder<'tcx>> RefDecodable<'tcx, D> for [(ty::Predicate<'tcx>, } } -impl<'tcx, D: TyDecoder<'tcx>> RefDecodable<'tcx, D> for [mir::abstract_const::Node<'tcx>] { +impl<'tcx, D: TyDecoder<'tcx>> RefDecodable<'tcx, D> for [thir::abstract_const::Node<'tcx>] { fn decode(decoder: &mut D) -> Result<&'tcx Self, D::Error> { Ok(decoder.tcx().arena.alloc_from_iter( (0..decoder.read_usize()?) @@ -372,7 +373,7 @@ impl<'tcx, D: TyDecoder<'tcx>> RefDecodable<'tcx, D> for [mir::abstract_const::N } } -impl<'tcx, D: TyDecoder<'tcx>> RefDecodable<'tcx, D> for [mir::abstract_const::NodeId] { +impl<'tcx, D: TyDecoder<'tcx>> RefDecodable<'tcx, D> for [thir::abstract_const::NodeId] { fn decode(decoder: &mut D) -> Result<&'tcx Self, D::Error> { Ok(decoder.tcx().arena.alloc_from_iter( (0..decoder.read_usize()?) diff --git a/compiler/rustc_mir_build/src/build/mod.rs b/compiler/rustc_mir_build/src/build/mod.rs index 0a760a740dc..0ee740a6463 100644 --- a/compiler/rustc_mir_build/src/build/mod.rs +++ b/compiler/rustc_mir_build/src/build/mod.rs @@ -47,10 +47,12 @@ fn mir_build(tcx: TyCtxt<'_>, def: ty::WithOptConstParam) -> Body<'_ // Ensure unsafeck is ran before we steal the THIR. match def { ty::WithOptConstParam { did, const_param_did: Some(const_param_did) } => { - tcx.ensure().thir_check_unsafety_for_const_arg((did, const_param_did)) + tcx.ensure().thir_check_unsafety_for_const_arg((did, const_param_did)); + tcx.ensure().thir_abstract_const_of_const_arg((did, const_param_did)); } ty::WithOptConstParam { did, const_param_did: None } => { - tcx.ensure().thir_check_unsafety(did) + tcx.ensure().thir_check_unsafety(did); + tcx.ensure().thir_abstract_const(did); } } diff --git a/compiler/rustc_mir_build/src/check_unsafety.rs b/compiler/rustc_mir_build/src/check_unsafety.rs index 05a5fcef16a..0e82b187201 100644 --- a/compiler/rustc_mir_build/src/check_unsafety.rs +++ b/compiler/rustc_mir_build/src/check_unsafety.rs @@ -1,5 +1,5 @@ use crate::build::ExprCategory; -use crate::thir::visit::{self, Visitor}; +use rustc_middle::thir::visit::{self, Visitor}; use rustc_errors::struct_span_err; use rustc_hir as hir; diff --git a/compiler/rustc_mir_build/src/thir/mod.rs b/compiler/rustc_mir_build/src/thir/mod.rs index e5123d8ef0c..ddbe1b0b69c 100644 --- a/compiler/rustc_mir_build/src/thir/mod.rs +++ b/compiler/rustc_mir_build/src/thir/mod.rs @@ -11,4 +11,3 @@ crate mod cx; crate mod pattern; mod util; -pub mod visit; diff --git a/compiler/rustc_mir_transform/src/lib.rs b/compiler/rustc_mir_transform/src/lib.rs index 9a074c10ef4..90d7cbee976 100644 --- a/compiler/rustc_mir_transform/src/lib.rs +++ b/compiler/rustc_mir_transform/src/lib.rs @@ -306,7 +306,6 @@ fn mir_promoted( // this point, before we steal the mir-const result. // Also this means promotion can rely on all const checks having been done. let _ = tcx.mir_const_qualif_opt_const_arg(def); - let _ = tcx.mir_abstract_const_opt_const_arg(def.to_global()); let mut body = tcx.mir_const(def).steal(); let mut required_consts = Vec::new(); diff --git a/compiler/rustc_privacy/src/lib.rs b/compiler/rustc_privacy/src/lib.rs index 35e25e52dc5..391e4305423 100644 --- a/compiler/rustc_privacy/src/lib.rs +++ b/compiler/rustc_privacy/src/lib.rs @@ -19,8 +19,8 @@ use rustc_hir::{AssocItemKind, HirIdSet, Node, PatKind}; use rustc_middle::bug; use rustc_middle::hir::map::Map; use rustc_middle::middle::privacy::{AccessLevel, AccessLevels}; -use rustc_middle::mir::abstract_const::Node as ACNode; use rustc_middle::span_bug; +use rustc_middle::thir::abstract_const::Node as ACNode; use rustc_middle::ty::fold::TypeVisitor; use rustc_middle::ty::query::Providers; use rustc_middle::ty::subst::{InternalSubsts, Subst}; diff --git a/compiler/rustc_query_impl/src/on_disk_cache.rs b/compiler/rustc_query_impl/src/on_disk_cache.rs index a54d1556b3e..bfd36bfb2db 100644 --- a/compiler/rustc_query_impl/src/on_disk_cache.rs +++ b/compiler/rustc_query_impl/src/on_disk_cache.rs @@ -9,6 +9,7 @@ use rustc_index::vec::{Idx, IndexVec}; use rustc_middle::dep_graph::{DepNode, DepNodeIndex, SerializedDepNodeIndex}; use rustc_middle::mir::interpret::{AllocDecodingSession, AllocDecodingState}; use rustc_middle::mir::{self, interpret}; +use rustc_middle::thir; use rustc_middle::ty::codec::{RefDecodable, TyDecoder, TyEncoder}; use rustc_middle::ty::{self, Ty, TyCtxt}; use rustc_query_system::dep_graph::DepContext; @@ -921,7 +922,7 @@ impl<'a, 'tcx> Decodable> } } -impl<'a, 'tcx> Decodable> for &'tcx [mir::abstract_const::Node<'tcx>] { +impl<'a, 'tcx> Decodable> for &'tcx [thir::abstract_const::Node<'tcx>] { fn decode(d: &mut CacheDecoder<'a, 'tcx>) -> Result { RefDecodable::decode(d) } diff --git a/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs index ddabe5967d7..24fa5007f1e 100644 --- a/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs +++ b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs @@ -6,16 +6,16 @@ //! this is not as easy. //! //! In this case we try to build an abstract representation of this constant using -//! `mir_abstract_const` which can then be checked for structural equality with other +//! `thir_abstract_const` which can then be checked for structural equality with other //! generic constants mentioned in the `caller_bounds` of the current environment. use rustc_errors::ErrorReported; use rustc_hir::def::DefKind; -use rustc_index::bit_set::BitSet; use rustc_index::vec::IndexVec; use rustc_infer::infer::InferCtxt; -use rustc_middle::mir::abstract_const::{Node, NodeId, NotConstEvaluatable}; +use rustc_middle::mir; use rustc_middle::mir::interpret::ErrorHandled; -use rustc_middle::mir::{self, Rvalue, StatementKind, TerminatorKind}; +use rustc_middle::thir; +use rustc_middle::thir::abstract_const::{self, Node, NodeId, NotConstEvaluatable}; use rustc_middle::ty::subst::{Subst, SubstsRef}; use rustc_middle::ty::{self, TyCtxt, TypeFoldable}; use rustc_session::lint; @@ -196,7 +196,7 @@ impl<'tcx> AbstractConst<'tcx> { tcx: TyCtxt<'tcx>, uv: ty::Unevaluated<'tcx, ()>, ) -> Result>, ErrorReported> { - let inner = tcx.mir_abstract_const_opt_const_arg(uv.def)?; + let inner = tcx.thir_abstract_const_opt_const_arg(uv.def)?; debug!("AbstractConst::new({:?}) = {:?}", uv, inner); Ok(inner.map(|inner| AbstractConst { inner, substs: uv.substs(tcx) })) } @@ -223,35 +223,24 @@ impl<'tcx> AbstractConst<'tcx> { } } -#[derive(Debug, Clone, Copy, PartialEq, Eq)] -struct WorkNode<'tcx> { - node: Node<'tcx>, - span: Span, - used: bool, -} - struct AbstractConstBuilder<'a, 'tcx> { tcx: TyCtxt<'tcx>, - body: &'a mir::Body<'tcx>, + body_id: thir::ExprId, + body: &'a thir::Thir<'tcx>, /// The current WIP node tree. - /// - /// We require all nodes to be used in the final abstract const, - /// so we store this here. Note that we also consider nodes as used - /// if they are mentioned in an assert, so some used nodes are never - /// actually reachable by walking the [`AbstractConst`]. - nodes: IndexVec>, - locals: IndexVec, - /// We only allow field accesses if they access - /// the result of a checked operation. - checked_op_locals: BitSet, + nodes: IndexVec>, } impl<'a, 'tcx> AbstractConstBuilder<'a, 'tcx> { + fn root_span(&self) -> Span { + self.body.exprs[self.body_id].span + } + fn error(&mut self, span: Option, msg: &str) -> Result { self.tcx .sess - .struct_span_err(self.body.span, "overly complex generic constant") - .span_label(span.unwrap_or(self.body.span), msg) + .struct_span_err(self.root_span(), "overly complex generic constant") + .span_label(span.unwrap_or(self.root_span()), msg) .help("consider moving this anonymous constant into a `const` function") .emit(); @@ -260,100 +249,51 @@ impl<'a, 'tcx> AbstractConstBuilder<'a, 'tcx> { fn new( tcx: TyCtxt<'tcx>, - body: &'a mir::Body<'tcx>, + (body, body_id): (&'a thir::Thir<'tcx>, thir::ExprId), ) -> Result>, ErrorReported> { - let mut builder = AbstractConstBuilder { - tcx, - body, - nodes: IndexVec::new(), - locals: IndexVec::from_elem(NodeId::MAX, &body.local_decls), - checked_op_locals: BitSet::new_empty(body.local_decls.len()), - }; + let builder = AbstractConstBuilder { tcx, body_id, body, nodes: IndexVec::new() }; - // We don't have to look at concrete constants, as we - // can just evaluate them. - if !body.is_polymorphic { + struct IsThirPolymorphic<'a, 'tcx> { + is_poly: bool, + thir: &'a thir::Thir<'tcx>, + tcx: TyCtxt<'tcx>, + } + + use thir::visit; + impl<'a, 'tcx: 'a> visit::Visitor<'a, 'tcx> for IsThirPolymorphic<'a, 'tcx> { + fn thir(&self) -> &'a thir::Thir<'tcx> { + &self.thir + } + + fn visit_expr(&mut self, expr: &thir::Expr<'tcx>) { + self.is_poly |= expr.ty.definitely_has_param_types_or_consts(self.tcx); + if self.is_poly == false { + visit::walk_expr(self, expr) + } + } + + fn visit_pat(&mut self, pat: &thir::Pat<'tcx>) { + self.is_poly |= pat.ty.definitely_has_param_types_or_consts(self.tcx); + if self.is_poly == false { + visit::walk_pat(self, pat); + } + } + + fn visit_const(&mut self, ct: &'tcx ty::Const<'tcx>) { + self.is_poly |= ct.definitely_has_param_types_or_consts(self.tcx); + } + } + + let mut is_poly_vis = IsThirPolymorphic { is_poly: false, thir: body, tcx }; + visit::walk_expr(&mut is_poly_vis, &body[body_id]); + debug!("AbstractConstBuilder: is_poly={}", is_poly_vis.is_poly); + if is_poly_vis.is_poly == false { return Ok(None); } - // We only allow consts without control flow, so - // we check for cycles here which simplifies the - // rest of this implementation. - if body.is_cfg_cyclic() { - builder.error(None, "cyclic anonymous constants are forbidden")?; - } - Ok(Some(builder)) } - fn add_node(&mut self, node: Node<'tcx>, span: Span) -> NodeId { - // Mark used nodes. - match node { - Node::Leaf(_) => (), - Node::Binop(_, lhs, rhs) => { - self.nodes[lhs].used = true; - self.nodes[rhs].used = true; - } - Node::UnaryOp(_, input) => { - self.nodes[input].used = true; - } - Node::FunctionCall(func, nodes) => { - self.nodes[func].used = true; - nodes.iter().for_each(|&n| self.nodes[n].used = true); - } - Node::Cast(_, operand, _) => { - self.nodes[operand].used = true; - } - } - - // Nodes start as unused. - self.nodes.push(WorkNode { node, span, used: false }) - } - - fn place_to_local( - &mut self, - span: Span, - p: &mir::Place<'tcx>, - ) -> Result { - const ZERO_FIELD: mir::Field = mir::Field::from_usize(0); - // Do not allow any projections. - // - // One exception are field accesses on the result of checked operations, - // which are required to support things like `1 + 2`. - if let Some(p) = p.as_local() { - debug_assert!(!self.checked_op_locals.contains(p)); - Ok(p) - } else if let &[mir::ProjectionElem::Field(ZERO_FIELD, _)] = p.projection.as_ref() { - // Only allow field accesses if the given local - // contains the result of a checked operation. - if self.checked_op_locals.contains(p.local) { - Ok(p.local) - } else { - self.error(Some(span), "unsupported projection")?; - } - } else { - self.error(Some(span), "unsupported projection")?; - } - } - - fn operand_to_node( - &mut self, - span: Span, - op: &mir::Operand<'tcx>, - ) -> Result { - debug!("operand_to_node: op={:?}", op); - match op { - mir::Operand::Copy(p) | mir::Operand::Move(p) => { - let local = self.place_to_local(span, p)?; - Ok(self.locals[local]) - } - mir::Operand::Constant(ct) => match ct.literal { - mir::ConstantKind::Ty(ct) => Ok(self.add_node(Node::Leaf(ct), span)), - mir::ConstantKind::Val(..) => self.error(Some(span), "unsupported constant")?, - }, - } - } - /// We do not allow all binary operations in abstract consts, so filter disallowed ones. fn check_binop(op: mir::BinOp) -> bool { use mir::BinOp::*; @@ -373,170 +313,126 @@ impl<'a, 'tcx> AbstractConstBuilder<'a, 'tcx> { } } - fn build_statement(&mut self, stmt: &mir::Statement<'tcx>) -> Result<(), ErrorReported> { - debug!("AbstractConstBuilder: stmt={:?}", stmt); - let span = stmt.source_info.span; - match stmt.kind { - StatementKind::Assign(box (ref place, ref rvalue)) => { - let local = self.place_to_local(span, place)?; - match *rvalue { - Rvalue::Use(ref operand) => { - self.locals[local] = self.operand_to_node(span, operand)?; - Ok(()) - } - Rvalue::BinaryOp(op, box (ref lhs, ref rhs)) if Self::check_binop(op) => { - let lhs = self.operand_to_node(span, lhs)?; - let rhs = self.operand_to_node(span, rhs)?; - self.locals[local] = self.add_node(Node::Binop(op, lhs, rhs), span); - if op.is_checkable() { - bug!("unexpected unchecked checkable binary operation"); - } else { - Ok(()) - } - } - Rvalue::CheckedBinaryOp(op, box (ref lhs, ref rhs)) - if Self::check_binop(op) => - { - let lhs = self.operand_to_node(span, lhs)?; - let rhs = self.operand_to_node(span, rhs)?; - self.locals[local] = self.add_node(Node::Binop(op, lhs, rhs), span); - self.checked_op_locals.insert(local); - Ok(()) - } - Rvalue::UnaryOp(op, ref operand) if Self::check_unop(op) => { - let operand = self.operand_to_node(span, operand)?; - self.locals[local] = self.add_node(Node::UnaryOp(op, operand), span); - Ok(()) - } - Rvalue::Cast(cast_kind, ref operand, ty) => { - let operand = self.operand_to_node(span, operand)?; - self.locals[local] = - self.add_node(Node::Cast(cast_kind, operand, ty), span); - Ok(()) - } - _ => self.error(Some(span), "unsupported rvalue")?, - } - } - // These are not actually relevant for us here, so we can ignore them. - StatementKind::AscribeUserType(..) - | StatementKind::StorageLive(_) - | StatementKind::StorageDead(_) => Ok(()), - _ => self.error(Some(stmt.source_info.span), "unsupported statement")?, - } - } - - /// Possible return values: - /// - /// - `None`: unsupported terminator, stop building - /// - `Some(None)`: supported terminator, finish building - /// - `Some(Some(block))`: support terminator, build `block` next - fn build_terminator( - &mut self, - terminator: &mir::Terminator<'tcx>, - ) -> Result, ErrorReported> { - debug!("AbstractConstBuilder: terminator={:?}", terminator); - match terminator.kind { - TerminatorKind::Goto { target } => Ok(Some(target)), - TerminatorKind::Return => Ok(None), - TerminatorKind::Call { - ref func, - ref args, - destination: Some((ref place, target)), - // We do not care about `cleanup` here. Any branch which - // uses `cleanup` will fail const-eval and they therefore - // do not matter when checking for const evaluatability. - // - // Do note that even if `panic::catch_unwind` is made const, - // we still do not have to care about this, as we do not look - // into functions. - cleanup: _, - // Do not allow overloaded operators for now, - // we probably do want to allow this in the future. - // - // This is currently fairly irrelevant as it requires `const Trait`s. - from_hir_call: true, - fn_span, - } => { - let local = self.place_to_local(fn_span, place)?; - let func = self.operand_to_node(fn_span, func)?; - let args = self.tcx.arena.alloc_from_iter( - args.iter() - .map(|arg| self.operand_to_node(terminator.source_info.span, arg)) - .collect::, _>>()?, - ); - self.locals[local] = self.add_node(Node::FunctionCall(func, args), fn_span); - Ok(Some(target)) - } - TerminatorKind::Assert { ref cond, expected: false, target, .. } => { - let p = match cond { - mir::Operand::Copy(p) | mir::Operand::Move(p) => p, - mir::Operand::Constant(_) => bug!("unexpected assert"), - }; - - const ONE_FIELD: mir::Field = mir::Field::from_usize(1); - debug!("proj: {:?}", p.projection); - if let Some(p) = p.as_local() { - debug_assert!(!self.checked_op_locals.contains(p)); - // Mark locals directly used in asserts as used. - // - // This is needed because division does not use `CheckedBinop` but instead - // adds an explicit assert for `divisor != 0`. - self.nodes[self.locals[p]].used = true; - return Ok(Some(target)); - } else if let &[mir::ProjectionElem::Field(ONE_FIELD, _)] = p.projection.as_ref() { - // Only allow asserts checking the result of a checked operation. - if self.checked_op_locals.contains(p.local) { - return Ok(Some(target)); - } - } - - self.error(Some(terminator.source_info.span), "unsupported assertion")?; - } - _ => self.error(Some(terminator.source_info.span), "unsupported terminator")?, - } - } - - /// Builds the abstract const by walking the mir from start to finish - /// and bailing out when encountering an unsupported operation. + /// Builds the abstract const by walking the thir and bailing out when + /// encountering an unspported operation. fn build(mut self) -> Result<&'tcx [Node<'tcx>], ErrorReported> { - let mut block = &self.body.basic_blocks()[mir::START_BLOCK]; - // We checked for a cyclic cfg above, so this should terminate. - loop { - debug!("AbstractConstBuilder: block={:?}", block); - for stmt in block.statements.iter() { - self.build_statement(stmt)?; - } + debug!("Abstractconstbuilder::build: body={:?}", &*self.body); + self.recurse_build(self.body_id)?; - if let Some(next) = self.build_terminator(block.terminator())? { - block = &self.body.basic_blocks()[next]; - } else { - break; - } - } - - assert_eq!(self.locals[mir::RETURN_PLACE], self.nodes.last().unwrap()); for n in self.nodes.iter() { - if let Node::Leaf(ty::Const { val: ty::ConstKind::Unevaluated(ct), ty: _ }) = n.node { + if let Node::Leaf(ty::Const { val: ty::ConstKind::Unevaluated(ct), ty: _ }) = n { // `AbstractConst`s should not contain any promoteds as they require references which // are not allowed. assert_eq!(ct.promoted, None); } } - self.nodes[self.locals[mir::RETURN_PLACE]].used = true; - if let Some(&unused) = self.nodes.iter().find(|n| !n.used) { - self.error(Some(unused.span), "dead code")?; - } + Ok(self.tcx.arena.alloc_from_iter(self.nodes.into_iter())) + } - Ok(self.tcx.arena.alloc_from_iter(self.nodes.into_iter().map(|n| n.node))) + fn recurse_build(&mut self, node: thir::ExprId) -> Result { + use thir::ExprKind; + let node = &self.body.exprs[node]; + debug!("recurse_build: node={:?}", node); + Ok(match &node.kind { + // I dont know if handling of these 3 is correct + &ExprKind::Scope { value, .. } => self.recurse_build(value)?, + &ExprKind::PlaceTypeAscription { source, .. } | + &ExprKind::ValueTypeAscription { source, .. } => self.recurse_build(source)?, + + // subtle: associated consts are literals this arm handles + // `::ASSOC` as well as `12` + &ExprKind::Literal { literal, .. } => self.nodes.push(Node::Leaf(literal)), + + ExprKind::Call { fun, args, .. } => { + let fun = self.recurse_build(*fun)?; + + let mut new_args = Vec::::with_capacity(args.len()); + for &id in args.iter() { + new_args.push(self.recurse_build(id)?); + } + let new_args = self.tcx.arena.alloc_slice(&new_args); + self.nodes.push(Node::FunctionCall(fun, new_args)) + }, + &ExprKind::Binary { op, lhs, rhs } if Self::check_binop(op) => { + let lhs = self.recurse_build(lhs)?; + let rhs = self.recurse_build(rhs)?; + self.nodes.push(Node::Binop(op, lhs, rhs)) + } + &ExprKind::Unary { op, arg } if Self::check_unop(op) => { + let arg = self.recurse_build(arg)?; + self.nodes.push(Node::UnaryOp(op, arg)) + }, + // This is necessary so that the following compiles: + // + // ``` + // fn foo(a: [(); N + 1]) { + // bar::<{ N + 1 }>(); + // } + // ``` + ExprKind::Block { body: thir::Block { stmts: box [], expr: Some(e), .. }} => self.recurse_build(*e)?, + // `ExprKind::Use` happens when a `hir::ExprKind::Cast` is a + // "coercion cast" i.e. using a coercion or is a no-op. + // This is important so that `N as usize as usize` doesnt unify with `N as usize`. (untested) + &ExprKind::Use { source } => { + let arg = self.recurse_build(source)?; + self.nodes.push(Node::Cast(abstract_const::CastKind::Use, arg, node.ty)) + }, + &ExprKind::Cast { source } => { + let arg = self.recurse_build(source)?; + self.nodes.push(Node::Cast(abstract_const::CastKind::As, arg, node.ty)) + }, + + // FIXME(generic_const_exprs): We may want to support these. + ExprKind::AddressOf { .. } + | ExprKind::Borrow { .. } + | ExprKind::Deref { .. } + | ExprKind::Repeat { .. } + | ExprKind::Array { .. } + | ExprKind::Block { .. } + | ExprKind::NeverToAny { .. } + | ExprKind::Tuple { .. } + | ExprKind::Index { .. } + | ExprKind::Field { .. } + | ExprKind::ConstBlock { .. } + | ExprKind::Adt(_) => self.error( + Some(node.span), + "unsupported operation in generic constant, this may be supported in the future", + )?, + + ExprKind::Match { .. } + // we dont permit let stmts so `VarRef` and `UpvarRef` cant happen + | ExprKind::VarRef { .. } + | ExprKind::UpvarRef { .. } + | ExprKind::Closure { .. } + | ExprKind::Let { .. } // let expressions imply control flow + | ExprKind::Loop { .. } + | ExprKind::Assign { .. } + | ExprKind::StaticRef { .. } + | ExprKind::LogicalOp { .. } + // we handle valid unary/binary ops above + | ExprKind::Unary { .. } + | ExprKind::Binary { .. } + | ExprKind::Break { .. } + | ExprKind::Continue { .. } + | ExprKind::If { .. } + | ExprKind::Pointer { .. } // dont know if this is correct + | ExprKind::ThreadLocalRef(_) + | ExprKind::LlvmInlineAsm { .. } + | ExprKind::Return { .. } + | ExprKind::Box { .. } // allocations not allowed in constants + | ExprKind::AssignOp { .. } + | ExprKind::InlineAsm { .. } + | ExprKind::Yield { .. } => self.error(Some(node.span), "unsupported operation in generic constant")?, + }) } } /// Builds an abstract const, do not use this directly, but use `AbstractConst::new` instead. -pub(super) fn mir_abstract_const<'tcx>( +pub(super) fn thir_abstract_const<'tcx>( tcx: TyCtxt<'tcx>, def: ty::WithOptConstParam, -) -> Result]>, ErrorReported> { +) -> Result]>, ErrorReported> { if tcx.features().generic_const_exprs { match tcx.def_kind(def.did) { // FIXME(generic_const_exprs): We currently only do this for anonymous constants, @@ -547,8 +443,16 @@ pub(super) fn mir_abstract_const<'tcx>( DefKind::AnonConst => (), _ => return Ok(None), } - let body = tcx.mir_const(def).borrow(); - AbstractConstBuilder::new(tcx, &body)?.map(AbstractConstBuilder::build).transpose() + + let body = tcx.thir_body(def); + if body.0.borrow().exprs.is_empty() { + // type error in constant, there is no thir + return Err(ErrorReported); + } + + AbstractConstBuilder::new(tcx, (&*body.0.borrow(), body.1))? + .map(AbstractConstBuilder::build) + .transpose() } else { Ok(None) } @@ -682,11 +586,16 @@ pub(super) fn try_unify<'tcx>( && iter::zip(a_args, b_args) .all(|(&an, &bn)| try_unify(tcx, a.subtree(an), b.subtree(bn))) } - (Node::Cast(a_cast_kind, a_operand, a_ty), Node::Cast(b_cast_kind, b_operand, b_ty)) - if (a_ty == b_ty) && (a_cast_kind == b_cast_kind) => + (Node::Cast(a_kind, a_operand, a_ty), Node::Cast(b_kind, b_operand, b_ty)) + if (a_ty == b_ty) && (a_kind == b_kind) => { try_unify(tcx, a.subtree(a_operand), b.subtree(b_operand)) } - _ => false, + // use this over `_ => false` to make adding variants to `Node` less error prone + (Node::Cast(..), _) + | (Node::FunctionCall(..), _) + | (Node::UnaryOp(..), _) + | (Node::Binop(..), _) + | (Node::Leaf(..), _) => false, } } 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 52367661a4c..761b217c78f 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs @@ -19,7 +19,7 @@ use rustc_hir::intravisit::Visitor; use rustc_hir::GenericParam; use rustc_hir::Item; use rustc_hir::Node; -use rustc_middle::mir::abstract_const::NotConstEvaluatable; +use rustc_middle::thir::abstract_const::NotConstEvaluatable; use rustc_middle::ty::error::ExpectedFound; use rustc_middle::ty::fold::TypeFolder; use rustc_middle::ty::{ diff --git a/compiler/rustc_trait_selection/src/traits/fulfill.rs b/compiler/rustc_trait_selection/src/traits/fulfill.rs index 18abcc72bce..b376f429292 100644 --- a/compiler/rustc_trait_selection/src/traits/fulfill.rs +++ b/compiler/rustc_trait_selection/src/traits/fulfill.rs @@ -5,8 +5,8 @@ use rustc_data_structures::obligation_forest::{ObligationForest, ObligationProce use rustc_errors::ErrorReported; use rustc_hir as hir; use rustc_infer::traits::{SelectionError, TraitEngine, TraitEngineExt as _, TraitObligation}; -use rustc_middle::mir::abstract_const::NotConstEvaluatable; use rustc_middle::mir::interpret::ErrorHandled; +use rustc_middle::thir::abstract_const::NotConstEvaluatable; use rustc_middle::ty::error::{ExpectedFound, TypeError}; use rustc_middle::ty::subst::SubstsRef; use rustc_middle::ty::ToPredicate; diff --git a/compiler/rustc_trait_selection/src/traits/mod.rs b/compiler/rustc_trait_selection/src/traits/mod.rs index 44c67524383..ef208c44471 100644 --- a/compiler/rustc_trait_selection/src/traits/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/mod.rs @@ -827,16 +827,16 @@ pub fn provide(providers: &mut ty::query::Providers) { vtable_entries, vtable_trait_upcasting_coercion_new_vptr_slot, subst_and_check_impossible_predicates, - mir_abstract_const: |tcx, def_id| { + thir_abstract_const: |tcx, def_id| { let def_id = def_id.expect_local(); if let Some(def) = ty::WithOptConstParam::try_lookup(def_id, tcx) { - tcx.mir_abstract_const_of_const_arg(def) + tcx.thir_abstract_const_of_const_arg(def) } else { - const_evaluatable::mir_abstract_const(tcx, ty::WithOptConstParam::unknown(def_id)) + const_evaluatable::thir_abstract_const(tcx, ty::WithOptConstParam::unknown(def_id)) } }, - mir_abstract_const_of_const_arg: |tcx, (did, param_did)| { - const_evaluatable::mir_abstract_const( + thir_abstract_const_of_const_arg: |tcx, (did, param_did)| { + const_evaluatable::thir_abstract_const( tcx, ty::WithOptConstParam { did, const_param_did: Some(param_did) }, ) diff --git a/compiler/rustc_trait_selection/src/traits/object_safety.rs b/compiler/rustc_trait_selection/src/traits/object_safety.rs index 0ecfda19141..4922cf45a4a 100644 --- a/compiler/rustc_trait_selection/src/traits/object_safety.rs +++ b/compiler/rustc_trait_selection/src/traits/object_safety.rs @@ -836,7 +836,7 @@ fn contains_illegal_self_type_reference<'tcx, T: TypeFoldable<'tcx>>( // // This shouldn't really matter though as we can't really use any // constants which are not considered const evaluatable. - use rustc_middle::mir::abstract_const::Node; + use rustc_middle::thir::abstract_const::Node; if let Ok(Some(ct)) = AbstractConst::new(self.tcx, uv.shrink()) { const_evaluatable::walk_abstract_const(self.tcx, ct, |node| match node.root() { Node::Leaf(leaf) => { diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs index 9824b644c3e..f5be8bf0949 100644 --- a/compiler/rustc_trait_selection/src/traits/select/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs @@ -34,8 +34,8 @@ use rustc_hir as hir; use rustc_hir::def_id::DefId; use rustc_infer::infer::LateBoundRegionConversionTime; use rustc_middle::dep_graph::{DepKind, DepNodeIndex}; -use rustc_middle::mir::abstract_const::NotConstEvaluatable; use rustc_middle::mir::interpret::ErrorHandled; +use rustc_middle::thir::abstract_const::NotConstEvaluatable; use rustc_middle::ty::fast_reject; use rustc_middle::ty::print::with_no_trimmed_paths; use rustc_middle::ty::relate::TypeRelation; diff --git a/src/test/ui/const-generics/generic_const_exprs/abstract-consts-as-cast-5.rs b/src/test/ui/const-generics/generic_const_exprs/abstract-consts-as-cast-5.rs new file mode 100644 index 00000000000..916d60c0e0d --- /dev/null +++ b/src/test/ui/const-generics/generic_const_exprs/abstract-consts-as-cast-5.rs @@ -0,0 +1,11 @@ +#![feature(generic_const_exprs)] +#![allow(incomplete_features)] + +fn foo(a: [(); N as usize]) { + bar::<{ N as usize as usize }>(); + //~^ error: unconstrained generic constant +} + +fn bar() {} + +fn main() {} diff --git a/src/test/ui/const-generics/generic_const_exprs/abstract-consts-as-cast-5.stderr b/src/test/ui/const-generics/generic_const_exprs/abstract-consts-as-cast-5.stderr new file mode 100644 index 00000000000..d48b639dbde --- /dev/null +++ b/src/test/ui/const-generics/generic_const_exprs/abstract-consts-as-cast-5.stderr @@ -0,0 +1,10 @@ +error: unconstrained generic constant + --> $DIR/abstract-consts-as-cast-5.rs:5:11 + | +LL | bar::<{ N as usize as usize }>(); + | ^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: try adding a `where` bound using this expression: `where [(); { N as usize as usize }]:` + +error: aborting due to previous error + diff --git a/src/test/ui/const-generics/generic_const_exprs/array-size-in-generic-struct-param.full.stderr b/src/test/ui/const-generics/generic_const_exprs/array-size-in-generic-struct-param.full.stderr index deb6f3bd12c..9b3c32a9397 100644 --- a/src/test/ui/const-generics/generic_const_exprs/array-size-in-generic-struct-param.full.stderr +++ b/src/test/ui/const-generics/generic_const_exprs/array-size-in-generic-struct-param.full.stderr @@ -10,7 +10,7 @@ error: overly complex generic constant --> $DIR/array-size-in-generic-struct-param.rs:19:15 | LL | arr: [u8; CFG.arr_size], - | ^^^^^^^^^^^^ unsupported projection + | ^^^^^^^^^^^^ unsupported operation in generic constant, this may be supported in the future | = help: consider moving this anonymous constant into a `const` function diff --git a/src/test/ui/const-generics/generic_const_exprs/closures.stderr b/src/test/ui/const-generics/generic_const_exprs/closures.stderr index 9f0b7252e83..95dae4ecc04 100644 --- a/src/test/ui/const-generics/generic_const_exprs/closures.stderr +++ b/src/test/ui/const-generics/generic_const_exprs/closures.stderr @@ -4,7 +4,7 @@ error: overly complex generic constant LL | fn test() -> [u8; N + (|| 42)()] {} | ^^^^-------^^ | | - | unsupported rvalue + | unsupported operation in generic constant, this may be supported in the future | = help: consider moving this anonymous constant into a `const` function diff --git a/src/test/ui/const-generics/generic_const_exprs/let-bindings.stderr b/src/test/ui/const-generics/generic_const_exprs/let-bindings.stderr index 5749defb3e1..c9f84799522 100644 --- a/src/test/ui/const-generics/generic_const_exprs/let-bindings.stderr +++ b/src/test/ui/const-generics/generic_const_exprs/let-bindings.stderr @@ -2,9 +2,7 @@ error: overly complex generic constant --> $DIR/let-bindings.rs:6:68 | LL | fn test() -> [u8; { let x = N; N + 1 }] where [u8; { let x = N; N + 1 }]: Default { - | ^^^^^^-^^^^^^^^^^^^^ - | | - | unsupported statement + | ^^^^^^^^^^^^^^^^^^^^ unsupported operation in generic constant, this may be supported in the future | = help: consider moving this anonymous constant into a `const` function @@ -12,9 +10,7 @@ error: overly complex generic constant --> $DIR/let-bindings.rs:6:35 | LL | fn test() -> [u8; { let x = N; N + 1 }] where [u8; { let x = N; N + 1 }]: Default { - | ^^^^^^-^^^^^^^^^^^^^ - | | - | unsupported statement + | ^^^^^^^^^^^^^^^^^^^^ unsupported operation in generic constant, this may be supported in the future | = help: consider moving this anonymous constant into a `const` function diff --git a/src/test/ui/const-generics/generic_const_exprs/unify-op-with-fn-call.rs b/src/test/ui/const-generics/generic_const_exprs/unify-op-with-fn-call.rs new file mode 100644 index 00000000000..c0404d35b08 --- /dev/null +++ b/src/test/ui/const-generics/generic_const_exprs/unify-op-with-fn-call.rs @@ -0,0 +1,35 @@ +#![feature(generic_const_exprs, adt_const_params, const_trait_impl)] +#![allow(incomplete_features)] + +// test `N + N` unifies with explicit function calls for non-builtin-types +#[derive(PartialEq, Eq)] +struct Foo(u8); + +impl const std::ops::Add for Foo { + type Output = Self; + + fn add(self, rhs: Self) -> Self::Output { + self + } +} + +struct Evaluatable; + +fn foo(a: Evaluatable<{ N + N }>) { + bar::<{ std::ops::Add::add(N, N) }>(); +} + +fn bar() {} + +// test that `N + N` unifies with explicit function calls for builin-types +struct Evaluatable2; + +fn foo2(a: Evaluatable2<{ N + N }>) { + bar2::<{ std::ops::Add::add(N, N) }>(); + //~^ error: unconstrained generic constant + // FIXME(generic_const_exprs) make this not an error +} + +fn bar2() {} + +fn main() {} diff --git a/src/test/ui/const-generics/generic_const_exprs/unify-op-with-fn-call.stderr b/src/test/ui/const-generics/generic_const_exprs/unify-op-with-fn-call.stderr new file mode 100644 index 00000000000..d18c7916f5f --- /dev/null +++ b/src/test/ui/const-generics/generic_const_exprs/unify-op-with-fn-call.stderr @@ -0,0 +1,10 @@ +error: unconstrained generic constant + --> $DIR/unify-op-with-fn-call.rs:28:12 + | +LL | bar2::<{ std::ops::Add::add(N, N) }>(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: try adding a `where` bound using this expression: `where [(); { std::ops::Add::add(N, N) }]:` + +error: aborting due to previous error + diff --git a/src/test/ui/const-generics/generic_const_exprs/unused_expr.stderr b/src/test/ui/const-generics/generic_const_exprs/unused_expr.stderr index 1687dbbcbe3..3da91b19a5e 100644 --- a/src/test/ui/const-generics/generic_const_exprs/unused_expr.stderr +++ b/src/test/ui/const-generics/generic_const_exprs/unused_expr.stderr @@ -2,9 +2,7 @@ error: overly complex generic constant --> $DIR/unused_expr.rs:4:34 | LL | fn add() -> [u8; { N + 1; 5 }] { - | ^^-----^^^^^ - | | - | dead code + | ^^^^^^^^^^^^ unsupported operation in generic constant, this may be supported in the future | = help: consider moving this anonymous constant into a `const` function @@ -12,9 +10,7 @@ error: overly complex generic constant --> $DIR/unused_expr.rs:9:34 | LL | fn div() -> [u8; { N / 1; 5 }] { - | ^^-----^^^^^ - | | - | dead code + | ^^^^^^^^^^^^ unsupported operation in generic constant, this may be supported in the future | = help: consider moving this anonymous constant into a `const` function @@ -22,9 +18,7 @@ error: overly complex generic constant --> $DIR/unused_expr.rs:16:38 | LL | fn fn_call() -> [u8; { foo(N); 5 }] { - | ^^------^^^^^ - | | - | dead code + | ^^^^^^^^^^^^^ unsupported operation in generic constant, this may be supported in the future | = help: consider moving this anonymous constant into a `const` function diff --git a/src/test/ui/const-generics/issues/issue-67375.full.stderr b/src/test/ui/const-generics/issues/issue-67375.full.stderr index 5386ef56a24..d7b52063dc4 100644 --- a/src/test/ui/const-generics/issues/issue-67375.full.stderr +++ b/src/test/ui/const-generics/issues/issue-67375.full.stderr @@ -2,9 +2,9 @@ error: overly complex generic constant --> $DIR/issue-67375.rs:7:17 | LL | inner: [(); { [|_: &T| {}; 0].len() }], - | ^^^----------^^^^^^^^^^^^ - | | - | unsupported rvalue + | ^^---------------^^^^^^^^ + | | + | unsupported operation in generic constant | = help: consider moving this anonymous constant into a `const` function diff --git a/src/test/ui/const-generics/issues/issue-67945-2.full.stderr b/src/test/ui/const-generics/issues/issue-67945-2.full.stderr index 118cf447c01..fe0351a8292 100644 --- a/src/test/ui/const-generics/issues/issue-67945-2.full.stderr +++ b/src/test/ui/const-generics/issues/issue-67945-2.full.stderr @@ -5,11 +5,10 @@ LL | A: [(); { | _____________^ LL | | LL | | let x: Option> = None; - | | ---- unsupported rvalue LL | | LL | | 0 LL | | }], - | |_____^ + | |_____^ unsupported operation in generic constant, this may be supported in the future | = help: consider moving this anonymous constant into a `const` function