Skip to content

Commit a12d0d4

Browse files
committed
honor #[rustc_const_unstable] attributes
1 parent 824952f commit a12d0d4

File tree

10 files changed

+197
-39
lines changed

10 files changed

+197
-39
lines changed

src/librustc/ich/impls_syntax.rs

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,12 @@ impl_stable_hash_for!(enum ::syntax::abi::Abi {
8181
});
8282

8383
impl_stable_hash_for!(struct ::syntax::attr::Deprecation { since, note });
84-
impl_stable_hash_for!(struct ::syntax::attr::Stability { level, feature, rustc_depr });
84+
impl_stable_hash_for!(struct ::syntax::attr::Stability {
85+
level,
86+
feature,
87+
rustc_depr,
88+
rustc_const_unstable
89+
});
8590

8691
impl<'a, 'gcx, 'tcx> HashStable<StableHashingContext<'a, 'gcx, 'tcx>>
8792
for ::syntax::attr::StabilityLevel {
@@ -102,6 +107,7 @@ for ::syntax::attr::StabilityLevel {
102107
}
103108

104109
impl_stable_hash_for!(struct ::syntax::attr::RustcDeprecation { since, reason });
110+
impl_stable_hash_for!(struct ::syntax::attr::RustcConstUnstable { feature });
105111

106112

107113
impl_stable_hash_for!(enum ::syntax::attr::IntType {

src/librustc/middle/stability.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -427,6 +427,7 @@ impl<'a, 'tcx> Index<'tcx> {
427427
},
428428
feature: Symbol::intern("rustc_private"),
429429
rustc_depr: None,
430+
rustc_const_unstable: None,
430431
});
431432
annotator.parent_stab = Some(stability);
432433
}

src/librustc_mir/transform/qualify_consts.rs

Lines changed: 38 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ use rustc::mir::transform::{MirPass, MirSource};
3030
use rustc::mir::visit::{LvalueContext, Visitor};
3131
use rustc::middle::lang_items;
3232
use syntax::abi::Abi;
33+
use syntax::attr;
3334
use syntax::feature_gate::UnstableFeatures;
3435
use syntax_pos::{Span, DUMMY_SP};
3536

