Skip to content

Commit d8d6b6a

Browse files
committed
separate feature gates for the internal machinery that should never be user exposed versus the interface we want to ship externally eventually.
1 parent 253aa98 commit d8d6b6a

File tree

15 files changed

+136
-18
lines changed

15 files changed

+136
-18
lines changed

compiler/rustc_ast_passes/src/feature_gate.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -563,6 +563,8 @@ pub fn check_crate(krate: &ast::Crate, sess: &Session, features: &Features) {
563563
gate_all!(return_type_notation, "return type notation is experimental");
564564
gate_all!(pin_ergonomics, "pinned reference syntax is experimental");
565565
gate_all!(unsafe_fields, "`unsafe` fields are experimental");
566+
gate_all!(rustc_contracts, "contracts are experimental");
567+
gate_all!(rustc_contracts_internals, "contract internal machinery is for internal use only");
566568

567569
if !visitor.features.never_patterns() {
568570
if let Some(spans) = spans.get(&sym::never_patterns) {

compiler/rustc_builtin_macros/src/contracts.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ impl AttrProcMacro for ExpandEnsures {
3737
}
3838

3939
fn expand_injecting_circa_where_clause(
40-
_ecx: &mut ExtCtxt<'_>,
40+
ecx: &mut ExtCtxt<'_>,
4141
attr_span: Span,
4242
annotated: TokenStream,
4343
inject: impl FnOnce(&mut Vec<TokenTree>) -> Result<(), ErrorGuaranteed>,
@@ -119,6 +119,8 @@ fn expand_injecting_circa_where_clause(
119119
new_tts.push(tt.clone());
120120
}
121121

122+
ecx.psess().contract_attribute_spans.push(attr_span);
123+
122124
Ok(TokenStream::new(new_tts))
123125
}
124126

compiler/rustc_feature/src/unstable.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -598,6 +598,10 @@ declare_features! (
598598
(unstable, return_type_notation, "1.70.0", Some(109417)),
599599
/// Allows `extern "rust-cold"`.
600600
(unstable, rust_cold_cc, "1.63.0", Some(97544)),
601+
/// Allows use of contracts attributes.
602+
(unstable, rustc_contracts, "CURRENT_RUSTC_VERSION", None),
603+
/// Allows access to internal machinery used to implement contracts.
604+
(unstable, rustc_contracts_internals, "CURRENT_RUSTC_VERSION", None),
601605
/// Allows use of x86 SHA512, SM3 and SM4 target-features and intrinsics
602606
(unstable, sha512_sm_x86, "1.82.0", Some(126624)),
603607
/// Allows the use of SIMD types in functions declared in `extern` blocks.

compiler/rustc_parse/src/parser/generics.rs

Lines changed: 18 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ use rustc_ast::{
55
};
66
use rustc_errors::{Applicability, PResult};
77
use rustc_span::Span;
8-
use rustc_span::symbol::{Ident, kw};
8+
use rustc_span::symbol::{Ident, kw, sym};
99
use thin_vec::ThinVec;
1010

1111
use super::{ForceCollect, Parser, Trailing, UsePreAttrPos};
@@ -300,21 +300,34 @@ impl<'a> Parser<'a> {
300300
/// Parses a rustc-internal fn contract
301301
/// (`rustc_contract_requires(WWW) rustc_contract_ensures(ZZZ)`)
302302
pub(super) fn parse_contract(&mut self) -> PResult<'a, Option<rustc_ast::ptr::P<ast::FnContract>>> {
303-
let requires = if self.eat_keyword(kw::RustcContractRequires) {
304-
Some(self.parse_expr()?)
303+
let gate = |span| {
304+
if self.psess.contract_attribute_spans.contains(span) {
305+
// span was generated via a builtin contracts attribute, so gate as end-user visible
306+
self.psess.gated_spans.gate(sym::rustc_contracts, span);
307+
} else {
308+
// span was not generated via a builtin contracts attribute, so gate as internal machinery
309+
self.psess.gated_spans.gate(sym::rustc_contracts_internals, span);
310+
}
311+
};
312+
let requires = if self.eat_keyword(kw::RustcContractRequires) {
313+
let precond = self.parse_expr()?;
314+
gate(precond.span);
315+
Some(precond)
305316
} else {
306317
None
307318
};
308319
let ensures = if self.eat_keyword(kw::RustcContractEnsures) {
309-
Some(self.parse_expr()?)
320+
let postcond = self.parse_expr()?;
321+
gate(postcond.span);
322+
Some(postcond)
310323
} else {
311324
None
312325
};
313326
if requires.is_none() && ensures.is_none() {
314327
Ok(None)
315328
} else {
316329
Ok(Some(rustc_ast::ptr::P(ast::FnContract { requires, ensures })))
317-
}
330+
}
318331
}
319332

320333
/// Parses an optional where-clause.

compiler/rustc_session/src/parse.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -207,6 +207,10 @@ pub struct ParseSess {
207207
pub config: Cfg,
208208
pub check_config: CheckCfg,
209209
pub edition: Edition,
210+
/// Places where contract attributes were expanded into unstable AST forms.
211+
/// This is used to allowlist those spans (so that we only check them against the feature
212+
/// gate for the externally visible interface, and not internal implmentation machinery).
213+
pub contract_attribute_spans: AppendOnlyVec<Span>,
210214
/// Places where raw identifiers were used. This is used to avoid complaining about idents
211215
/// clashing with keywords in new editions.
212216
pub raw_identifier_spans: AppendOnlyVec<Span>,
@@ -255,6 +259,7 @@ impl ParseSess {
255259
config: Cfg::default(),
256260
check_config: CheckCfg::default(),
257261
edition: ExpnId::root().expn_data().edition,
262+
contract_attribute_spans: Default::default(),
258263
raw_identifier_spans: Default::default(),
259264
bad_unicode_identifiers: Lock::new(Default::default()),
260265
source_map,

compiler/rustc_span/src/symbol.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1696,6 +1696,8 @@ symbols! {
16961696
rustc_const_stable,
16971697
rustc_const_stable_indirect,
16981698
rustc_const_unstable,
1699+
rustc_contracts,
1700+
rustc_contracts_internals,
16991701
rustc_conversion_suggestion,
17001702
rustc_deallocator,
17011703
rustc_def_path,

library/core/src/contracts.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ pub use crate::macros::builtin::contracts_requires as requires;
88
/// Emitted by rustc as a desugaring of `#[requires(PRED)] fn foo(x: X) { ... }`
99
/// into: `fn foo(x: X) { check_requires(|| PRED) ... }`
1010
#[cfg(not(bootstrap))]
11-
#[unstable(feature = "rustc_contracts", issue = "none" /* compiler-team#759 */)]
11+
#[unstable(feature = "rustc_contracts_internals", issue = "none" /* compiler-team#759 */)]
1212
#[lang = "contract_check_requires"]
1313
#[track_caller]
1414
pub fn check_requires<C: FnOnce() -> bool>(c: C) {
@@ -21,7 +21,7 @@ pub fn check_requires<C: FnOnce() -> bool>(c: C) {
2121
/// into: `fn foo() { let _check = build_check_ensures(|ret| PRED) ... [return _check(R);] ... }`
2222
/// (including the implicit return of the tail expression, if any).
2323
#[cfg(not(bootstrap))]
24-
#[unstable(feature = "rustc_contracts", issue = "none" /* compiler-team#759 */)]
24+
#[unstable(feature = "rustc_contracts_internals", issue = "none" /* compiler-team#759 */)]
2525
#[lang = "contract_build_check_ensures"]
2626
#[track_caller]
2727
pub fn build_check_ensures<Ret, C: for<'a> FnOnce(&'a Ret) -> bool + Copy + 'static>(c: C) -> impl (FnOnce(Ret) -> Ret) + Copy {

library/core/src/intrinsics/mod.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4015,8 +4015,8 @@ pub const unsafe fn const_deallocate(_ptr: *mut u8, _size: usize, _align: usize)
40154015
/// checking is turned on, so that we can specify contracts in libstd
40164016
/// and let an end user opt into turning them on.
40174017
#[cfg(not(bootstrap))]
4018-
#[rustc_const_unstable(feature = "rustc_contracts", issue = "none" /* compiler-team#759 */)]
4019-
#[unstable(feature = "rustc_contracts", issue = "none" /* compiler-team#759 */)]
4018+
#[rustc_const_unstable(feature = "rustc_contracts_internals", issue = "none" /* compiler-team#759 */)]
4019+
#[unstable(feature = "rustc_contracts_internals", issue = "none" /* compiler-team#759 */)]
40204020
#[inline(always)]
40214021
#[rustc_intrinsic]
40224022
pub const fn contract_checks() -> bool {
@@ -4027,14 +4027,14 @@ pub const fn contract_checks() -> bool {
40274027
}
40284028

40294029
#[cfg(not(bootstrap))]
4030-
#[unstable(feature = "rustc_contracts", issue = "none" /* compiler-team#759 */)]
4030+
#[unstable(feature = "rustc_contracts_internals", issue = "none" /* compiler-team#759 */)]
40314031
#[rustc_intrinsic]
40324032
pub fn contract_check_requires<C: FnOnce() -> bool>(c: C) -> bool {
40334033
c()
40344034
}
40354035

40364036
#[cfg(not(bootstrap))]
4037-
#[unstable(feature = "rustc_contracts", issue = "none" /* compiler-team#759 */)]
4037+
#[unstable(feature = "rustc_contracts_internals", issue = "none" /* compiler-team#759 */)]
40384038
#[rustc_intrinsic]
40394039
pub fn contract_check_ensures<'a, Ret, C: FnOnce(&'a Ret) -> bool>(ret: &'a Ret, c: C) -> bool {
40404040
c(ret)

library/core/src/macros/mod.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1721,7 +1721,7 @@ pub(crate) mod builtin {
17211721
/// invoked on a reference to the return value.
17221722
#[cfg(not(bootstrap))]
17231723
#[unstable(feature = "rustc_contracts", issue = "none")]
1724-
#[allow_internal_unstable(core_intrinsics)]
1724+
#[allow_internal_unstable(rustc_contracts_internals)]
17251725
#[rustc_builtin_macro]
17261726
pub macro contracts_ensures($item:item) {
17271727
/* compiler built-in */
@@ -1734,7 +1734,7 @@ pub(crate) mod builtin {
17341734
/// function's formal parameters
17351735
#[cfg(not(bootstrap))]
17361736
#[unstable(feature = "rustc_contracts", issue = "none")]
1737-
#[allow_internal_unstable(core_intrinsics)]
1737+
#[allow_internal_unstable(rustc_contracts_internals)]
17381738
#[rustc_builtin_macro]
17391739
pub macro contracts_requires($item:item) {
17401740
/* compiler built-in */

tests/ui/contracts/contract-ast-extensions-nest.rs renamed to tests/ui/contracts/internal_machinery/contract-ast-extensions-nest.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616
//@ [chk_fail_pre] compile-flags: -Zcontract-checks=yes
1717
//@ [chk_fail_post] compile-flags: -Zcontract-checks=yes
1818

19-
#![feature(rustc_contracts)]
19+
#![feature(rustc_contracts_internals)]
2020

2121
fn nest(x: Baz) -> i32
2222
rustc_contract_requires(|| x.baz > 0)

0 commit comments

Comments
 (0)