From e617025e96fa95f074291a1cc284235a80824eaf Mon Sep 17 00:00:00 2001 From: Taylor Cramer Date: Fri, 5 Apr 2019 14:13:44 -0700 Subject: [PATCH] Add rustc_allow_const_fn_ptr --- src/librustc/ich/impls_syntax.rs | 1 + src/librustc/middle/stability.rs | 1 + src/librustc/query/mod.rs | 2 ++ src/librustc/ty/constness.rs | 7 +++++++ .../transform/qualify_min_const_fn.rs | 8 ++++++-- src/libsyntax/attr/builtin.rs | 18 ++++++++++++++---- .../consts/min_const_fn/allow_const_fn_ptr.rs | 10 ++++++++++ .../min_const_fn/allow_const_fn_ptr.stderr | 11 +++++++++++ .../allow_const_fn_ptr_feature_gate.rs | 11 +++++++++++ .../allow_const_fn_ptr_feature_gate.stderr | 12 ++++++++++++ .../allow_const_fn_ptr_run_pass.rs | 18 ++++++++++++++++++ 11 files changed, 93 insertions(+), 6 deletions(-) create mode 100644 src/test/ui/consts/min_const_fn/allow_const_fn_ptr.rs create mode 100644 src/test/ui/consts/min_const_fn/allow_const_fn_ptr.stderr create mode 100644 src/test/ui/consts/min_const_fn/allow_const_fn_ptr_feature_gate.rs create mode 100644 src/test/ui/consts/min_const_fn/allow_const_fn_ptr_feature_gate.stderr create mode 100644 src/test/ui/consts/min_const_fn/allow_const_fn_ptr_run_pass.rs diff --git a/src/librustc/ich/impls_syntax.rs b/src/librustc/ich/impls_syntax.rs index 496ccc888b61a..40cce8e77c0e0 100644 --- a/src/librustc/ich/impls_syntax.rs +++ b/src/librustc/ich/impls_syntax.rs @@ -121,6 +121,7 @@ impl_stable_hash_for!(struct ::syntax::attr::Stability { feature, rustc_depr, promotable, + allow_const_fn_ptr, const_stability }); diff --git a/src/librustc/middle/stability.rs b/src/librustc/middle/stability.rs index ef1270d304523..8ce86f70a551f 100644 --- a/src/librustc/middle/stability.rs +++ b/src/librustc/middle/stability.rs @@ -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); } diff --git a/src/librustc/query/mod.rs b/src/librustc/query/mod.rs index 8c1e345cdaec5..1861420b408b6 100644 --- a/src/librustc/query/mod.rs +++ b/src/librustc/query/mod.rs @@ -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 {} diff --git a/src/librustc/ty/constness.rs b/src/librustc/ty/constness.rs index e33d0a74ea013..7298b548f3197 100644 --- a/src/librustc/ty/constness.rs +++ b/src/librustc/ty/constness.rs @@ -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 }; } diff --git a/src/librustc_mir/transform/qualify_min_const_fn.rs b/src/librustc_mir/transform/qualify_min_const_fn.rs index 776985ab79802..d5f04ca64e4c4 100644 --- a/src/librustc_mir/transform/qualify_min_const_fn.rs +++ b/src/librustc_mir/transform/qualify_min_const_fn.rs @@ -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() { diff --git a/src/libsyntax/attr/builtin.rs b/src/libsyntax/attr/builtin.rs index 74c952b076cd7..db821f4e5369d 100644 --- a/src/libsyntax/attr/builtin.rs +++ b/src/libsyntax/attr/builtin.rs @@ -114,6 +114,8 @@ pub struct Stability { pub const_stability: Option, /// 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 = None; let mut rustc_const_unstable: Option = 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"); } } diff --git a/src/test/ui/consts/min_const_fn/allow_const_fn_ptr.rs b/src/test/ui/consts/min_const_fn/allow_const_fn_ptr.rs new file mode 100644 index 0000000000000..3992607c387e1 --- /dev/null +++ b/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() {} diff --git a/src/test/ui/consts/min_const_fn/allow_const_fn_ptr.stderr b/src/test/ui/consts/min_const_fn/allow_const_fn_ptr.stderr new file mode 100644 index 0000000000000..ed9cba9fa2fc4 --- /dev/null +++ b/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`. diff --git a/src/test/ui/consts/min_const_fn/allow_const_fn_ptr_feature_gate.rs b/src/test/ui/consts/min_const_fn/allow_const_fn_ptr_feature_gate.rs new file mode 100644 index 0000000000000..0395795ef7bfe --- /dev/null +++ b/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() {} diff --git a/src/test/ui/consts/min_const_fn/allow_const_fn_ptr_feature_gate.stderr b/src/test/ui/consts/min_const_fn/allow_const_fn_ptr_feature_gate.stderr new file mode 100644 index 0000000000000..c934307e918b9 --- /dev/null +++ b/src/test/ui/consts/min_const_fn/allow_const_fn_ptr_feature_gate.stderr @@ -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`. diff --git a/src/test/ui/consts/min_const_fn/allow_const_fn_ptr_run_pass.rs b/src/test/ui/consts/min_const_fn/allow_const_fn_ptr_run_pass.rs new file mode 100644 index 0000000000000..1d8b95ab1a2fd --- /dev/null +++ b/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(); +}