Auto merge of #61209 - matthewjasper:const-tuple-constructors, r=oli-obk

Make tuple constructors real const fns

Mir construction special cases `Ctor(...)` to be lowered as `Ctor { 0: ... }`, which means this doesn't come up much in practice, but it seems inconsistent not to allow this.

r? @oli-obk
This commit is contained in:
bors 2019-06-07 09:41:06 +00:00
commit c1c60d292e
19 changed files with 516 additions and 168 deletions

View file

@ -2,7 +2,7 @@ use crate::ty::query::Providers;
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 @@ pub fn provide<'tcx>(providers: &mut Providers<'tcx>) {
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
}

View file

@ -1167,6 +1167,7 @@ impl<'a, 'tcx> CrateMetadata {
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

View file

@ -91,34 +91,6 @@ fn mir_borrowck<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> BorrowC
let input_mir = tcx.mir_validated(def_id);
debug!("run query mir_borrowck: {}", tcx.def_path_str(def_id));
// We are not borrow checking the automatically generated struct/variant constructors
// because we want to accept structs such as this (taken from the `linked-hash-map`
// crate):
// ```rust
// struct Qey<Q: ?Sized>(Q);
// ```
// MIR of this struct constructor looks something like this:
// ```rust
// fn Qey(_1: Q) -> Qey<Q>{
// let mut _0: Qey<Q>; // return place
//
// bb0: {
// (_0.0: Q) = move _1; // bb0[0]: scope 0 at src/main.rs:1:1: 1:26
// return; // bb0[1]: scope 0 at src/main.rs:1:1: 1:26
// }
// }
// ```
// The problem here is that `(_0.0: Q) = move _1;` is valid only if `Q` is
// of statically known size, which is not known to be true because of the
// `Q: ?Sized` constraint. However, it is true because the constructor can be
// called only when `Q` is of statically known size.
if tcx.is_constructor(def_id) {
return BorrowCheckResult {
closure_requirements: None,
used_mut_upvars: SmallVec::new(),
};
}
let opt_closure_req = tcx.infer_ctxt().enter(|infcx| {
let input_mir: &Body<'_> = &input_mir.borrow();
do_mir_borrowck(&infcx, input_mir, def_id)

View file

@ -2,7 +2,6 @@ use crate::build;
use crate::build::scope::DropKind;
use crate::hair::cx::Cx;
use crate::hair::{LintLevel, BindingMode, PatternKind};
use crate::shim;
use crate::transform::MirSource;
use crate::util as mir_util;
use rustc::hir;
@ -31,8 +30,6 @@ pub fn mir_build<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> Body<'
// Figure out what primary body this item has.
let (body_id, return_ty_span) = match tcx.hir().get_by_hir_id(id) {
Node::Ctor(ctor) => return create_constructor_shim(tcx, id, ctor),
Node::Expr(hir::Expr { node: hir::ExprKind::Closure(_, decl, body_id, _, _), .. })
| Node::Item(hir::Item { node: hir::ItemKind::Fn(decl, _, _, body_id), .. })
| Node::ImplItem(
@ -234,38 +231,6 @@ impl<'a, 'gcx: 'tcx, 'tcx> MutVisitor<'tcx> for GlobalizeMir<'a, 'gcx> {
}
}
fn create_constructor_shim<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
ctor_id: hir::HirId,
v: &'tcx hir::VariantData)
-> Body<'tcx>
{
let span = tcx.hir().span_by_hir_id(ctor_id);
if let hir::VariantData::Tuple(ref fields, ctor_id) = *v {
tcx.infer_ctxt().enter(|infcx| {
let mut mir = shim::build_adt_ctor(&infcx, ctor_id, fields, span);
// Convert the `mir::Body` to global types.
let tcx = infcx.tcx.global_tcx();
let mut globalizer = GlobalizeMir {
tcx,
span: mir.span
};
globalizer.visit_body(&mut mir);
let mir = unsafe {
mem::transmute::<Body<'_>, Body<'tcx>>(mir)
};
mir_util::dump_mir(tcx, None, "mir_map", &0,
MirSource::item(tcx.hir().local_def_id_from_hir_id(ctor_id)),
&mir, |_, _| Ok(()) );
mir
})
} else {
span_bug!(span, "attempting to create MIR for non-tuple variant {:?}", v);
}
}
///////////////////////////////////////////////////////////////////////////
// BuildMir -- walks a crate, looking for fn items and methods to build MIR from

View file

@ -22,6 +22,7 @@ Rust MIR: a lowered representation of Rust. Also: an experiment!
#![feature(unicode_internals)]
#![feature(step_trait)]
#![feature(slice_concat_ext)]
#![feature(trusted_len)]
#![feature(try_blocks)]
#![recursion_limit="256"]

View file

@ -1,6 +1,5 @@
use rustc::hir;
use rustc::hir::def_id::DefId;
use rustc::infer;
use rustc::mir::*;
use rustc::ty::{self, Ty, TyCtxt};
use rustc::ty::layout::VariantIdx;
@ -21,6 +20,7 @@ use crate::transform::{
};
use crate::util::elaborate_drops::{self, DropElaborator, DropStyle, DropFlagMode};
use crate::util::patch::MirPatch;
use crate::util::expand_aggregate;
pub fn provide(providers: &mut Providers<'_>) {
providers.mir_shims = make_shim;
@ -842,29 +842,26 @@ fn build_call_shim<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
mir
}
pub fn build_adt_ctor<'a, 'gcx, 'tcx>(infcx: &infer::InferCtxt<'a, 'gcx, 'tcx>,
ctor_id: hir::HirId,
fields: &[hir::StructField],
span: Span)
-> Body<'tcx>
{
let tcx = infcx.tcx;
let gcx = tcx.global_tcx();
let def_id = tcx.hir().local_def_id_from_hir_id(ctor_id);
let param_env = gcx.param_env(def_id);
pub fn build_adt_ctor<'gcx>(tcx: TyCtxt<'_, 'gcx, 'gcx>, ctor_id: DefId) -> &'gcx Body<'gcx> {
debug_assert!(tcx.is_constructor(ctor_id));
let span = tcx.hir().span_if_local(ctor_id)
.unwrap_or_else(|| bug!("no span for ctor {:?}", ctor_id));
let param_env = tcx.param_env(ctor_id);
// Normalize the sig.
let sig = gcx.fn_sig(def_id)
let sig = tcx.fn_sig(ctor_id)
.no_bound_vars()
.expect("LBR in ADT constructor signature");
let sig = gcx.normalize_erasing_regions(param_env, sig);
let sig = tcx.normalize_erasing_regions(param_env, sig);
let (adt_def, substs) = match sig.output().sty {
ty::Adt(adt_def, substs) => (adt_def, substs),
_ => bug!("unexpected type for ADT ctor {:?}", sig.output())
};
debug!("build_ctor: def_id={:?} sig={:?} fields={:?}", def_id, sig, fields);
debug!("build_ctor: ctor_id={:?} sig={:?}", ctor_id, sig);
let local_decls = local_decls_for_sig(&sig, span);
@ -873,26 +870,37 @@ pub fn build_adt_ctor<'a, 'gcx, 'tcx>(infcx: &infer::InferCtxt<'a, 'gcx, 'tcx>,
scope: OUTERMOST_SOURCE_SCOPE
};
let variant_no = if adt_def.is_enum() {
adt_def.variant_index_with_ctor_id(def_id)
let variant_index = if adt_def.is_enum() {
adt_def.variant_index_with_ctor_id(ctor_id)
} else {
VariantIdx::new(0)
};
// return = ADT(arg0, arg1, ...); return
// Generate the following MIR:
//
// (return as Variant).field0 = arg0;
// (return as Variant).field1 = arg1;
//
// return;
debug!("build_ctor: variant_index={:?}", variant_index);
let statements = expand_aggregate(
Place::RETURN_PLACE,
adt_def
.variants[variant_index]
.fields
.iter()
.enumerate()
.map(|(idx, field_def)| (
Operand::Move(Place::Base(PlaceBase::Local(Local::new(idx + 1)))),
field_def.ty(tcx, substs),
)),
AggregateKind::Adt(adt_def, variant_index, substs, None, None),
source_info,
).collect();
let start_block = BasicBlockData {
statements: vec![Statement {
source_info,
kind: StatementKind::Assign(
Place::RETURN_PLACE,
box Rvalue::Aggregate(
box AggregateKind::Adt(adt_def, variant_no, substs, None, None),
(1..sig.inputs().len()+1).map(|i| {
Operand::Move(Place::Base(PlaceBase::Local(Local::new(i))))
}).collect()
)
)
}],
statements,
terminator: Some(Terminator {
source_info,
kind: TerminatorKind::Return,
@ -900,7 +908,7 @@ pub fn build_adt_ctor<'a, 'gcx, 'tcx>(infcx: &infer::InferCtxt<'a, 'gcx, 'tcx>,
is_cleanup: false
};
Body::new(
let body = Body::new(
IndexVec::from_elem_n(start_block, 1),
IndexVec::from_elem_n(
SourceScopeData { span: span, parent_scope: None }, 1
@ -914,5 +922,17 @@ pub fn build_adt_ctor<'a, 'gcx, 'tcx>(infcx: &infer::InferCtxt<'a, 'gcx, 'tcx>,
vec![],
span,
vec![],
)
);
crate::util::dump_mir(
tcx,
None,
"mir_map",
&0,
crate::transform::MirSource::item(ctor_id),
&body,
|_, _| Ok(()),
);
tcx.arena.alloc(body)
}

View file

@ -1,8 +1,7 @@
use rustc::mir::*;
use rustc::ty::TyCtxt;
use rustc::ty::layout::VariantIdx;
use rustc_data_structures::indexed_vec::Idx;
use crate::transform::{MirPass, MirSource};
use crate::util::expand_aggregate;
pub struct Deaggregator;
@ -31,7 +30,7 @@ impl MirPass for Deaggregator {
let stmt = stmt.replace_nop();
let source_info = stmt.source_info;
let (mut lhs, kind, operands) = match stmt.kind {
let (lhs, kind, operands) = match stmt.kind {
StatementKind::Assign(lhs, box rvalue) => {
match rvalue {
Rvalue::Aggregate(kind, operands) => (lhs, kind, operands),
@ -41,62 +40,15 @@ impl MirPass for Deaggregator {
_ => bug!()
};
let mut set_discriminant = None;
let active_field_index = match *kind {
AggregateKind::Adt(adt_def, variant_index, _, _, active_field_index) => {
if adt_def.is_enum() {
set_discriminant = Some(Statement {
kind: StatementKind::SetDiscriminant {
place: lhs.clone(),
variant_index,
},
source_info,
});
lhs = lhs.downcast(adt_def, variant_index);
}
active_field_index
}
AggregateKind::Generator(..) => {
// Right now we only support initializing generators to
// variant 0 (Unresumed).
let variant_index = VariantIdx::new(0);
set_discriminant = Some(Statement {
kind: StatementKind::SetDiscriminant {
place: lhs.clone(),
variant_index,
},
source_info,
});
// Operands are upvars stored on the base place, so no
// downcast is necessary.
None
}
_ => None
};
Some(operands.into_iter().enumerate().map(move |(i, op)| {
let lhs_field = if let AggregateKind::Array(_) = *kind {
// FIXME(eddyb) `offset` should be u64.
let offset = i as u32;
assert_eq!(offset as usize, i);
lhs.clone().elem(ProjectionElem::ConstantIndex {
offset,
// FIXME(eddyb) `min_length` doesn't appear to be used.
min_length: offset + 1,
from_end: false
})
} else {
Some(expand_aggregate(
lhs,
operands.into_iter().map(|op| {
let ty = op.ty(local_decls, tcx);
let field = Field::new(active_field_index.unwrap_or(i));
lhs.clone().field(field, ty)
};
Statement {
source_info,
kind: StatementKind::Assign(lhs_field, box Rvalue::Use(op)),
}
}).chain(set_discriminant))
(op, ty)
}),
*kind,
source_info,
))
});
}
}

View file

@ -1,4 +1,4 @@
use crate::build;
use crate::{build, shim};
use rustc::hir::def_id::{CrateNum, DefId, LOCAL_CRATE};
use rustc::mir::{Body, MirPhase, Promoted};
use rustc::ty::{TyCtxt, InstanceDef};
@ -228,7 +228,15 @@ fn mir_validated<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> &'tcx
}
fn optimized_mir<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> &'tcx Body<'tcx> {
// `mir_borrowck` uses `mir_validated`, so we have to force it to
if tcx.is_constructor(def_id) {
// There's no reason to run all of the MIR passes on constructors when
// we can just output the MIR we want directly. This also saves const
// qualification and borrow checking the trouble of special casing
// constructors.
return shim::build_adt_ctor(tcx, def_id);
}
// (Mir-)Borrowck uses `mir_validated`, so we have to force it to
// execute before we can steal.
tcx.ensure().mir_borrowck(def_id);

View file

@ -0,0 +1,76 @@
use rustc::mir::*;
use rustc::ty::Ty;
use rustc::ty::layout::VariantIdx;
use rustc_data_structures::indexed_vec::Idx;
use std::iter::TrustedLen;
/// Expand `lhs = Rvalue::Aggregate(kind, operands)` into assignments to the fields.
///
/// Produces something like
///
/// (lhs as Variant).field0 = arg0; // We only have a downcast if this is an enum
/// (lhs as Variant).field1 = arg1;
/// discriminant(lhs) = variant_index; // If lhs is an enum or generator.
pub fn expand_aggregate<'tcx>(
mut lhs: Place<'tcx>,
operands: impl Iterator<Item=(Operand<'tcx>, Ty<'tcx>)> + TrustedLen,
kind: AggregateKind<'tcx>,
source_info: SourceInfo,
) -> impl Iterator<Item=Statement<'tcx>> + TrustedLen {
let mut set_discriminant = None;
let active_field_index = match kind {
AggregateKind::Adt(adt_def, variant_index, _, _, active_field_index) => {
if adt_def.is_enum() {
set_discriminant = Some(Statement {
kind: StatementKind::SetDiscriminant {
place: lhs.clone(),
variant_index,
},
source_info,
});
lhs = lhs.downcast(adt_def, variant_index);
}
active_field_index
}
AggregateKind::Generator(..) => {
// Right now we only support initializing generators to
// variant 0 (Unresumed).
let variant_index = VariantIdx::new(0);
set_discriminant = Some(Statement {
kind: StatementKind::SetDiscriminant {
place: lhs.clone(),
variant_index,
},
source_info,
});
// Operands are upvars stored on the base place, so no
// downcast is necessary.
None
}
_ => None
};
operands.into_iter().enumerate().map(move |(i, (op, ty))| {
let lhs_field = if let AggregateKind::Array(_) = kind {
// FIXME(eddyb) `offset` should be u64.
let offset = i as u32;
assert_eq!(offset as usize, i);
lhs.clone().elem(ProjectionElem::ConstantIndex {
offset,
// FIXME(eddyb) `min_length` doesn't appear to be used.
min_length: offset + 1,
from_end: false
})
} else {
let field = Field::new(active_field_index.unwrap_or(i));
lhs.clone().field(field, ty)
};
Statement {
source_info,
kind: StatementKind::Assign(lhs_field, box Rvalue::Use(op)),
}
}).chain(set_discriminant)
}

View file

@ -2,6 +2,7 @@ use core::unicode::property::Pattern_White_Space;
use rustc::ty::TyCtxt;
use syntax_pos::Span;
pub mod aggregate;
pub mod borrowck_errors;
pub mod elaborate_drops;
pub mod def_use;
@ -13,6 +14,7 @@ pub(crate) mod pretty;
pub mod liveness;
pub mod collect_writes;
pub use self::aggregate::expand_aggregate;
pub use self::alignment::is_disaligned;
pub use self::pretty::{dump_enabled, dump_mir, write_mir_pretty, PassWhere};
pub use self::graphviz::{graphviz_safe_def_name, write_mir_graphviz};

View file

@ -560,6 +560,10 @@ declare_features! (
// 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
// -------------------------------------------------------------------------

View file

@ -185,6 +185,7 @@ symbols! {
conservative_impl_trait,
console,
const_compare_raw_pointers,
const_constructor,
const_fn,
const_fn_union,
const_generics,

View file

@ -78,7 +78,8 @@ fn main() {
// let mut _0: Test;
//
// bb0: {
// _0 = Test::X(move _1,);
// ((_0 as X).0: usize) = move _1;
// discriminant(_0) = 0;
// return;
// }
// }

View file

@ -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,
)
);
}

View file

@ -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

View file

@ -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

View file

@ -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() {}

View file

@ -0,0 +1,71 @@
// Unit test for the "user substitutions" that are annotated on each
// node.
struct SomeStruct<T>(T);
fn no_annot() {
let c = 66;
let f = SomeStruct;
f(&c);
}
fn annot_underscore() {
let c = 66;
let f = SomeStruct::<_>;
f(&c);
}
fn annot_reference_any_lifetime() {
let c = 66;
let f = SomeStruct::<&u32>;
f(&c);
}
fn annot_reference_static_lifetime() {
let c = 66;
let f = SomeStruct::<&'static u32>;
f(&c); //~ ERROR
}
fn annot_reference_named_lifetime<'a>(_d: &'a u32) {
let c = 66;
let f = SomeStruct::<&'a u32>;
f(&c); //~ ERROR
}
fn annot_reference_named_lifetime_ok<'a>(c: &'a u32) {
let f = SomeStruct::<&'a u32>;
f(c);
}
fn annot_reference_named_lifetime_in_closure<'a>(_: &'a u32) {
let _closure = || {
let c = 66;
let f = SomeStruct::<&'a u32>;
f(&c); //~ ERROR
};
}
fn annot_reference_named_lifetime_across_closure<'a>(_: &'a u32) {
let f = SomeStruct::<&'a u32>;
let _closure = || {
let c = 66;
f(&c); //~ ERROR
};
}
fn annot_reference_named_lifetime_in_closure_ok<'a>(c: &'a u32) {
let _closure = || {
let f = SomeStruct::<&'a u32>;
f(c);
};
}
fn annot_reference_named_lifetime_across_closure_ok<'a>(c: &'a u32) {
let f = SomeStruct::<&'a u32>;
let _closure = || {
f(c);
};
}
fn main() { }

