blob: 1924db99f21f5ad723425827ff65024d3b164339 [file] [log] [blame]
<!DOCTYPE HTML>
<html lang="en" class="light sidebar-visible" dir="ltr">
<head>
<!-- Book generated using mdBook -->
<meta charset="UTF-8">
<title>Stability attributes - Rust Compiler Development Guide</title>
<!-- Custom HTML head -->
<meta name="description" content="A guide to developing the Rust compiler (rustc)">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="theme-color" content="#ffffff">
<link rel="icon" href="favicon.svg">
<link rel="shortcut icon" href="favicon.png">
<link rel="stylesheet" href="css/variables.css">
<link rel="stylesheet" href="css/general.css">
<link rel="stylesheet" href="css/chrome.css">
<link rel="stylesheet" href="css/print.css" media="print">
<!-- Fonts -->
<link rel="stylesheet" href="FontAwesome/css/font-awesome.css">
<link rel="stylesheet" href="fonts/fonts.css">
<!-- Highlight.js Stylesheets -->
<link rel="stylesheet" id="highlight-css" href="highlight.css">
<link rel="stylesheet" id="tomorrow-night-css" href="tomorrow-night.css">
<link rel="stylesheet" id="ayu-highlight-css" href="ayu-highlight.css">
<!-- Custom theme stylesheets -->
<!-- Provide site root and default themes to javascript -->
<script>
const path_to_root = "";
const default_light_theme = "light";
const default_dark_theme = "navy";
</script>
<!-- Start loading toc.js asap -->
<script src="toc.js"></script>
</head>
<body>
<div id="body-container">
<!-- Work around some values being stored in localStorage wrapped in quotes -->
<script>
try {
let theme = localStorage.getItem('mdbook-theme');
let sidebar = localStorage.getItem('mdbook-sidebar');
if (theme.startsWith('"') && theme.endsWith('"')) {
localStorage.setItem('mdbook-theme', theme.slice(1, theme.length - 1));
}
if (sidebar.startsWith('"') && sidebar.endsWith('"')) {
localStorage.setItem('mdbook-sidebar', sidebar.slice(1, sidebar.length - 1));
}
} catch (e) { }
</script>
<!-- Set the theme before any content is loaded, prevents flash -->
<script>
const default_theme = window.matchMedia("(prefers-color-scheme: dark)").matches ? default_dark_theme : default_light_theme;
let theme;
try { theme = localStorage.getItem('mdbook-theme'); } catch(e) { }
if (theme === null || theme === undefined) { theme = default_theme; }
const html = document.documentElement;
html.classList.remove('light')
html.classList.add(theme);
html.classList.add("js");
</script>
<input type="checkbox" id="sidebar-toggle-anchor" class="hidden">
<!-- Hide / unhide sidebar before it is displayed -->
<script>
let sidebar = null;
const sidebar_toggle = document.getElementById("sidebar-toggle-anchor");
if (document.body.clientWidth >= 1080) {
try { sidebar = localStorage.getItem('mdbook-sidebar'); } catch(e) { }
sidebar = sidebar || 'visible';
} else {
sidebar = 'hidden';
}
sidebar_toggle.checked = sidebar === 'visible';
html.classList.remove('sidebar-visible');
html.classList.add("sidebar-" + sidebar);
</script>
<nav id="sidebar" class="sidebar" aria-label="Table of contents">
<!-- populated by js -->
<mdbook-sidebar-scrollbox class="sidebar-scrollbox"></mdbook-sidebar-scrollbox>
<noscript>
<iframe class="sidebar-iframe-outer" src="toc.html"></iframe>
</noscript>
<div id="sidebar-resize-handle" class="sidebar-resize-handle">
<div class="sidebar-resize-indicator"></div>
</div>
</nav>
<div id="page-wrapper" class="page-wrapper">
<div class="page">
<div id="menu-bar-hover-placeholder"></div>
<div id="menu-bar" class="menu-bar sticky">
<div class="left-buttons">
<label id="sidebar-toggle" class="icon-button" for="sidebar-toggle-anchor" title="Toggle Table of Contents" aria-label="Toggle Table of Contents" aria-controls="sidebar">
<i class="fa fa-bars"></i>
</label>
<button id="theme-toggle" class="icon-button" type="button" title="Change theme" aria-label="Change theme" aria-haspopup="true" aria-expanded="false" aria-controls="theme-list">
<i class="fa fa-paint-brush"></i>
</button>
<ul id="theme-list" class="theme-popup" aria-label="Themes" role="menu">
<li role="none"><button role="menuitem" class="theme" id="default_theme">Auto</button></li>
<li role="none"><button role="menuitem" class="theme" id="light">Light</button></li>
<li role="none"><button role="menuitem" class="theme" id="rust">Rust</button></li>
<li role="none"><button role="menuitem" class="theme" id="coal">Coal</button></li>
<li role="none"><button role="menuitem" class="theme" id="navy">Navy</button></li>
<li role="none"><button role="menuitem" class="theme" id="ayu">Ayu</button></li>
</ul>
<button id="search-toggle" class="icon-button" type="button" title="Search. (Shortkey: s)" aria-label="Toggle Searchbar" aria-expanded="false" aria-keyshortcuts="S" aria-controls="searchbar">
<i class="fa fa-search"></i>
</button>
</div>
<h1 class="menu-title">Rust Compiler Development Guide</h1>
<div class="right-buttons">
<a href="print.html" title="Print this book" aria-label="Print this book">
<i id="print-button" class="fa fa-print"></i>
</a>
<a href="https://github.com/rust-lang/rustc-dev-guide" title="Git repository" aria-label="Git repository">
<i id="git-repository-button" class="fa fa-github"></i>
</a>
<a href="https://github.com/rust-lang/rustc-dev-guide/edit/master/src/stability.md" title="Suggest an edit" aria-label="Suggest an edit">
<i id="git-edit-button" class="fa fa-edit"></i>
</a>
</div>
</div>
<div id="search-wrapper" class="hidden">
<form id="searchbar-outer" class="searchbar-outer">
<input type="search" id="searchbar" name="searchbar" placeholder="Search this book ..." aria-controls="searchresults-outer" aria-describedby="searchresults-header">
</form>
<div id="searchresults-outer" class="searchresults-outer hidden">
<div id="searchresults-header" class="searchresults-header"></div>
<ul id="searchresults">
</ul>
</div>
</div>
<!-- Apply ARIA attributes after the sidebar and the sidebar toggle button are added to the DOM -->
<script>
document.getElementById('sidebar-toggle').setAttribute('aria-expanded', sidebar === 'visible');
document.getElementById('sidebar').setAttribute('aria-hidden', sidebar !== 'visible');
Array.from(document.querySelectorAll('#sidebar a')).forEach(function(link) {
link.setAttribute('tabIndex', sidebar === 'visible' ? 0 : -1);
});
</script>
<div id="content" class="content">
<main>
<h1 id="stability-attributes"><a class="header" href="#stability-attributes">Stability attributes</a></h1>
<p>This section is about the stability attributes and schemes that allow stable
APIs to use unstable APIs internally in the rustc standard library.</p>
<p><strong>NOTE</strong>: this section is for <em>library</em> features, not <em>language</em> features. For instructions on
stabilizing a language feature see <a href="./stabilization_guide.html">Stabilizing Features</a>.</p>
<ul>
<li><a href="#unstable">unstable</a></li>
<li><a href="#stable">stable</a></li>
<li><a href="#rustc_const_unstable">rustc_const_unstable</a></li>
<li><a href="#rustc_const_stable">rustc_const_stable</a></li>
<li><a href="#rustc_const_stable_indirect">rustc_const_stable_indirect</a></li>
<li><a href="#rustc_intrinsic_const_stable_indirect">rustc_intrinsic_const_stable_indirect</a></li>
<li><a href="#rustc_default_body_unstable">rustc_default_body_unstable</a></li>
<li><a href="#stabilizing-a-library-feature">Stabilizing a library feature</a></li>
<li><a href="#allow_internal_unstable">allow_internal_unstable</a></li>
<li><a href="#rustc_allow_const_fn_unstable">rustc_allow_const_fn_unstable</a></li>
<li><a href="#staged_api">staged_api</a></li>
<li><a href="#deprecated">deprecated</a></li>
</ul>
<h2 id="unstable"><a class="header" href="#unstable">unstable</a></h2>
<p>The <code>#[unstable(feature = "foo", issue = "1234", reason = "lorem ipsum")]</code>
attribute explicitly marks an item as unstable. Items that are marked as
"unstable" cannot be used without a corresponding <code>#![feature]</code> attribute on
the crate, even on a nightly compiler. This restriction only applies across
crate boundaries, unstable items may be used within the crate that defines
them.</p>
<p>The <code>issue</code> field specifies the associated GitHub <a href="https://github.com/rust-lang/rust/issues">issue number</a>. This field is
required and all unstable features should have an associated tracking issue. In
rare cases where there is no sensible value <code>issue = "none"</code> is used.</p>
<p>The <code>unstable</code> attribute infects all sub-items, where the attribute doesn't
have to be reapplied. So if you apply this to a module, all items in the module
will be unstable.</p>
<p>You can make specific sub-items stable by using the <code>#[stable]</code> attribute on
them. The stability scheme works similarly to how <code>pub</code> works. You can have
public functions of nonpublic modules and you can have stable functions in
unstable modules or vice versa.</p>
<p>Previously, due to a <a href="https://github.com/rust-lang/rust/issues/15702">rustc bug</a>, stable items inside unstable modules were
available to stable code in that location.
As of <!-- date-check --> September 2024, items with <a href="https://github.com/rust-lang/rust/issues/113387">accidentally stabilized
paths</a> are marked with the <code>#[rustc_allowed_through_unstable_modules]</code> attribute
to prevent code dependent on those paths from breaking. Do <em>not</em> add this attribute
to any more items unless that is needed to avoid breaking changes.</p>
<p>The <code>unstable</code> attribute may also have the <code>soft</code> value, which makes it a
future-incompatible deny-by-default lint instead of a hard error. This is used
by the <code>bench</code> attribute which was accidentally accepted in the past. This
prevents breaking dependencies by leveraging Cargo's lint capping.</p>
<h2 id="stable"><a class="header" href="#stable">stable</a></h2>
<p>The <code>#[stable(feature = "foo", since = "1.420.69")]</code> attribute explicitly
marks an item as stabilized. Note that stable functions may use unstable things in their body.</p>
<h2 id="rustc_const_unstable"><a class="header" href="#rustc_const_unstable">rustc_const_unstable</a></h2>
<p>The <code>#[rustc_const_unstable(feature = "foo", issue = "1234", reason = "lorem ipsum")]</code> has the same interface as the <code>unstable</code> attribute. It is used to mark
<code>const fn</code> as having their constness be unstable. This is only needed in rare cases:</p>
<ul>
<li>If a <code>const fn</code> makes use of unstable language features or intrinsics.
(The compiler will tell you to add the attribute if you run into this.)</li>
<li>If a <code>const fn</code> is <code>#[stable]</code> but not yet intended to be const-stable.</li>
<li>To change the feature gate that is required to call a const-unstable intrinsic.</li>
</ul>
<p>Const-stability differs from regular stability in that it is <em>recursive</em>: a
<code>#[rustc_const_unstable(...)]</code> function cannot even be indirectly called from stable code. This is
to avoid accidentally leaking unstable compiler implementation artifacts to stable code or locking
us into the accidental quirks of an incomplete implementation. See the rustc_const_stable_indirect
and rustc_allow_const_fn_unstable attributes below for how to fine-tune this check.</p>
<h2 id="rustc_const_stable"><a class="header" href="#rustc_const_stable">rustc_const_stable</a></h2>
<p>The <code>#[rustc_const_stable(feature = "foo", since = "1.420.69")]</code> attribute explicitly marks
a <code>const fn</code> as having its constness be <code>stable</code>.</p>
<h2 id="rustc_const_stable_indirect"><a class="header" href="#rustc_const_stable_indirect">rustc_const_stable_indirect</a></h2>
<p>The <code>#[rustc_const_stable_indirect]</code> attribute can be added to a <code>#[rustc_const_unstable(...)]</code>
function to make it callable from <code>#[rustc_const_stable(...)]</code> functions. This indicates that the
function is ready for stable in terms of its implementation (i.e., it doesn't use any unstable
compiler features); the only reason it is not const-stable yet are API concerns.</p>
<p>This should also be added to lang items for which const-calls are synthesized in the compiler, to
ensure those calls do not bypass recursive const stability rules.</p>
<h2 id="rustc_intrinsic_const_stable_indirect"><a class="header" href="#rustc_intrinsic_const_stable_indirect">rustc_intrinsic_const_stable_indirect</a></h2>
<p>On an intrinsic, this attribute marks the intrinsic as "ready to be used by public stable functions".
If the intrinsic has a <code>rustc_const_unstable</code> attribute, it should be removed.
<strong>Adding this attribute to an intrinsic requires t-lang and wg-const-eval approval!</strong></p>
<h2 id="rustc_default_body_unstable"><a class="header" href="#rustc_default_body_unstable">rustc_default_body_unstable</a></h2>
<p>The <code>#[rustc_default_body_unstable(feature = "foo", issue = "1234", reason = "lorem ipsum")]</code> attribute has the same interface as the <code>unstable</code> attribute.
It is used to mark the default implementation for an item within a trait as
unstable.
A trait with a default-body-unstable item can be implemented stably by providing
an explicit body for any such item, or the default body can be used by enabling
its corresponding <code>#![feature]</code>.</p>
<h2 id="stabilizing-a-library-feature"><a class="header" href="#stabilizing-a-library-feature">Stabilizing a library feature</a></h2>
<p>To stabilize a feature, follow these steps:</p>
<ol>
<li>Ask a <strong>@T-libs-api</strong> member to start an FCP on the tracking issue and wait for
the FCP to complete (with <code>disposition-merge</code>).</li>
<li>Change <code>#[unstable(...)]</code> to <code>#[stable(since = "CURRENT_RUSTC_VERSION")]</code>.</li>
<li>Remove <code>#![feature(...)]</code> from any test or doc-test for this API. If the feature is used in the
compiler or tools, remove it from there as well.</li>
<li>If this is a <code>const fn</code>, add <code>#[rustc_const_stable(since = "CURRENT_RUSTC_VERSION")]</code>.
Alternatively, if this is not supposed to be const-stabilized yet,
add <code>#[rustc_const_unstable(...)]</code> for some new feature gate (with a new tracking issue).</li>
<li>Open a PR against <code>rust-lang/rust</code>.
<ul>
<li>Add the appropriate labels: <code>@rustbot modify labels: +T-libs-api</code>.</li>
<li>Link to the tracking issue and say "Closes #XXXXX".</li>
</ul>
</li>
</ol>
<p>You can see an example of stabilizing a feature with
<a href="https://github.com/rust-lang/rust/issues/81656">tracking issue #81656 with FCP</a>
and the associated
<a href="https://github.com/rust-lang/rust/pull/84642">implementation PR #84642</a>.</p>
<h2 id="allow_internal_unstable"><a class="header" href="#allow_internal_unstable">allow_internal_unstable</a></h2>
<p>Macros and compiler desugarings expose their bodies to the call
site. To work around not being able to use unstable things in the standard
library's macros, there's the <code>#[allow_internal_unstable(feature1, feature2)]</code>
attribute that allows the given features to be used in stable macros.</p>
<p>Note that if a macro is used in const context and generates a call to a
<code>#[rustc_const_unstable(...)]</code> function, that will <em>still</em> be rejected even with
<code>allow_internal_unstable</code>. Add <code>#[rustc_const_stable_indirect]</code> to the function to ensure the macro
cannot accidentally bypass the recursive const stability checks.</p>
<h2 id="rustc_allow_const_fn_unstable"><a class="header" href="#rustc_allow_const_fn_unstable">rustc_allow_const_fn_unstable</a></h2>
<p>As explained above, no unstable const features are allowed inside stable <code>const fn</code>, not even
indirectly.</p>
<p>However, sometimes we do know that a feature will get stabilized, just not when, or there is a
stable (but e.g. runtime-slow) workaround, so we could always fall back to some stable version if we
scrapped the unstable feature. In those cases, the <code>[rustc_allow_const_fn_unstable(feature1, feature2)]</code> attribute can be used to allow some unstable features in the body of a stable (or
indirectly stable) <code>const fn</code>.</p>
<p>You also need to take care to uphold the <code>const fn</code> invariant that calling it at runtime and
compile-time needs to behave the same (see also <a href="https://www.ralfj.de/blog/2018/07/19/const.html">this blog post</a>). This means that you
may not create a <code>const fn</code> that e.g. transmutes a memory address to an integer,
because the addresses of things are nondeterministic and often unknown at
compile-time.</p>
<p><strong>Always ping @rust-lang/wg-const-eval if you are adding more
<code>rustc_allow_const_fn_unstable</code> attributes to any <code>const fn</code>.</strong></p>
<h2 id="staged_api"><a class="header" href="#staged_api">staged_api</a></h2>
<p>Any crate that uses the <code>stable</code> or <code>unstable</code> attributes must include the
<code>#![feature(staged_api)]</code> attribute on the crate.</p>
<h2 id="deprecated"><a class="header" href="#deprecated">deprecated</a></h2>
<p>Deprecations in the standard library are nearly identical to deprecations in
user code. When <code>#[deprecated]</code> is used on an item, it must also have a <code>stable</code>
or <code>unstable </code>attribute.</p>
<p><code>deprecated</code> has the following form:</p>
<pre><code class="language-rust ignore">#[deprecated(
since = "1.38.0",
note = "explanation for deprecation",
suggestion = "other_function"
)]</code></pre>
<p>The <code>suggestion</code> field is optional. If given, it should be a string that can be
used as a machine-applicable suggestion to correct the warning. This is
typically used when the identifier is renamed, but no other significant changes
are necessary. When the <code>suggestion</code> field is used, you need to have
<code>#![feature(deprecated_suggestion)]</code> at the crate root.</p>
<p>Another difference from user code is that the <code>since</code> field is actually checked
against the current version of <code>rustc</code>. If <code>since</code> is in a future version, then
the <code>deprecated_in_future</code> lint is triggered which is default <code>allow</code>, but most
of the standard library raises it to a warning with
<code>#![warn(deprecated_in_future)]</code>.</p>
</main>
<nav class="nav-wrapper" aria-label="Page navigation">
<!-- Mobile navigation buttons -->
<a rel="prev" href="implementing_new_features.html" class="mobile-nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
<i class="fa fa-angle-left"></i>
</a>
<a rel="next prefetch" href="stabilization_guide.html" class="mobile-nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
<i class="fa fa-angle-right"></i>
</a>
<div style="clear: both"></div>
</nav>
</div>
</div>
<nav class="nav-wide-wrapper" aria-label="Page navigation">
<a rel="prev" href="implementing_new_features.html" class="nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
<i class="fa fa-angle-left"></i>
</a>
<a rel="next prefetch" href="stabilization_guide.html" class="nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
<i class="fa fa-angle-right"></i>
</a>
</nav>
</div>
<script>
window.playground_copyable = true;
</script>
<script src="elasticlunr.min.js"></script>
<script src="mark.min.js"></script>
<script src="searcher.js"></script>
<script src="clipboard.min.js"></script>
<script src="highlight.js"></script>
<script src="book.js"></script>
<!-- Custom JS scripts -->
<script src="mermaid.min.js"></script>
<script src="mermaid-init.js"></script>
</div>
</body>
</html>