Auto merge of #139949 - matthiaskrgr:rollup-pxc5tsx, r=matthiaskrgr

Rollup of 8 pull requests

Successful merges:

 - #138632 (Stabilize `cfg_boolean_literals`)
 - #139416 (unstable book; document `macro_metavar_expr_concat`)
 - #139782 (Consistent with treating Ctor Call as Struct in liveness analysis)
 - #139885 (document RUSTC_BOOTSTRAP, RUSTC_OVERRIDE_VERSION_STRING, and -Z allow-features in the unstable book)
 - #139904 (Explicitly annotate edition for `unpretty=expanded` and `unpretty=hir` tests)
 - #139932 (transmutability: Refactor tests for simplicity)
 - #139944 (Move eager translation to a method on Diag)
 - #139948 (git: ignore `60600a6fa4` for blame purposes)

r? `@ghost`
`@rustbot` modify labels: rollup
This commit is contained in:
bors 2025-04-17 11:21:54 +00:00
commit 883f9f72e8
240 changed files with 1038 additions and 978 deletions

View file

@ -31,3 +31,5 @@ ec2cc761bc7067712ecc7734502f703fe3b024c8
c682aa162b0d41e21cc6748f4fecfe01efb69d1f
# reformat with updated edition 2024
1fcae03369abb4c2cc180cd5a49e1f4440a81300
# Breaking up of compiletest runtest.rs
60600a6fa403216bfd66e04f948b1822f6450af7

View file

