Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
07d41a7
Correctly handle `--no-run` rustdoc test option
GuillaumeGomez Jul 13, 2025
796c4ef
Correctly handle `should_panic` doctest attribute
GuillaumeGomez Jul 7, 2025
11b7070
Add regression test for #143009
GuillaumeGomez Jul 4, 2025
21a4d9d
Update std doctests
GuillaumeGomez Jul 7, 2025
5f2ae4f
Add regression test for #143858
GuillaumeGomez Jul 13, 2025
b001ba6
Add FIXME comments to use `test::ERROR_EXIT_CODE` once public and fix…
GuillaumeGomez Aug 1, 2025
030b664
Use libtest `ERROR_EXIT_CODE` constant
GuillaumeGomez Oct 4, 2025
560d450
Correctly handle `should_panic` on targets not supporting it
GuillaumeGomez Oct 5, 2025
a11fe5d
Add diagnostic items for `pub mod consts` of FP types
samueltardieu Oct 6, 2025
b70e20a
Correctly handle `-C panic=abort` in doctests
GuillaumeGomez Oct 7, 2025
ec99e3e
clarify wording of match ergonomics diagnostics
dianne Jul 16, 2025
6060bcc
Improve error messages for failing `should_panic` doctests
GuillaumeGomez Oct 8, 2025
849feea
Add a test for the cold attribute
ehuss Oct 8, 2025
d4ecd71
format: some small cleanup
hkBst Oct 8, 2025
730221e
Fix double error for `#[no_mangle]` on closures
JonathanBrouwer Oct 8, 2025
c050bfb
Fix double error for `#[no_mangle]` on consts
JonathanBrouwer Oct 8, 2025
918e6c2
Rollup merge of #143900 - GuillaumeGomez:fix-no-run, r=fmease
matthiaskrgr Oct 8, 2025
2733474
Rollup merge of #144006 - dianne:match-ergonomics-jargon, r=Nadrieril
matthiaskrgr Oct 8, 2025
889ab6c
Rollup merge of #147420 - samueltardieu:diag-items/consts-mod, r=joboet
matthiaskrgr Oct 8, 2025
2654b69
Rollup merge of #147467 - JonathanBrouwer:double_warnings, r=Jonathan…
matthiaskrgr Oct 8, 2025
e9d8b3f
Rollup merge of #147476 - ehuss:cold-attribute-test, r=chenyukang
matthiaskrgr Oct 8, 2025
a2b476b
Rollup merge of #147481 - hkBst:format-1, r=jackh726
matthiaskrgr Oct 8, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions compiler/rustc_ast/src/token.rs
Original file line number Diff line number Diff line change
Expand Up @@ -881,11 +881,11 @@ impl Token {
}

pub fn is_qpath_start(&self) -> bool {
self == &Lt || self == &Shl
matches!(self.kind, Lt | Shl)
}

