From ab36a2fe16006a34c7d19baa6ef8e23f6ec079cc Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Wed, 19 Oct 2022 18:34:01 +0000 Subject: [PATCH 1/3] Revert "Unify tcx.constness and param env constness checks" This reverts commit bef8681a1837790f2745c1f6a7f8214af2fd7f5d. This reverts commit c646c4d403d8c88cd3450f859fbdc34ec26d5bb5. --- .../src/const_eval/fn_queries.rs | 72 +++++-------------- compiler/rustc_metadata/src/rmeta/encoder.rs | 56 ++++----------- compiler/rustc_ty_utils/src/ty.rs | 69 +++++++++++++++++- 3 files changed, 99 insertions(+), 98 deletions(-) diff --git a/compiler/rustc_const_eval/src/const_eval/fn_queries.rs b/compiler/rustc_const_eval/src/const_eval/fn_queries.rs index cdcebb61c2e8c..f1674d04f8d15 100644 --- a/compiler/rustc_const_eval/src/const_eval/fn_queries.rs +++ b/compiler/rustc_const_eval/src/const_eval/fn_queries.rs @@ -25,10 +25,12 @@ pub fn is_parent_const_impl_raw(tcx: TyCtxt<'_>, def_id: LocalDefId) -> bool { /// report whether said intrinsic has a `rustc_const_{un,}stable` attribute. Otherwise, return /// `Constness::NotConst`. fn constness(tcx: TyCtxt<'_>, def_id: DefId) -> hir::Constness { - let hir_id = tcx.hir().local_def_id_to_hir_id(def_id.expect_local()); - match tcx.hir().get(hir_id) { - hir::Node::Ctor(_) => hir::Constness::Const, + let def_id = def_id.expect_local(); + let node = tcx.hir().get_by_def_id(def_id); + match node { + hir::Node::Ctor(_) => hir::Constness::Const, + hir::Node::Item(hir::Item { kind: hir::ItemKind::Impl(impl_), .. }) => impl_.constness, hir::Node::ForeignItem(hir::ForeignItem { kind: hir::ForeignItemKind::Fn(..), .. }) => { // Intrinsics use `rustc_const_{un,}stable` attributes to indicate constness. All other // foreign items cannot be evaluated at compile-time. @@ -39,62 +41,20 @@ fn constness(tcx: TyCtxt<'_>, def_id: DefId) -> hir::Constness { }; if is_const { hir::Constness::Const } else { hir::Constness::NotConst } } + _ => { + if let Some(fn_kind) = node.fn_kind() { + if fn_kind.constness() == hir::Constness::Const { + return hir::Constness::Const; + } - hir::Node::TraitItem(hir::TraitItem { kind: hir::TraitItemKind::Fn(..), .. }) - if tcx.is_const_default_method(def_id) => - { - hir::Constness::Const - } - - hir::Node::Item(hir::Item { kind: hir::ItemKind::Const(..), .. }) - | hir::Node::Item(hir::Item { kind: hir::ItemKind::Static(..), .. }) - | hir::Node::TraitItem(hir::TraitItem { kind: hir::TraitItemKind::Const(..), .. }) - | hir::Node::AnonConst(_) - | hir::Node::ImplItem(hir::ImplItem { kind: hir::ImplItemKind::Const(..), .. }) - | hir::Node::ImplItem(hir::ImplItem { - kind: - hir::ImplItemKind::Fn( - hir::FnSig { - header: hir::FnHeader { constness: hir::Constness::Const, .. }, - .. - }, - .., - ), - .. - }) => hir::Constness::Const, - - hir::Node::ImplItem(hir::ImplItem { - kind: hir::ImplItemKind::Type(..) | hir::ImplItemKind::Fn(..), - .. - }) => { - let parent_hir_id = tcx.hir().get_parent_node(hir_id); - match tcx.hir().get(parent_hir_id) { - hir::Node::Item(hir::Item { - kind: hir::ItemKind::Impl(hir::Impl { constness, .. }), - .. - }) => *constness, - _ => span_bug!( - tcx.def_span(parent_hir_id.owner), - "impl item's parent node is not an impl", - ), + // If the function itself is not annotated with `const`, it may still be a `const fn` + // if it resides in a const trait impl. + let is_const = is_parent_const_impl_raw(tcx, def_id); + if is_const { hir::Constness::Const } else { hir::Constness::NotConst } + } else { + hir::Constness::NotConst } } - - hir::Node::Item(hir::Item { - kind: hir::ItemKind::Fn(hir::FnSig { header: hir::FnHeader { constness, .. }, .. }, ..), - .. - }) - | hir::Node::TraitItem(hir::TraitItem { - kind: - hir::TraitItemKind::Fn(hir::FnSig { header: hir::FnHeader { constness, .. }, .. }, ..), - .. - }) - | hir::Node::Item(hir::Item { - kind: hir::ItemKind::Impl(hir::Impl { constness, .. }), - .. - }) => *constness, - - _ => hir::Constness::NotConst, } } diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs index 68119598285c5..3fc10197b9129 100644 --- a/compiler/rustc_metadata/src/rmeta/encoder.rs +++ b/compiler/rustc_metadata/src/rmeta/encoder.rs @@ -1059,43 +1059,6 @@ fn should_encode_const(def_kind: DefKind) -> bool { } } -fn should_encode_constness(def_kind: DefKind) -> bool { - match def_kind { - DefKind::Struct - | DefKind::Union - | DefKind::Enum - | DefKind::Trait - | DefKind::AssocTy - | DefKind::Fn - | DefKind::Const - | DefKind::Static(..) - | DefKind::Ctor(..) - | DefKind::AssocFn - | DefKind::AssocConst - | DefKind::AnonConst - | DefKind::InlineConst - | DefKind::OpaqueTy - | DefKind::ImplTraitPlaceholder - | DefKind::Impl - | DefKind::Closure - | DefKind::Generator - | DefKind::TyAlias => true, - DefKind::Variant - | DefKind::TraitAlias - | DefKind::ForeignTy - | DefKind::Field - | DefKind::TyParam - | DefKind::Mod - | DefKind::ForeignMod - | DefKind::ConstParam - | DefKind::Macro(..) - | DefKind::Use - | DefKind::LifetimeParam - | DefKind::GlobalAsm - | DefKind::ExternCrate => false, - } -} - fn should_encode_trait_impl_trait_tys<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId) -> bool { if tcx.def_kind(def_id) != DefKind::AssocFn { return false; @@ -1202,9 +1165,6 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { { record!(self.tables.trait_impl_trait_tys[def_id] <- table); } - if should_encode_constness(def_kind) { - self.tables.constness.set(def_id.index, tcx.constness(def_id)); - } } let inherent_impls = tcx.crate_inherent_impls(()); for (def_id, implementations) in inherent_impls.inherent_impls.iter() { @@ -1232,6 +1192,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { }; record!(self.tables.variant_data[def_id] <- data); + self.tables.constness.set(def_id.index, hir::Constness::Const); record_array!(self.tables.children[def_id] <- variant.fields.iter().map(|f| { assert!(f.did.is_local()); f.did.index @@ -1259,6 +1220,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { }; record!(self.tables.variant_data[def_id] <- data); + self.tables.constness.set(def_id.index, hir::Constness::Const); if variant.ctor_kind == CtorKind::Fn { record!(self.tables.fn_sig[def_id] <- tcx.fn_sig(def_id)); } @@ -1322,6 +1284,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { record!(self.tables.repr_options[def_id] <- adt_def.repr()); record!(self.tables.variant_data[def_id] <- data); + self.tables.constness.set(def_id.index, hir::Constness::Const); if variant.ctor_kind == CtorKind::Fn { record!(self.tables.fn_sig[def_id] <- tcx.fn_sig(def_id)); } @@ -1357,6 +1320,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { } }; self.tables.asyncness.set(def_id.index, m_sig.header.asyncness); + self.tables.constness.set(def_id.index, hir::Constness::NotConst); } ty::AssocKind::Type => { self.encode_explicit_item_bounds(def_id); @@ -1381,6 +1345,13 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { let hir::ImplItemKind::Fn(ref sig, body) = ast_item.kind else { bug!() }; self.tables.asyncness.set(def_id.index, sig.header.asyncness); record_array!(self.tables.fn_arg_names[def_id] <- self.tcx.hir().body_param_names(body)); + // Can be inside `impl const Trait`, so using sig.header.constness is not reliable + let constness = if self.tcx.is_const_fn_raw(def_id) { + hir::Constness::Const + } else { + hir::Constness::NotConst + }; + self.tables.constness.set(def_id.index, constness); } ty::AssocKind::Const | ty::AssocKind::Type => {} } @@ -1503,6 +1474,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { hir::ItemKind::Fn(ref sig, .., body) => { self.tables.asyncness.set(def_id.index, sig.header.asyncness); record_array!(self.tables.fn_arg_names[def_id] <- self.tcx.hir().body_param_names(body)); + self.tables.constness.set(def_id.index, sig.header.constness); } hir::ItemKind::Macro(ref macro_def, _) => { if macro_def.macro_rules { @@ -1523,6 +1495,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { hir::ItemKind::Struct(ref struct_def, _) => { let adt_def = self.tcx.adt_def(def_id); record!(self.tables.repr_options[def_id] <- adt_def.repr()); + self.tables.constness.set(def_id.index, hir::Constness::Const); // Encode def_ids for each field and method // for methods, write all the stuff get_trait_method @@ -1551,8 +1524,9 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { is_non_exhaustive: variant.is_field_list_non_exhaustive(), }); } - hir::ItemKind::Impl(hir::Impl { defaultness, .. }) => { + hir::ItemKind::Impl(hir::Impl { defaultness, constness, .. }) => { self.tables.impl_defaultness.set(def_id.index, *defaultness); + self.tables.constness.set(def_id.index, *constness); let trait_ref = self.tcx.impl_trait_ref(def_id); if let Some(trait_ref) = trait_ref { diff --git a/compiler/rustc_ty_utils/src/ty.rs b/compiler/rustc_ty_utils/src/ty.rs index 196d70614e7c9..cd9d229640571 100644 --- a/compiler/rustc_ty_utils/src/ty.rs +++ b/compiler/rustc_ty_utils/src/ty.rs @@ -137,10 +137,77 @@ fn param_env(tcx: TyCtxt<'_>, def_id: DefId) -> ty::ParamEnv<'_> { let local_did = def_id.as_local(); let hir_id = local_did.map(|def_id| tcx.hir().local_def_id_to_hir_id(def_id)); + let constness = match hir_id { + Some(hir_id) => match tcx.hir().get(hir_id) { + hir::Node::TraitItem(hir::TraitItem { kind: hir::TraitItemKind::Fn(..), .. }) + if tcx.is_const_default_method(def_id) => + { + hir::Constness::Const + } + + hir::Node::Item(hir::Item { kind: hir::ItemKind::Const(..), .. }) + | hir::Node::Item(hir::Item { kind: hir::ItemKind::Static(..), .. }) + | hir::Node::TraitItem(hir::TraitItem { + kind: hir::TraitItemKind::Const(..), .. + }) + | hir::Node::AnonConst(_) + | hir::Node::ImplItem(hir::ImplItem { kind: hir::ImplItemKind::Const(..), .. }) + | hir::Node::ImplItem(hir::ImplItem { + kind: + hir::ImplItemKind::Fn( + hir::FnSig { + header: hir::FnHeader { constness: hir::Constness::Const, .. }, + .. + }, + .., + ), + .. + }) => hir::Constness::Const, + + hir::Node::ImplItem(hir::ImplItem { + kind: hir::ImplItemKind::Type(..) | hir::ImplItemKind::Fn(..), + .. + }) => { + let parent_hir_id = tcx.hir().get_parent_node(hir_id); + match tcx.hir().get(parent_hir_id) { + hir::Node::Item(hir::Item { + kind: hir::ItemKind::Impl(hir::Impl { constness, .. }), + .. + }) => *constness, + _ => span_bug!( + tcx.def_span(parent_hir_id.owner), + "impl item's parent node is not an impl", + ), + } + } + + hir::Node::Item(hir::Item { + kind: + hir::ItemKind::Fn(hir::FnSig { header: hir::FnHeader { constness, .. }, .. }, ..), + .. + }) + | hir::Node::TraitItem(hir::TraitItem { + kind: + hir::TraitItemKind::Fn( + hir::FnSig { header: hir::FnHeader { constness, .. }, .. }, + .., + ), + .. + }) + | hir::Node::Item(hir::Item { + kind: hir::ItemKind::Impl(hir::Impl { constness, .. }), + .. + }) => *constness, + + _ => hir::Constness::NotConst, + }, + None => hir::Constness::NotConst, + }; + let unnormalized_env = ty::ParamEnv::new( tcx.intern_predicates(&predicates), traits::Reveal::UserFacing, - tcx.constness(def_id), + constness, ); let body_id = From 43f2c37f9350b2bed0b81bf858e7478869d8c306 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Wed, 19 Oct 2022 19:05:15 +0000 Subject: [PATCH 2/3] Note discrepancies in constness calculation --- compiler/rustc_ty_utils/src/ty.rs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/compiler/rustc_ty_utils/src/ty.rs b/compiler/rustc_ty_utils/src/ty.rs index cd9d229640571..3eebb4ace477f 100644 --- a/compiler/rustc_ty_utils/src/ty.rs +++ b/compiler/rustc_ty_utils/src/ty.rs @@ -137,6 +137,7 @@ fn param_env(tcx: TyCtxt<'_>, def_id: DefId) -> ty::ParamEnv<'_> { let local_did = def_id.as_local(); let hir_id = local_did.map(|def_id| tcx.hir().local_def_id_to_hir_id(def_id)); + // FIXME(consts): This is not exactly in line with the constness query. let constness = match hir_id { Some(hir_id) => match tcx.hir().get(hir_id) { hir::Node::TraitItem(hir::TraitItem { kind: hir::TraitItemKind::Fn(..), .. }) @@ -201,6 +202,10 @@ fn param_env(tcx: TyCtxt<'_>, def_id: DefId) -> ty::ParamEnv<'_> { _ => hir::Constness::NotConst, }, + // FIXME(consts): It's suspicious that a param-env for a foreign item + // will always have NotConst param-env, though we don't typically use + // that param-env for anything meaningful right now, so it's likely + // not an issue. None => hir::Constness::NotConst, }; From 751ac6ce5168b8bbefd83040fb262204072fc4df Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Thu, 20 Oct 2022 04:19:54 +0000 Subject: [PATCH 3/3] Bless test --- .../rfc-2632-const-trait-impl/issue-102985.rs | 3 ++- .../issue-102985.stderr | 19 +++++++++++++++++-- 2 files changed, 19 insertions(+), 3 deletions(-) diff --git a/src/test/ui/rfc-2632-const-trait-impl/issue-102985.rs b/src/test/ui/rfc-2632-const-trait-impl/issue-102985.rs index e0df72003844c..07d3f51edce5e 100644 --- a/src/test/ui/rfc-2632-const-trait-impl/issue-102985.rs +++ b/src/test/ui/rfc-2632-const-trait-impl/issue-102985.rs @@ -4,7 +4,8 @@ struct Bug { inner: [(); match || 1 { n => n(), //~^ ERROR the trait bound - //~| ERROR cannot call non-const fn `Bug::inner::{constant#0}::{closure#0}` in constants + //~| ERROR the trait bound + //~| ERROR cannot call non-const closure in constants }], } diff --git a/src/test/ui/rfc-2632-const-trait-impl/issue-102985.stderr b/src/test/ui/rfc-2632-const-trait-impl/issue-102985.stderr index 14d87e7cdc64a..b98ccbe5d03ec 100644 --- a/src/test/ui/rfc-2632-const-trait-impl/issue-102985.stderr +++ b/src/test/ui/rfc-2632-const-trait-impl/issue-102985.stderr @@ -12,15 +12,30 @@ LL | n => n(), | ^^^ = note: wrap the `[closure@$DIR/issue-102985.rs:4:23: 4:25]` in a closure with no arguments: `|| { /* code */ }` -error[E0015]: cannot call non-const fn `Bug::inner::{constant#0}::{closure#0}` in constants +error[E0277]: the trait bound `[closure@$DIR/issue-102985.rs:4:23: 4:25]: ~const Fn<()>` is not satisfied + --> $DIR/issue-102985.rs:5:14 + | +LL | n => n(), + | ^^^ expected an `Fn<()>` closure, found `[closure@$DIR/issue-102985.rs:4:23: 4:25]` + | + = help: the trait `~const Fn<()>` is not implemented for closure `[closure@$DIR/issue-102985.rs:4:23: 4:25]` +note: the trait `Fn<()>` is implemented for `[closure@$DIR/issue-102985.rs:4:23: 4:25]`, but that implementation is not `const` + --> $DIR/issue-102985.rs:5:14 + | +LL | n => n(), + | ^^^ + = note: wrap the `[closure@$DIR/issue-102985.rs:4:23: 4:25]` in a closure with no arguments: `|| { /* code */ }` + +error[E0015]: cannot call non-const closure in constants --> $DIR/issue-102985.rs:5:14 | LL | n => n(), | ^^^ | + = note: closures need an RFC before allowed to be called in constants = note: calls in constants are limited to constant functions, tuple structs and tuple variants -error: aborting due to 2 previous errors +error: aborting due to 3 previous errors Some errors have detailed explanations: E0015, E0277. For more information about an error, try `rustc --explain E0015`.