@@ -713,14 +714,14 @@ impl<'a, 'tcx> Visitor<'tcx> for Qualifier<'a, 'tcx, 'tcx> {
713714
self.visit_operand(func, location);
714715

715716
let fn_ty = func.ty(self.mir, self.tcx);
716-
let (mut is_shuffle, mut is_const_fn) = (false, false);
717+
let (mut is_shuffle, mut is_const_fn) = (false, None);
717718
if let ty::TyFnDef(def_id, _) = fn_ty.sty {
718719
match self.tcx.fn_sig(def_id).abi() {
719720
Abi::RustIntrinsic |
720721
Abi::PlatformIntrinsic => {
721722
assert!(!self.tcx.is_const_fn(def_id));
722723
match &self.tcx.item_name(def_id)[..] {
723-
"size_of" | "min_align_of" => is_const_fn = true,
724+
"size_of" | "min_align_of" => is_const_fn = Some(def_id),
724725

725726
name if name.starts_with("simd_shuffle") => {
726727
is_shuffle = true;
@@ -730,7 +731,9 @@ impl<'a, 'tcx> Visitor<'tcx> for Qualifier<'a, 'tcx, 'tcx> {
730731
}
731732
}
732733
_ => {
733-
is_const_fn = self.tcx.is_const_fn(def_id);
734+
if self.tcx.is_const_fn(def_id) {
735+
is_const_fn = Some(def_id);
736+
}
734737
}
735738
}
736739
}
@@ -751,25 +754,38 @@ impl<'a, 'tcx> Visitor<'tcx> for Qualifier<'a, 'tcx, 'tcx> {
751754
}
752755

753756
// Const fn calls.
754-
if is_const_fn {
755-
// We are in a const or static initializer,
756-
if self.mode != Mode::Fn &&
757-
758-
// feature-gate is not enabled,
759-
!self.tcx.sess.features.borrow().const_fn &&
760-
761-
// this doesn't come from a crate with the feature-gate enabled,
762-
self.def_id.is_local() &&
763-
764-
// this doesn't come from a macro that has #[allow_internal_unstable]
765-
!self.span.allows_unstable()
766-
{
767-
let mut err = self.tcx.sess.struct_span_err(self.span,
768-
"const fns are an unstable feature");
769-
help!(&mut err,
770-
"in Nightly builds, add `#![feature(const_fn)]` \
771-
to the crate attributes to enable");
772-
err.emit();
757+
if let Some(def_id) = is_const_fn {
758+
// find corresponding rustc_const_unstable feature
759+
if let Some(&attr::Stability {
760+
rustc_const_unstable: Some(attr::RustcConstUnstable {
761+
feature: ref feature_name
762+
}),
763+
.. }) = self.tcx.lookup_stability(def_id) {
764+
765+
// We are in a const or static initializer,
766+
if self.mode != Mode::Fn &&
767+
768+
// feature-gate is not enabled,
769+
!self.tcx.sess.features.borrow()
770+
.declared_lib_features
771+
.iter()
772+
.any(|&(ref sym, _)| sym == feature_name) &&
773+
774+
// this doesn't come from a crate with the feature-gate enabled,
775+
self.def_id.is_local() &&
776+
777+
// this doesn't come from a macro that has #[allow_internal_unstable]
778+
!self.span.allows_unstable()
779+
{
780+
let mut err = self.tcx.sess.struct_span_err(self.span,
781+
&format!("`{}` is not yet stable as a const fn",
782+
self.tcx.item_path_str(def_id)));
783+
help!(&mut err,
784+
"in Nightly builds, add `#![feature({})]` \
785+
to the crate attributes to enable",
786+
feature_name);
787+
err.emit();
788+
}
773789
}
774790
} else {
775791
self.qualif = Qualif::NOT_CONST;

src/libsyntax/attr.rs

Lines changed: 65 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -637,12 +637,13 @@ pub fn eval_condition<F>(cfg: &ast::MetaItem, sess: &ParseSess, eval: &mut F)
637637
}
638638
}
639639

640-
/// Represents the #[stable], #[unstable] and #[rustc_deprecated] attributes.
640+
/// Represents the #[stable], #[unstable], #[rustc_{deprecated,const_unstable}] attributes.
641641
#[derive(RustcEncodable, RustcDecodable, Clone, Debug, PartialEq, Eq, Hash)]
642642
pub struct Stability {
643643
pub level: StabilityLevel,
644644
pub feature: Symbol,
645645
pub rustc_depr: Option<RustcDeprecation>,
646+
pub rustc_const_unstable: Option<RustcConstUnstable>,
646647
}
647648

648649
/// The available stability levels.
@@ -659,6 +660,11 @@ pub struct RustcDeprecation {
659660
pub reason: Symbol,
660661
}
661662

663+
#[derive(RustcEncodable, RustcDecodable, PartialEq, PartialOrd, Clone, Debug, Eq, Hash)]
664+
pub struct RustcConstUnstable {
665+
pub feature: Symbol,
666+
}
667+
662668
#[derive(RustcEncodable, RustcDecodable, PartialEq, PartialOrd, Clone, Debug, Eq, Hash)]
663669
pub struct Deprecation {
664670
pub since: Option<Symbol>,
@@ -678,9 +684,15 @@ fn find_stability_generic<'a, I>(diagnostic: &Handler,
678684
{
679685
let mut stab: Option<Stability> = None;
680686
let mut rustc_depr: Option<RustcDeprecation> = None;
687+
let mut rustc_const_unstable: Option<RustcConstUnstable> = None;
681688

682689
'outer: for attr in attrs_iter {
683-
if attr.path != "rustc_deprecated" && attr.path != "unstable" && attr.path != "stable" {
690+
if ![
691+
"rustc_deprecated",
692+
"rustc_const_unstable",
693+
"unstable",
694+
"stable",
695+
].iter().any(|&s| attr.path == s) {
684696
continue // not a stability level
685697
}
686698

@@ -703,21 +715,18 @@ fn find_stability_generic<'a, I>(diagnostic: &Handler,
703715
}
704716
};
705717

706-
match &*meta.name.as_str() {
707-
"rustc_deprecated" => {
708-
if rustc_depr.is_some() {
709-
span_err!(diagnostic, item_sp, E0540,
710-
"multiple rustc_deprecated attributes");
711-
break
712-
}
713-
714-
let mut since = None;
715-
let mut reason = None;
718+
macro_rules! get_meta {
719+
($($name:ident),+) => {
720+
$(
721+
let mut $name = None;
722+
)+
716723
for meta in metas {
717724
if let Some(mi) = meta.meta_item() {
718725
match &*mi.name().as_str() {
719-
"since" => if !get(mi, &mut since) { continue 'outer },
720-
"reason" => if !get(mi, &mut reason) { continue 'outer },
726+
$(
727+
stringify!($name)
728+
=> if !get(mi, &mut $name) { continue 'outer },
729+
)+
721730
_ => {
722731
handle_errors(diagnostic, mi.span,
723732
AttrError::UnknownMetaItem(mi.name()));
@@ -729,6 +738,18 @@ fn find_stability_generic<'a, I>(diagnostic: &Handler,
729738
continue 'outer
730739
}
731740
}
741+
}
742+
}
743+
744+
match &*meta.name.as_str() {
745+
"rustc_deprecated" => {
746+
if rustc_depr.is_some() {
747+
span_err!(diagnostic, item_sp, E0540,
748+
"multiple rustc_deprecated attributes");
749+
continue 'outer
750+
}
751+
752+
get_meta!(since, reason);
732753

733754
match (since, reason) {
734755
(Some(since), Some(reason)) => {
@@ -747,6 +768,23 @@ fn find_stability_generic<'a, I>(diagnostic: &Handler,
747768
}
748769
}
749770
}
771+
"rustc_const_unstable" => {
772+
if rustc_const_unstable.is_some() {
773+
span_err!(diagnostic, item_sp, E0553,
774+
"multiple rustc_const_unstable attributes");
775+
continue 'outer
776+
}
777+
778+
get_meta!(feature);
779+
if let Some(feature) = feature {
780+
rustc_const_unstable = Some(RustcConstUnstable {
781+
feature
782+
});
783+
} else {
784+
span_err!(diagnostic, attr.span(), E0629, "missing 'feature'");
785+
continue
786+
}
787+
}
750788
"unstable" => {
751789
if stab.is_some() {
752790
handle_errors(diagnostic, attr.span(), AttrError::MultipleStabilityLevels);
@@ -791,6 +829,7 @@ fn find_stability_generic<'a, I>(diagnostic: &Handler,
791829
},
792830
feature,
793831
rustc_depr: None,
832+
rustc_const_unstable: None,
794833
})
795834
}
796835
(None, _, _) => {
@@ -836,6 +875,7 @@ fn find_stability_generic<'a, I>(diagnostic: &Handler,
836875
},
837876
feature,
838877
rustc_depr: None,
878+
rustc_const_unstable: None,
839879
})
840880
}
841881
(None, _) => {
@@ -867,6 +907,17 @@ fn find_stability_generic<'a, I>(diagnostic: &Handler,
867907
}
868908
}
869909

910+
// Merge the const-unstable info into the stability info
911+
if let Some(rustc_const_unstable) = rustc_const_unstable {
912+
if let Some(ref mut stab) = stab {
913+
stab.rustc_const_unstable = Some(rustc_const_unstable);
914+
} else {
915+
span_err!(diagnostic, item_sp, E0630,
916+
"rustc_const_unstable attribute must be paired with \
917+
either stable or unstable attribute");
918+
}
919+
}
920+
870921
stab
871922
}
872923

src/libsyntax/diagnostic_list.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -357,8 +357,11 @@ register_diagnostics! {
357357
E0549, // rustc_deprecated attribute must be paired with either stable or unstable attribute
358358
E0550, // multiple deprecated attributes
359359
E0551, // incorrect meta item
360+
E0553, // multiple rustc_const_unstable attributes
360361
E0555, // malformed feature attribute, expected #![feature(...)]
361362
E0556, // malformed feature, expected just one word
362363
E0584, // file for module `..` found at both .. and ..
363364
E0589, // invalid `repr(align)` attribute
365+
E0629, // missing 'feature' (rustc_const_unstable)
366+
E0630, // rustc_const_unstable attribute must be paired with stable/unstable attribute
364367
}

src/libsyntax/feature_gate.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -137,6 +137,7 @@ declare_features! (
137137

138138
// rustc internal
139139
(active, rustc_diagnostic_macros, "1.0.0", None),
140+
(active, rustc_const_unstable, "1.0.0", None),
140141
(active, advanced_slice_patterns, "1.0.0", Some(23121)),
141142
(active, box_syntax, "1.0.0", Some(27779)),
142143
(active, placement_in_syntax, "1.0.0", Some(27779)),
@@ -622,6 +623,11 @@ pub const BUILTIN_ATTRIBUTES: &'static [(&'static str, AttributeType, AttributeG
622623
"the `#[rustc_on_unimplemented]` attribute \
623624
is an experimental feature",
624625
cfg_fn!(on_unimplemented))),
626+
("rustc_const_unstable", Normal, Gated(Stability::Unstable,
627+
"rustc_const_unstable",
628+
"the `#[rustc_const_unstable]` attribute \
629+
is an internal feature",
630+
cfg_fn!(rustc_const_unstable))),
625631
("global_allocator", Normal, Gated(Stability::Unstable,
626632
"global_allocator",
627633
"the `#[global_allocator]` attribute is \
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
// Test use of const fns in std using individual feature gates.
12+
13+
use std::cell::Cell;
14+
15+
const CELL: Cell<i32> = Cell::new(42); //~ERROR not yet stable as a const fn
16+
//~^HELP #![feature(const_cell_new)]
17+
18+
fn main() {
19+
let v = CELL.get();
20+
CELL.set(v+1);
21+
22+
assert_eq!(CELL.get(), v);
23+
}
24+
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
// Test internal const fn feature gate.
12+
13+
#![feature(staged_api)]
14+
#![feature(const_fn)]
15+
//#![feature(rustc_const_unstable)]
16+
17+
#[stable(feature="zing", since="1.0.0")]
18+
#[rustc_const_unstable(feature="fzzzzzt")] //~ERROR internal feature
19+
pub const fn bazinga() {}
20+
21+
fn main() {
22+
}
23+

src/test/compile-fail/stability-attribute-sanity.rs

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010

1111
// Various checks that stability attributes are used correctly, per RFC 507
1212

13-
#![feature(staged_api)]
13+
#![feature(const_fn, staged_api, rustc_const_unstable)]
1414

1515
#![stable(feature = "rust1", since = "1.0.0")]
1616

@@ -88,8 +88,11 @@ fn multiple3() { }
8888
#[stable(feature = "a", since = "b")]
8989
#[rustc_deprecated(since = "b", reason = "text")]
9090
#[rustc_deprecated(since = "b", reason = "text")]
91-
fn multiple4() { } //~ ERROR multiple rustc_deprecated attributes [E0540]
91+
#[rustc_const_unstable(feature = "a")]
92+
#[rustc_const_unstable(feature = "b")]
93+
pub const fn multiple4() { } //~ ERROR multiple rustc_deprecated attributes [E0540]
9294
//~^ ERROR Invalid stability or deprecation version found
95+
//~| ERROR multiple rustc_const_unstable attributes
9396

9497
#[rustc_deprecated(since = "a", reason = "text")]
9598
fn deprecated_without_unstable_or_stable() { }

0 commit comments

Comments
 (0)