Skip to content

Conversation

@epage
Copy link
Contributor

@epage epage commented Oct 23, 2025

Stabilization report

Summary

This report proposes the stabilization of #[feature(frontmatter)] in preparation for Cargo Script to be stabilized.

A frontmatter is a special kind of attribute intended to be read and modified by external tools, like Cargo. This puts a particular constraint on this attribute in that full awareness of the Rust grammar would be prohibitive.

For example:

#!/usr/bin/env cargo
---
[dependencies]
clap = "4"
---

fn main() {
}

The goal of Cargo script is to improve:

  • Learning by reducing the bar for experimenting and prototyping
  • Collaboration, including bug reports, chats, blogs, and books
  • Interoperability between tools that need similar solutions (playgrounds,
  • One off utilities where it makes sense (e.g. integrating with Rust-specific libraries)

Closes #136889

Tracking:

Reference PRs:

cc @rust-lang/lang @rust-lang/lang-advisors, @rust-lang/compiler

What is stabilized

This is stabilizing frontmatter, an optional section in a source file that can only exist before any Rust code or comments, for use by external tools.

#!/usr/bin/env cargo

---
[dependencies]
clap = "4"
---

fn main() {
}

After the opening frontmatter fence, an infostring is allowed that can identify the contents.
Calling tools are responsible for interpreting the infostring.

What isn't stabilized

Only a subset of the allowed infostring syntax is being stabilized.

  • RFC: "an optional term (one or more characters excluding whitespace and commas)"
  • rustc: (XID_Start | _) ( XID_Continue | -|. )*
  • The RFC allowed - in the start of an infostring which is ambiguous with frontmatter open which accepts 3 or more -
  • We simplified to a minimal, closed set as a precaution with a focus on what would make most file names work
  • See Implement RFC 3503: frontmatters #140035

Future possibilities include:

  • Infostring attributes: the supported syntax for infostrings was restricted to leave the door open
  • Tracking this as an attribute in the AST
  • Multiple frontmatters

Design

Reference

RFC history

  • RFC 3503 adds a new lexical section to the Reference to describe the frontmatter, including the grammar.

Answers to unresolved questions

What questions were left unresolved by the RFC? How have they been answered? Link to any relevant lang decisions.

The RFC has no unresolved questions

Post-RFC changes

What other user-visible changes have occurred since the RFC was accepted? Describe both changes that the lang team accepted (and link to those decisions) as well as changes that are being presented to the team for the first time in this stabilization report.

Key points

What decisions have been most difficult and what behaviors to be stabilized have proved most contentious? Summarize the major arguments on all sides and link to earlier documents and discussions.

  • whitespace between opening and infostring
  • rust-analyzer wanting an external indicator for cargo-scripts
    • This would allow them to differentiate between unlinked files and cargo scripts without ambiguity and without having to read the content. The latter means they either pre-load and take a performance hit or load on-demand
    • Resolving this runs counter to some of the design goals within the RFC
    • From the outside, it is not clear why this is as big of a problem as they feel it is
    • As this is re-litigating an RFC decision, the responsibility for making the case for why this is important was put on them and there has been no progress on this in the last 2 months
    • See also #t-compiler/rust-analyzer > Frontmatter vs `import_rules!` for scripts @ 💬
  • whether indented --- needs to be escaped
    • The RFC only said that --- at the start of a line needs escaping
    • #140035 also had indented --- needing escaping
    • #145754 switched the implementation to match the RFC
  • interactions with -Zunpretty
  • whether external tools should silently fail, delegating error reporting to rustc
    • Cargo has gone with high quality error reporting to report problems quickly, including non-compiling commands, rather than deferring errors to compilation. In particular, the contents of the frontmatter can make a big difference in how compilation happens.

Nightly extensions

Are there extensions to this feature that remain unstable? How do we know that we are not accidentally committing to those?

No nightly extensions exist

Doors closed

What doors does this stabilization close for later changes to the language? E.g., does this stabilization make any other RFCs, lang experiments, or known in-flight proposals more difficult or impossible to do later?

There are no known efforts that this affects.

Feedback

Call for testing

Has a "call for testing" been done? If so, what feedback was received?

Call for testing with feedback at:

Previous call for testing: rust-lang/rfcs#3424 (comment) with some feedback at rust-lang/cargo#12207 (comment)

Overall, feedback is enthusiastic. Any quibbles are with the Cargo side.

Nightly use

Do any known nightly users use this feature? Counting instances of #![feature(FEATURE_NAME)] on GitHub with grep might be informative.

Samples from grepping for -Zscript

Implementation

Major parts

Summarize the major parts of the implementation and provide links into the code and to relevant PRs.

See, e.g., this breakdown of the major parts of async closures:

Parts:

PRs:

Coverage

Summarize the test coverage of this feature.

Consider what the "edges" of this feature are. We're particularly interested in seeing tests that assure us about exactly what nearby things we're not stabilizing. Tests should of course comprehensively demonstrate that the feature works. Think too about demonstrating the diagnostics seen when common mistakes are made and the feature is used incorrectly.

Within each test, include a comment at the top describing the purpose of the test and what set of invariants it intends to demonstrate. This is a great help to our review.

Describe any known or intentional gaps in test coverage.

Contextualize and link to test folders and individual tests.

Tests (directory):

  • Location
    • May or may not be preceded by a shebang
    • Can't have comments (or other non-whitespace content) before opening
    • Whitespace is allowed before frontmatter
  • General
    • CR/LR is supported
    • Invalid to have multiple frontmatters
  • Infostring
    • Can't have a , in the infostring
    • Can't have a leading . or -
    • Can have a . or - elsewhere
    • Can be preceded by horizontal whitespace
  • Fences
    • Invalid to have non-whitespace content after close
    • Invalid to have whitespace between newline and fence
    • Horizontal whitespace is allowed after fences
    • Fence must be closed
      • On missing close, recover after use
    • Open close lengths must match
  • Content
    • Cover whitespace corner cases in content
    • Multi-byte characters don't cause crashes
    • Allow characters not accepted by the lexer
  • Escaping
    • Non-leading --- doesn't need escaping
    • More - escape lines starting with fewer -
  • Other uses
    • include! doesn't treat --- as frontmatter
    • proc-macro doesn't treat --- as frontmatter

Outstanding bugs

What outstanding bugs involve this feature? List them. Should any block the stabilization? Discuss why or why not.

No known bugs

Outstanding FIXMEs

What FIXMEs are still in the code for that feature and why is it OK to leave them there?

An idea for future editions

// FIXME(frontmatter): Consider stripping frontmatter in a future edition. We can't strip them
// in the current edition since that would be breaking.
// See also <https://github.com/rust-lang/rust/issues/145520>.
// Alternatively, stop stripping shebangs here, too, if T-lang and crater approve.
source_file_to_stream(psess, source_file, override_span, StripTokens::Shebang)

Diagnostic improvements can be iterated on over time, particularly with use feedback

---
//~^ ERROR: expected item, found `-`
// FIXME(frontmatter): make this diagnostic better
---

---
---
---
//~^ ERROR: expected item, found `-`
// FIXME(frontmatter): make this diagnostic better
---

Both can be handled as need is shown.

Tool changes

What changes must be made to our other tools to support this feature. Has this work been done? Link to any relevant PRs and issues.

Breaking changes

If this stabilization represents a known breaking change, link to the crater report, the analysis of the crater report, and to all PRs we've made to ecosystem projects affected by this breakage. Discuss any limitations of what we're able to know about or to fix.

No known breaking change

Type system, opsem

Compile-time checks

What compilation-time checks are done that are needed to prevent undefined behavior?

Link to tests demonstrating that these checks are being done.

N/A, this is only relevant to tools inspecting the source

Type system rules

What type system rules are enforced for this feature and what is the purpose of each?

N/A, this is only relevant to tools inspecting the source

Sound by default?

Does the feature's implementation need specific checks to prevent UB, or is it sound by default and need specific opt-in to perform the dangerous/unsafe operations? If it is not sound by default, what is the rationale?

No, this is only relevant to tools inspecting the source

Breaks the AM?

Can users use this feature to introduce undefined behavior, or use this feature to break the abstraction of Rust and expose the underlying assembly-level implementation? Describe this if so.

No, this is only relevant to tools inspecting the source

Common interactions

Temporaries

Does this feature introduce new expressions that can produce temporaries? What are the scopes of those temporaries?

No, this is only relevant to tools inspecting the source

Drop order

Does this feature raise questions about the order in which we should drop values? Talk about the decisions made here and how they're consistent with our earlier decisions.

No, this is only relevant to tools inspecting the source

Pre-expansion / post-expansion

Does this feature raise questions about what should be accepted pre-expansion (e.g. in code covered by #[cfg(false)]) versus what should be accepted post-expansion? What decisions were made about this?

No, this is only relevant to tools inspecting the source

Edition hygiene

If this feature is gated on an edition, how do we decide, in the context of the edition hygiene of tokens, whether to accept or reject code. E.g., what token do we use to decide?

N/A, this is independent of editions

SemVer implications

Does this feature create any new ways in which library authors must take care to prevent breaking downstreams when making minor-version releases? Describe these. Are these new hazards "major" or "minor" according to RFC 1105?

N/A, downstream users cannot access this feature

Exposing other features

Are there any other unstable features whose behavior may be exposed by this feature in any way? What features present the highest risk of that?

Not aware of any

History

List issues and PRs that are important for understanding how we got here.

PRs

Acknowledgments

Open items

List any known items that have not yet been completed and that should be before this is stabilized.

@epage epage added T-lang Relevant to the language team F-frontmatter `#![feature(frontmatter)]` labels Oct 23, 2025
@rustbot
Copy link
Collaborator

rustbot commented Oct 23, 2025

Some changes occurred in src/doc/style-guide

cc @rust-lang/style

@rustbot rustbot added S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. T-style Relevant to the style team, which will review and decide on the PR/issue. labels Oct 23, 2025
@rustbot
Copy link
Collaborator

rustbot commented Oct 23, 2025

r? @davidtwco

rustbot has assigned @davidtwco.
They will have a look at your PR within the next two weeks and either review your PR or reassign to another reviewer.

Use r? to explicitly pick a reviewer

gate_all!(unsafe_fields, "`unsafe` fields are experimental");
gate_all!(unsafe_binders, "unsafe binder types are experimental");
gate_all!(contracts, "contracts are incomplete");
gate_all!(contracts_internals, "contract internal machinery is for internal use only");
Copy link
Member

@fmease fmease Oct 23, 2025

Choose a reason for hiding this comment

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

(Commenting on an arbitrary line to make this discussion threaded)

From the PR description (emphasis and ellipses mine):

Post-RFC changes

[…]

  • acceptable places for frontmatter
    • […]
    • rustc: support removed from […] include! […]
    • […]
    • include! can be used to inject code into the middle of a file which becomes ambiguous between a frontmatter start and a very negated number (----x)

In #146340 I actually struck a (temporary) compromise: We do still strip/lex/recognize frontmatter (and shebang) in item-context include!s. However, we no longer strip frontmatter in expression/statement-context include!s like in let _ = include!(…); (to prevent the manifold negation backcompat issue you've rightly mentioned).

Now, I don't know what's best here. I'm eager to know your and T-lang's stance on the matter. Note that we do strip shebang in expression/statement-context include!s which I consider to be quite odd (but still understandable on a lexical level). I have an open PR #146377 which would stop stripping shebang in that position, too. I still need to rebase+polish, lang-nominate and possibly crater it. The outcome of that T-lang discussion likely affects the decision mentioned in the first paragraph (†).

(†): If that PR was accepted it would mean that we would strip shebang+frontmatter in item-ctxt includes and wouldn't strip either(!) shebang or frontmatter in expr/stmt-ctxt includes which would make the behavior of shebang+frontmatter consistent thereby fulfilling the original goal of "This applies anywhere shebang stripping is performed." in this specific case (obviously the goal wasn't achieved in other cases, like in the proc_macro API case).

@traviscross traviscross added the I-lang-radar Items that are on lang's radar and will need eventual work or consideration. label Oct 23, 2025
epage added a commit to epage/rust that referenced this pull request Oct 24, 2025
When working on the stabilization report (rust-lang#148051),
I found it annoying to determine what cases were covered because areas
of the frontmatter feature were either not in the file name or in
inconsistent locations.

This moves the area of frontmatter to the start of the file name and the
moves to more specific the later in the file name so coverage is easier
to see.
bors added a commit that referenced this pull request Oct 24, 2025
test(frontmatter): Rename tests to make coverage more obvious

When working on the stabilization report (#148051), I found it annoying to determine what cases were covered because areas of the frontmatter feature were either not in the file name or in inconsistent locations.

This moves the area of frontmatter to the start of the file name and the moves to more specific the later in the file name so coverage is easier to see.

Tracking issue: #136889
jhpratt added a commit to jhpratt/rust that referenced this pull request Oct 25, 2025
test(frontmatter): Rename tests to make coverage more obvious

When working on the stabilization report (rust-lang#148051), I found it annoying to determine what cases were covered because areas of the frontmatter feature were either not in the file name or in inconsistent locations.

This moves the area of frontmatter to the start of the file name and the moves to more specific the later in the file name so coverage is easier to see.

Tracking issue: rust-lang#136889
jhpratt added a commit to jhpratt/rust that referenced this pull request Oct 25, 2025
test(frontmatter): Rename tests to make coverage more obvious

When working on the stabilization report (rust-lang#148051), I found it annoying to determine what cases were covered because areas of the frontmatter feature were either not in the file name or in inconsistent locations.

This moves the area of frontmatter to the start of the file name and the moves to more specific the later in the file name so coverage is easier to see.

Tracking issue: rust-lang#136889
rust-timer added a commit that referenced this pull request Oct 25, 2025
Rollup merge of #148073 - epage:org-frontmatter, r=jieyouxu

test(frontmatter): Rename tests to make coverage more obvious

When working on the stabilization report (#148051), I found it annoying to determine what cases were covered because areas of the frontmatter feature were either not in the file name or in inconsistent locations.

This moves the area of frontmatter to the start of the file name and the moves to more specific the later in the file name so coverage is easier to see.

Tracking issue: #136889
Copy link
Member

@davidtwco davidtwco left a comment

Choose a reason for hiding this comment

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

Implementation of this LGTM, r=me once t-lang has approved stabilisation

View changes since this review

@bors
Copy link
Collaborator

bors commented Oct 25, 2025

☔ The latest upstream changes (presumably #148090) made this pull request unmergeable. Please resolve the merge conflicts.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

F-frontmatter `#![feature(frontmatter)]` I-lang-radar Items that are on lang's radar and will need eventual work or consideration. S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. T-lang Relevant to the language team T-style Relevant to the style team, which will review and decide on the PR/issue.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Tracking Issue for frontmatter

7 participants