Auto merge of #65188 - matthewjasper:stabilize-const-constructor, r=Centril

Stabilize `const_constructor`

# Stabilization proposal

I propose that we stabilize `#![feature(const_constructor)]`.

Tracking issue: https://github.com/rust-lang/rust/issues/61456
Version target: 1.40 (2019-11-05 => beta, 2019-12-19 => stable).

## What is stabilized

### User guide

Tuple struct and tuple variant constructors are now considered to be constant functions. As such a call expression where the callee has a tuple struct or variant constructor "function item" type can be called:

```rust
const fn make_options() {
    // These already work because they are special cased:
    Some(0);
    (Option::Some)(1);
    // These also work now:
    let f = Option::Some;
    f(2);
    {Option::Some}(3);
    <Option<_>>::Some(5);
}
```

### Motivation

Consistency with other `const fn`. Consistency between syntactic path forms.

This should also ensure that constructors implement `const Fn` traits and can be coerced to `const fn` function pointers, if they are introduced.

## Tests

* [ui/consts/const_constructor/const-construct-call.rs](0d75ab2293/src/test/ui/consts/const_constructor/const-construct-call.rs) - Tests various syntactic forms, use in both `const fn` and `const` items, and constructors in both the current and extern crates.
* [ui/consts/const_constructor/const_constructor_qpath.rs](1850dfcdab/src/test/ui/consts/const_constructor/const_constructor_qpath.rs) - Tests that type qualified paths to enum variants are also considered to be `const fn`.(#64247)

r? @oli-obk

Closes #61456
Closes  #64247
This commit is contained in:
bors 2019-10-28 07:38:49 +00:00
commit 03a50ae9b8
8 changed files with 45 additions and 109 deletions

View File

@ -2,7 +2,7 @@
use crate::hir::def_id::DefId;
use crate::hir;
use crate::ty::TyCtxt;
use syntax_pos::symbol::{sym, Symbol};
use syntax_pos::symbol::Symbol;
use crate::hir::map::blocks::FnLikeNode;
use syntax::attr;
@ -13,14 +13,11 @@ pub fn is_const_fn(self, def_id: DefId) -> bool {
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, const_constructor is not a lib feature, so has
// to be checked separately.
// corresponding feature gate.
self.features()
.declared_lib_features
.iter()
.any(|&(sym, _)| sym == feature_name)
|| (feature_name == sym::const_constructor
&& self.features().const_constructor)
},
// functions without const stability are either stable user written
// const fn or the user is using feature gates and we thus don't
@ -31,9 +28,7 @@ pub fn is_const_fn(self, def_id: DefId) -> bool {
/// 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_constructor(def_id) {
Some(sym::const_constructor)
} else if self.is_const_fn_raw(def_id) {
if self.is_const_fn_raw(def_id) {
self.lookup_stability(def_id)?.const_stability
} else {
None

View File

@ -249,6 +249,8 @@ macro_rules! declare_features {
(accepted, macros_in_extern, "1.40.0", Some(49476), None),
/// Allows future-proofing enums/structs with the `#[non_exhaustive]` attribute (RFC 2008).
(accepted, non_exhaustive, "1.40.0", Some(44109), None),
/// Allows calling constructor functions in `const fn`.
(accepted, const_constructor, "1.40.0", Some(61456), None),
// -------------------------------------------------------------------------
// feature-group-end: accepted features

View File

@ -488,9 +488,6 @@ pub fn set(&self, features: &mut Features, span: Span) {
/// Allows the user of associated type bounds.
(active, associated_type_bounds, "1.34.0", Some(52662), None),
/// Allows calling constructor functions in `const fn`.
(active, const_constructor, "1.37.0", Some(61456), None),
/// Allows `if/while p && let q = r && ...` chains.
(active, let_chains, "1.37.0", Some(53667), None),

View File

@ -6,8 +6,6 @@
#![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.

View File

@ -0,0 +1,40 @@
// revisions: min_const_fn const_fn
// run-pass
#![cfg_attr(const_fn, feature(const_fn))]
trait ConstDefault {
const DEFAULT: Self;
}
#[derive(PartialEq)]
enum E {
V(i32),
W(usize),
}
impl ConstDefault for E {
const DEFAULT: Self = Self::V(23);
}
impl ConstDefault for Option<i32> {
const DEFAULT: Self = Self::Some(23);
}
impl E {
const NON_DEFAULT: Self = Self::W(12);
const fn local_fn() -> Self {
Self::V(23)
}
}
const fn explicit_qpath() -> E {
let _x = <Option<usize>>::Some(23);
<E>::W(12)
}
fn main() {
assert!(E::DEFAULT == E::local_fn());
assert!(Option::DEFAULT == Some(23));
assert!(E::NON_DEFAULT == explicit_qpath());
}

View File

@ -1,34 +0,0 @@
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

View File

@ -1,34 +0,0 @@
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

View File

@ -1,28 +0,0 @@
// 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() {}