Add rustc_allow_const_fn_ptr

This commit is contained in:
Taylor Cramer 2019-04-05 14:13:44 -07:00
parent e938c2b9aa
commit e617025e96
11 changed files with 93 additions and 6 deletions

View File

@ -121,6 +121,7 @@ impl_stable_hash_for!(struct ::syntax::attr::Stability {
feature,
rustc_depr,
promotable,
allow_const_fn_ptr,
const_stability
});

View File

@ -441,6 +441,7 @@ impl<'a, 'tcx> Index<'tcx> {
rustc_depr: None,
const_stability: None,
promotable: false,
allow_const_fn_ptr: false,
});
annotator.parent_stab = Some(stability);
}

View File

@ -235,6 +235,8 @@ rustc_queries! {
/// constructor function).
query is_promotable_const_fn(_: DefId) -> bool {}
query const_fn_is_allowed_fn_ptr(_: DefId) -> bool {}
/// True if this is a foreign item (i.e., linked via `extern { ... }`).
query is_foreign_item(_: DefId) -> bool {}

View File

@ -95,9 +95,16 @@ pub fn provide<'tcx>(providers: &mut Providers<'tcx>) {
}
}
fn const_fn_is_allowed_fn_ptr<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> bool {
tcx.is_const_fn(def_id) &&
tcx.lookup_stability(def_id)
.map(|stab| stab.allow_const_fn_ptr).unwrap_or(false)
}
*providers = Providers {
is_const_fn_raw,
is_promotable_const_fn,
const_fn_is_allowed_fn_ptr,
..*providers
};
}

View File

@ -60,13 +60,14 @@ pub fn is_min_const_fn(
}
for local in &mir.local_decls {
check_ty(tcx, local.ty, local.source_info.span)?;
check_ty(tcx, local.ty, local.source_info.span, def_id)?;
}
// impl trait is gone in MIR, so check the return type manually
check_ty(
tcx,
tcx.fn_sig(def_id).output().skip_binder(),
mir.local_decls.iter().next().unwrap().source_info.span,
def_id,
)?;
for bb in mir.basic_blocks() {
@ -82,6 +83,7 @@ fn check_ty(
tcx: TyCtxt<'a, 'tcx, 'tcx>,
ty: ty::Ty<'tcx>,
span: Span,
fn_def_id: DefId,
) -> McfResult {
for ty in ty.walk() {
match ty.sty {
@ -91,7 +93,9 @@ fn check_ty(
)),
ty::Opaque(..) => return Err((span, "`impl Trait` in const fn is unstable".into())),
ty::FnPtr(..) => {
return Err((span, "function pointers in const fn are unstable".into()))
if !tcx.const_fn_is_allowed_fn_ptr(fn_def_id) {
return Err((span, "function pointers in const fn are unstable".into()))
}
}
ty::Dynamic(preds, _) => {
for pred in preds.iter() {

View File

@ -114,6 +114,8 @@ pub struct Stability {
pub const_stability: Option<Symbol>,
/// whether the function has a `#[rustc_promotable]` attribute
pub promotable: bool,
/// whether the function has a `#[rustc_allow_const_fn_ptr]` attribute
pub allow_const_fn_ptr: bool,
}
/// The available stability levels.
@ -178,6 +180,7 @@ fn find_stability_generic<'a, I>(sess: &ParseSess,
let mut rustc_depr: Option<RustcDeprecation> = None;
let mut rustc_const_unstable: Option<Symbol> = None;
let mut promotable = false;
let mut allow_const_fn_ptr = false;
let diagnostic = &sess.span_diagnostic;
'outer: for attr in attrs_iter {
@ -187,6 +190,7 @@ fn find_stability_generic<'a, I>(sess: &ParseSess,
"unstable",
"stable",
"rustc_promotable",
"rustc_allow_const_fn_ptr",
].iter().any(|&s| attr.path == s) {
continue // not a stability level
}
@ -198,6 +202,9 @@ fn find_stability_generic<'a, I>(sess: &ParseSess,
if attr.path == "rustc_promotable" {
promotable = true;
}
if attr.path == "rustc_allow_const_fn_ptr" {
allow_const_fn_ptr = true;
}
// attributes with data
else if let Some(MetaItem { node: MetaItemKind::List(ref metas), .. }) = meta {
let meta = meta.as_ref().unwrap();
@ -354,6 +361,7 @@ fn find_stability_generic<'a, I>(sess: &ParseSess,
rustc_depr: None,
const_stability: None,
promotable: false,
allow_const_fn_ptr: false,
})
}
(None, _, _) => {
@ -418,6 +426,7 @@ fn find_stability_generic<'a, I>(sess: &ParseSess,
rustc_depr: None,
const_stability: None,
promotable: false,
allow_const_fn_ptr: false,
})
}
(None, _) => {
@ -458,13 +467,14 @@ fn find_stability_generic<'a, I>(sess: &ParseSess,
}
// Merge the const-unstable info into the stability info
if promotable {
if promotable || allow_const_fn_ptr {
if let Some(ref mut stab) = stab {
stab.promotable = true;
stab.promotable = promotable;
stab.allow_const_fn_ptr = allow_const_fn_ptr;
} else {
span_err!(diagnostic, item_sp, E0717,
"rustc_promotable attribute must be paired with \
either stable or unstable attribute");
"rustc_promotable and rustc_allow_const_fn_ptr attributes \
must be paired with either stable or unstable attribute");
}
}

View File

@ -0,0 +1,10 @@
#![feature(rustc_attrs, staged_api)]
#[stable(feature = "rust1", since = "1.0.0")]
const fn error(_: fn()) {} //~ ERROR function pointers in const fn are unstable
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_allow_const_fn_ptr]
const fn compiles(_: fn()) {}
fn main() {}

View File

@ -0,0 +1,11 @@
error[E0723]: function pointers in const fn are unstable (see issue #57563)
--> $DIR/allow_const_fn_ptr.rs:4:16
|
LL | const fn error(_: fn()) {}
| ^
|
= help: add #![feature(const_fn)] to the crate attributes to enable
error: aborting due to previous error
For more information about this error, try `rustc --explain E0723`.

View File

@ -0,0 +1,11 @@
#![feature(staged_api)]
#[stable(feature = "rust1", since = "1.0.0")]
const fn error(_: fn()) {}
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_allow_const_fn_ptr]
//~^ ERROR unless otherwise specified, attributes with the prefix `rustc_` are reserved
const fn compiles(_: fn()) {}
fn main() {}

View File

@ -0,0 +1,12 @@
error[E0658]: unless otherwise specified, attributes with the prefix `rustc_` are reserved for internal compiler diagnostics
--> $DIR/allow_const_fn_ptr_feature_gate.rs:7:3
|
LL | #[rustc_allow_const_fn_ptr]
| ^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: for more information, see https://github.com/rust-lang/rust/issues/29642
= help: add #![feature(rustc_attrs)] to the crate attributes to enable
error: aborting due to previous error
For more information about this error, try `rustc --explain E0658`.

View File

@ -0,0 +1,18 @@
// run-pass
#![feature(rustc_attrs, staged_api)]
#![stable(feature = "rust1", since = "1.0.0")]
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_allow_const_fn_ptr]
const fn takes_fn_ptr(_: fn()) {}
const FN: fn() = || ();
const fn gives_fn_ptr() {
takes_fn_ptr(FN)
}
fn main() {
gives_fn_ptr();
}