use crate::hir::def_id::DefId;
use crate::hir;
use crate::ty::TyCtxt;
-use syntax_pos::symbol::Symbol;
+use syntax_pos::symbol::{sym, Symbol};
use crate::hir::map::blocks::FnLikeNode;
use syntax::attr;
/// Whether the `def_id` counts as const fn in your current crate, considering all active
/// feature gates
pub fn is_const_fn(self, def_id: DefId) -> bool {
- self.is_const_fn_raw(def_id) && match self.lookup_stability(def_id) {
- Some(stab) => match stab.const_stability {
+ self.is_const_fn_raw(def_id) && match self.is_unstable_const_fn(def_id) {
+ Some(feature_name) => {
// has a `rustc_const_unstable` attribute, check whether the user enabled the
- // corresponding feature gate
- Some(feature_name) => self.features()
+ // corresponding feature gate, const_constructor is not a lib feature, so has
+ // to be checked separately.
+ self.features()
.declared_lib_features
.iter()
- .any(|&(sym, _)| sym == feature_name),
- // the function has no stability attribute, it is stable as const fn or the user
- // needs to use feature gates to use the function at all
- None => true,
+ .any(|&(sym, _)| sym == feature_name)
+ || (feature_name == sym::const_constructor
+ && self.features().const_constructor)
},
- // functions without stability are either stable user written const fn or the user is
- // using feature gates and we thus don't care what they do
+ // functions without const stability are either stable user written
+ // const fn or the user is using feature gates and we thus don't
+ // care what they do
None => true,
}
}
/// Whether the `def_id` is an unstable const fn and what feature gate is necessary to enable it
pub fn is_unstable_const_fn(self, def_id: DefId) -> Option<Symbol> {
- if self.is_const_fn_raw(def_id) {
+ if self.is_constructor(def_id) {
+ Some(sym::const_constructor)
+ } else if self.is_const_fn_raw(def_id) {
self.lookup_stability(def_id)?.const_stability
} else {
None
let hir_id = tcx.hir().as_local_hir_id(def_id)
.expect("Non-local call to local provider is_const_fn");
- if let Some(fn_like) = FnLikeNode::from_node(tcx.hir().get_by_hir_id(hir_id)) {
+ let node = tcx.hir().get_by_hir_id(hir_id);
+ if let Some(fn_like) = FnLikeNode::from_node(node) {
fn_like.constness() == hir::Constness::Const
+ } else if let hir::Node::Ctor(_) = node {
+ true
} else {
false
}
let constness = match self.entry(id).kind {
EntryKind::Method(data) => data.decode(self).fn_data.constness,
EntryKind::Fn(data) => data.decode(self).constness,
+ EntryKind::Variant(..) | EntryKind::Struct(..) => hir::Constness::Const,
_ => hir::Constness::NotConst,
};
constness == hir::Constness::Const
// Allows the user of associated type bounds.
(active, associated_type_bounds, "1.34.0", Some(52662), None),
+ // Allows calling constructor functions in `const fn`
+ // FIXME Create issue
+ (active, const_constructor, "1.37.0", Some(61456), None),
+
// -------------------------------------------------------------------------
// feature-group-end: actual feature gates
// -------------------------------------------------------------------------
conservative_impl_trait,
console,
const_compare_raw_pointers,
+ const_constructor,
const_fn,
const_fn_union,
const_generics,
--- /dev/null
+// Test that constructors are considered to be const fns with the required feature.
+
+// run-pass
+
+// revisions: min_const_fn const_fn
+
+#![cfg_attr(const_fn, feature(const_fn))]
+
+#![feature(const_constructor)]
+
+// Ctor(..) is transformed to Ctor { 0: ... } in HAIR lowering, so directly
+// calling constructors doesn't require them to be const.
+
+type ExternalType = std::panic::AssertUnwindSafe<(Option<i32>, Result<i32, bool>)>;
+
+const fn call_external_constructors_in_local_vars() -> ExternalType {
+ let f = Some;
+ let g = Err;
+ let h = std::panic::AssertUnwindSafe;
+ let x = f(5);
+ let y = g(false);
+ let z = h((x, y));
+ z
+}
+
+const CALL_EXTERNAL_CONSTRUCTORS_IN_LOCAL_VARS: ExternalType = {
+ let f = Some;
+ let g = Err;
+ let h = std::panic::AssertUnwindSafe;
+ let x = f(5);
+ let y = g(false);
+ let z = h((x, y));
+ z
+};
+
+const fn call_external_constructors_in_temps() -> ExternalType {
+ let x = { Some }(5);
+ let y = (*&Err)(false);
+ let z = [std::panic::AssertUnwindSafe][0]((x, y));
+ z
+}
+
+const CALL_EXTERNAL_CONSTRUCTORS_IN_TEMPS: ExternalType = {
+ let x = { Some }(5);
+ let y = (*&Err)(false);
+ let z = [std::panic::AssertUnwindSafe][0]((x, y));
+ z
+};
+
+#[derive(Debug, PartialEq)]
+enum LocalOption<T> {
+ Some(T),
+ _None,
+}
+
+#[derive(Debug, PartialEq)]
+enum LocalResult<T, E> {
+ _Ok(T),
+ Err(E),
+}
+
+#[derive(Debug, PartialEq)]
+struct LocalAssertUnwindSafe<T>(T);
+
+type LocalType = LocalAssertUnwindSafe<(LocalOption<i32>, LocalResult<i32, bool>)>;
+
+const fn call_local_constructors_in_local_vars() -> LocalType {
+ let f = LocalOption::Some;
+ let g = LocalResult::Err;
+ let h = LocalAssertUnwindSafe;
+ let x = f(5);
+ let y = g(false);
+ let z = h((x, y));
+ z
+}
+
+const CALL_LOCAL_CONSTRUCTORS_IN_LOCAL_VARS: LocalType = {
+ let f = LocalOption::Some;
+ let g = LocalResult::Err;
+ let h = LocalAssertUnwindSafe;
+ let x = f(5);
+ let y = g(false);
+ let z = h((x, y));
+ z
+};
+
+const fn call_local_constructors_in_temps() -> LocalType {
+ let x = { LocalOption::Some }(5);
+ let y = (*&LocalResult::Err)(false);
+ let z = [LocalAssertUnwindSafe][0]((x, y));
+ z
+}
+
+const CALL_LOCAL_CONSTRUCTORS_IN_TEMPS: LocalType = {
+ let x = { LocalOption::Some }(5);
+ let y = (*&LocalResult::Err)(false);
+ let z = [LocalAssertUnwindSafe][0]((x, y));
+ z
+};
+
+fn main() {
+ assert_eq!(
+ (
+ call_external_constructors_in_local_vars().0,
+ call_external_constructors_in_temps().0,
+ call_local_constructors_in_local_vars(),
+ call_local_constructors_in_temps(),
+ ),
+ (
+ CALL_EXTERNAL_CONSTRUCTORS_IN_LOCAL_VARS.0,
+ CALL_EXTERNAL_CONSTRUCTORS_IN_TEMPS.0,
+ CALL_LOCAL_CONSTRUCTORS_IN_LOCAL_VARS,
+ CALL_LOCAL_CONSTRUCTORS_IN_TEMPS,
+ )
+ );
+}
--- /dev/null
+error: `std::prelude::v1::Some` is not yet stable as a const fn
+ --> $DIR/feature-gate-const_constructor.rs:9:37
+ |
+LL | const EXTERNAL_CONST: Option<i32> = {Some}(1);
+ | ^^^^^^^^^
+ |
+ = help: add `#![feature(const_constructor)]` to the crate attributes to enable
+
+error: `E::V` is not yet stable as a const fn
+ --> $DIR/feature-gate-const_constructor.rs:12:24
+ |
+LL | const LOCAL_CONST: E = {E::V}(1);
+ | ^^^^^^^^^
+ |
+ = help: add `#![feature(const_constructor)]` to the crate attributes to enable
+
+error: `std::prelude::v1::Some` is not yet stable as a const fn
+ --> $DIR/feature-gate-const_constructor.rs:17:13
+ |
+LL | let _ = {Some}(1);
+ | ^^^^^^^^^
+ |
+ = help: add `#![feature(const_constructor)]` to the crate attributes to enable
+
+error: `E::V` is not yet stable as a const fn
+ --> $DIR/feature-gate-const_constructor.rs:23:13
+ |
+LL | let _ = {E::V}(1);
+ | ^^^^^^^^^
+ |
+ = help: add `#![feature(const_constructor)]` to the crate attributes to enable
+
+error: aborting due to 4 previous errors
+
--- /dev/null
+error: `std::prelude::v1::Some` is not yet stable as a const fn
+ --> $DIR/feature-gate-const_constructor.rs:9:37
+ |
+LL | const EXTERNAL_CONST: Option<i32> = {Some}(1);
+ | ^^^^^^^^^
+ |
+ = help: add `#![feature(const_constructor)]` to the crate attributes to enable
+
+error: `E::V` is not yet stable as a const fn
+ --> $DIR/feature-gate-const_constructor.rs:12:24
+ |
+LL | const LOCAL_CONST: E = {E::V}(1);
+ | ^^^^^^^^^
+ |
+ = help: add `#![feature(const_constructor)]` to the crate attributes to enable
+
+error: `std::prelude::v1::Some` is not yet stable as a const fn
+ --> $DIR/feature-gate-const_constructor.rs:17:13
+ |
+LL | let _ = {Some}(1);
+ | ^^^^^^^^^
+ |
+ = help: add `#![feature(const_constructor)]` to the crate attributes to enable
+
+error: `E::V` is not yet stable as a const fn
+ --> $DIR/feature-gate-const_constructor.rs:23:13
+ |
+LL | let _ = {E::V}(1);
+ | ^^^^^^^^^
+ |
+ = help: add `#![feature(const_constructor)]` to the crate attributes to enable
+
+error: aborting due to 4 previous errors
+
--- /dev/null
+// revisions: min_const_fn const_fn
+
+#![cfg_attr(const_fn, feature(const_fn))]
+
+enum E {
+ V(i32),
+}
+
+const EXTERNAL_CONST: Option<i32> = {Some}(1);
+//[min_const_fn]~^ ERROR is not yet stable as a const fn
+//[const_fn]~^^ ERROR is not yet stable as a const fn
+const LOCAL_CONST: E = {E::V}(1);
+//[min_const_fn]~^ ERROR is not yet stable as a const fn
+//[const_fn]~^^ ERROR is not yet stable as a const fn
+
+const fn external_fn() {
+ let _ = {Some}(1);
+ //[min_const_fn]~^ ERROR is not yet stable as a const fn
+ //[const_fn]~^^ ERROR is not yet stable as a const fn
+}
+
+const fn local_fn() {
+ let _ = {E::V}(1);
+ //[min_const_fn]~^ ERROR is not yet stable as a const fn
+ //[const_fn]~^^ ERROR is not yet stable as a const fn
+}
+
+fn main() {}