View file

@ -0,0 +1,56 @@
error[E0597]: `c` does not live long enough
--> $DIR/adt-tuple-struct-calls.rs:27:7
|
LL | f(&c);
| --^^-
| | |
| | borrowed value does not live long enough
| argument requires that `c` is borrowed for `'static`
LL | }
| - `c` dropped here while still borrowed
error[E0597]: `c` does not live long enough
--> $DIR/adt-tuple-struct-calls.rs:33:7
|
LL | fn annot_reference_named_lifetime<'a>(_d: &'a u32) {
| -- lifetime `'a` defined here
...
LL | f(&c);
| --^^-
| | |
| | borrowed value does not live long enough
| argument requires that `c` is borrowed for `'a`
LL | }
| - `c` dropped here while still borrowed
error[E0597]: `c` does not live long enough
--> $DIR/adt-tuple-struct-calls.rs:45:11
|
LL | fn annot_reference_named_lifetime_in_closure<'a>(_: &'a u32) {
| -- lifetime `'a` defined here
...
LL | f(&c);
| --^^-
| | |
| | borrowed value does not live long enough
| argument requires that `c` is borrowed for `'a`
LL | };
| - `c` dropped here while still borrowed
error[E0597]: `c` does not live long enough
--> $DIR/adt-tuple-struct-calls.rs:53:11
|
LL | let f = SomeStruct::<&'a u32>;
| - lifetime `'1` appears in the type of `f`
...
LL | f(&c);
| --^^-
| | |
| | borrowed value does not live long enough
| argument requires that `c` is borrowed for `'1`
LL | };
| - `c` dropped here while still borrowed
error: aborting due to 4 previous errors
For more information about this error, try `rustc --explain E0597`.