Skip to content

Commit 0d75ab2

Browse files
committed
Make constructors actually be const functions
1 parent 6c9a018 commit 0d75ab2

File tree

8 files changed

+237
-13
lines changed

8 files changed

+237
-13
lines changed

src/librustc/ty/constness.rs

+19-13
Original file line numberDiff line numberDiff line change
@@ -2,35 +2,38 @@ use crate::ty::query::Providers;
22
use crate::hir::def_id::DefId;
33
use crate::hir;
44
use crate::ty::TyCtxt;
5-
use syntax_pos::symbol::Symbol;
5+
use syntax_pos::symbol::{sym, Symbol};
66
use crate::hir::map::blocks::FnLikeNode;
77
use syntax::attr;
88

99
impl<'a, 'tcx> TyCtxt<'a, 'tcx, 'tcx> {
1010
/// Whether the `def_id` counts as const fn in your current crate, considering all active
1111
/// feature gates
1212
pub fn is_const_fn(self, def_id: DefId) -> bool {
13-
self.is_const_fn_raw(def_id) && match self.lookup_stability(def_id) {
14-
Some(stab) => match stab.const_stability {
13+
self.is_const_fn_raw(def_id) && match self.is_unstable_const_fn(def_id) {
14+
Some(feature_name) => {
1515
// has a `rustc_const_unstable` attribute, check whether the user enabled the
16-
// corresponding feature gate
17-
Some(feature_name) => self.features()
16+
// corresponding feature gate, const_constructor is not a lib feature, so has
17+
// to be checked separately.
18+
self.features()
1819
.declared_lib_features
1920
.iter()
20-
.any(|&(sym, _)| sym == feature_name),
21-
// the function has no stability attribute, it is stable as const fn or the user
22-
// needs to use feature gates to use the function at all
23-
None => true,
21+
.any(|&(sym, _)| sym == feature_name)
22+
|| (feature_name == sym::const_constructor
23+
&& self.features().const_constructor)
2424
},
25-
// functions without stability are either stable user written const fn or the user is
26-
// using feature gates and we thus don't care what they do
25+
// functions without const stability are either stable user written
26+
// const fn or the user is using feature gates and we thus don't
27+
// care what they do
2728
None => true,
2829
}
2930
}
3031

3132
/// Whether the `def_id` is an unstable const fn and what feature gate is necessary to enable it
3233
pub fn is_unstable_const_fn(self, def_id: DefId) -> Option<Symbol> {
33-
if self.is_const_fn_raw(def_id) {
34+
if self.is_constructor(def_id) {
35+
Some(sym::const_constructor)
36+
} else if self.is_const_fn_raw(def_id) {
3437
self.lookup_stability(def_id)?.const_stability
3538
} else {
3639
None
@@ -70,8 +73,11 @@ pub fn provide<'tcx>(providers: &mut Providers<'tcx>) {
7073
let hir_id = tcx.hir().as_local_hir_id(def_id)
7174
.expect("Non-local call to local provider is_const_fn");
7275

73-
if let Some(fn_like) = FnLikeNode::from_node(tcx.hir().get_by_hir_id(hir_id)) {
76+
let node = tcx.hir().get_by_hir_id(hir_id);
77+
if let Some(fn_like) = FnLikeNode::from_node(node) {
7478
fn_like.constness() == hir::Constness::Const
79+
} else if let hir::Node::Ctor(_) = node {
80+
true
7581
} else {
7682
false
7783
}

src/librustc_metadata/decoder.rs

+1
Original file line numberDiff line numberDiff line change
@@ -1167,6 +1167,7 @@ impl<'a, 'tcx> CrateMetadata {
11671167
let constness = match self.entry(id).kind {
11681168
EntryKind::Method(data) => data.decode(self).fn_data.constness,
11691169
EntryKind::Fn(data) => data.decode(self).constness,
1170+
EntryKind::Variant(..) | EntryKind::Struct(..) => hir::Constness::Const,
11701171
_ => hir::Constness::NotConst,
11711172
};
11721173
constness == hir::Constness::Const

src/libsyntax/feature_gate.rs

+4
Original file line numberDiff line numberDiff line change
@@ -560,6 +560,10 @@ declare_features! (
560560
// Allows the user of associated type bounds.
561561
(active, associated_type_bounds, "1.34.0", Some(52662), None),
562562

563+
// Allows calling constructor functions in `const fn`
564+
// FIXME Create issue
565+
(active, const_constructor, "1.37.0", Some(61456), None),
566+
563567
// -------------------------------------------------------------------------
564568
// feature-group-end: actual feature gates
565569
// -------------------------------------------------------------------------

src/libsyntax_pos/symbol.rs

+1
Original file line numberDiff line numberDiff line change
@@ -185,6 +185,7 @@ symbols! {
185185
conservative_impl_trait,
186186
console,
187187
const_compare_raw_pointers,
188+
const_constructor,
188189
const_fn,
189190
const_fn_union,
190191
const_generics,
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,116 @@
1+
// Test that constructors are considered to be const fns with the required feature.
2+
3+
// run-pass
4+
5+
// revisions: min_const_fn const_fn
6+
7+
#![cfg_attr(const_fn, feature(const_fn))]
8+
9+
#![feature(const_constructor)]
10+
11+
// Ctor(..) is transformed to Ctor { 0: ... } in HAIR lowering, so directly
12+
// calling constructors doesn't require them to be const.
13+
14+
type ExternalType = std::panic::AssertUnwindSafe<(Option<i32>, Result<i32, bool>)>;
15+
16+
const fn call_external_constructors_in_local_vars() -> ExternalType {
17+
let f = Some;
18+
let g = Err;
19+
let h = std::panic::AssertUnwindSafe;
20+
let x = f(5);
21+
let y = g(false);
22+
let z = h((x, y));
23+
z
24+
}
25+
26+
const CALL_EXTERNAL_CONSTRUCTORS_IN_LOCAL_VARS: ExternalType = {
27+
let f = Some;
28+
let g = Err;
29+
let h = std::panic::AssertUnwindSafe;
30+
let x = f(5);
31+
let y = g(false);
32+
let z = h((x, y));
33+
z
34+
};
35+
36+
const fn call_external_constructors_in_temps() -> ExternalType {
37+
let x = { Some }(5);
38+
let y = (*&Err)(false);
39+
let z = [std::panic::AssertUnwindSafe][0]((x, y));
40+
z
41+
}
42+
43+
const CALL_EXTERNAL_CONSTRUCTORS_IN_TEMPS: ExternalType = {
44+
let x = { Some }(5);
45+
let y = (*&Err)(false);
46+
let z = [std::panic::AssertUnwindSafe][0]((x, y));
47+
z
48+
};
49+
50+
#[derive(Debug, PartialEq)]
51+
enum LocalOption<T> {
52+
Some(T),
53+
_None,
54+
}
55+
56+
#[derive(Debug, PartialEq)]
57+
enum LocalResult<T, E> {
58+
_Ok(T),
59+
Err(E),
60+
}
61+
62+
#[derive(Debug, PartialEq)]
63+
struct LocalAssertUnwindSafe<T>(T);
64+
65+
type LocalType = LocalAssertUnwindSafe<(LocalOption<i32>, LocalResult<i32, bool>)>;
66+
67+
const fn call_local_constructors_in_local_vars() -> LocalType {
68+
let f = LocalOption::Some;
69+
let g = LocalResult::Err;
70+
let h = LocalAssertUnwindSafe;
71+
let x = f(5);
72+
let y = g(false);
73+
let z = h((x, y));
74+
z
75+
}
76+
77+
const CALL_LOCAL_CONSTRUCTORS_IN_LOCAL_VARS: LocalType = {
78+
let f = LocalOption::Some;
79+
let g = LocalResult::Err;
80+
let h = LocalAssertUnwindSafe;
81+
let x = f(5);
82+
let y = g(false);
83+
let z = h((x, y));
84+
z
85+
};
86+
87+
const fn call_local_constructors_in_temps() -> LocalType {
88+
let x = { LocalOption::Some }(5);
89+
let y = (*&LocalResult::Err)(false);
90+
let z = [LocalAssertUnwindSafe][0]((x, y));
91+
z
92+
}
93+
94+
const CALL_LOCAL_CONSTRUCTORS_IN_TEMPS: LocalType = {
95+
let x = { LocalOption::Some }(5);
96+
let y = (*&LocalResult::Err)(false);
97+
let z = [LocalAssertUnwindSafe][0]((x, y));
98+
z
99+
};
100+
101+
fn main() {
102+
assert_eq!(
103+
(
104+
call_external_constructors_in_local_vars().0,
105+
call_external_constructors_in_temps().0,
106+
call_local_constructors_in_local_vars(),
107+
call_local_constructors_in_temps(),
108+
),
109+
(
110+
CALL_EXTERNAL_CONSTRUCTORS_IN_LOCAL_VARS.0,
111+
CALL_EXTERNAL_CONSTRUCTORS_IN_TEMPS.0,
112+
CALL_LOCAL_CONSTRUCTORS_IN_LOCAL_VARS,
113+
CALL_LOCAL_CONSTRUCTORS_IN_TEMPS,
114+
)
115+
);
116+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
error: `std::prelude::v1::Some` is not yet stable as a const fn
2+
--> $DIR/feature-gate-const_constructor.rs:9:37
3+
|
4+
LL | const EXTERNAL_CONST: Option<i32> = {Some}(1);
5+
| ^^^^^^^^^
6+
|
7+
= help: add `#![feature(const_constructor)]` to the crate attributes to enable
8+
9+
error: `E::V` is not yet stable as a const fn
10+
--> $DIR/feature-gate-const_constructor.rs:12:24
11+
|
12+
LL | const LOCAL_CONST: E = {E::V}(1);
13+
| ^^^^^^^^^
14+
|
15+
= help: add `#![feature(const_constructor)]` to the crate attributes to enable
16+
17+
error: `std::prelude::v1::Some` is not yet stable as a const fn
18+
--> $DIR/feature-gate-const_constructor.rs:17:13
19+
|
20+
LL | let _ = {Some}(1);
21+
| ^^^^^^^^^
22+
|
23+
= help: add `#![feature(const_constructor)]` to the crate attributes to enable
24+
25+
error: `E::V` is not yet stable as a const fn
26+
--> $DIR/feature-gate-const_constructor.rs:23:13
27+
|
28+
LL | let _ = {E::V}(1);
29+
| ^^^^^^^^^
30+
|
31+
= help: add `#![feature(const_constructor)]` to the crate attributes to enable
32+
33+
error: aborting due to 4 previous errors
34+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
error: `std::prelude::v1::Some` is not yet stable as a const fn
2+
--> $DIR/feature-gate-const_constructor.rs:9:37
3+
|
4+
LL | const EXTERNAL_CONST: Option<i32> = {Some}(1);
5+
| ^^^^^^^^^
6+
|
7+
= help: add `#![feature(const_constructor)]` to the crate attributes to enable
8+
9+
error: `E::V` is not yet stable as a const fn
10+
--> $DIR/feature-gate-const_constructor.rs:12:24
11+
|
12+
LL | const LOCAL_CONST: E = {E::V}(1);
13+
| ^^^^^^^^^
14+
|
15+
= help: add `#![feature(const_constructor)]` to the crate attributes to enable
16+
17+
error: `std::prelude::v1::Some` is not yet stable as a const fn
18+
--> $DIR/feature-gate-const_constructor.rs:17:13
19+
|
20+
LL | let _ = {Some}(1);
21+
| ^^^^^^^^^
22+
|
23+
= help: add `#![feature(const_constructor)]` to the crate attributes to enable
24+
25+
error: `E::V` is not yet stable as a const fn
26+
--> $DIR/feature-gate-const_constructor.rs:23:13
27+
|
28+
LL | let _ = {E::V}(1);
29+
| ^^^^^^^^^
30+
|
31+
= help: add `#![feature(const_constructor)]` to the crate attributes to enable
32+
33+
error: aborting due to 4 previous errors
34+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
// revisions: min_const_fn const_fn
2+
3+
#![cfg_attr(const_fn, feature(const_fn))]
4+
5+
enum E {
6+
V(i32),
7+
}
8+
9+
const EXTERNAL_CONST: Option<i32> = {Some}(1);
10+
//[min_const_fn]~^ ERROR is not yet stable as a const fn
11+
//[const_fn]~^^ ERROR is not yet stable as a const fn
12+
const LOCAL_CONST: E = {E::V}(1);
13+
//[min_const_fn]~^ ERROR is not yet stable as a const fn
14+
//[const_fn]~^^ ERROR is not yet stable as a const fn
15+
16+
const fn external_fn() {
17+
let _ = {Some}(1);
18+
//[min_const_fn]~^ ERROR is not yet stable as a const fn
19+
//[const_fn]~^^ ERROR is not yet stable as a const fn
20+
}
21+
22+
const fn local_fn() {
23+
let _ = {E::V}(1);
24+
//[min_const_fn]~^ ERROR is not yet stable as a const fn
25+
//[const_fn]~^^ ERROR is not yet stable as a const fn
26+
}
27+
28+
fn main() {}

0 commit comments

Comments
 (0)