pub fn is_path_start(&self) -> bool {
self == &PathSep
self.kind == PathSep
|| self.is_qpath_start()
|| matches!(self.is_metavar_seq(), Some(MetaVarKind::Path))
|| self.is_path_segment_keyword()
Expand Down
3 changes: 3 additions & 0 deletions compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ use crate::session_diagnostics::{
NakedFunctionIncompatibleAttribute, NullOnExport, NullOnObjcClass, NullOnObjcSelector,
ObjcClassExpectedStringLiteral, ObjcSelectorExpectedStringLiteral,
};
use crate::target_checking::Policy::AllowSilent;

pub(crate) struct OptimizeParser;

Expand Down Expand Up @@ -362,6 +363,8 @@ impl<S: Stage> NoArgsAttributeParser<S> for NoMangleParser {
Allow(Target::Static),
Allow(Target::Method(MethodKind::Inherent)),
Allow(Target::Method(MethodKind::TraitImpl)),
AllowSilent(Target::Const), // Handled in the `InvalidNoMangleItems` pass
Error(Target::Closure),
]);
const CREATE: fn(Span) -> AttributeKind = AttributeKind::NoMangle;
}
Expand Down
17 changes: 15 additions & 2 deletions compiler/rustc_attr_parsing/src/target_checking.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,9 @@ impl AllowedTargets {
pub(crate) fn is_allowed(&self, target: Target) -> AllowedResult {
match self {
AllowedTargets::AllowList(list) => {
if list.contains(&Policy::Allow(target)) {
if list.contains(&Policy::Allow(target))
|| list.contains(&Policy::AllowSilent(target))
{
AllowedResult::Allowed
} else if list.contains(&Policy::Warn(target)) {
AllowedResult::Warn
Expand All @@ -40,7 +42,9 @@ impl AllowedTargets {
}
}
AllowedTargets::AllowListWarnRest(list) => {
if list.contains(&Policy::Allow(target)) {
if list.contains(&Policy::Allow(target))
|| list.contains(&Policy::AllowSilent(target))
{
AllowedResult::Allowed
} else if list.contains(&Policy::Error(target)) {
AllowedResult::Error
Expand All @@ -61,17 +65,26 @@ impl AllowedTargets {
.iter()
.filter_map(|target| match target {
Policy::Allow(target) => Some(*target),
Policy::AllowSilent(_) => None, // Not listed in possible targets
Policy::Warn(_) => None,
Policy::Error(_) => None,
})
.collect()
}
}

/// This policy determines what diagnostics should be emitted based on the `Target` of the attribute.
#[derive(Debug, Eq, PartialEq)]
pub(crate) enum Policy {
/// A target that is allowed.
Allow(Target),
/// A target that is allowed and not listed in the possible targets.
/// This is useful if the target is checked elsewhere.
AllowSilent(Target),
/// Emits a FCW on this target.
/// This is useful if the target was previously allowed but should not be.
Warn(Target),
/// Emits an error on this target.
Error(Target),
}

Expand Down
37 changes: 17 additions & 20 deletions compiler/rustc_builtin_macros/src/format.rs
Original file line number Diff line number Diff line change
Expand Up @@ -69,35 +69,26 @@ struct MacroInput {
/// Ok((fmtstr, parsed arguments))
/// ```
fn parse_args<'a>(ecx: &ExtCtxt<'a>, sp: Span, tts: TokenStream) -> PResult<'a, MacroInput> {
let mut args = FormatArguments::new();

let mut p = ecx.new_parser_from_tts(tts);

if p.token == token::Eof {
return Err(ecx.dcx().create_err(errors::FormatRequiresString { span: sp }));
}

let first_token = &p.token;

let fmtstr = if let token::Literal(lit) = first_token.kind
&& matches!(lit.kind, token::Str | token::StrRaw(_))
{
// parse the format string
let fmtstr = match p.token.kind {
token::Eof => return Err(ecx.dcx().create_err(errors::FormatRequiresString { span: sp })),
// This allows us to properly handle cases when the first comma
// after the format string is mistakenly replaced with any operator,
// which cause the expression parser to eat too much tokens.
p.parse_literal_maybe_minus()?
} else {
token::Literal(token::Lit { kind: token::Str | token::StrRaw(_), .. }) => {
p.parse_literal_maybe_minus()?
}
// Otherwise, we fall back to the expression parser.
p.parse_expr()?
_ => p.parse_expr()?,
};

// Only allow implicit captures to be used when the argument is a direct literal
// instead of a macro expanding to one.
let is_direct_literal = matches!(fmtstr.kind, ExprKind::Lit(_));

// parse comma FormatArgument pairs
let mut args = FormatArguments::new();
let mut first = true;

while p.token != token::Eof {
// parse a comma, or else report an error
if !p.eat(exp!(Comma)) {
if first {
p.clear_expected_token_types();
Expand All @@ -120,9 +111,11 @@ fn parse_args<'a>(ecx: &ExtCtxt<'a>, sp: Span, tts: TokenStream) -> PResult<'a,
}
}
first = false;
// accept a trailing comma
if p.token == token::Eof {
break;
} // accept trailing commas
}
// parse a FormatArgument
match p.token.ident() {
Some((ident, _)) if p.look_ahead(1, |t| *t == token::Eq) => {
p.bump();
Expand Down Expand Up @@ -156,6 +149,10 @@ fn parse_args<'a>(ecx: &ExtCtxt<'a>, sp: Span, tts: TokenStream) -> PResult<'a,
}
}
}

// Only allow implicit captures for direct literals
let is_direct_literal = matches!(fmtstr.kind, ExprKind::Lit(_));

Ok(MacroInput { fmtstr, args, is_direct_literal })
}

Expand Down
2 changes: 0 additions & 2 deletions compiler/rustc_codegen_ssa/messages.ftl
Original file line number Diff line number Diff line change
Expand Up @@ -223,8 +223,6 @@ codegen_ssa_multiple_main_functions = entry symbol `main` declared multiple time
codegen_ssa_no_field = no field `{$name}`
codegen_ssa_no_mangle_nameless = `#[no_mangle]` cannot be used on {$definition} as it has no name
codegen_ssa_no_module_named =
no module named `{$user_path}` (mangled: {$cgu_name}). available modules: {$cgu_names}
Expand Down
13 changes: 4 additions & 9 deletions compiler/rustc_codegen_ssa/src/codegen_attrs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@ use rustc_span::{Ident, Span, sym};
use rustc_target::spec::SanitizerSet;

use crate::errors;
use crate::errors::NoMangleNameless;
use crate::target_features::{
check_target_feature_trait_unsafe, check_tied_features, from_target_feature_attr,
};
Expand Down Expand Up @@ -182,14 +181,10 @@ fn process_builtin_attrs(
if tcx.opt_item_name(did.to_def_id()).is_some() {
codegen_fn_attrs.flags |= CodegenFnAttrFlags::NO_MANGLE;
} else {
tcx.dcx().emit_err(NoMangleNameless {
span: *attr_span,
definition: format!(
"{} {}",
tcx.def_descr_article(did.to_def_id()),
tcx.def_descr(did.to_def_id())
),
});
tcx.dcx().span_delayed_bug(
*attr_span,
"no_mangle should be on a named function",
);
}
}
AttributeKind::Optimize(optimize, _) => codegen_fn_attrs.optimize = *optimize,
Expand Down
8 changes: 0 additions & 8 deletions compiler/rustc_codegen_ssa/src/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1284,14 +1284,6 @@ impl<G: EmissionGuarantee> Diagnostic<'_, G> for TargetFeatureDisableOrEnable<'_
}
}

#[derive(Diagnostic)]
#[diag(codegen_ssa_no_mangle_nameless)]
pub(crate) struct NoMangleNameless {
#[primary_span]
pub span: Span,
pub definition: String,
}

#[derive(Diagnostic)]
#[diag(codegen_ssa_feature_not_valid)]
pub(crate) struct FeatureNotValid<'a> {
Expand Down
21 changes: 13 additions & 8 deletions compiler/rustc_hir_typeck/src/pat.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3115,20 +3115,29 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// binding mode. This keeps it from making those suggestions, as doing so could panic.
let info = table.entry(pat_id).or_insert_with(|| ty::Rust2024IncompatiblePatInfo {
primary_labels: Vec::new(),
bad_modifiers: false,
bad_ref_modifiers: false,
bad_mut_modifiers: false,
bad_ref_pats: false,
suggest_eliding_modes: !self.tcx.features().ref_pat_eat_one_layer_2024()
&& !self.tcx.features().ref_pat_eat_one_layer_2024_structural(),
});

let pat_kind = if let PatKind::Binding(user_bind_annot, _, _, _) = subpat.kind {
info.bad_modifiers = true;
// If the user-provided binding modifier doesn't match the default binding mode, we'll
// need to suggest reference patterns, which can affect other bindings.
// For simplicity, we opt to suggest making the pattern fully explicit.
info.suggest_eliding_modes &=
user_bind_annot == BindingMode(ByRef::Yes(def_br_mutbl), Mutability::Not);
"binding modifier"
if user_bind_annot == BindingMode(ByRef::No, Mutability::Mut) {
info.bad_mut_modifiers = true;
"`mut` binding modifier"
} else {
info.bad_ref_modifiers = true;
match user_bind_annot.1 {
Mutability::Not => "explicit `ref` binding modifier",
Mutability::Mut => "explicit `ref mut` binding modifier",
}
}
} else {
info.bad_ref_pats = true;
// For simplicity, we don't try to suggest eliding reference patterns. Thus, we'll
Expand All @@ -3147,11 +3156,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// so, we may want to inspect the span's source callee or macro backtrace.
"occurs within macro expansion".to_owned()
} else {
let dbm_str = match def_br_mutbl {
Mutability::Not => "ref",
Mutability::Mut => "ref mut",
};
format!("{pat_kind} not allowed under `{dbm_str}` default binding mode")
format!("{pat_kind} not allowed when implicitly borrowing")
};
info.primary_labels.push((trimmed_span, primary_label));
}
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_lint_defs/src/builtin.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1601,7 +1601,7 @@ declare_lint! {
"detects patterns whose meaning will change in Rust 2024",
@future_incompatible = FutureIncompatibleInfo {
reason: FutureIncompatibilityReason::EditionSemanticsChange(Edition::Edition2024),
reference: "<https://doc.rust-lang.org/nightly/edition-guide/rust-2024/match-ergonomics.html>",
reference: "<https://doc.rust-lang.org/edition-guide/rust-2024/match-ergonomics.html>",
};
}

Expand Down
6 changes: 4 additions & 2 deletions compiler/rustc_middle/src/ty/typeck_results.rs
Original file line number Diff line number Diff line change
Expand Up @@ -858,8 +858,10 @@ impl<'tcx> std::fmt::Display for UserTypeKind<'tcx> {
pub struct Rust2024IncompatiblePatInfo {
/// Labeled spans for `&`s, `&mut`s, and binding modifiers incompatible with Rust 2024.
pub primary_labels: Vec<(Span, String)>,
/// Whether any binding modifiers occur under a non-`move` default binding mode.
pub bad_modifiers: bool,
/// Whether any `mut` binding modifiers occur under a non-`move` default binding mode.
pub bad_mut_modifiers: bool,
/// Whether any `ref`/`ref mut` binding modifiers occur under a non-`move` default binding mode.
pub bad_ref_modifiers: bool,
/// Whether any `&` or `&mut` patterns occur under a non-`move` default binding mode.
pub bad_ref_pats: bool,
/// If `true`, we can give a simpler suggestion solely by eliding explicit binding modifiers.
Expand Down
11 changes: 0 additions & 11 deletions compiler/rustc_mir_build/messages.ftl
Original file line number Diff line number Diff line change
Expand Up @@ -322,17 +322,6 @@ mir_build_pointer_pattern = function pointers and raw pointers not derived from

mir_build_privately_uninhabited = pattern `{$witness_1}` is currently uninhabited, but this variant contains private fields which may become inhabited in the future

mir_build_rust_2024_incompatible_pat = {$bad_modifiers ->
*[true] binding modifiers{$bad_ref_pats ->
*[true] {" "}and reference patterns
[false] {""}
}
[false] reference patterns
} may only be written when the default binding mode is `move`{$is_hard_error ->
*[true] {""}
[false] {" "}in Rust 2024
}

mir_build_static_in_pattern = statics cannot be referenced in patterns
.label = can't be used in patterns
mir_build_static_in_pattern_def = `static` defined here
Expand Down
66 changes: 1 addition & 65 deletions compiler/rustc_mir_build/src/errors.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
use rustc_data_structures::fx::FxIndexMap;
use rustc_errors::codes::*;
use rustc_errors::{
Applicability, Diag, DiagArgValue, DiagCtxtHandle, Diagnostic, EmissionGuarantee, Level,
MultiSpan, Subdiagnostic, pluralize,
MultiSpan, Subdiagnostic,
};
use rustc_macros::{Diagnostic, LintDiagnostic, Subdiagnostic};
use rustc_middle::ty::{self, Ty};
Expand Down Expand Up @@ -1087,69 +1086,6 @@ pub(crate) enum MiscPatternSuggestion {
},
}

#[derive(LintDiagnostic)]
#[diag(mir_build_rust_2024_incompatible_pat)]
pub(crate) struct Rust2024IncompatiblePat {
#[subdiagnostic]
pub(crate) sugg: Rust2024IncompatiblePatSugg,
pub(crate) bad_modifiers: bool,
pub(crate) bad_ref_pats: bool,
pub(crate) is_hard_error: bool,
}

pub(crate) struct Rust2024IncompatiblePatSugg {
/// If true, our suggestion is to elide explicit binding modifiers.
/// If false, our suggestion is to make the pattern fully explicit.
pub(crate) suggest_eliding_modes: bool,
pub(crate) suggestion: Vec<(Span, String)>,
pub(crate) ref_pattern_count: usize,
pub(crate) binding_mode_count: usize,
/// Labels for where incompatibility-causing by-ref default binding modes were introduced.
pub(crate) default_mode_labels: FxIndexMap<Span, ty::Mutability>,
}

impl Subdiagnostic for Rust2024IncompatiblePatSugg {
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() {
// Don't point to a macro call site.
if !span.from_expansion() {
let note_msg = "matching on a reference type with a non-reference pattern changes the default binding mode";
let label_msg =
format!("this matches on type `{}_`", def_br_mutbl.ref_prefix_str());
let mut label = MultiSpan::from(span);
label.push_span_label(span, label_msg);
diag.span_note(label, note_msg);
}
}

// Format and emit the suggestion.
let applicability =
if self.suggestion.iter().all(|(span, _)| span.can_be_used_for_suggestions()) {
Applicability::MachineApplicable
} else {
Applicability::MaybeIncorrect
};
let msg = if self.suggest_eliding_modes {
let plural_modes = pluralize!(self.binding_mode_count);
format!("remove the unnecessary binding modifier{plural_modes}")
} else {
let plural_derefs = pluralize!(self.ref_pattern_count);
let and_modes = if self.binding_mode_count > 0 {
format!(" and variable binding mode{}", pluralize!(self.binding_mode_count))
} else {
String::new()
};
format!("make the implied reference pattern{plural_derefs}{and_modes} explicit")
};
// FIXME(dianne): for peace of mind, don't risk emitting a 0-part suggestion (that panics!)
if !self.suggestion.is_empty() {
diag.multipart_suggestion_verbose(msg, self.suggestion, applicability);
}
}
}

#[derive(Diagnostic)]
#[diag(mir_build_loop_match_invalid_update)]
pub(crate) struct LoopMatchInvalidUpdate {
Expand Down
Loading
Loading