diff options
| author | Felix S. Klock II <pnkfelix@pnkfx.org> | 2024-12-03 16:13:00 +0000 |
|---|---|---|
| committer | Celina G. Val <celinval@amazon.com> | 2025-02-03 13:55:15 -0800 |
| commit | 6a6c6b891bb0350b3f16abd3e84ff12dbd1b4c5b (patch) | |
| tree | 8e16cd67997426132fcfa3a0877a8e7d829f124c /compiler | |
| parent | b279ff9dcfadcdb6976097d58044d151af81cf51 (diff) | |
| download | rust-6a6c6b891bb0350b3f16abd3e84ff12dbd1b4c5b.tar.gz rust-6a6c6b891bb0350b3f16abd3e84ff12dbd1b4c5b.zip | |
Separate contract feature gates for the internal machinery
The extended syntax for function signature that includes contract clauses should never be user exposed versus the interface we want to ship externally eventually.
Diffstat (limited to 'compiler')
| -rw-r--r-- | compiler/rustc_ast_passes/src/feature_gate.rs | 2 | ||||
| -rw-r--r-- | compiler/rustc_builtin_macros/src/contracts.rs | 20 | ||||
| -rw-r--r-- | compiler/rustc_feature/src/unstable.rs | 4 | ||||
| -rw-r--r-- | compiler/rustc_parse/src/parser/generics.rs | 20 | ||||
| -rw-r--r-- | compiler/rustc_session/src/parse.rs | 5 | ||||
| -rw-r--r-- | compiler/rustc_span/src/symbol.rs | 2 |
6 files changed, 42 insertions, 11 deletions
diff --git a/compiler/rustc_ast_passes/src/feature_gate.rs b/compiler/rustc_ast_passes/src/feature_gate.rs index 80b99f94485..a3af942a10f 100644 --- a/compiler/rustc_ast_passes/src/feature_gate.rs +++ b/compiler/rustc_ast_passes/src/feature_gate.rs @@ -548,6 +548,8 @@ pub fn check_crate(krate: &ast::Crate, sess: &Session, features: &Features) { gate_all!(pin_ergonomics, "pinned reference syntax is experimental"); gate_all!(unsafe_fields, "`unsafe` fields are experimental"); gate_all!(unsafe_binders, "unsafe binder types are experimental"); + gate_all!(rustc_contracts, "contracts are experimental"); + gate_all!(rustc_contracts_internals, "contract internal machinery is for internal use only"); if !visitor.features.never_patterns() { if let Some(spans) = spans.get(&sym::never_patterns) { diff --git a/compiler/rustc_builtin_macros/src/contracts.rs b/compiler/rustc_builtin_macros/src/contracts.rs index d269287b555..be7f276cdaa 100644 --- a/compiler/rustc_builtin_macros/src/contracts.rs +++ b/compiler/rustc_builtin_macros/src/contracts.rs @@ -36,17 +36,17 @@ impl AttrProcMacro for ExpandEnsures { } fn expand_injecting_circa_where_clause( - _ecx: &mut ExtCtxt<'_>, + ecx: &mut ExtCtxt<'_>, attr_span: Span, annotated: TokenStream, inject: impl FnOnce(&mut Vec<TokenTree>) -> Result<(), ErrorGuaranteed>, ) -> Result<TokenStream, ErrorGuaranteed> { let mut new_tts = Vec::with_capacity(annotated.len()); - let mut cursor = annotated.into_trees(); + let mut cursor = annotated.iter(); // Find the `fn name<G,...>(x:X,...)` and inject the AST contract forms right after // the formal parameters (and return type if any). - while let Some(tt) = cursor.next_ref() { + while let Some(tt) = cursor.next() { new_tts.push(tt.clone()); if let TokenTree::Token(tok, _) = tt && tok.is_ident_named(kw::Fn) @@ -58,7 +58,7 @@ fn expand_injecting_circa_where_clause( // Found the `fn` keyword, now find the formal parameters. // // FIXME: can this fail if you have parentheticals in a generics list, like `fn foo<F: Fn(X) -> Y>` ? - while let Some(tt) = cursor.next_ref() { + while let Some(tt) = cursor.next() { new_tts.push(tt.clone()); if let TokenTree::Delimited(_, _, token::Delimiter::Parenthesis, _) = tt { @@ -81,7 +81,7 @@ fn expand_injecting_circa_where_clause( // parse the type expression itself. But rather than try to fix things with hacks like that, // time might be better spent extending the attribute expander to suport tt-annotation atop // ast-annotated, which would be an elegant way to sidestep all of this. - let mut opt_next_tt = cursor.next_ref(); + let mut opt_next_tt = cursor.next(); while let Some(next_tt) = opt_next_tt { if let TokenTree::Token(tok, _) = next_tt && tok.is_ident_named(kw::Where) @@ -97,8 +97,7 @@ fn expand_injecting_circa_where_clause( // for anything else, transcribe the tt and keep looking. new_tts.push(next_tt.clone()); - opt_next_tt = cursor.next_ref(); - continue; + opt_next_tt = cursor.next(); } // At this point, we've transcribed everything from the `fn` through the formal parameter list @@ -118,10 +117,15 @@ fn expand_injecting_circa_where_clause( if let Some(tt) = opt_next_tt { new_tts.push(tt.clone()); } - while let Some(tt) = cursor.next_ref() { + while let Some(tt) = cursor.next() { new_tts.push(tt.clone()); } + // Record the span as a contract attribute expansion. + // This is used later to stop users from using the extended syntax directly + // which is gated via `rustc_contracts_internals`. + ecx.psess().contract_attribute_spans.push(attr_span); + Ok(TokenStream::new(new_tts)) } diff --git a/compiler/rustc_feature/src/unstable.rs b/compiler/rustc_feature/src/unstable.rs index 08a5e22db3a..57bcd8c5eca 100644 --- a/compiler/rustc_feature/src/unstable.rs +++ b/compiler/rustc_feature/src/unstable.rs @@ -608,6 +608,10 @@ declare_features! ( (unstable, return_type_notation, "1.70.0", Some(109417)), /// Allows `extern "rust-cold"`. (unstable, rust_cold_cc, "1.63.0", Some(97544)), + /// Allows use of contracts attributes. + (unstable, rustc_contracts, "CURRENT_RUSTC_VERSION", Some(133866)), + /// Allows access to internal machinery used to implement contracts. + (unstable, rustc_contracts_internals, "CURRENT_RUSTC_VERSION", Some(133866)), /// Allows use of x86 SHA512, SM3 and SM4 target-features and intrinsics (unstable, sha512_sm_x86, "1.82.0", Some(126624)), /// Allows the use of SIMD types in functions declared in `extern` blocks. diff --git a/compiler/rustc_parse/src/parser/generics.rs b/compiler/rustc_parse/src/parser/generics.rs index d5ac8d1588d..14b949dbc3d 100644 --- a/compiler/rustc_parse/src/parser/generics.rs +++ b/compiler/rustc_parse/src/parser/generics.rs @@ -4,7 +4,7 @@ use rustc_ast::{ WhereClause, token, }; use rustc_errors::{Applicability, PResult}; -use rustc_span::{Ident, Span, kw}; +use rustc_span::{Ident, Span, kw, sym}; use thin_vec::ThinVec; use super::{ForceCollect, Parser, Trailing, UsePreAttrPos}; @@ -302,13 +302,27 @@ impl<'a> Parser<'a> { pub(super) fn parse_contract( &mut self, ) -> PResult<'a, Option<rustc_ast::ptr::P<ast::FnContract>>> { + let gate = |span| { + if self.psess.contract_attribute_spans.contains(span) { + // span was generated via a builtin contracts attribute, so gate as end-user visible + self.psess.gated_spans.gate(sym::rustc_contracts, span); + } else { + // span was not generated via a builtin contracts attribute, so gate as internal machinery + self.psess.gated_spans.gate(sym::rustc_contracts_internals, span); + } + }; + let requires = if self.eat_keyword_noexpect(exp!(RustcContractRequires).kw) { - Some(self.parse_expr()?) + let precond = self.parse_expr()?; + gate(precond.span); + Some(precond) } else { None }; let ensures = if self.eat_keyword_noexpect(exp!(RustcContractEnsures).kw) { - Some(self.parse_expr()?) + let postcond = self.parse_expr()?; + gate(postcond.span); + Some(postcond) } else { None }; diff --git a/compiler/rustc_session/src/parse.rs b/compiler/rustc_session/src/parse.rs index 81ae06602cd..abfd3efc611 100644 --- a/compiler/rustc_session/src/parse.rs +++ b/compiler/rustc_session/src/parse.rs @@ -207,6 +207,10 @@ pub struct ParseSess { pub config: Cfg, pub check_config: CheckCfg, pub edition: Edition, + /// Places where contract attributes were expanded into unstable AST forms. + /// This is used to allowlist those spans (so that we only check them against the feature + /// gate for the externally visible interface, and not internal implmentation machinery). + pub contract_attribute_spans: AppendOnlyVec<Span>, /// Places where raw identifiers were used. This is used to avoid complaining about idents /// clashing with keywords in new editions. pub raw_identifier_spans: AppendOnlyVec<Span>, @@ -255,6 +259,7 @@ impl ParseSess { config: Cfg::default(), check_config: CheckCfg::default(), edition: ExpnId::root().expn_data().edition, + contract_attribute_spans: Default::default(), raw_identifier_spans: Default::default(), bad_unicode_identifiers: Lock::new(Default::default()), source_map, diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 43bc69e6e7c..ea2ce5475c2 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -1716,6 +1716,8 @@ symbols! { rustc_const_stable, rustc_const_stable_indirect, rustc_const_unstable, + rustc_contracts, + rustc_contracts_internals, rustc_conversion_suggestion, rustc_deallocator, rustc_def_path, |
