Skip to content

Commit

Permalink
Add rustc_allow_const_fn_ptr
Browse files Browse the repository at this point in the history
  • Loading branch information
cramertj committed Apr 23, 2019
1 parent e938c2b commit e617025
Show file tree
Hide file tree
Showing 11 changed files with 93 additions and 6 deletions.
1 change: 1 addition & 0 deletions src/librustc/ich/impls_syntax.rs
Expand Up @@ -121,6 +121,7 @@ impl_stable_hash_for!(struct ::syntax::attr::Stability {
feature,
rustc_depr,
promotable,
allow_const_fn_ptr,
const_stability
});

Expand Down
1 change: 1 addition & 0 deletions src/librustc/middle/stability.rs
Expand Up @@ -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);
}
Expand Down
2 changes: 2 additions & 0 deletions src/librustc/query/mod.rs
Expand Up @@ -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 {}

Expand Down
7 changes: 7 additions & 0 deletions src/librustc/ty/constness.rs
Expand Up @@ -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
};
}
8 changes: 6 additions & 2 deletions src/librustc_mir/transform/qualify_min_const_fn.rs
Expand Up @@ -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() {
Expand All @@ -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 {
Expand All @@ -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() {
Expand Down
18 changes: 14 additions & 4 deletions src/libsyntax/attr/builtin.rs
Expand Up @@ -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.
Expand Down Expand Up @@ -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 {
Expand All @@ -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
}
Expand All @@ -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();
Expand Down Expand Up @@ -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, _, _) => {
Expand Down Expand Up @@ -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, _) => {
Expand Down Expand Up @@ -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");
}
}

Expand Down
10 changes: 10 additions & 0 deletions src/test/ui/consts/min_const_fn/allow_const_fn_ptr.rs
@@ -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() {}
11 changes: 11 additions & 0 deletions src/test/ui/consts/min_const_fn/allow_const_fn_ptr.stderr
@@ -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`.
11 changes: 11 additions & 0 deletions src/test/ui/consts/min_const_fn/allow_const_fn_ptr_feature_gate.rs
@@ -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() {}
@@ -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`.
18 changes: 18 additions & 0 deletions src/test/ui/consts/min_const_fn/allow_const_fn_ptr_run_pass.rs
@@ -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();
}

0 comments on commit e617025

Please sign in to comment.