diff --git a/compiler/rustc_builtin_macros/src/contracts.rs b/compiler/rustc_builtin_macros/src/contracts.rs
index 85a30f7bdc9b4..6a24af361fe78 100644
--- a/compiler/rustc_builtin_macros/src/contracts.rs
+++ b/compiler/rustc_builtin_macros/src/contracts.rs
@@ -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;
 
@@ -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(
@@ -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(
diff --git a/compiler/rustc_parse/src/parser/generics.rs b/compiler/rustc_parse/src/parser/generics.rs
index 86816819be275..11f0e579de5a1 100644
--- a/compiler/rustc_parse/src/parser/generics.rs
+++ b/compiler/rustc_parse/src/parser/generics.rs
@@ -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
diff --git a/compiler/rustc_session/src/parse.rs b/compiler/rustc_session/src/parse.rs
index d4db05ce139fa..e0405a71f65af 100644
--- a/compiler/rustc_session/src/parse.rs
+++ b/compiler/rustc_session/src/parse.rs
@@ -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>,
@@ -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,
diff --git a/tests/ui/contracts/internal_machinery/internal-feature-gating.stderr b/tests/ui/contracts/internal_machinery/internal-feature-gating.stderr
index c0e1522f54c61..7302694a7874a 100644
--- a/tests/ui/contracts/internal_machinery/internal-feature-gating.stderr
+++ b/tests/ui/contracts/internal_machinery/internal-feature-gating.stderr
@@ -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
diff --git a/tests/ui/feature-gates/feature-gate-contracts.rs b/tests/ui/feature-gates/feature-gate-contracts.rs
index 5544f1d82ee4c..1759d23077b53 100644
--- a/tests/ui/feature-gates/feature-gate-contracts.rs
+++ b/tests/ui/feature-gates/feature-gate-contracts.rs
@@ -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
diff --git a/tests/ui/feature-gates/feature-gate-contracts.stderr b/tests/ui/feature-gates/feature-gate-contracts.stderr
index 4403e7df50b49..4b0f7150973f1 100644
--- a/tests/ui/feature-gates/feature-gate-contracts.stderr
+++ b/tests/ui/feature-gates/feature-gate-contracts.stderr
@@ -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)]
    |   ^^^^^^^^^^^^^^^^^^^^^^^^
@@ -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
-  --> $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`.