| use rustc_hir as hir; |
| use rustc_hir::def::DefKind; |
| use rustc_hir::def_id::{DefId, LocalDefId}; |
| use rustc_middle::query::Providers; |
| use rustc_middle::ty::TyCtxt; |
| |
| fn parent_impl_or_trait_constness(tcx: TyCtxt<'_>, def_id: LocalDefId) -> hir::Constness { |
| let parent_id = tcx.local_parent(def_id); |
| match tcx.def_kind(parent_id) { |
| DefKind::Impl { of_trait: true } => tcx.impl_trait_header(parent_id).unwrap().constness, |
| DefKind::Trait => { |
| if tcx.is_const_trait(parent_id.into()) { |
| hir::Constness::Const |
| } else { |
| hir::Constness::NotConst |
| } |
| } |
| _ => hir::Constness::NotConst, |
| } |
| } |
| |
| /// Checks whether a function-like definition is considered to be `const`. |
| fn constness(tcx: TyCtxt<'_>, def_id: LocalDefId) -> hir::Constness { |
| let node = tcx.hir_node_by_def_id(def_id); |
| |
| match node { |
| hir::Node::Ctor(hir::VariantData::Tuple(..)) => hir::Constness::Const, |
| hir::Node::ForeignItem(item) if let hir::ForeignItemKind::Fn(..) = item.kind => { |
| // Foreign functions cannot be evaluated at compile-time. |
| hir::Constness::NotConst |
| } |
| hir::Node::Expr(e) if let hir::ExprKind::Closure(c) = e.kind => c.constness, |
| _ => { |
| if let Some(fn_kind) = node.fn_kind() { |
| if fn_kind.constness() == hir::Constness::Const { |
| return hir::Constness::Const; |
| } |
| |
| // If the function itself is not annotated with `const`, it may still be a `const fn` |
| // if it resides in a const trait impl. |
| parent_impl_or_trait_constness(tcx, def_id) |
| } else { |
| tcx.dcx().span_bug( |
| tcx.def_span(def_id), |
| format!("should not be requesting the constness of items that can't be const: {node:#?}: {:?}", tcx.def_kind(def_id)) |
| ) |
| } |
| } |
| } |
| } |
| |
| fn is_promotable_const_fn(tcx: TyCtxt<'_>, def_id: DefId) -> bool { |
| tcx.is_const_fn(def_id) |
| && match tcx.lookup_const_stability(def_id) { |
| Some(stab) => { |
| if cfg!(debug_assertions) && stab.promotable { |
| let sig = tcx.fn_sig(def_id); |
| assert!( |
| sig.skip_binder().safety().is_safe(), |
| "don't mark const unsafe fns as promotable", |
| // https://github.com/rust-lang/rust/pull/53851#issuecomment-418760682 |
| ); |
| } |
| stab.promotable |
| } |
| None => false, |
| } |
| } |
| |
| pub fn provide(providers: &mut Providers) { |
| *providers = Providers { constness, is_promotable_const_fn, ..*providers }; |
| } |