Skip to content

Stop using span hack for contracts feature gating #136835

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Feb 11, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 9 additions & 14 deletions compiler/rustc_builtin_macros/src/contracts.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,9 @@
#![allow(unused_imports, unused_variables)]

use rustc_ast::token;
use rustc_ast::tokenstream::{DelimSpacing, DelimSpan, Spacing, TokenStream, TokenTree};
use rustc_errors::ErrorGuaranteed;
use rustc_expand::base::{AttrProcMacro, ExtCtxt};
use rustc_span::Span;
use rustc_span::symbol::{Ident, Symbol, kw, sym};
use rustc_span::symbol::{Ident, Symbol, kw};

pub(crate) struct ExpandRequires;

Expand Down Expand Up @@ -121,23 +119,19 @@ fn expand_contract_clause(
}
}

// 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 `contracts_internals`.
ecx.psess().contract_attribute_spans.push(attr_span);

Ok(new_tts)
}

fn expand_requires_tts(
_ecx: &mut ExtCtxt<'_>,
ecx: &mut ExtCtxt<'_>,
attr_span: Span,
annotation: TokenStream,
annotated: TokenStream,
) -> Result<TokenStream, ErrorGuaranteed> {
expand_contract_clause(_ecx, attr_span, annotated, |new_tts| {
let feature_span = ecx.with_def_site_ctxt(attr_span);
expand_contract_clause(ecx, attr_span, annotated, |new_tts| {
new_tts.push_tree(TokenTree::Token(
token::Token::from_ast_ident(Ident::new(kw::ContractRequires, attr_span)),
token::Token::from_ast_ident(Ident::new(kw::ContractRequires, feature_span)),
Spacing::Joint,
));
new_tts.push_tree(TokenTree::Token(
Expand All @@ -155,14 +149,15 @@ fn expand_requires_tts(
}

fn expand_ensures_tts(
_ecx: &mut ExtCtxt<'_>,
ecx: &mut ExtCtxt<'_>,
attr_span: Span,
annotation: TokenStream,
annotated: TokenStream,
) -> Result<TokenStream, ErrorGuaranteed> {
expand_contract_clause(_ecx, attr_span, annotated, |new_tts| {
let feature_span = ecx.with_def_site_ctxt(attr_span);
expand_contract_clause(ecx, attr_span, annotated, |new_tts| {
new_tts.push_tree(TokenTree::Token(
token::Token::from_ast_ident(Ident::new(kw::ContractEnsures, attr_span)),
token::Token::from_ast_ident(Ident::new(kw::ContractEnsures, feature_span)),
Spacing::Joint,
));
new_tts.push_tree(TokenTree::Delimited(
Expand Down
14 changes: 2 additions & 12 deletions compiler/rustc_parse/src/parser/generics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -302,26 +302,16 @@ 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::contracts, span);
} else {
// span was not generated via a builtin contracts attribute, so gate as internal machinery
self.psess.gated_spans.gate(sym::contracts_internals, span);
}
};

let requires = if self.eat_keyword_noexpect(exp!(ContractRequires).kw) {
self.psess.gated_spans.gate(sym::contracts_internals, self.prev_token.span);
let precond = self.parse_expr()?;
gate(precond.span);
Some(precond)
} else {
None
};
let ensures = if self.eat_keyword_noexpect(exp!(ContractEnsures).kw) {
self.psess.gated_spans.gate(sym::contracts_internals, self.prev_token.span);
let postcond = self.parse_expr()?;
gate(postcond.span);
Some(postcond)
} else {
None
Expand Down
5 changes: 0 additions & 5 deletions compiler/rustc_session/src/parse.rs
Original file line number Diff line number Diff line change
Expand Up @@ -208,10 +208,6 @@ 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>,
Expand Down Expand Up @@ -260,7 +256,6 @@ 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,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,18 +1,18 @@
error[E0658]: contract internal machinery is for internal use only
--> $DIR/internal-feature-gating.rs:16:45
--> $DIR/internal-feature-gating.rs:16:28
|
LL | fn identity_1() -> i32 contract_requires(|| true) { 10 }
| ^^^^^^^^^
| ^^^^^^^^^^^^^^^^^
|
= note: see issue #128044 <https://github.com/rust-lang/rust/issues/128044> for more information
= help: add `#![feature(contracts_internals)]` to the crate attributes to enable
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date

error[E0658]: contract internal machinery is for internal use only
--> $DIR/internal-feature-gating.rs:18:44
--> $DIR/internal-feature-gating.rs:18:28
|
LL | fn identity_2() -> i32 contract_ensures(|_| true) { 10 }
| ^^^^^^^^^^
| ^^^^^^^^^^^^^^^^
|
= note: see issue #128044 <https://github.com/rust-lang/rust/issues/128044> for more information
= help: add `#![feature(contracts_internals)]` to the crate attributes to enable
Expand Down
2 changes: 0 additions & 2 deletions tests/ui/feature-gates/feature-gate-contracts.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,7 @@
#[core::contracts::requires(x > 0)]
pub fn requires_needs_it(x: i32) { }
//~^^ ERROR use of unstable library feature `contracts`
//~^^^ ERROR contracts are incomplete

#[core::contracts::ensures(|ret| *ret > 0)]
pub fn ensures_needs_it() -> i32 { 10 }
//~^^ ERROR use of unstable library feature `contracts`
//~^^^ ERROR contracts are incomplete
24 changes: 2 additions & 22 deletions tests/ui/feature-gates/feature-gate-contracts.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ LL | #[core::contracts::requires(x > 0)]
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date

error[E0658]: use of unstable library feature `contracts`
--> $DIR/feature-gate-contracts.rs:8:3
--> $DIR/feature-gate-contracts.rs:7:3
|
LL | #[core::contracts::ensures(|ret| *ret > 0)]
| ^^^^^^^^^^^^^^^^^^^^^^^^
Expand All @@ -18,26 +18,6 @@ LL | #[core::contracts::ensures(|ret| *ret > 0)]
= help: add `#![feature(contracts)]` to the crate attributes to enable
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date

error[E0658]: contracts are incomplete
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This was redundant. We're already issuing a library feature error above, since we're just using a library feature.

Changing it to supporting issuing two feature gates is an undue burden to the parser impl unless we want to gate the internal machinery under both contracts and contracts_internals.

--> $DIR/feature-gate-contracts.rs:3:1
|
LL | #[core::contracts::requires(x > 0)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: see issue #128044 <https://github.com/rust-lang/rust/issues/128044> for more information
= help: add `#![feature(contracts)]` to the crate attributes to enable
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date

error[E0658]: contracts are incomplete
--> $DIR/feature-gate-contracts.rs:8:1
|
LL | #[core::contracts::ensures(|ret| *ret > 0)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: see issue #128044 <https://github.com/rust-lang/rust/issues/128044> for more information
= help: add `#![feature(contracts)]` to the crate attributes to enable
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date

error: aborting due to 4 previous errors
error: aborting due to 2 previous errors

For more information about this error, try `rustc --explain E0658`.
Loading