@ -2,7 +2,7 @@
use rustc_ast::ParamKindOrd;
use rustc_errors::codes::*;
use rustc_errors::{Applicability, Diag, EmissionGuarantee, SubdiagMessageOp, Subdiagnostic};
use rustc_errors::{Applicability, Diag, EmissionGuarantee, Subdiagnostic};
use rustc_macros::{Diagnostic, Subdiagnostic};
use rustc_span::{Ident, Span, Symbol};
@ -394,11 +394,7 @@ pub(crate) struct EmptyLabelManySpans(pub Vec<Span>);
// The derive for `Vec<Span>` does multiple calls to `span_label`, adding commas between each
impl Subdiagnostic for EmptyLabelManySpans {
fn add_to_diag_with<G: EmissionGuarantee, F: SubdiagMessageOp<G>>(
self,
diag: &mut Diag<'_, G>,
_: &F,
) {
fn add_to_diag<G: EmissionGuarantee>(self, diag: &mut Diag<'_, G>) {
diag.span_labels(self.0, "");
}
}
@ -749,11 +745,7 @@ pub(crate) struct StableFeature {
}
impl Subdiagnostic for StableFeature {
fn add_to_diag_with<G: EmissionGuarantee, F: SubdiagMessageOp<G>>(
self,
diag: &mut Diag<'_, G>,
_: &F,
) {
fn add_to_diag<G: EmissionGuarantee>(self, diag: &mut Diag<'_, G>) {
diag.arg("name", self.name);
diag.arg("since", self.since);
diag.help(fluent::ast_passes_stable_since);

View file

@ -7,7 +7,6 @@ use rustc_session::config::ExpectedValues;
use rustc_session::lint::BuiltinLintDiag;
use rustc_session::lint::builtin::UNEXPECTED_CFGS;
use rustc_session::parse::feature_err;
use rustc_span::symbol::kw;
use rustc_span::{Span, Symbol, sym};
use crate::session_diagnostics::{self, UnsupportedLiteralReason};
@ -89,20 +88,6 @@ pub fn eval_condition(
let cfg = match cfg {
MetaItemInner::MetaItem(meta_item) => meta_item,
MetaItemInner::Lit(MetaItemLit { kind: LitKind::Bool(b), .. }) => {
if let Some(features) = features {
// we can't use `try_gate_cfg` as symbols don't differentiate between `r#true`
// and `true`, and we want to keep the former working without feature gate
gate_cfg(
&(
if *b { kw::True } else { kw::False },
sym::cfg_boolean_literals,
|features: &Features| features.cfg_boolean_literals(),
),
cfg.span(),
sess,
features,
);
}
return *b;
}
_ => {

View file

@ -1,7 +1,7 @@
use rustc_errors::codes::*;
use rustc_errors::{
Diag, DiagCtxtHandle, Diagnostic, EmissionGuarantee, Level, MultiSpan, SingleLabelManySpans,
SubdiagMessageOp, Subdiagnostic,
Subdiagnostic,
};
use rustc_macros::{Diagnostic, Subdiagnostic};
use rustc_span::{Ident, Span, Symbol};
@ -684,13 +684,9 @@ pub(crate) struct FormatUnusedArg {
// Allow the singular form to be a subdiagnostic of the multiple-unused
// form of diagnostic.
impl Subdiagnostic for FormatUnusedArg {
fn add_to_diag_with<G: EmissionGuarantee, F: SubdiagMessageOp<G>>(
self,
diag: &mut Diag<'_, G>,
f: &F,
) {
fn add_to_diag<G: EmissionGuarantee>(self, diag: &mut Diag<'_, G>) {
diag.arg("named", self.named);
let msg = f(diag, crate::fluent_generated::builtin_macros_format_unused_arg.into());
let msg = diag.eagerly_translate(crate::fluent_generated::builtin_macros_format_unused_arg);
diag.span_label(self.span, msg);
}
}

View file

@ -6,7 +6,7 @@ use rustc_abi::WrappingRange;
use rustc_errors::codes::*;
use rustc_errors::{
Diag, DiagArgValue, DiagCtxtHandle, DiagMessage, Diagnostic, EmissionGuarantee, Level,
MultiSpan, SubdiagMessageOp, Subdiagnostic,
MultiSpan, Subdiagnostic,
};
use rustc_hir::ConstContext;
use rustc_macros::{Diagnostic, LintDiagnostic, Subdiagnostic};
@ -290,11 +290,7 @@ pub struct FrameNote {
}
impl Subdiagnostic for FrameNote {
fn add_to_diag_with<G: EmissionGuarantee, F: SubdiagMessageOp<G>>(
self,
diag: &mut Diag<'_, G>,
f: &F,
) {
fn add_to_diag<G: EmissionGuarantee>(self, diag: &mut Diag<'_, G>) {
diag.arg("times", self.times);
diag.arg("where_", self.where_);
diag.arg("instance", self.instance);
@ -302,7 +298,7 @@ impl Subdiagnostic for FrameNote {
if self.has_label && !self.span.is_dummy() {
span.push_span_label(self.span, fluent::const_eval_frame_note_last);
}
let msg = f(diag, fluent::const_eval_frame_note.into());
let msg = diag.eagerly_translate(fluent::const_eval_frame_note);
diag.span_note(span, msg);
}
}

View file

@ -181,22 +181,9 @@ where
Self: Sized,
{
/// Add a subdiagnostic to an existing diagnostic.
fn add_to_diag<G: EmissionGuarantee>(self, diag: &mut Diag<'_, G>) {
self.add_to_diag_with(diag, &|_, m| m);
fn add_to_diag<G: EmissionGuarantee>(self, diag: &mut Diag<'_, G>);
}
/// Add a subdiagnostic to an existing diagnostic where `f` is invoked on every message used
/// (to optionally perform eager translation).
fn add_to_diag_with<G: EmissionGuarantee, F: SubdiagMessageOp<G>>(
self,
diag: &mut Diag<'_, G>,
f: &F,
);
}
pub trait SubdiagMessageOp<G: EmissionGuarantee> =
Fn(&mut Diag<'_, G>, SubdiagMessage) -> SubdiagMessage;
/// Trait implemented by lint types. This should not be implemented manually. Instead, use
/// `#[derive(LintDiagnostic)]` -- see [rustc_macros::LintDiagnostic].
#[rustc_diagnostic_item = "LintDiagnostic"]
@ -1227,15 +1214,21 @@ impl<'a, G: EmissionGuarantee> Diag<'a, G> {
/// interpolated variables).
#[rustc_lint_diagnostics]
pub fn subdiagnostic(&mut self, subdiagnostic: impl Subdiagnostic) -> &mut Self {
let dcx = self.dcx;
subdiagnostic.add_to_diag_with(self, &|diag, msg| {
let args = diag.args.iter();
let msg = diag.subdiagnostic_message_to_diagnostic_message(msg);
dcx.eagerly_translate(msg, args)
});
subdiagnostic.add_to_diag(self);
self
}
/// Fluent variables are not namespaced from each other, so when
/// `Diagnostic`s and `Subdiagnostic`s use the same variable name,
/// one value will clobber the other. Eagerly translating the
/// diagnostic uses the variables defined right then, before the
/// clobbering occurs.
pub fn eagerly_translate(&self, msg: impl Into<SubdiagMessage>) -> SubdiagMessage {
let args = self.args.iter();
let msg = self.subdiagnostic_message_to_diagnostic_message(msg.into());
self.dcx.eagerly_translate(msg, args)
}
with_fn! { with_span,
/// Add a span.
#[rustc_lint_diagnostics]

View file

@ -19,7 +19,7 @@ use {rustc_ast as ast, rustc_hir as hir};
use crate::diagnostic::DiagLocation;
use crate::{
Diag, DiagArgValue, DiagCtxtHandle, Diagnostic, EmissionGuarantee, ErrCode, IntoDiagArg, Level,
SubdiagMessageOp, Subdiagnostic, fluent_generated as fluent,
Subdiagnostic, fluent_generated as fluent,
};
pub struct DiagArgFromDisplay<'a>(pub &'a dyn fmt::Display);
@ -384,11 +384,7 @@ pub struct SingleLabelManySpans {
pub label: &'static str,
}
impl Subdiagnostic for SingleLabelManySpans {
fn add_to_diag_with<G: EmissionGuarantee, F: SubdiagMessageOp<G>>(
self,
diag: &mut Diag<'_, G>,
_: &F,
) {
fn add_to_diag<G: EmissionGuarantee>(self, diag: &mut Diag<'_, G>) {
diag.span_labels(self.spans, self.label);
}
}

View file

@ -47,7 +47,7 @@ pub use codes::*;
pub use diagnostic::{
BugAbort, Diag, DiagArg, DiagArgMap, DiagArgName, DiagArgValue, DiagInner, DiagStyledString,
Diagnostic, EmissionGuarantee, FatalAbort, IntoDiagArg, LintDiagnostic, StringPart, Subdiag,
SubdiagMessageOp, Subdiagnostic,
Subdiagnostic,
};
pub use diagnostic_impls::{
DiagArgFromDisplay, DiagSymbolList, ElidedLifetimeInPathSubdiag, ExpectedLifetimeParameter,

View file

@ -95,6 +95,8 @@ declare_features! (
(accepted, c_unwind, "1.81.0", Some(74990)),
/// Allows `#[cfg_attr(predicate, multiple, attributes, here)]`.
(accepted, cfg_attr_multi, "1.33.0", Some(54881)),
/// Allows the use of `#[cfg(<true/false>)]`.
(accepted, cfg_boolean_literals, "CURRENT_RUSTC_VERSION", Some(131204)),
/// Allows the use of `#[cfg(doctest)]`, set when rustdoc is collecting doctests.
(accepted, cfg_doctest, "1.40.0", Some(62210)),
/// Enables `#[cfg(panic = "...")]` config key.

View file

@ -391,8 +391,6 @@ declare_features! (
(unstable, async_trait_bounds, "1.85.0", Some(62290)),
/// Allows using C-variadics.
(unstable, c_variadic, "1.34.0", Some(44930)),
/// Allows the use of `#[cfg(<true/false>)]`.
(unstable, cfg_boolean_literals, "1.83.0", Some(131204)),
/// Allows the use of `#[cfg(contract_checks)` to check if contract checks are enabled.
(unstable, cfg_contract_checks, "1.86.0", Some(128044)),
/// Allows the use of `#[cfg(overflow_checks)` to check if integer overflow behaviour.

View file

@ -5,7 +5,7 @@ use std::borrow::Cow;
use rustc_errors::codes::*;
use rustc_errors::{
Applicability, Diag, DiagArgValue, DiagSymbolList, EmissionGuarantee, IntoDiagArg, MultiSpan,
SubdiagMessageOp, Subdiagnostic,
Subdiagnostic,
};
use rustc_macros::{Diagnostic, LintDiagnostic, Subdiagnostic};
use rustc_middle::ty::{self, Ty};
@ -270,11 +270,7 @@ pub(crate) struct SuggestAnnotations {
pub suggestions: Vec<SuggestAnnotation>,
}
impl Subdiagnostic for SuggestAnnotations {
fn add_to_diag_with<G: EmissionGuarantee, F: SubdiagMessageOp<G>>(
self,
diag: &mut Diag<'_, G>,
_: &F,
) {
fn add_to_diag<G: EmissionGuarantee>(self, diag: &mut Diag<'_, G>) {
if self.suggestions.is_empty() {
return;
}
@ -337,11 +333,7 @@ pub(crate) struct TypeMismatchFruTypo {
}
impl Subdiagnostic for TypeMismatchFruTypo {
fn add_to_diag_with<G: EmissionGuarantee, F: SubdiagMessageOp<G>>(
self,
diag: &mut Diag<'_, G>,
_f: &F,
) {
fn add_to_diag<G: EmissionGuarantee>(self, diag: &mut Diag<'_, G>) {
diag.arg("expr", self.expr.as_deref().unwrap_or("NONE"));
// Only explain that `a ..b` is a range if it's split up
@ -599,11 +591,7 @@ pub(crate) struct RemoveSemiForCoerce {
}
impl Subdiagnostic for RemoveSemiForCoerce {
fn add_to_diag_with<G: EmissionGuarantee, F: SubdiagMessageOp<G>>(
self,
diag: &mut Diag<'_, G>,
_f: &F,
) {
fn add_to_diag<G: EmissionGuarantee>(self, diag: &mut Diag<'_, G>) {
let mut multispan: MultiSpan = self.semi.into();
multispan.push_span_label(self.expr, fluent::hir_typeck_remove_semi_for_coerce_expr);
multispan.push_span_label(self.ret, fluent::hir_typeck_remove_semi_for_coerce_ret);
@ -778,20 +766,16 @@ pub(crate) enum CastUnknownPointerSub {
}
impl rustc_errors::Subdiagnostic for CastUnknownPointerSub {
fn add_to_diag_with<G: EmissionGuarantee, F: SubdiagMessageOp<G>>(
self,
diag: &mut Diag<'_, G>,
f: &F,
) {
fn add_to_diag<G: EmissionGuarantee>(self, diag: &mut Diag<'_, G>) {
match self {
CastUnknownPointerSub::To(span) => {
let msg = f(diag, crate::fluent_generated::hir_typeck_label_to);
let msg = diag.eagerly_translate(fluent::hir_typeck_label_to);
diag.span_label(span, msg);
let msg = f(diag, crate::fluent_generated::hir_typeck_note);
let msg = diag.eagerly_translate(fluent::hir_typeck_note);
diag.note(msg);
}
CastUnknownPointerSub::From(span) => {
let msg = f(diag, crate::fluent_generated::hir_typeck_label_from);
let msg = diag.eagerly_translate(fluent::hir_typeck_label_from);
diag.span_label(span, msg);
}
}

View file

@ -1,5 +1,5 @@
use rustc_errors::codes::*;
use rustc_errors::{Diag, EmissionGuarantee, SubdiagMessageOp, Subdiagnostic};
use rustc_errors::{Diag, EmissionGuarantee, Subdiagnostic};
use rustc_macros::{Diagnostic, Subdiagnostic};
use rustc_session::lint::Level;
use rustc_span::{Span, Symbol};
@ -26,11 +26,7 @@ pub(crate) enum OverruledAttributeSub {
}
impl Subdiagnostic for OverruledAttributeSub {
fn add_to_diag_with<G: EmissionGuarantee, F: SubdiagMessageOp<G>>(
self,
diag: &mut Diag<'_, G>,
_f: &F,
) {
fn add_to_diag<G: EmissionGuarantee>(self, diag: &mut Diag<'_, G>) {
match self {
OverruledAttributeSub::DefaultSource { id } => {
diag.note(fluent::lint_default_source);

View file

@ -3,9 +3,7 @@ use std::ops::ControlFlow;
use hir::intravisit::{self, Visitor};
use rustc_ast::Recovered;
use rustc_errors::{
Applicability, Diag, EmissionGuarantee, SubdiagMessageOp, Subdiagnostic, SuggestionStyle,
};
use rustc_errors::{Applicability, Diag, EmissionGuarantee, Subdiagnostic, SuggestionStyle};
use rustc_hir::{self as hir, HirIdSet};
use rustc_macros::{LintDiagnostic, Subdiagnostic};
use rustc_middle::ty::adjustment::Adjust;
@ -327,11 +325,7 @@ struct IfLetRescopeRewrite {
}
impl Subdiagnostic for IfLetRescopeRewrite {
fn add_to_diag_with<G: EmissionGuarantee, F: SubdiagMessageOp<G>>(
self,
diag: &mut Diag<'_, G>,
f: &F,
) {
fn add_to_diag<G: EmissionGuarantee>(self, diag: &mut Diag<'_, G>) {
let mut suggestions = vec![];
for match_head in self.match_heads {
match match_head {
@ -360,7 +354,7 @@ impl Subdiagnostic for IfLetRescopeRewrite {
.chain(repeat('}').take(closing_brackets.count))
.collect(),
));
let msg = f(diag, crate::fluent_generated::lint_suggestion);
let msg = diag.eagerly_translate(crate::fluent_generated::lint_suggestion);
diag.multipart_suggestion_with_style(
msg,
suggestions,

View file

@ -6,7 +6,7 @@ use rustc_abi::ExternAbi;
use rustc_errors::codes::*;
use rustc_errors::{
Applicability, Diag, DiagArgValue, DiagMessage, DiagStyledString, ElidedLifetimeInPathSubdiag,
EmissionGuarantee, LintDiagnostic, MultiSpan, SubdiagMessageOp, Subdiagnostic, SuggestionStyle,
EmissionGuarantee, LintDiagnostic, MultiSpan, Subdiagnostic, SuggestionStyle,
};
use rustc_hir::def::Namespace;
use rustc_hir::def_id::DefId;
@ -449,11 +449,7 @@ pub(crate) struct BuiltinUnpermittedTypeInitSub {
}
impl Subdiagnostic for BuiltinUnpermittedTypeInitSub {
fn add_to_diag_with<G: EmissionGuarantee, F: SubdiagMessageOp<G>>(
self,
diag: &mut Diag<'_, G>,
_f: &F,
) {
fn add_to_diag<G: EmissionGuarantee>(self, diag: &mut Diag<'_, G>) {
let mut err = self.err;
loop {
if let Some(span) = err.span {
@ -504,11 +500,7 @@ pub(crate) struct BuiltinClashingExternSub<'a> {
}
impl Subdiagnostic for BuiltinClashingExternSub<'_> {
fn add_to_diag_with<G: EmissionGuarantee, F: SubdiagMessageOp<G>>(
self,
diag: &mut Diag<'_, G>,
_f: &F,
) {
fn add_to_diag<G: EmissionGuarantee>(self, diag: &mut Diag<'_, G>) {
let mut expected_str = DiagStyledString::new();
expected_str.push(self.expected.fn_sig(self.tcx).to_string(), false);
let mut found_str = DiagStyledString::new();
@ -824,11 +816,7 @@ pub(crate) struct HiddenUnicodeCodepointsDiagLabels {
}
impl Subdiagnostic for HiddenUnicodeCodepointsDiagLabels {
fn add_to_diag_with<G: EmissionGuarantee, F: SubdiagMessageOp<G>>(
self,
diag: &mut Diag<'_, G>,
_f: &F,
) {
fn add_to_diag<G: EmissionGuarantee>(self, diag: &mut Diag<'_, G>) {
for (c, span) in self.spans {
diag.span_label(span, format!("{c:?}"));
}
@ -842,11 +830,7 @@ pub(crate) enum HiddenUnicodeCodepointsDiagSub {
// Used because of multiple multipart_suggestion and note
impl Subdiagnostic for HiddenUnicodeCodepointsDiagSub {
fn add_to_diag_with<G: EmissionGuarantee, F: SubdiagMessageOp<G>>(
self,
diag: &mut Diag<'_, G>,
_f: &F,
) {
fn add_to_diag<G: EmissionGuarantee>(self, diag: &mut Diag<'_, G>) {
match self {
HiddenUnicodeCodepointsDiagSub::Escape { spans } => {
diag.multipart_suggestion_with_style(
@ -1015,11 +999,7 @@ pub(crate) struct NonBindingLetSub {
}
impl Subdiagnostic for NonBindingLetSub {
fn add_to_diag_with<G: EmissionGuarantee, F: SubdiagMessageOp<G>>(
self,
diag: &mut Diag<'_, G>,
_f: &F,
) {
fn add_to_diag<G: EmissionGuarantee>(self, diag: &mut Diag<'_, G>) {
let can_suggest_binding = self.drop_fn_start_end.is_some() || !self.is_assign_desugar;
if can_suggest_binding {
@ -1303,11 +1283,7 @@ pub(crate) enum NonSnakeCaseDiagSub {
}
impl Subdiagnostic for NonSnakeCaseDiagSub {
fn add_to_diag_with<G: EmissionGuarantee, F: SubdiagMessageOp<G>>(
self,
diag: &mut Diag<'_, G>,
_f: &F,
) {
fn add_to_diag<G: EmissionGuarantee>(self, diag: &mut Diag<'_, G>) {
match self {
NonSnakeCaseDiagSub::Label { span } => {
diag.span_label(span, fluent::lint_label);
@ -1629,11 +1605,7 @@ pub(crate) enum OverflowingBinHexSign {
}
impl Subdiagnostic for OverflowingBinHexSign {
fn add_to_diag_with<G: EmissionGuarantee, F: SubdiagMessageOp<G>>(
self,
diag: &mut Diag<'_, G>,
_f: &F,
) {
fn add_to_diag<G: EmissionGuarantee>(self, diag: &mut Diag<'_, G>) {
match self {
OverflowingBinHexSign::Positive => {
diag.note(fluent::lint_positive_note);

View file

@ -20,14 +20,12 @@ use crate::diagnostics::utils::{
/// The central struct for constructing the `add_to_diag` method from an annotated struct.
pub(crate) struct SubdiagnosticDerive {
diag: syn::Ident,
f: syn::Ident,
}
impl SubdiagnosticDerive {
pub(crate) fn new() -> Self {
let diag = format_ident!("diag");
let f = format_ident!("f");
Self { diag, f }
Self { diag }
}
pub(crate) fn into_tokens(self, mut structure: Structure<'_>) -> TokenStream {
@ -86,19 +84,16 @@ impl SubdiagnosticDerive {
};
let diag = &self.diag;
let f = &self.f;
// FIXME(edition_2024): Fix the `keyword_idents_2024` lint to not trigger here?
#[allow(keyword_idents_2024)]
let ret = structure.gen_impl(quote! {
gen impl rustc_errors::Subdiagnostic for @Self {
fn add_to_diag_with<__G, __F>(
fn add_to_diag<__G>(
self,
#diag: &mut rustc_errors::Diag<'_, __G>,
#f: &__F
) where
__G: rustc_errors::EmissionGuarantee,
__F: rustc_errors::SubdiagMessageOp<__G>,
{
#implementation
}
@ -384,11 +379,10 @@ impl<'parent, 'a> SubdiagnosticDeriveVariantBuilder<'parent, 'a> {
Ok(quote! {})
}
"subdiagnostic" => {
let f = &self.parent.f;
let diag = &self.parent.diag;
let binding = &info.binding;
self.has_subdiagnostic = true;
Ok(quote! { #binding.add_to_diag_with(#diag, #f); })
Ok(quote! { #binding.add_to_diag(#diag); })
}
_ => {
let mut span_attrs = vec![];
@ -531,12 +525,11 @@ impl<'parent, 'a> SubdiagnosticDeriveVariantBuilder<'parent, 'a> {
let span_field = self.span_field.value_ref();
let diag = &self.parent.diag;
let f = &self.parent.f;
let mut calls = TokenStream::new();
for (kind, slug, no_span) in kind_slugs {
let message = format_ident!("__message");
calls.extend(
quote! { let #message = #f(#diag, crate::fluent_generated::#slug.into()); },
quote! { let #message = #diag.eagerly_translate(crate::fluent_generated::#slug); },
);
let name = format_ident!(

View file

@ -2,7 +2,7 @@ use rustc_data_structures::fx::FxIndexMap;
use rustc_errors::codes::*;
use rustc_errors::{
Applicability, Diag, DiagArgValue, DiagCtxtHandle, Diagnostic, EmissionGuarantee, Level,
MultiSpan, SubdiagMessageOp, Subdiagnostic, pluralize,
MultiSpan, Subdiagnostic, pluralize,
};
use rustc_macros::{Diagnostic, LintDiagnostic, Subdiagnostic};
use rustc_middle::ty::{self, Ty};
@ -546,11 +546,7 @@ pub(crate) struct UnsafeNotInheritedLintNote {
}
impl Subdiagnostic for UnsafeNotInheritedLintNote {
fn add_to_diag_with<G: EmissionGuarantee, F: SubdiagMessageOp<G>>(
self,
diag: &mut Diag<'_, G>,
_f: &F,
) {
fn add_to_diag<G: EmissionGuarantee>(self, diag: &mut Diag<'_, G>) {
diag.span_note(self.signature_span, fluent::mir_build_unsafe_fn_safe_body);
let body_start = self.body_span.shrink_to_lo();
let body_end = self.body_span.shrink_to_hi();
@ -1031,11 +1027,7 @@ pub(crate) struct Variant {
}
impl<'tcx> Subdiagnostic for AdtDefinedHere<'tcx> {
fn add_to_diag_with<G: EmissionGuarantee, F: SubdiagMessageOp<G>>(
self,
diag: &mut Diag<'_, G>,
_f: &F,
) {
fn add_to_diag<G: EmissionGuarantee>(self, diag: &mut Diag<'_, G>) {
diag.arg("ty", self.ty);
let mut spans = MultiSpan::from(self.adt_def_span);
@ -1117,11 +1109,7 @@ pub(crate) struct Rust2024IncompatiblePatSugg {
}
impl Subdiagnostic for Rust2024IncompatiblePatSugg {
fn add_to_diag_with<G: EmissionGuarantee, F: SubdiagMessageOp<G>>(
self,
diag: &mut Diag<'_, G>,
_f: &F,
) {
fn add_to_diag<G: EmissionGuarantee>(self, diag: &mut Diag<'_, G>) {
// Format and emit explanatory notes about default binding modes. Reversing the spans' order
// means if we have nested spans, the innermost ones will be visited first.
for (span, def_br_mutbl) in self.default_mode_labels.into_iter().rev() {

View file

@ -512,23 +512,17 @@ struct LocalLabel<'a> {
/// A custom `Subdiagnostic` implementation so that the notes are delivered in a specific order
impl Subdiagnostic for LocalLabel<'_> {
fn add_to_diag_with<
G: rustc_errors::EmissionGuarantee,
F: rustc_errors::SubdiagMessageOp<G>,
>(
self,
diag: &mut rustc_errors::Diag<'_, G>,
f: &F,
) {
fn add_to_diag<G: rustc_errors::EmissionGuarantee>(self, diag: &mut rustc_errors::Diag<'_, G>) {
diag.arg("name", self.name);
diag.arg("is_generated_name", self.is_generated_name);
diag.arg("is_dropped_first_edition_2024", self.is_dropped_first_edition_2024);
let msg = f(diag, crate::fluent_generated::mir_transform_tail_expr_local.into());
let msg = diag.eagerly_translate(crate::fluent_generated::mir_transform_tail_expr_local);
diag.span_label(self.span, msg);
for dtor in self.destructors {
dtor.add_to_diag_with(diag, f);
dtor.add_to_diag(diag);
}
let msg = f(diag, crate::fluent_generated::mir_transform_label_local_epilogue);
let msg =
diag.eagerly_translate(crate::fluent_generated::mir_transform_label_local_epilogue);
diag.span_label(self.span, msg);
}
}

View file

@ -7,8 +7,7 @@ use rustc_ast::util::parser::ExprPrecedence;
use rustc_ast::{Path, Visibility};
use rustc_errors::codes::*;
use rustc_errors::{
Applicability, Diag, DiagCtxtHandle, Diagnostic, EmissionGuarantee, Level, SubdiagMessageOp,
Subdiagnostic,
Applicability, Diag, DiagCtxtHandle, Diagnostic, EmissionGuarantee, Level, Subdiagnostic,
};
use rustc_macros::{Diagnostic, Subdiagnostic};
use rustc_session::errors::ExprParenthesesNeeded;
@ -1550,11 +1549,7 @@ pub(crate) struct FnTraitMissingParen {
}
impl Subdiagnostic for FnTraitMissingParen {
fn add_to_diag_with<G: EmissionGuarantee, F: SubdiagMessageOp<G>>(
self,
diag: &mut Diag<'_, G>,
_: &F,
) {
fn add_to_diag<G: EmissionGuarantee>(self, diag: &mut Diag<'_, G>) {
diag.span_label(self.span, crate::fluent_generated::parse_fn_trait_missing_paren);
diag.span_suggestion_short(
self.span.shrink_to_hi(),

View file

@ -5,7 +5,7 @@ use rustc_ast::Label;
use rustc_errors::codes::*;
use rustc_errors::{
Applicability, Diag, DiagCtxtHandle, DiagSymbolList, Diagnostic, EmissionGuarantee, Level,
MultiSpan, SubdiagMessageOp, Subdiagnostic,
MultiSpan, Subdiagnostic,
};
use rustc_hir::{self as hir, ExprKind, Target};
use rustc_macros::{Diagnostic, LintDiagnostic, Subdiagnostic};
@ -1852,11 +1852,7 @@ pub(crate) struct UnusedVariableStringInterp {
}
impl Subdiagnostic for UnusedVariableStringInterp {
fn add_to_diag_with<G: EmissionGuarantee, F: SubdiagMessageOp<G>>(
self,
diag: &mut Diag<'_, G>,
_f: &F,
) {
fn add_to_diag<G: EmissionGuarantee>(self, diag: &mut Diag<'_, G>) {
diag.span_label(self.lit, crate::fluent_generated::passes_maybe_string_interpolation);
diag.multipart_suggestion(
crate::fluent_generated::passes_string_interpolation_only_works,

View file

@ -1020,7 +1020,10 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
}
hir::ExprKind::Call(ref f, args) => {
let succ = self.check_is_ty_uninhabited(expr, succ);
let is_ctor = |f: &Expr<'_>| matches!(f.kind, hir::ExprKind::Path(hir::QPath::Resolved(_, path)) if matches!(path.res, rustc_hir::def::Res::Def(rustc_hir::def::DefKind::Ctor(_, _), _)));
let succ =
if !is_ctor(f) { self.check_is_ty_uninhabited(expr, succ) } else { succ };
let succ = self.propagate_through_exprs(args, succ);
self.propagate_through_expr(f, succ)
}

View file

@ -1,4 +1,4 @@
use rustc_errors::{Diag, EmissionGuarantee, SubdiagMessageOp, Subdiagnostic};
use rustc_errors::{Diag, EmissionGuarantee, Subdiagnostic};
use rustc_macros::{LintDiagnostic, Subdiagnostic};
use rustc_middle::ty::Ty;
use rustc_span::Span;
@ -55,11 +55,7 @@ pub struct Overlap {
}
impl Subdiagnostic for Overlap {
fn add_to_diag_with<G: EmissionGuarantee, F: SubdiagMessageOp<G>>(
self,
diag: &mut Diag<'_, G>,
_: &F,
) {
fn add_to_diag<G: EmissionGuarantee>(self, diag: &mut Diag<'_, G>) {
let Overlap { span, range } = self;
// FIXME(mejrs) unfortunately `#[derive(LintDiagnostic)]`
@ -103,11 +99,7 @@ pub struct GappedRange {
}
impl Subdiagnostic for GappedRange {
fn add_to_diag_with<G: EmissionGuarantee, F: SubdiagMessageOp<G>>(
self,
diag: &mut Diag<'_, G>,
_: &F,
) {
fn add_to_diag<G: EmissionGuarantee>(self, diag: &mut Diag<'_, G>) {
let GappedRange { span, gap, first_range } = self;
// FIXME(mejrs) unfortunately `#[derive(LintDiagnostic)]`

View file

@ -4,7 +4,7 @@ use rustc_data_structures::fx::{FxHashSet, FxIndexSet};
use rustc_errors::codes::*;
use rustc_errors::{
Applicability, Diag, DiagCtxtHandle, DiagMessage, DiagStyledString, Diagnostic,
EmissionGuarantee, IntoDiagArg, Level, MultiSpan, SubdiagMessageOp, Subdiagnostic,
EmissionGuarantee, IntoDiagArg, Level, MultiSpan, Subdiagnostic,
};
use rustc_hir::def::DefKind;
use rustc_hir::def_id::{DefId, LocalDefId};
@ -107,11 +107,7 @@ pub enum AdjustSignatureBorrow {
}
impl Subdiagnostic for AdjustSignatureBorrow {
fn add_to_diag_with<G: EmissionGuarantee, F: SubdiagMessageOp<G>>(
self,
diag: &mut Diag<'_, G>,
_f: &F,
) {
fn add_to_diag<G: EmissionGuarantee>(self, diag: &mut Diag<'_, G>) {
match self {
AdjustSignatureBorrow::Borrow { to_borrow } => {
diag.arg("len", to_borrow.len());
@ -381,11 +377,7 @@ pub enum RegionOriginNote<'a> {
}
impl Subdiagnostic for RegionOriginNote<'_> {
fn add_to_diag_with<G: EmissionGuarantee, F: SubdiagMessageOp<G>>(
self,
diag: &mut Diag<'_, G>,
_f: &F,
) {
fn add_to_diag<G: EmissionGuarantee>(self, diag: &mut Diag<'_, G>) {
let mut label_or_note = |span, msg: DiagMessage| {
let sub_count = diag.children.iter().filter(|d| d.span.is_dummy()).count();
let expanded_sub_count = diag.children.iter().filter(|d| !d.span.is_dummy()).count();
@ -446,11 +438,7 @@ pub enum LifetimeMismatchLabels {
}
impl Subdiagnostic for LifetimeMismatchLabels {
fn add_to_diag_with<G: EmissionGuarantee, F: SubdiagMessageOp<G>>(
self,
diag: &mut Diag<'_, G>,
_f: &F,
) {
fn add_to_diag<G: EmissionGuarantee>(self, diag: &mut Diag<'_, G>) {
match self {
LifetimeMismatchLabels::InRet { param_span, ret_span, span, label_var1 } => {
diag.span_label(param_span, fluent::trait_selection_declared_different);
@ -495,11 +483,7 @@ pub struct AddLifetimeParamsSuggestion<'a> {
}
impl Subdiagnostic for AddLifetimeParamsSuggestion<'_> {
fn add_to_diag_with<G: EmissionGuarantee, F: SubdiagMessageOp<G>>(
self,
diag: &mut Diag<'_, G>,
_f: &F,
) {
fn add_to_diag<G: EmissionGuarantee>(self, diag: &mut Diag<'_, G>) {
let mut mk_suggestion = || {
let Some(anon_reg) = self.tcx.is_suitable_region(self.generic_param_scope, self.sub)
else {
@ -689,11 +673,7 @@ pub struct IntroducesStaticBecauseUnmetLifetimeReq {
}
impl Subdiagnostic for IntroducesStaticBecauseUnmetLifetimeReq {
fn add_to_diag_with<G: EmissionGuarantee, F: SubdiagMessageOp<G>>(
mut self,
diag: &mut Diag<'_, G>,
_f: &F,
) {
fn add_to_diag<G: EmissionGuarantee>(mut self, diag: &mut Diag<'_, G>) {
self.unmet_requirements
.push_span_label(self.binding_span, fluent::trait_selection_msl_introduces_static);
diag.span_note(self.unmet_requirements, fluent::trait_selection_msl_unmet_req);
@ -1008,17 +988,13 @@ pub struct ConsiderBorrowingParamHelp {
}
impl Subdiagnostic for ConsiderBorrowingParamHelp {
fn add_to_diag_with<G: EmissionGuarantee, F: SubdiagMessageOp<G>>(
self,
diag: &mut Diag<'_, G>,
f: &F,
) {
fn add_to_diag<G: EmissionGuarantee>(self, diag: &mut Diag<'_, G>) {
let mut type_param_span: MultiSpan = self.spans.clone().into();
for &span in &self.spans {
// Seems like we can't call f() here as Into<DiagMessage> is required
type_param_span.push_span_label(span, fluent::trait_selection_tid_consider_borrowing);
}
let msg = f(diag, fluent::trait_selection_tid_param_help.into());
let msg = diag.eagerly_translate(fluent::trait_selection_tid_param_help);
diag.span_help(type_param_span, msg);
}
}
@ -1053,18 +1029,14 @@ pub struct DynTraitConstraintSuggestion {
}
impl Subdiagnostic for DynTraitConstraintSuggestion {
fn add_to_diag_with<G: EmissionGuarantee, F: SubdiagMessageOp<G>>(
self,
diag: &mut Diag<'_, G>,
f: &F,
) {
fn add_to_diag<G: EmissionGuarantee>(self, diag: &mut Diag<'_, G>) {
let mut multi_span: MultiSpan = vec![self.span].into();
multi_span.push_span_label(self.span, fluent::trait_selection_dtcs_has_lifetime_req_label);
multi_span
.push_span_label(self.ident.span, fluent::trait_selection_dtcs_introduces_requirement);
let msg = f(diag, fluent::trait_selection_dtcs_has_req_note.into());
let msg = diag.eagerly_translate(fluent::trait_selection_dtcs_has_req_note);
diag.span_note(multi_span, msg);
let msg = f(diag, fluent::trait_selection_dtcs_suggestion.into());
let msg = diag.eagerly_translate(fluent::trait_selection_dtcs_suggestion);
diag.span_suggestion_verbose(
self.span.shrink_to_hi(),
msg,
@ -1101,11 +1073,7 @@ pub struct ReqIntroducedLocations {
}
impl Subdiagnostic for ReqIntroducedLocations {
fn add_to_diag_with<G: EmissionGuarantee, F: SubdiagMessageOp<G>>(
mut self,
diag: &mut Diag<'_, G>,
f: &F,
) {
fn add_to_diag<G: EmissionGuarantee>(mut self, diag: &mut Diag<'_, G>) {
for sp in self.spans {
self.span.push_span_label(sp, fluent::trait_selection_ril_introduced_here);
}
@ -1114,7 +1082,7 @@ impl Subdiagnostic for ReqIntroducedLocations {
self.span.push_span_label(self.fn_decl_span, fluent::trait_selection_ril_introduced_by);
}
self.span.push_span_label(self.cause_span, fluent::trait_selection_ril_because_of);
let msg = f(diag, fluent::trait_selection_ril_static_introduced_by.into());
let msg = diag.eagerly_translate(fluent::trait_selection_ril_static_introduced_by);
diag.span_note(self.span, msg);
}
}
@ -1513,13 +1481,9 @@ pub struct SuggestTuplePatternMany {
}
impl Subdiagnostic for SuggestTuplePatternMany {
fn add_to_diag_with<G: EmissionGuarantee, F: SubdiagMessageOp<G>>(
self,
diag: &mut Diag<'_, G>,
f: &F,
) {
fn add_to_diag<G: EmissionGuarantee>(self, diag: &mut Diag<'_, G>) {
diag.arg("path", self.path);
let message = f(diag, crate::fluent_generated::trait_selection_stp_wrap_many.into());
let message = diag.eagerly_translate(fluent::trait_selection_stp_wrap_many);
diag.multipart_suggestions(
message,
self.compatible_variants.into_iter().map(|variant| {
@ -1752,11 +1716,7 @@ pub struct AddPreciseCapturingAndParams {
}
impl Subdiagnostic for AddPreciseCapturingAndParams {
fn add_to_diag_with<G: EmissionGuarantee, F: SubdiagMessageOp<G>>(
self,
diag: &mut Diag<'_, G>,
_f: &F,
) {
fn add_to_diag<G: EmissionGuarantee>(self, diag: &mut Diag<'_, G>) {
diag.arg("new_lifetime", self.new_lifetime);
diag.multipart_suggestion_verbose(
fluent::trait_selection_precise_capturing_new_but_apit,
@ -1896,11 +1856,7 @@ pub struct AddPreciseCapturingForOvercapture {
}
impl Subdiagnostic for AddPreciseCapturingForOvercapture {
fn add_to_diag_with<G: EmissionGuarantee, F: SubdiagMessageOp<G>>(
self,
diag: &mut Diag<'_, G>,
_f: &F,
) {
fn add_to_diag<G: EmissionGuarantee>(self, diag: &mut Diag<'_, G>) {
let applicability = if self.apit_spans.is_empty() {
Applicability::MachineApplicable
} else {

View file

@ -1,4 +1,4 @@
use rustc_errors::{Diag, EmissionGuarantee, IntoDiagArg, SubdiagMessageOp, Subdiagnostic};
use rustc_errors::{Diag, EmissionGuarantee, IntoDiagArg, Subdiagnostic};
use rustc_hir::def_id::LocalDefId;
use rustc_middle::bug;
use rustc_middle::ty::{self, TyCtxt};
@ -162,17 +162,13 @@ impl RegionExplanation<'_> {
}
impl Subdiagnostic for RegionExplanation<'_> {
fn add_to_diag_with<G: EmissionGuarantee, F: SubdiagMessageOp<G>>(
self,
diag: &mut Diag<'_, G>,
f: &F,
) {
fn add_to_diag<G: EmissionGuarantee>(self, diag: &mut Diag<'_, G>) {
diag.arg("pref_kind", self.prefix);
diag.arg("suff_kind", self.suffix);
diag.arg("desc_kind", self.desc.kind);
diag.arg("desc_arg", self.desc.arg);
let msg = f(diag, fluent::trait_selection_region_explanation.into());
let msg = diag.eagerly_translate(fluent::trait_selection_region_explanation);
if let Some(span) = self.desc.span {
diag.span_note(span, msg);
} else {

View file

@ -1,93 +1,115 @@
use itertools::Itertools;
use super::query_context::test::{Def, UltraMinimal};
use crate::maybe_transmutable::MaybeTransmutableQuery;
use crate::{Reason, layout};
mod safety {
use super::*;
use crate::Answer;
use crate::{Answer, Assume, Reason, layout};
type Tree = layout::Tree<Def, !>;
type Dfa = layout::Dfa<!>;
const DST_HAS_SAFETY_INVARIANTS: Answer<!> =
Answer::No(crate::Reason::DstMayHaveSafetyInvariants);
trait Representation {
fn is_transmutable(src: Self, dst: Self, assume: Assume) -> Answer<!>;
}
fn is_transmutable(src: &Tree, dst: &Tree, assume_safety: bool) -> crate::Answer<!> {
impl Representation for Tree {
fn is_transmutable(src: Self, dst: Self, assume: Assume) -> Answer<!> {
crate::maybe_transmutable::MaybeTransmutableQuery::new(src, dst, assume, UltraMinimal)
.answer()
}
}
impl Representation for Dfa {
fn is_transmutable(src: Self, dst: Self, assume: Assume) -> Answer<!> {
crate::maybe_transmutable::MaybeTransmutableQuery::new(src, dst, assume, UltraMinimal)
.answer()
}
}
fn is_transmutable<R: Representation + Clone>(
src: &R,
dst: &R,
assume: Assume,
) -> crate::Answer<!> {
let src = src.clone();
let dst = dst.clone();
// The only dimension of the transmutability analysis we want to test
// here is the safety analysis. To ensure this, we disable all other
// toggleable aspects of the transmutability analysis.
let assume = crate::Assume {
alignment: true,
lifetimes: true,
validity: true,
safety: assume_safety,
};
crate::maybe_transmutable::MaybeTransmutableQuery::new(src, dst, assume, UltraMinimal)
.answer()
R::is_transmutable(src, dst, assume)
}
mod safety {
use super::*;
use crate::Answer;
const DST_HAS_SAFETY_INVARIANTS: Answer<!> =
Answer::No(crate::Reason::DstMayHaveSafetyInvariants);
#[test]
fn src_safe_dst_safe() {
let src = Tree::Def(Def::NoSafetyInvariants).then(Tree::u8());
let dst = Tree::Def(Def::NoSafetyInvariants).then(Tree::u8());
assert_eq!(is_transmutable(&src, &dst, false), Answer::Yes);
assert_eq!(is_transmutable(&src, &dst, true), Answer::Yes);
assert_eq!(is_transmutable(&src, &dst, Assume::default()), Answer::Yes);
assert_eq!(
is_transmutable(&src, &dst, Assume { safety: true, ..Assume::default() }),
Answer::Yes
);
}
#[test]
fn src_safe_dst_unsafe() {
let src = Tree::Def(Def::NoSafetyInvariants).then(Tree::u8());
let dst = Tree::Def(Def::HasSafetyInvariants).then(Tree::u8());
assert_eq!(is_transmutable(&src, &dst, false), DST_HAS_SAFETY_INVARIANTS);
assert_eq!(is_transmutable(&src, &dst, true), Answer::Yes);
assert_eq!(is_transmutable(&src, &dst, Assume::default()), DST_HAS_SAFETY_INVARIANTS);
assert_eq!(
is_transmutable(&src, &dst, Assume { safety: true, ..Assume::default() }),
Answer::Yes
);
}
#[test]
fn src_unsafe_dst_safe() {
let src = Tree::Def(Def::HasSafetyInvariants).then(Tree::u8());
let dst = Tree::Def(Def::NoSafetyInvariants).then(Tree::u8());
assert_eq!(is_transmutable(&src, &dst, false), Answer::Yes);
assert_eq!(is_transmutable(&src, &dst, true), Answer::Yes);
assert_eq!(is_transmutable(&src, &dst, Assume::default()), Answer::Yes);
assert_eq!(
is_transmutable(&src, &dst, Assume { safety: true, ..Assume::default() }),
Answer::Yes
);
}
#[test]
fn src_unsafe_dst_unsafe() {
let src = Tree::Def(Def::HasSafetyInvariants).then(Tree::u8());
let dst = Tree::Def(Def::HasSafetyInvariants).then(Tree::u8());
assert_eq!(is_transmutable(&src, &dst, false), DST_HAS_SAFETY_INVARIANTS);
assert_eq!(is_transmutable(&src, &dst, true), Answer::Yes);
assert_eq!(is_transmutable(&src, &dst, Assume::default()), DST_HAS_SAFETY_INVARIANTS);
assert_eq!(
is_transmutable(&src, &dst, Assume { safety: true, ..Assume::default() }),
Answer::Yes
);
}
}
mod bool {
use super::*;
use crate::Answer;
#[test]
fn should_permit_identity_transmutation_tree() {
let answer = crate::maybe_transmutable::MaybeTransmutableQuery::new(
layout::Tree::<Def, !>::bool(),
layout::Tree::<Def, !>::bool(),
crate::Assume { alignment: false, lifetimes: false, validity: true, safety: false },
UltraMinimal,
)
.answer();
assert_eq!(answer, Answer::Yes);
let src = Tree::bool();
assert_eq!(is_transmutable(&src, &src, Assume::default()), Answer::Yes);
assert_eq!(
is_transmutable(&src, &src, Assume { validity: true, ..Assume::default() }),
Answer::Yes
);
}
#[test]
fn should_permit_identity_transmutation_dfa() {
let answer = crate::maybe_transmutable::MaybeTransmutableQuery::new(
layout::Dfa::<!>::bool(),
layout::Dfa::<!>::bool(),
crate::Assume { alignment: false, lifetimes: false, validity: true, safety: false },
UltraMinimal,
)
.answer();
assert_eq!(answer, Answer::Yes);
let src = Dfa::bool();
assert_eq!(is_transmutable(&src, &src, Assume::default()), Answer::Yes);
assert_eq!(
is_transmutable(&src, &src, Assume { validity: true, ..Assume::default() }),
Answer::Yes
);
}
#[test]
@ -122,13 +144,7 @@ mod bool {
if src_set.is_subset(&dst_set) {
assert_eq!(
Answer::Yes,
MaybeTransmutableQuery::new(
src_layout.clone(),
dst_layout.clone(),
crate::Assume { validity: false, ..crate::Assume::default() },
UltraMinimal,
)
.answer(),
is_transmutable(&src_layout, &dst_layout, Assume::default()),
"{:?} SHOULD be transmutable into {:?}",
src_layout,
dst_layout
@ -136,13 +152,11 @@ mod bool {
} else if !src_set.is_disjoint(&dst_set) {
assert_eq!(
Answer::Yes,
MaybeTransmutableQuery::new(
src_layout.clone(),
dst_layout.clone(),
crate::Assume { validity: true, ..crate::Assume::default() },
UltraMinimal,
)
.answer(),
is_transmutable(
&src_layout,
&dst_layout,
Assume { validity: true, ..Assume::default() }
),
"{:?} SHOULD be transmutable (assuming validity) into {:?}",
src_layout,
dst_layout
@ -150,13 +164,7 @@ mod bool {
} else {
assert_eq!(
Answer::No(Reason::DstIsBitIncompatible),
MaybeTransmutableQuery::new(
src_layout.clone(),
dst_layout.clone(),
crate::Assume { validity: false, ..crate::Assume::default() },
UltraMinimal,
)
.answer(),
is_transmutable(&src_layout, &dst_layout, Assume::default()),
"{:?} should NOT be transmutable into {:?}",
src_layout,
dst_layout

0
diff Normal file
View file

View file

@ -0,0 +1,14 @@
# `allow-features`
This feature is perma-unstable and has no tracking issue.
----
This flag allows limiting the features which can be enabled with `#![feature(...)]` attributes.
By default, all features are allowed on nightly and no features are allowed on stable or beta (but see [`RUSTC_BOOTSTRAP`]).
Features are comma-separated, for example `-Z allow-features=ffi_pure,f16`.
If the flag is present, any feature listed will be allowed and any feature not listed will be disallowed.
Any unrecognized feature is ignored.
[`RUSTC_BOOTSTRAP`]: ./rustc-bootstrap.html

View file

@ -0,0 +1,56 @@
# `RUSTC_BOOTSTRAP`
This feature is perma-unstable and has no tracking issue.
----
The `RUSTC_BOOTSTRAP` environment variable tells rustc to act as if it is a nightly compiler;
in particular, it allows `#![feature(...)]` attributes and `-Z` flags even on the stable release channel.
Setting `RUSTC_BOOTSTRAP=1` instructs rustc to enable this for all crates.
Setting `RUSTC_BOOTSTRAP=crate_name` instructs rustc to only apply this to crates named `crate_name`.
Setting `RUSTC_BOOTSTRAP=-1` instructs rustc to act as if it is a stable compiler, even on the nightly release channel.
Cargo disallows setting `cargo::rustc-env=RUSTC_BOOTSTRAP` in build scripts.
Build systems can limit the features they enable with [`-Z allow-features=feature1,feature2`][Z-allow-features].
Crates can fully opt out of unstable features by using [`#![forbid(unstable_features)]`][unstable-features] at the crate root (or any other way of enabling lints, such as `-F unstable-features`).
[Z-allow-features]: ./allow-features.html
[unstable-features]: ../../rustc/lints/listing/allowed-by-default.html#unstable-features
## Why does this environment variable exist?
`RUSTC_BOOTSTRAP`, as the name suggests, is used for bootstrapping the compiler from an earlier version.
In particular, nightly is built with beta, and beta is built with stable.
Since the standard library and compiler both use unstable features, `RUSTC_BOOTSTRAP` is required so that we can use the previous version to build them.
## Why is this environment variable so easy to use for people not in the rust project?
Originally, `RUSTC_BOOTSTRAP` required passing in a hash of the previous compiler version, to discourage using it for any purpose other than bootstrapping.
That constraint was later relaxed; see <https://github.com/rust-lang/rust/issues/36548> for the discussion that happened at that time.
People have at various times proposed re-adding the technical constraints.
However, doing so is extremely disruptive for several major projects that we very much want to keep using the latest stable toolchain version, such as Firefox, Rust for Linux, and Chromium.
We continue to allow `RUSTC_BOOTSTRAP` until we can come up with an alternative that does not disrupt our largest constituents.
## Stability policy
Despite being usable on stable, this is an unstable feature.
Like any other unstable feature, we reserve the right to change or remove this feature in the future, as well as any other unstable feature that it enables.
Using this feature opts you out of the normal stability/backwards compatibility guarantee of stable.
Although we do not take technical measures to prevent it from being used, we strongly discourage using this feature.
If at all possible, please contribute to stabilizing the features you care about instead of bypassing the Rust project's stability policy.
For library crates, we especially discourage the use of this feature.
The crates depending on you do not know that you use this feature, have little recourse if it breaks, and can be used in contexts that are hard to predict.
For libraries that do use this feature, please document the versions you support (including a *maximum* as well as minimum version), and a mechanism to disable it.
If you do not have a mechanism to disable the use of `RUSTC_BOOTSTRAP`, consider removing its use altogether, such that people can only use your library if they are already using a nightly toolchain.
This leaves the choice of whether to opt-out of Rust's stability guarantees up to the end user building their code.
## History
- [Allowed without a hash](https://github.com/rust-lang/rust/pull/37265) ([discussion](https://github.com/rust-lang/rust/issues/36548))
- [Extended to crate names](https://github.com/rust-lang/rust/pull/77802) ([discussion](https://github.com/rust-lang/cargo/issues/7088))
- [Disallowed for build scripts](https://github.com/rust-lang/cargo/pull/9181) ([discussion](https://github.com/rust-lang/compiler-team/issues/350))
- [Extended to emulate stable](https://github.com/rust-lang/rust/pull/132993) ([discussion](https://github.com/rust-lang/rust/issues/123404))

View file

@ -0,0 +1,39 @@
# `RUSTC_OVERRIDE_VERSION_STRING`
This feature is perma-unstable and has no tracking issue.
----
The `RUSTC_OVERRIDE_VERSION_STRING` environment variable overrides the version reported by `rustc --version`. For example:
```console
$ rustc --version
rustc 1.87.0-nightly (43f0014ef 2025-03-25)
$ env RUSTC_OVERRIDE_VERSION_STRING=1.81.0-nightly rustc --version
rustc 1.81.0-nightly
```
Note that the version string is completely overwritten; i.e. rustc discards commit hash and commit date information unless it is explicitly included in the environment variable. The string only applies to the "release" part of the version; for example:
```console
$ RUSTC_OVERRIDE_VERSION_STRING="1.81.0-nightly (aaaaaaaaa 2025-03-22)" rustc -vV
rustc 1.81.0-nightly (aaaaaaaaa 2025-03-22)
binary: rustc
commit-hash: 43f0014ef0f242418674f49052ed39b70f73bc1c
commit-date: 2025-03-25
host: x86_64-unknown-linux-gnu
release: 1.81.0-nightly (aaaaaaaaa 2025-03-22)
LLVM version: 20.1.1
```
Note here that `commit-hash` and `commit-date` do not match the values in the string, and `release` includes the fake hash and date.
This variable has no effect on whether or not unstable features are allowed to be used. It only affects the output of `--version`.
## Why does this environment variable exist?
Various library crates have incomplete or incorrect feature detection.
This environment variable allows bisecting crates that do incorrect detection with `version_check::supports_feature`.
This is not intended to be used for any other case (and, except for bisection, is not particularly useful).
See <https://github.com/rust-lang/rust/pull/124339> for further discussion.

View file

@ -1,22 +0,0 @@
# `cfg_boolean_literals`
The tracking issue for this feature is: [#131204]
[#131204]: https://github.com/rust-lang/rust/issues/131204
------------------------
The `cfg_boolean_literals` feature makes it possible to use the `true`/`false`
literal as cfg predicate. They always evaluate to true/false respectively.
## Examples
```rust
#![feature(cfg_boolean_literals)]
#[cfg(true)]
const A: i32 = 5;
#[cfg(all(false))]
const A: i32 = 58 * 89;
```

View file

@ -0,0 +1,133 @@
# `macro_metavar_expr_concat`
The tracking issue for this feature is: [#124225]
------------------------
In stable Rust, there is no way to create new identifiers by joining identifiers to literals or other identifiers without using procedural macros such as [`paste`].
`#![feature(macro_metavar_expr_concat)]` introduces a way to do this, using the concat metavariable expression.
> This feature uses the syntax from [`macro_metavar_expr`] but is otherwise
> independent. It replaces the old unstable feature [`concat_idents`].
> This is an experimental feature; it and its syntax will require a RFC before stabilization.
### Overview
`#![feature(macro_metavar_expr_concat)]` provides the `concat` metavariable expression for creating new identifiers:
```rust
#![feature(macro_metavar_expr_concat)]
macro_rules! create_some_structs {
($name:ident) => {
pub struct ${ concat(First, $name) };
pub struct ${ concat(Second, $name) };
pub struct ${ concat(Third, $name) };
}
}
create_some_structs!(Thing);
```
This macro invocation expands to:
```rust
pub struct FirstThing;
pub struct SecondThing;
pub struct ThirdThing;
```
### Syntax
This feature builds upon the metavariable expression syntax `${ .. }` as specified in [RFC 3086] ([`macro_metavar_expr`]).
`concat` is available like `${ concat(items) }`, where `items` is a comma separated sequence of idents and/or literals.
### Examples
#### Create a function or method with a concatenated name
```rust
#![feature(macro_metavar_expr_concat)]
macro_rules! make_getter {
($name:ident, $field: ident, $ret:ty) => {
impl $name {
pub fn ${ concat(get_, $field) }(&self) -> &$ret {
&self.$field
}
}
}
}
pub struct Thing {
description: String,
}
make_getter!(Thing, description, String);
```
This expands to:
```rust
pub struct Thing {
description: String,
}
impl Thing {
pub fn get_description(&self) -> &String {
&self.description
}
}
```
#### Create names for macro generated tests
```rust
#![feature(macro_metavar_expr_concat)]
macro_rules! test_math {
($integer:ident) => {
#[test]
fn ${ concat(test_, $integer, _, addition) } () {
let a: $integer = 73;
let b: $integer = 42;
assert_eq!(a + b, 115)
}
#[test]
fn ${ concat(test_, $integer, _, subtraction) } () {
let a: $integer = 73;
let b: $integer = 42;
assert_eq!(a - b, 31)
}
}
}
test_math!(i32);
test_math!(u64);
test_math!(u128);
```
Running this returns the following output:
```text
running 6 tests
test test_i32_subtraction ... ok
test test_i32_addition ... ok
test test_u128_addition ... ok
test test_u128_subtraction ... ok
test test_u64_addition ... ok
test test_u64_subtraction ... ok
test result: ok. 6 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s
```
[`paste`]: https://crates.io/crates/paste
[RFC 3086]: https://rust-lang.github.io/rfcs/3086-macro-metavar-expr.html
[`concat_idents!`]: https://doc.rust-lang.org/nightly/std/macro.concat_idents.html
[`macro_metavar_expr`]: ../language-features/macro-metavar-expr.md
[`concat_idents`]: ../library-features/concat-idents.md
[#124225]: https://github.com/rust-lang/rust/issues/124225
[declarative macros]: https://doc.rust-lang.org/stable/reference/macros-by-example.html

View file

@ -0,0 +1,10 @@
# `macro_metavar_expr`
The tracking issue for this feature is: [#83527]
------------------------
> This feature is not to be confused with [`macro_metavar_expr_concat`].
[`macro_metavar_expr_concat`]: ./macro-metavar-expr-concat.md
[#83527]: https://github.com/rust-lang/rust/issues/83527

View file

@ -6,6 +6,8 @@ The tracking issue for this feature is: [#29599]
------------------------
> This feature is expected to be superseded by [`macro_metavar_expr_concat`](../language-features/macro-metavar-expr-concat.md).
The `concat_idents` feature adds a macro for concatenating multiple identifiers
into one identifier.

View file

@ -3789,35 +3789,6 @@ The tracking issue for this feature is: [#64797]
[#64797]: https://github.com/rust-lang/rust/issues/64797
------------------------
"##,
default_severity: Severity::Allow,
warn_since: None,
deny_since: None,
},
Lint {
label: "cfg_boolean_literals",
description: r##"# `cfg_boolean_literals`
The tracking issue for this feature is: [#131204]
[#131204]: https://github.com/rust-lang/rust/issues/131204
------------------------
The `cfg_boolean_literals` feature makes it possible to use the `true`/`false`
literal as cfg predicate. They always evaluate to true/false respectively.
## Examples
```rust
#![feature(cfg_boolean_literals)]
#[cfg(true)]
const A: i32 = 5;
#[cfg(all(false))]
const A: i32 = 58 * 89;
```
"##,
default_severity: Severity::Allow,
warn_since: None,

View file

@ -2,7 +2,7 @@
fn main() {}
#[cfg(FALSE)]
#[cfg(false)]
fn syntax() {
let _ = #[attr] [];
let _ = #[attr] [0];

View file

@ -4,5 +4,5 @@
fn main() {}
#[cfg(FALSE)]
#[cfg(false)]
enum Foo { pub V, }

View file

@ -1,6 +1,6 @@
//@ pp-exact
#[cfg(FALSE)]
#[cfg(false)]
fn simple_attr() {
#[attr]
@ -10,21 +10,21 @@ fn simple_attr() {
if true {}
}
#[cfg(FALSE)]
#[cfg(false)]
fn if_else_chain() {
#[first_attr]
if true {} else if false {} else {}
}
#[cfg(FALSE)]
#[cfg(false)]
fn if_let() {
#[attr]
if let Some(_) = Some(true) {}
}
#[cfg(FALSE)]
#[cfg(false)]
fn let_attr_if() {
let _ = #[attr] if let _ = 0 {};
let _ = #[attr] if true {};

View file

@ -4,7 +4,7 @@
fn main() {}
#[cfg(FALSE)]
#[cfg(false)]
extern "C" {
static X: u8;
type X;
@ -14,7 +14,7 @@ extern "C" {
pub fn foo();
}
#[cfg(FALSE)]
#[cfg(false)]
trait T {
const X: u8;
type X;
@ -30,7 +30,7 @@ trait T {
pub default fn foo();
}
#[cfg(FALSE)]
#[cfg(false)]
impl T for S {
const X: u8;
type X;

View file

@ -1,6 +1,5 @@
//@ check-pass
#![feature(cfg_boolean_literals)]
#![feature(doc_cfg)]
#[doc(cfg(false))]

View file

@ -1,10 +1,6 @@
// #138113: rustdoc didn't gate unstable predicates inside `doc(cfg(..))`
#![feature(doc_cfg)]
// `cfg_boolean_literals`
#[doc(cfg(false))] //~ ERROR `cfg(false)` is experimental and subject to change
pub fn cfg_boolean_literals() {}
// `cfg_version`
#[doc(cfg(sanitize = "thread"))] //~ ERROR `cfg(sanitize)` is experimental and subject to change
pub fn cfg_sanitize() {}

View file

@ -1,15 +1,5 @@
error[E0658]: `cfg(false)` is experimental and subject to change
--> $DIR/doc-cfg-unstable.rs:5:11
|
LL | #[doc(cfg(false))]
| ^^^^^
|
= note: see issue #131204 <https://github.com/rust-lang/rust/issues/131204> for more information
= help: add `#![feature(cfg_boolean_literals)]` 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]: `cfg(sanitize)` is experimental and subject to change
--> $DIR/doc-cfg-unstable.rs:9:11
--> $DIR/doc-cfg-unstable.rs:5:11
|
LL | #[doc(cfg(sanitize = "thread"))]
| ^^^^^^^^^^^^^^^^^^^
@ -18,6 +8,6 @@ LL | #[doc(cfg(sanitize = "thread"))]
= help: add `#![feature(cfg_sanitize)]` 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 2 previous errors
error: aborting due to 1 previous error
For more information about this error, try `rustc --explain E0658`.

View file

@ -15,7 +15,7 @@ extern crate rustc_span;
use rustc_errors::{
Diag, DiagCtxtHandle, DiagInner, DiagMessage, Diagnostic, EmissionGuarantee, Level,
LintDiagnostic, SubdiagMessage, SubdiagMessageOp, Subdiagnostic,
LintDiagnostic, SubdiagMessage, Subdiagnostic,
};
use rustc_macros::{Diagnostic, Subdiagnostic};
use rustc_span::Span;
@ -56,10 +56,9 @@ impl<'a, G: EmissionGuarantee> Diagnostic<'a, G> for TranslatableInDiagnostic {
pub struct UntranslatableInAddtoDiag;
impl Subdiagnostic for UntranslatableInAddtoDiag {
fn add_to_diag_with<G: EmissionGuarantee, F: SubdiagMessageOp<G>>(
fn add_to_diag<G: EmissionGuarantee>(
self,
diag: &mut Diag<'_, G>,
f: &F,
) {
diag.note("untranslatable diagnostic");
//~^ ERROR diagnostics should be created using translatable messages
@ -69,10 +68,9 @@ impl Subdiagnostic for UntranslatableInAddtoDiag {
pub struct TranslatableInAddtoDiag;
impl Subdiagnostic for TranslatableInAddtoDiag {
fn add_to_diag_with<G: EmissionGuarantee, F: SubdiagMessageOp<G>>(
fn add_to_diag<G: EmissionGuarantee>(
self,
diag: &mut Diag<'_, G>,
f: &F,
) {
diag.note(crate::fluent_generated::no_crate_note);
}

View file

@ -11,19 +11,19 @@ LL | #![deny(rustc::untranslatable_diagnostic)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: diagnostics should be created using translatable messages
--> $DIR/diagnostics.rs:64:19
--> $DIR/diagnostics.rs:63:19
|
LL | diag.note("untranslatable diagnostic");
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: diagnostics should be created using translatable messages
--> $DIR/diagnostics.rs:85:19
--> $DIR/diagnostics.rs:83:19
|
LL | diag.note("untranslatable diagnostic");
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: diagnostics should only be created in `Diagnostic`/`Subdiagnostic`/`LintDiagnostic` impls
--> $DIR/diagnostics.rs:99:21
--> $DIR/diagnostics.rs:97:21
|
LL | let _diag = dcx.struct_err(crate::fluent_generated::no_crate_example);
| ^^^^^^^^^^
@ -35,37 +35,37 @@ LL | #![deny(rustc::diagnostic_outside_of_impl)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: diagnostics should only be created in `Diagnostic`/`Subdiagnostic`/`LintDiagnostic` impls
--> $DIR/diagnostics.rs:102:21
--> $DIR/diagnostics.rs:100:21
|
LL | let _diag = dcx.struct_err("untranslatable diagnostic");
| ^^^^^^^^^^
error: diagnostics should be created using translatable messages
--> $DIR/diagnostics.rs:102:32
--> $DIR/diagnostics.rs:100:32
|
LL | let _diag = dcx.struct_err("untranslatable diagnostic");
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: diagnostics should be created using translatable messages
--> $DIR/diagnostics.rs:120:7
--> $DIR/diagnostics.rs:118:7
|
LL | f("untranslatable diagnostic", crate::fluent_generated::no_crate_example);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: diagnostics should be created using translatable messages
--> $DIR/diagnostics.rs:122:50
--> $DIR/diagnostics.rs:120:50
|
LL | f(crate::fluent_generated::no_crate_example, "untranslatable diagnostic");
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: diagnostics should be created using translatable messages
--> $DIR/diagnostics.rs:124:7
--> $DIR/diagnostics.rs:122:7
|
LL | f("untranslatable diagnostic", "untranslatable diagnostic");
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: diagnostics should be created using translatable messages
--> $DIR/diagnostics.rs:124:36
--> $DIR/diagnostics.rs:122:36
|
LL | f("untranslatable diagnostic", "untranslatable diagnostic");
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^

View file

@ -1,4 +1,5 @@
//@ needs-asm-support
//@ check-pass
//@ compile-flags: -Zunpretty=expanded
//@ edition: 2015
core::arch::global_asm!("x: .byte 42");

View file

@ -7,4 +7,5 @@ extern crate std;
//@ needs-asm-support
//@ check-pass
//@ compile-flags: -Zunpretty=expanded
//@ edition: 2015
global_asm! ("x: .byte 42");

View file

@ -1,4 +1,4 @@
fn main() {
#[cfg(FALSE)]
#[cfg(false)]
<() as module>::mac!(); //~ ERROR macros cannot use qualified paths
}

View file

@ -11,7 +11,7 @@ fn f() {
};
}
#[cfg(FALSE)]
#[cfg(false)]
fn g() {
let _ = async {
for await _i in core::async_iter::from_iter(0..3) {

View file

@ -3,11 +3,11 @@
struct S;
impl S {
#[cfg(FALSE)]
#[cfg(false)]
unsafe async fn g() {} //~ ERROR expected one of `extern` or `fn`, found keyword `async`
}
#[cfg(FALSE)]
#[cfg(false)]
unsafe async fn f() {} //~ ERROR expected one of `extern` or `fn`, found keyword `async`
fn main() {}

View file

@ -1,5 +1,5 @@
// Ensure that `-Z crate-attr=cfg(FALSE)` can comment out the whole crate
//@ compile-flags: --crate-type=lib -Zcrate-attr=cfg(FALSE)
// Ensure that `-Z crate-attr=cfg(false)` can comment out the whole crate
//@ compile-flags: --crate-type=lib -Zcrate-attr=cfg(false)
//@ check-pass
// NOTE: duplicate items are load-bearing

View file

@ -1,6 +1,6 @@
//@ check-pass
#[cfg(FALSE)]
#[cfg(false)]
auto trait Foo {}
//~^ WARN `auto` traits are unstable
//~| WARN unstable syntax can change at any point in the future, causing a hard error!

View file

@ -1,4 +1,4 @@
// `#![no_std]` on a fully unconfigured crate is respected if it's placed before `cfg(FALSE)`.
// `#![no_std]` on a fully unconfigured crate is respected if it's placed before `cfg(false)`.
// This crate has no such attribute, therefore this crate does link to libstd.
#![cfg(FALSE)]
#![cfg(false)]

View file

@ -1,5 +1,5 @@
// `#![no_std]` on a fully unconfigured crate is respected if it's placed before `cfg(FALSE)`.
// `#![no_std]` on a fully unconfigured crate is respected if it's placed before `cfg(false)`.
// Therefore this crate does link to libstd.
#![cfg(FALSE)]
#![cfg(false)]
#![no_std]

View file

@ -1,8 +1,8 @@
// `#![no_std]` on a fully unconfigured crate is respected if it's placed before `cfg(FALSE)`.
// `#![no_std]` on a fully unconfigured crate is respected if it's placed before `cfg(false)`.
// Therefore this crate doesn't link to libstd.
//@ no-prefer-dynamic
#![no_std]
#![crate_type = "lib"]
#![cfg(FALSE)]
#![cfg(false)]

View file

@ -1,8 +1,8 @@
pub mod inner {
#[cfg(FALSE)]
#[cfg(false)]
pub fn uwu() {}
#[cfg(FALSE)]
#[cfg(false)]
pub mod doesnt_exist {
pub fn hello() {}
}

View file

@ -0,0 +1,14 @@
/// Test that placing a `cfg(true)` and `cfg(false)` on the same item result in
//. it being disabled.`
#[cfg(false)]
#[cfg(true)]
fn foo() {}
#[cfg(true)]
#[cfg(false)]
fn foo() {}
fn main() {
foo(); //~ ERROR cannot find function `foo` in this scope
}

View file

@ -0,0 +1,9 @@
error[E0425]: cannot find function `foo` in this scope
--> $DIR/both-true-false.rs:13:5
|
LL | foo();
| ^^^ not found in this scope
error: aborting due to 1 previous error
For more information about this error, try `rustc --explain E0425`.

View file

@ -1,10 +1,10 @@
// Features above `cfg(FALSE)` are in effect in a fully unconfigured crate (issue #104633).
// Features above `cfg(false)` are in effect in a fully unconfigured crate (issue #104633).
//@ check-pass
//@ compile-flags: --crate-type lib
#![feature(decl_macro)]
#![cfg(FALSE)]
#![cfg(false)]
#![feature(box_patterns)]
macro mac() {} // OK

View file

@ -3,7 +3,7 @@
// check that cfg correctly chooses between the macro impls (see also
// cfg-macros-foo.rs)
#[cfg(FALSE)]
#[cfg(false)]
#[macro_use]
mod foo {
macro_rules! bar {

View file

@ -11,7 +11,7 @@ fn foo(f: Foo) {
Foo::Bar => {},
#[cfg(not(FALSE))]
Foo::Baz => {},
#[cfg(FALSE)]
#[cfg(false)]
Basdfwe => {}
}
}

View file

@ -6,7 +6,7 @@
#[cfg_eval]
fn main() {
#[cfg_eval]
let _ = #[cfg(FALSE)] 0;
let _ = #[cfg(false)] 0;
//~^ ERROR removing an expression is not supported in this position
//~| ERROR expected expression, found `;`
//~| ERROR removing an expression is not supported in this position

View file

@ -1,19 +1,19 @@
error: removing an expression is not supported in this position
--> $DIR/cfg-stmt-recovery.rs:9:13
|
LL | let _ = #[cfg(FALSE)] 0;
LL | let _ = #[cfg(false)] 0;
| ^^^^^^^^^^^^^
error: expected expression, found `;`
--> $DIR/cfg-stmt-recovery.rs:9:28
|
LL | let _ = #[cfg(FALSE)] 0;
LL | let _ = #[cfg(false)] 0;
| ^ expected expression
error: removing an expression is not supported in this position
--> $DIR/cfg-stmt-recovery.rs:9:13
|
LL | let _ = #[cfg(FALSE)] 0;
LL | let _ = #[cfg(false)] 0;
| ^^^^^^^^^^^^^
error: aborting due to 3 previous errors

View file

@ -7,47 +7,47 @@
fn main() {
let a = 413;
#[cfg(FALSE)]
#[cfg(false)]
let a = ();
assert_eq!(a, 413);
let mut b = 612;
#[cfg(FALSE)]
#[cfg(false)]
{
b = 1111;
}
assert_eq!(b, 612);
#[cfg(FALSE)]
#[cfg(false)]
undefined_fn();
#[cfg(FALSE)]
#[cfg(false)]
undefined_macro!();
#[cfg(FALSE)]
#[cfg(false)]
undefined_macro![];
#[cfg(FALSE)]
#[cfg(false)]
undefined_macro!{};
// pretty printer bug...
// #[cfg(FALSE)]
// #[cfg(false)]
// undefined_macro!{}
let () = (#[cfg(FALSE)] 341,); // Should this also work on parens?
let t = (1, #[cfg(FALSE)] 3, 4);
let () = (#[cfg(false)] 341,); // Should this also work on parens?
let t = (1, #[cfg(false)] 3, 4);
assert_eq!(t, (1, 4));
let f = |_: u32, _: u32| ();
f(2, 1, #[cfg(FALSE)] 6);
f(2, 1, #[cfg(false)] 6);
let _: u32 = a.clone(#[cfg(FALSE)] undefined);
let _: u32 = a.clone(#[cfg(false)] undefined);
let _: [(); 0] = [#[cfg(FALSE)] 126];
let t = [#[cfg(FALSE)] 1, 2, 6];
let _: [(); 0] = [#[cfg(false)] 126];
let t = [#[cfg(false)] 1, 2, 6];
assert_eq!(t, [2, 6]);
{
let r;
#[cfg(FALSE)]
#[cfg(false)]
(r = 5);
#[cfg(not(FALSE))]
(r = 10);
@ -75,7 +75,7 @@ fn main() {
612
});
assert_eq!((#[cfg(FALSE)] 1, #[cfg(not(FALSE))] 2), (2,));
assert_eq!((#[cfg(false)] 1, #[cfg(not(FALSE))] 2), (2,));
assert_eq!(n, 612);
// check that lints work

View file

@ -0,0 +1,9 @@
/// Test that `--cfg false` doesn't cause `cfg(false)` to evaluate to `true`
//@ compile-flags: --cfg false
#[cfg(false)]
fn foo() {}
fn main() {
foo(); //~ ERROR cannot find function `foo` in this scope
}

View file

@ -0,0 +1,9 @@
error[E0425]: cannot find function `foo` in this scope
--> $DIR/cmdline-false.rs:8:5
|
LL | foo();
| ^^^ not found in this scope
error: aborting due to 1 previous error
For more information about this error, try `rustc --explain E0425`.

View file

@ -6,16 +6,16 @@
// Crate use statements
#[cfg(FALSE)]
#[cfg(false)]
use flippity;
#[cfg(FALSE)]
#[cfg(false)]
static b: bool = false;
static b: bool = true;
mod rustrt {
#[cfg(FALSE)]
#[cfg(false)]
extern "C" {
// This symbol doesn't exist and would be a link error if this
// module was codegened
@ -25,12 +25,12 @@ mod rustrt {
extern "C" {}
}
#[cfg(FALSE)]
#[cfg(false)]
type t = isize;
type t = bool;
#[cfg(FALSE)]
#[cfg(false)]
enum tg {
foo,
}
@ -39,12 +39,12 @@ enum tg {
bar,
}
#[cfg(FALSE)]
#[cfg(false)]
struct r {
i: isize,
}
#[cfg(FALSE)]
#[cfg(false)]
fn r(i: isize) -> r {
r { i: i }
}
@ -57,7 +57,7 @@ fn r(i: isize) -> r {
r { i: i }
}
#[cfg(FALSE)]
#[cfg(false)]
mod m {
// This needs to parse but would fail in typeck. Since it's not in
// the current config it should not be typechecked.
@ -69,7 +69,7 @@ mod m {
mod m {
// Submodules have slightly different code paths than the top-level
// module, so let's make sure this jazz works here as well
#[cfg(FALSE)]
#[cfg(false)]
pub fn f() {}
pub fn f() {}
@ -77,7 +77,7 @@ mod m {
// Since the FALSE configuration isn't defined main will just be
// parsed, but nothing further will be done with it
#[cfg(FALSE)]
#[cfg(false)]
pub fn main() {
panic!()
}
@ -93,14 +93,14 @@ pub fn main() {
}
fn test_in_fn_ctxt() {
#[cfg(FALSE)]
#[cfg(false)]
fn f() {
panic!()
}
fn f() {}
f();
#[cfg(FALSE)]
#[cfg(false)]
static i: isize = 0;
static i: isize = 1;
assert_eq!(i, 1);
@ -109,7 +109,7 @@ fn test_in_fn_ctxt() {
mod test_foreign_items {
pub mod rustrt {
extern "C" {
#[cfg(FALSE)]
#[cfg(false)]
pub fn write() -> String;
pub fn write() -> String;
}
@ -117,7 +117,7 @@ mod test_foreign_items {
}
mod test_use_statements {
#[cfg(FALSE)]
#[cfg(false)]
use flippity_foo;
}
@ -127,24 +127,24 @@ mod test_methods {
}
impl Fooable for Foo {
#[cfg(FALSE)]
#[cfg(false)]
fn what(&self) {}
fn what(&self) {}
#[cfg(FALSE)]
#[cfg(false)]
fn the(&self) {}
fn the(&self) {}
}
trait Fooable {
#[cfg(FALSE)]
#[cfg(false)]
fn what(&self);
fn what(&self);
#[cfg(FALSE)]
#[cfg(false)]
fn the(&self);
fn the(&self);

View file

@ -12,7 +12,7 @@ LL | pub mod doesnt_exist {
note: the item is gated here
--> $DIR/auxiliary/cfged_out.rs:5:5
|
LL | #[cfg(FALSE)]
LL | #[cfg(false)]
| ^^^^^^^^^^^^^
error[E0425]: cannot find function `uwu` in crate `cfged_out`
@ -35,7 +35,7 @@ LL | pub fn uwu() {}
note: the item is gated here
--> $DIR/auxiliary/cfged_out.rs:2:5
|
LL | #[cfg(FALSE)]
LL | #[cfg(false)]
| ^^^^^^^^^^^^^
error[E0425]: cannot find function `meow` in module `cfged_out::inner::right`

View file

@ -1,10 +1,10 @@
pub mod inner {
#[cfg(FALSE)]
#[cfg(false)]
mod gone {
pub fn uwu() {}
}
#[cfg(FALSE)] //~ NOTE the item is gated here
#[cfg(false)] //~ NOTE the item is gated here
pub use super::uwu;
//~^ NOTE found an item that was configured out
}
@ -14,7 +14,7 @@ pub use a::x;
//~| NOTE no `x` in `a`
mod a {
#[cfg(FALSE)] //~ NOTE the item is gated here
#[cfg(false)] //~ NOTE the item is gated here
pub fn x() {}
//~^ NOTE found an item that was configured out
}
@ -25,10 +25,10 @@ pub use b::{x, y};
//~| NOTE no `y` in `b`
mod b {
#[cfg(FALSE)] //~ NOTE the item is gated here
#[cfg(false)] //~ NOTE the item is gated here
pub fn x() {}
//~^ NOTE found an item that was configured out
#[cfg(FALSE)] //~ NOTE the item is gated here
#[cfg(false)] //~ NOTE the item is gated here
pub fn y() {}
//~^ NOTE found an item that was configured out
}

View file

@ -12,7 +12,7 @@ LL | pub fn x() {}
note: the item is gated here
--> $DIR/diagnostics-reexport.rs:17:5
|
LL | #[cfg(FALSE)]
LL | #[cfg(false)]
| ^^^^^^^^^^^^^
error[E0432]: unresolved imports `b::x`, `b::y`
@ -31,7 +31,7 @@ LL | pub fn x() {}
note: the item is gated here
--> $DIR/diagnostics-reexport.rs:28:5
|
LL | #[cfg(FALSE)]
LL | #[cfg(false)]
| ^^^^^^^^^^^^^
note: found an item that was configured out
--> $DIR/diagnostics-reexport.rs:32:12
@ -41,7 +41,7 @@ LL | pub fn y() {}
note: the item is gated here
--> $DIR/diagnostics-reexport.rs:31:5
|
LL | #[cfg(FALSE)]
LL | #[cfg(false)]
| ^^^^^^^^^^^^^
error[E0425]: cannot find function `uwu` in module `inner`
@ -58,7 +58,7 @@ LL | pub use super::uwu;
note: the item is gated here
--> $DIR/diagnostics-reexport.rs:7:5
|
LL | #[cfg(FALSE)]
LL | #[cfg(false)]
| ^^^^^^^^^^^^^
error: aborting due to 3 previous errors

View file

@ -1,11 +1,11 @@
#![allow(unexpected_cfgs)] // since we want to recognize them as unexpected
pub mod inner {
#[cfg(FALSE)] //~ NOTE the item is gated here
#[cfg(false)] //~ NOTE the item is gated here
pub fn uwu() {}
//~^ NOTE found an item that was configured out
#[cfg(FALSE)] //~ NOTE the item is gated here
#[cfg(false)] //~ NOTE the item is gated here
//~^ NOTE the item is gated here
//~| NOTE the item is gated here
pub mod doesnt_exist {

View file

@ -12,7 +12,7 @@ LL | pub mod doesnt_exist {
note: the item is gated here
--> $DIR/diagnostics-same-crate.rs:8:5
|
LL | #[cfg(FALSE)]
LL | #[cfg(false)]
| ^^^^^^^^^^^^^
error[E0432]: unresolved import `super::inner::doesnt_exist`
@ -29,7 +29,7 @@ LL | pub mod doesnt_exist {
note: the item is gated here
--> $DIR/diagnostics-same-crate.rs:8:5
|
LL | #[cfg(FALSE)]
LL | #[cfg(false)]
| ^^^^^^^^^^^^^
error[E0433]: failed to resolve: could not find `doesnt_exist` in `inner`
@ -46,7 +46,7 @@ LL | pub mod doesnt_exist {
note: the item is gated here
--> $DIR/diagnostics-same-crate.rs:8:5
|
LL | #[cfg(FALSE)]
LL | #[cfg(false)]
| ^^^^^^^^^^^^^
error[E0425]: cannot find function `uwu` in module `inner`
@ -63,7 +63,7 @@ LL | pub fn uwu() {}
note: the item is gated here
--> $DIR/diagnostics-same-crate.rs:4:5
|
LL | #[cfg(FALSE)]
LL | #[cfg(false)]
| ^^^^^^^^^^^^^
error[E0425]: cannot find function `meow` in module `inner::right`

View file

@ -1,7 +1,6 @@
//@ run-pass
#![feature(link_cfg)]
#![feature(cfg_boolean_literals)]
#[cfg(true)]
fn foo() -> bool {

View file

@ -12,7 +12,7 @@
//@ compile-flags: --check-cfg=cfg() --cfg=unknown_but_active_cfg
#[allow(unexpected_cfgs)]
#[cfg(FALSE)]
#[cfg(unknown_and_inactive_cfg)]
//~^ WARNING unexpected `cfg` condition name
fn bar() {}

View file

@ -1,10 +1,10 @@
warning: unexpected `cfg` condition name: `FALSE`
warning: unexpected `cfg` condition name: `unknown_and_inactive_cfg`
--> $DIR/allow-same-level.rs:15:7
|
LL | #[cfg(FALSE)]
| ^^^^^
LL | #[cfg(unknown_and_inactive_cfg)]
| ^^^^^^^^^^^^^^^^^^^^^^^^
|
= help: to expect this configuration use `--check-cfg=cfg(FALSE)`
= help: to expect this configuration use `--check-cfg=cfg(unknown_and_inactive_cfg)`
= note: see <https://doc.rust-lang.org/nightly/rustc/check-cfg.html> for more information about checking conditional configuration
= note: `#[warn(unexpected_cfgs)]` on by default

View file

@ -6,7 +6,7 @@
#![allow(unexpected_cfgs)]
#[cfg(FALSE)]
#[cfg(false)]
fn bar() {}
fn foo() {

View file

@ -6,7 +6,7 @@
#[allow(unexpected_cfgs)]
mod aa {
#[cfg(FALSE)]
#[cfg(false)]
fn bar() {}
}

View file

@ -7,6 +7,7 @@ extern crate std;
//@ revisions: normal expanded
//@[expanded] check-pass
//@[expanded]compile-flags: -Zunpretty=expanded
//@ edition: 2015
extern "路濫狼á́́" fn foo() {}

View file

@ -1,5 +1,5 @@
error[E0703]: invalid ABI: found `路濫狼á́́`
--> $DIR/unicode.rs:5:8
--> $DIR/unicode.rs:6:8
|
LL | extern "路濫狼á́́" fn foo() {}
| ^^^^^^^^^ invalid ABI

View file

@ -1,6 +1,7 @@
//@ revisions: normal expanded
//@[expanded] check-pass
//@[expanded]compile-flags: -Zunpretty=expanded
//@ edition: 2015
extern "路濫狼á́́" fn foo() {} //[normal]~ ERROR invalid ABI

View file

@ -1,18 +1,18 @@
//@ compile-flags:--cfg yes --check-cfg=cfg(yes,no)
fn f_lt<#[cfg(yes)] 'a: 'a, #[cfg(FALSE)] T>() {}
fn f_ty<#[cfg(FALSE)] 'a: 'a, #[cfg(yes)] T>() {}
fn f_lt<#[cfg(yes)] 'a: 'a, #[cfg(false)] T>() {}
fn f_ty<#[cfg(false)] 'a: 'a, #[cfg(yes)] T>() {}
type FnGood = for<#[cfg(yes)] 'a, #[cfg(FALSE)] T> fn(); // OK
type FnBad = for<#[cfg(FALSE)] 'a, #[cfg(yes)] T> fn();
type FnGood = for<#[cfg(yes)] 'a, #[cfg(false)] T> fn(); // OK
type FnBad = for<#[cfg(false)] 'a, #[cfg(yes)] T> fn();
//~^ ERROR only lifetime parameters can be used in this context
type PolyGood = dyn for<#[cfg(yes)] 'a, #[cfg(FALSE)] T> Copy; // OK
type PolyBad = dyn for<#[cfg(FALSE)] 'a, #[cfg(yes)] T> Copy;
type PolyGood = dyn for<#[cfg(yes)] 'a, #[cfg(false)] T> Copy; // OK
type PolyBad = dyn for<#[cfg(false)] 'a, #[cfg(yes)] T> Copy;
//~^ ERROR only lifetime parameters can be used in this context
struct WhereGood where for<#[cfg(yes)] 'a, #[cfg(FALSE)] T> u8: Copy; // OK
struct WhereBad where for<#[cfg(FALSE)] 'a, #[cfg(yes)] T> u8: Copy;
struct WhereGood where for<#[cfg(yes)] 'a, #[cfg(false)] T> u8: Copy; // OK
struct WhereBad where for<#[cfg(false)] 'a, #[cfg(yes)] T> u8: Copy;
//~^ ERROR only lifetime parameters can be used in this context
fn f_lt_no<#[cfg_attr(FALSE, unknown)] 'a>() {} // OK

View file

@ -31,7 +31,7 @@ LL | struct WhereYes where for<#[cfg_attr(yes, unknown)] 'a> u8: Copy;
error[E0658]: only lifetime parameters can be used in this context
--> $DIR/cfg-generic-params.rs:7:48
|
LL | type FnBad = for<#[cfg(FALSE)] 'a, #[cfg(yes)] T> fn();
LL | type FnBad = for<#[cfg(false)] 'a, #[cfg(yes)] T> fn();
| ^
|
= note: see issue #108185 <https://github.com/rust-lang/rust/issues/108185> for more information
@ -41,7 +41,7 @@ LL | type FnBad = for<#[cfg(FALSE)] 'a, #[cfg(yes)] T> fn();
error[E0658]: only lifetime parameters can be used in this context
--> $DIR/cfg-generic-params.rs:11:54
|
LL | type PolyBad = dyn for<#[cfg(FALSE)] 'a, #[cfg(yes)] T> Copy;
LL | type PolyBad = dyn for<#[cfg(false)] 'a, #[cfg(yes)] T> Copy;
| ^
|
= note: see issue #108185 <https://github.com/rust-lang/rust/issues/108185> for more information
@ -51,7 +51,7 @@ LL | type PolyBad = dyn for<#[cfg(FALSE)] 'a, #[cfg(yes)] T> Copy;
error[E0658]: only lifetime parameters can be used in this context
--> $DIR/cfg-generic-params.rs:15:57
|
LL | struct WhereBad where for<#[cfg(FALSE)] 'a, #[cfg(yes)] T> u8: Copy;
LL | struct WhereBad where for<#[cfg(false)] 'a, #[cfg(yes)] T> u8: Copy;
| ^
|
= note: see issue #108185 <https://github.com/rust-lang/rust/issues/108185> for more information

View file

@ -1 +1 @@
#![cfg(FALSE)] //~ ERROR `main` function not found in crate `cfg_in_crate_1`
#![cfg(false)] //~ ERROR `main` function not found in crate `cfg_in_crate_1`

View file

@ -1,7 +1,7 @@
error[E0601]: `main` function not found in crate `cfg_in_crate_1`
--> $DIR/cfg-in-crate-1.rs:1:15
|
LL | #![cfg(FALSE)]
LL | #![cfg(false)]
| ^ consider adding a `main` function to `$DIR/cfg-in-crate-1.rs`
error: aborting due to 1 previous error

View file

@ -2,10 +2,10 @@
#![feature(custom_test_frameworks)]
fn main() {
let _ = #[cfg(FALSE)] ();
let _ = #[cfg(false)] ();
//~^ ERROR removing an expression is not supported in this position
let _ = 1 + 2 + #[cfg(FALSE)] 3;
let _ = 1 + 2 + #[cfg(false)] 3;
//~^ ERROR removing an expression is not supported in this position
let _ = [1, 2, 3][#[cfg(FALSE)] 1];
let _ = [1, 2, 3][#[cfg(false)] 1];
//~^ ERROR removing an expression is not supported in this position
}

View file

@ -1,19 +1,19 @@
error: removing an expression is not supported in this position
--> $DIR/cfg-non-opt-expr.rs:5:13
|
LL | let _ = #[cfg(FALSE)] ();
LL | let _ = #[cfg(false)] ();
| ^^^^^^^^^^^^^
error: removing an expression is not supported in this position
--> $DIR/cfg-non-opt-expr.rs:7:21
|
LL | let _ = 1 + 2 + #[cfg(FALSE)] 3;
LL | let _ = 1 + 2 + #[cfg(false)] 3;
| ^^^^^^^^^^^^^
error: removing an expression is not supported in this position
--> $DIR/cfg-non-opt-expr.rs:9:23
|
LL | let _ = [1, 2, 3][#[cfg(FALSE)] 1];
LL | let _ = [1, 2, 3][#[cfg(false)] 1];
| ^^^^^^^^^^^^^
error: aborting due to 3 previous errors

View file

@ -1,3 +1,3 @@
//@ ignore-test (auxiliary, used by other tests)
#![cfg_attr(all(), cfg(FALSE))]
#![cfg_attr(all(), cfg(false))]

View file

@ -1,6 +1,7 @@
// Test the AST pretty printer correctly handles default values for const generics
//@ check-pass
//@ compile-flags: -Z unpretty=expanded
//@ edition: 2015
#![crate_type = "lib"]

View file

@ -3,6 +3,7 @@
// Test the AST pretty printer correctly handles default values for const generics
//@ check-pass
//@ compile-flags: -Z unpretty=expanded
//@ edition: 2015
#![crate_type = "lib"]
#[prelude_import]

View file

@ -1,6 +1,6 @@
fn main() {}
#[cfg(FALSE)]
#[cfg(false)]
fn container() {
const unsafe WhereIsFerris Now() {}
//~^ ERROR expected one of `extern` or `fn`

View file

@ -1,6 +1,6 @@
fn main() {}
#[cfg(FALSE)]
#[cfg(false)]
fn container() {
const extern "Rust" PUT_ANYTHING_YOU_WANT_HERE bug() -> usize { 1 }
//~^ ERROR expected `fn`

View file

@ -6,7 +6,7 @@
mod to_reuse {
use crate::S;
pub fn foo<'a>(#[cfg(FALSE)] a: u8, _b: &'a S) -> u32 {
pub fn foo<'a>(#[cfg(false)] a: u8, _b: &'a S) -> u32 {
1
}
}

View file

@ -1,6 +1,7 @@
//@ check-pass
//@ proc-macro: another-proc-macro.rs
//@ compile-flags: -Zunpretty=expanded
//@ edition:2015
#![feature(derive_coerce_pointee)]

View file

@ -3,6 +3,7 @@
//@ check-pass
//@ proc-macro: another-proc-macro.rs
//@ compile-flags: -Zunpretty=expanded
//@ edition:2015
#![feature(derive_coerce_pointee)]
#[prelude_import]

View file

@ -1,5 +1,6 @@
//@ check-pass
//@ compile-flags: -Zunpretty=expanded
//@ edition: 2015
#![feature(derive_coerce_pointee)]
use std::marker::CoercePointee;

View file

@ -2,6 +2,7 @@
#![no_std]
//@ check-pass
//@ compile-flags: -Zunpretty=expanded
//@ edition: 2015
#![feature(derive_coerce_pointee)]
#[prelude_import]
use ::std::prelude::rust_2015::*;

View file

@ -7,6 +7,7 @@
//@ check-pass
//@ proc-macro: another-proc-macro.rs
//@ compile-flags: -Zunpretty=expanded
//@ edition: 2015
#![feature(derive_coerce_pointee)]

View file

@ -9,6 +9,7 @@
//@ check-pass
//@ proc-macro: another-proc-macro.rs
//@ compile-flags: -Zunpretty=expanded
//@ edition: 2015
#![feature(derive_coerce_pointee)]
#[prelude_import]

View file

@ -1,5 +1,5 @@
#![feature(stmt_expr_attributes)]
fn main() {
let _ = #[cfg(FALSE)] if true {}; //~ ERROR removing an expression
let _ = #[cfg(false)] if true {}; //~ ERROR removing an expression
}

View file

@ -1,7 +1,7 @@
error: removing an expression is not supported in this position
--> $DIR/bad-cfg.rs:4:13
|
LL | let _ = #[cfg(FALSE)] if true {};
LL | let _ = #[cfg(false)] if true {};
| ^^^^^^^^^^^^^
error: aborting due to 1 previous error

View file

@ -1,12 +1,12 @@
//@ check-pass
#[cfg(FALSE)]
#[cfg(false)]
fn simple_attr() {
#[attr] if true {}
#[allow_warnings] if true {}
}
#[cfg(FALSE)]
#[cfg(false)]
fn if_else_chain() {
#[first_attr] if true {
} else if false {
@ -14,20 +14,20 @@ fn if_else_chain() {
}
}
#[cfg(FALSE)]
#[cfg(false)]
fn if_let() {
#[attr] if let Some(_) = Some(true) {}
}
fn bar() {
#[cfg(FALSE)]
#[cfg(false)]
if true {
let x: () = true; // Should not error due to the #[cfg(FALSE)]
let x: () = true; // Should not error due to the #[cfg(false)]
}
#[cfg_attr(not(FALSE), cfg(FALSE))]
#[cfg_attr(not(FALSE), cfg(false))]
if true {
let a: () = true; // Should not error due to the applied #[cfg(FALSE)]
let a: () = true; // Should not error due to the applied #[cfg(false)]
}
}

View file

@ -1,11 +1,11 @@
#[cfg(FALSE)]
#[cfg(false)]
fn if_else_parse_error() {
if true {
} #[attr] else if false { //~ ERROR expected
}
}
#[cfg(FALSE)]
#[cfg(false)]
fn else_attr_ifparse_error() {
if true {
} else #[attr] if false { //~ ERROR outer attributes are not allowed
@ -13,7 +13,7 @@ fn else_attr_ifparse_error() {
}
}
#[cfg(FALSE)]
#[cfg(false)]
fn else_parse_error() {
if true {
} else if false {

View file

@ -3,7 +3,7 @@
fn main() {
let x = 1;
#[cfg(FALSE)]
#[cfg(false)]
if false {
x = 2;
} else if true {

Some files were not shown because too many files have changed in this diff Show more