]> git.lizzy.rs Git - rust.git/commitdiff
Make constructors actually be const functions
authorMatthew Jasper <mjjasper1@gmail.com>
Sun, 26 May 2019 08:58:06 +0000 (09:58 +0100)
committerMatthew Jasper <mjjasper1@gmail.com>
Thu, 6 Jun 2019 16:20:06 +0000 (17:20 +0100)
src/librustc/ty/constness.rs
src/librustc_metadata/decoder.rs
src/libsyntax/feature_gate.rs
src/libsyntax_pos/symbol.rs
src/test/ui/consts/const_constructor/const-construct-call.rs [new file with mode: 0644]
src/test/ui/consts/const_constructor/feature-gate-const_constructor.const_fn.stderr [new file with mode: 0644]
src/test/ui/consts/const_constructor/feature-gate-const_constructor.min_const_fn.stderr [new file with mode: 0644]
src/test/ui/consts/const_constructor/feature-gate-const_constructor.rs [new file with mode: 0644]

index 7298b548f3197ab248581f3d9fa70aacffef76cb..56f75e800f2557739c7661595668bebed4f018e1 100644 (file)
@@ -2,7 +2,7 @@
 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;
 
@@ -10,27 +10,30 @@ impl<'a, 'tcx> TyCtxt<'a, 'tcx, 'tcx> {
     /// 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
@@ -70,8 +73,11 @@ fn is_const_fn_raw<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> bool
         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
         }
index 10ff606b013a75e582296f04908e2bc5bd6c9644..e3e327d0a5bd0920d487f4298f9e2771c372f210 100644 (file)
@@ -1167,6 +1167,7 @@ pub fn get_macro(&self, id: DefIndex) -> MacroDef {
         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
index 4a95b6f69a161a7834f4908f868c155c3adc9f38..0043b8a1c47c4424f61862fa1c2cb03664cb1b6a 100644 (file)
@@ -560,6 +560,10 @@ pub fn walk_feature_fields<F>(&self, mut f: F)
     // 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
     // -------------------------------------------------------------------------
index 4e080d115d2a8eed7860fecc2513a2cd3e48fd57..6fac343581427a0d25421f77d6618e1b41a82e86 100644 (file)
         conservative_impl_trait,
         console,
         const_compare_raw_pointers,
+        const_constructor,
         const_fn,
         const_fn_union,
         const_generics,
diff --git a/src/test/ui/consts/const_constructor/const-construct-call.rs b/src/test/ui/consts/const_constructor/const-construct-call.rs
new file mode 100644 (file)
index 0000000..f2d2bda
--- /dev/null
@@ -0,0 +1,116 @@
+// 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,
+        )
+    );
+}
diff --git a/src/test/ui/consts/const_constructor/feature-gate-const_constructor.const_fn.stderr b/src/test/ui/consts/const_constructor/feature-gate-const_constructor.const_fn.stderr
new file mode 100644 (file)
index 0000000..fa4f83e
--- /dev/null
@@ -0,0 +1,34 @@
+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
+
diff --git a/src/test/ui/consts/const_constructor/feature-gate-const_constructor.min_const_fn.stderr b/src/test/ui/consts/const_constructor/feature-gate-const_constructor.min_const_fn.stderr
new file mode 100644 (file)
index 0000000..fa4f83e
--- /dev/null
@@ -0,0 +1,34 @@
+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
+
diff --git a/src/test/ui/consts/const_constructor/feature-gate-const_constructor.rs b/src/test/ui/consts/const_constructor/feature-gate-const_constructor.rs
new file mode 100644 (file)
index 0000000..b37fd2f
--- /dev/null
@@ -0,0 +1,28 @@
+// 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() {}