Auto merge of #152274 - JonathanBrouwer:rollup-5GoDGKf, r=JonathanBrouwer

Rollup of 4 pull requests

Successful merges:

 - rust-lang/rust#146900 (Add avr_target_feature)
 - rust-lang/rust#150949 (Port symbol mangler attrs)
 - rust-lang/rust#152252 (Convert diagnostic style checks)
 - rust-lang/rust#152265 (Use `.map.collect` to aggregate in `.to_ty` of tuples)
This commit is contained in:
bors
2026-02-07 08:55:53 +00:00
55 changed files with 262 additions and 405 deletions
+1 -5
View File
@@ -656,11 +656,7 @@ pub fn to_ty(&self) -> Option<Box<Ty>> {
// A tuple pattern `(P0, .., Pn)` can be reparsed as `(T0, .., Tn)`
// assuming `T0` to `Tn` are all syntactically valid as types.
PatKind::Tuple(pats) => {
let mut tys = ThinVec::with_capacity(pats.len());
// FIXME(#48994) - could just be collected into an Option<Vec>
for pat in pats {
tys.push(pat.to_ty()?);
}
let tys = pats.iter().map(|pat| pat.to_ty()).collect::<Option<ThinVec<_>>>()?;
TyKind::Tup(tys)
}
_ => return None,
@@ -760,3 +760,53 @@ impl<S: Stage> NoArgsAttributeParser<S> for RustcEffectiveVisibilityParser {
]);
const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcEffectiveVisibility;
}
pub(crate) struct RustcSymbolName;
impl<S: Stage> SingleAttributeParser<S> for RustcSymbolName {
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[
Allow(Target::Fn),
Allow(Target::Method(MethodKind::TraitImpl)),
Allow(Target::Method(MethodKind::Inherent)),
Allow(Target::Method(MethodKind::Trait { body: true })),
Allow(Target::ForeignFn),
Allow(Target::ForeignStatic),
Allow(Target::Impl { of_trait: false }),
]);
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
const PATH: &[Symbol] = &[sym::rustc_symbol_name];
const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepInnermost;
const TEMPLATE: AttributeTemplate = template!(Word);
fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option<AttributeKind> {
if let Err(span) = args.no_args() {
cx.expected_no_args(span);
return None;
}
Some(AttributeKind::RustcSymbolName(cx.attr_span))
}
}
pub(crate) struct RustcDefPath;
impl<S: Stage> SingleAttributeParser<S> for RustcDefPath {
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[
Allow(Target::Fn),
Allow(Target::Method(MethodKind::TraitImpl)),
Allow(Target::Method(MethodKind::Inherent)),
Allow(Target::Method(MethodKind::Trait { body: true })),
Allow(Target::ForeignFn),
Allow(Target::ForeignStatic),
Allow(Target::Impl { of_trait: false }),
]);
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
const PATH: &[Symbol] = &[sym::rustc_def_path];
const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepInnermost;
const TEMPLATE: AttributeTemplate = template!(Word);
fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option<AttributeKind> {
if let Err(span) = args.no_args() {
cx.expected_no_args(span);
return None;
}
Some(AttributeKind::RustcDefPath(cx.attr_span))
}
}
@@ -194,6 +194,7 @@ mod late {
Single<RustcAbiParser>,
Single<RustcAllocatorZeroedVariantParser>,
Single<RustcBuiltinMacroParser>,
Single<RustcDefPath>,
Single<RustcForceInlineParser>,
Single<RustcIfThisChangedParser>,
Single<RustcLayoutScalarValidRangeEndParser>,
@@ -204,6 +205,7 @@ mod late {
Single<RustcObjectLifetimeDefaultParser>,
Single<RustcScalableVectorParser>,
Single<RustcSimdMonomorphizeLaneLimitParser>,
Single<RustcSymbolName>,
Single<SanitizeParser>,
Single<ShouldPanicParser>,
Single<SkipDuringMethodDispatchParser>,
+1 -1
View File
@@ -214,5 +214,5 @@ pub(crate) struct FixedX18InvalidArch<'a> {
}
#[derive(Diagnostic)]
#[diag("`-Zsanitizer-kcfi-arity` requires LLVM 21.0.0 or later.")]
#[diag("`-Zsanitizer-kcfi-arity` requires LLVM 21.0.0 or later")]
pub(crate) struct SanitizerKcfiArityRequiresLLVM2100;
+5 -5
View File
@@ -59,7 +59,7 @@ pub(crate) struct MissingQueryDepGraph {
#[derive(Diagnostic)]
#[diag(
"found malformed codegen unit name `{$user_path}`. codegen units names must always start with the name of the crate (`{$crate_name}` in this case)."
"found malformed codegen unit name `{$user_path}`. codegen units names must always start with the name of the crate (`{$crate_name}` in this case)"
)]
pub(crate) struct MalformedCguName {
#[primary_span]
@@ -562,12 +562,12 @@ pub(crate) struct UnableToExeLinker {
#[derive(Diagnostic)]
#[diag(
"please ensure that Visual Studio 2017 or later, or Build Tools for Visual Studio were installed with the Visual C++ option."
"please ensure that Visual Studio 2017 or later, or Build Tools for Visual Studio were installed with the Visual C++ option"
)]
pub(crate) struct CheckInstalledVisualStudio;
#[derive(Diagnostic)]
#[diag("VS Code is a different product, and is not sufficient.")]
#[diag("VS Code is a different product, and is not sufficient")]
pub(crate) struct InsufficientVSCodeProduct;
#[derive(Diagnostic)]
@@ -610,13 +610,13 @@ pub(crate) struct UnableToRun<'a> {
#[derive(Diagnostic)]
#[diag(
"link against the following native artifacts when linking against this static library. The order and any duplication can be significant on some platforms."
"link against the following native artifacts when linking against this static library. The order and any duplication can be significant on some platforms"
)]
pub(crate) struct StaticLibraryNativeArtifacts;
#[derive(Diagnostic)]
#[diag(
"native artifacts to link against have been written to {$path}. The order and any duplication can be significant on some platforms."
"native artifacts to link against have been written to {$path}. The order and any duplication can be significant on some platforms"
)]
pub(crate) struct StaticLibraryNativeArtifactsToFile<'a> {
pub path: &'a Path,
+2 -2
View File
@@ -309,7 +309,7 @@ pub(crate) struct UnallowedHeapAllocations {
pub span: Span,
pub kind: ConstContext,
#[note(
"The runtime heap is not yet available at compile-time, so no runtime heap allocations can be created."
"the runtime heap is not yet available at compile-time, so no runtime heap allocations can be created"
)]
pub teach: bool,
}
@@ -347,7 +347,7 @@ pub(crate) struct InteriorMutableBorrowEscaping {
#[diag("constant evaluation is taking a long time")]
#[note(
"this lint makes sure the compiler doesn't get stuck due to infinite loops in const eval.
If your compilation actually takes a long time, you can safely allow the lint."
If your compilation actually takes a long time, you can safely allow the lint"
)]
pub struct LongRunning {
#[help("the constant being evaluated")]
@@ -51,7 +51,7 @@ pub(crate) struct RlinkCorruptFile<'a> {
}
#[derive(Diagnostic)]
#[diag("the compiler unexpectedly panicked. this is a bug.")]
#[diag("the compiler unexpectedly panicked. This is a bug")]
pub(crate) struct Ice;
#[derive(Diagnostic)]
+2
View File
@@ -373,6 +373,8 @@ pub fn internal(&self, feature: Symbol) -> bool {
(unstable, async_for_loop, "1.77.0", Some(118898)),
/// Allows `async` trait bound modifier.
(unstable, async_trait_bounds, "1.85.0", Some(62290)),
/// Target features on avr.
(unstable, avr_target_feature, "CURRENT_RUSTC_VERSION", Some(146889)),
/// Allows using Intel AVX10 target features and intrinsics
(unstable, avx10_target_feature, "1.88.0", Some(138843)),
/// Target features on bpf.
@@ -1081,6 +1081,9 @@ pub enum AttributeKind {
/// Represents `#[rustc_deallocator]`
RustcDeallocator,
/// Represents `#[rustc_def_path]`
RustcDefPath(Span),
/// Represents `#[rustc_deny_explicit_impl]`.
RustcDenyExplicitImpl(Span),
@@ -1218,6 +1221,9 @@ pub enum AttributeKind {
/// Represents `#[rustc_std_internal_symbol]`.
RustcStdInternalSymbol(Span),
/// Represents `#[rustc_symbol_name]`
RustcSymbolName(Span),
/// Represents `#[rustc_then_this_would_need]`
RustcThenThisWouldNeed(Span, ThinVec<Ident>),
@@ -105,6 +105,7 @@ pub fn encode_cross_crate(&self) -> EncodeCrossCrate {
RustcConstStability { .. } => Yes,
RustcConstStabilityIndirect => No,
RustcDeallocator => No,
RustcDefPath(..) => No,
RustcDenyExplicitImpl(..) => No,
RustcDummy => No,
RustcDumpDefParents => No,
@@ -149,6 +150,7 @@ pub fn encode_cross_crate(&self) -> EncodeCrossCrate {
RustcSkipDuringMethodDispatch { .. } => No,
RustcSpecializationTrait(..) => No,
RustcStdInternalSymbol(..) => No,
RustcSymbolName(..) => Yes,
RustcThenThisWouldNeed(..) => No,
RustcUnsafeSpecializationMarker(..) => No,
RustcVariance => No,
+1 -1
View File
@@ -1145,7 +1145,7 @@ pub(crate) struct CastThinPointerToWidePointer<'tcx> {
pub expr_ty: Ty<'tcx>,
pub cast_ty: Ty<'tcx>,
#[note(
"Thin pointers are \"simple\" pointers: they are purely a reference to a
"thin pointers are \"simple\" pointers: they are purely a reference to a
memory address.
Wide pointers are pointers referencing \"Dynamically Sized Types\" (also
+1 -1
View File
@@ -281,7 +281,7 @@ pub(crate) struct DeleteWorkProduct<'a> {
#[derive(Diagnostic)]
#[diag(
"corrupt incremental compilation artifact found at `{$path}`. This file will automatically be ignored and deleted. If you see this message repeatedly or can provoke it without manually manipulating the compiler's artifacts, please file an issue. The incremental compilation system relies on hardlinks and filesystem locks behaving correctly, and may not deal well with OS crashes, so whatever information you can provide about your filesystem or other state may be very relevant."
"corrupt incremental compilation artifact found at `{$path}`. This file will automatically be ignored and deleted. If you see this message repeatedly or can provoke it without manually manipulating the compiler's artifacts, please file an issue. The incremental compilation system relies on hardlinks and filesystem locks behaving correctly, and may not deal well with OS crashes, so whatever information you can provide about your filesystem or other state may be very relevant"
)]
pub(crate) struct CorruptFile<'a> {
pub path: &'a Path,
@@ -23,9 +23,7 @@ pub(crate) fn diag_message(&self, variant: Option<&VariantInfo<'_>>) -> TokenStr
quote! { crate::fluent_generated::#slug }
}
Message::Inline(message_span, message) => {
if let Some(variant) = variant {
verify_fluent_message(*message_span, &message, variant);
}
verify_fluent_message(*message_span, &message, variant);
quote! { rustc_errors::DiagMessage::Inline(std::borrow::Cow::Borrowed(#message)) }
}
}
@@ -86,30 +84,37 @@ fn #ident() {
}
}
fn verify_fluent_message(msg_span: Span, message: &str, variant: &VariantInfo<'_>) {
fn verify_fluent_message(msg_span: Span, message_str: &str, variant: Option<&VariantInfo<'_>>) {
// Parse the fluent message
const GENERATED_MSG_ID: &str = "generated_msg";
let resource = FluentResource::try_new(format!("{GENERATED_MSG_ID} = {message}\n")).unwrap();
let resource =
FluentResource::try_new(format!("{GENERATED_MSG_ID} = {message_str}\n")).unwrap();
assert_eq!(resource.entries().count(), 1);
let Some(fluent_syntax::ast::Entry::Message(message)) = resource.get_entry(0) else {
panic!("Did not parse into a message")
};
// Check if all variables are used
let fields: Vec<String> = variant
.bindings()
.iter()
.flat_map(|b| b.ast().ident.as_ref())
.map(|id| id.to_string())
.collect();
for variable in variable_references(&message) {
if !fields.iter().any(|f| f == variable) {
span_err(msg_span.unwrap(), format!("Variable `{variable}` not found in diagnostic "))
if let Some(variant) = variant {
let fields: Vec<String> = variant
.bindings()
.iter()
.flat_map(|b| b.ast().ident.as_ref())
.map(|id| id.to_string())
.collect();
for variable in variable_references(&message) {
if !fields.iter().any(|f| f == variable) {
span_err(
msg_span.unwrap(),
format!("Variable `{variable}` not found in diagnostic "),
)
.help(format!("Available fields: {:?}", fields.join(", ")))
.emit();
}
}
// assert!(, );
}
verify_message_style(msg_span, message_str);
}
fn variable_references<'a>(msg: &fluent_syntax::ast::Message<&'a str>) -> Vec<&'a str> {
@@ -136,3 +141,40 @@ fn variable_references<'a>(msg: &fluent_syntax::ast::Message<&'a str>) -> Vec<&'
}
refs
}
const ALLOWED_CAPITALIZED_WORDS: &[&str] = &[
// tidy-alphabetical-start
"ABI",
"ABIs",
"ADT",
"C-variadic",
"CGU-reuse",
"Cargo",
"Ferris",
"GCC",
"MIR",
"NaNs",
"OK",
"VS",
// tidy-alphabetical-end
];
/// See: https://rustc-dev-guide.rust-lang.org/diagnostics.html#diagnostic-output-style-guide
fn verify_message_style(msg_span: Span, message: &str) {
// Verify that message starts with lowercase char
let Some(first_word) = message.split_whitespace().next() else {
span_err(msg_span.unwrap(), "message must not be empty").emit();
return;
};
let first_char = first_word.chars().next().expect("Word is not empty");
if first_char.is_uppercase() && !ALLOWED_CAPITALIZED_WORDS.contains(&first_word) {
span_err(msg_span.unwrap(), "message `{value}` starts with an uppercase letter. Fix it or add it to `ALLOWED_CAPITALIZED_WORDS`").emit();
return;
}
// Verify that message does not end in `.`
if message.ends_with(".") && !message.ends_with("...") {
span_err(msg_span.unwrap(), "message `{value}` ends with a period").emit();
return;
}
}
+1 -1
View File
@@ -849,7 +849,7 @@ pub(crate) struct LowerRangeBoundMustBeLessThanOrEqualToUpper {
#[label("lower bound larger than upper bound")]
pub(crate) span: Span,
#[note(
"When matching against a range, the compiler verifies that the range is non-empty. Range patterns include both end-points, so this is equivalent to requiring the start of the range to be less than or equal to the end of the range."
"when matching against a range, the compiler verifies that the range is non-empty. Range patterns include both end-points, so this is equivalent to requiring the start of the range to be less than or equal to the end of the range"
)]
pub(crate) teach: bool,
}
+2 -2
View File
@@ -300,6 +300,7 @@ fn check_attributes(
| AttributeKind::RustcConfusables { .. }
| AttributeKind::RustcConstStabilityIndirect
| AttributeKind::RustcDeallocator
| AttributeKind::RustcDefPath(..)
| AttributeKind::RustcDenyExplicitImpl(..)
| AttributeKind::RustcDummy
| AttributeKind::RustcDumpDefParents
@@ -340,6 +341,7 @@ fn check_attributes(
| AttributeKind::RustcSkipDuringMethodDispatch { .. }
| AttributeKind::RustcSpecializationTrait(..)
| AttributeKind::RustcStdInternalSymbol (..)
| AttributeKind::RustcSymbolName(..)
| AttributeKind::RustcThenThisWouldNeed(..)
| AttributeKind::RustcUnsafeSpecializationMarker(..)
| AttributeKind::RustcVariance
@@ -403,10 +405,8 @@ fn check_attributes(
| sym::rustc_strict_coherence
| sym::rustc_mir
| sym::rustc_outlives
| sym::rustc_symbol_name
| sym::rustc_evaluate_where_clauses
| sym::rustc_delayed_bug_from_inside_query
| sym::rustc_def_path
| sym::rustc_partition_reused
| sym::rustc_partition_codegened
| sym::rustc_expected_cgu_reuse
+1
View File
@@ -577,6 +577,7 @@
automatically_derived,
available_externally,
avr,
avr_target_feature,
avx,
avx10_target_feature,
avx512_target_feature,
+15 -10
View File
@@ -4,16 +4,14 @@
//! def-path. This is used for unit testing the code that generates
//! paths etc in all kinds of annoying scenarios.
use rustc_hir::attrs::AttributeKind;
use rustc_hir::def_id::LocalDefId;
use rustc_hir::find_attr;
use rustc_middle::ty::print::with_no_trimmed_paths;
use rustc_middle::ty::{GenericArgs, Instance, TyCtxt};
use rustc_span::{Symbol, sym};
use crate::errors::{Kind, TestOutput};
const SYMBOL_NAME: Symbol = sym::rustc_symbol_name;
const DEF_PATH: Symbol = sym::rustc_def_path;
pub fn report_symbol_names(tcx: TyCtxt<'_>) {
// if the `rustc_attrs` feature is not enabled, then the
// attributes we are interested in cannot be present anyway, so
@@ -54,7 +52,11 @@ fn process_attrs(&mut self, def_id: LocalDefId) {
// The formatting of `tag({})` is chosen so that tests can elect
// to test the entirety of the string, if they choose, or else just
// some subset.
for attr in tcx.get_attrs(def_id, SYMBOL_NAME) {
if let Some(attr_span) = find_attr!(
tcx.get_all_attrs(def_id),
AttributeKind::RustcSymbolName(span) => span
) {
let def_id = def_id.to_def_id();
let instance = Instance::new_raw(
def_id,
@@ -62,27 +64,30 @@ fn process_attrs(&mut self, def_id: LocalDefId) {
);
let mangled = tcx.symbol_name(instance);
tcx.dcx().emit_err(TestOutput {
span: attr.span(),
span: *attr_span,
kind: Kind::SymbolName,
content: format!("{mangled}"),
});
if let Ok(demangling) = rustc_demangle::try_demangle(mangled.name) {
tcx.dcx().emit_err(TestOutput {
span: attr.span(),
span: *attr_span,
kind: Kind::Demangling,
content: format!("{demangling}"),
});
tcx.dcx().emit_err(TestOutput {
span: attr.span(),
span: *attr_span,
kind: Kind::DemanglingAlt,
content: format!("{demangling:#}"),
});
}
}
for attr in tcx.get_attrs(def_id, DEF_PATH) {
if let Some(attr_span) = find_attr!(
tcx.get_all_attrs(def_id),
AttributeKind::RustcDefPath(span) => span
) {
tcx.dcx().emit_err(TestOutput {
span: attr.span(),
span: *attr_span,
kind: Kind::DefPath,
content: with_no_trimmed_paths!(tcx.def_path_str(def_id)),
});
+33 -8
View File
@@ -898,6 +898,28 @@ pub fn toggle_allowed(&self) -> Result<(), &'static str> {
// tidy-alphabetical-end
];
static AVR_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[
// tidy-alphabetical-start
("addsubiw", Unstable(sym::avr_target_feature), &[]),
("break", Unstable(sym::avr_target_feature), &[]),
("eijmpcall", Unstable(sym::avr_target_feature), &[]),
("elpm", Unstable(sym::avr_target_feature), &[]),
("elpmx", Unstable(sym::avr_target_feature), &[]),
("ijmpcall", Unstable(sym::avr_target_feature), &[]),
("jmpcall", Unstable(sym::avr_target_feature), &[]),
("lowbytefirst", Unstable(sym::avr_target_feature), &[]),
("lpm", Unstable(sym::avr_target_feature), &[]),
("lpmx", Unstable(sym::avr_target_feature), &[]),
("movw", Unstable(sym::avr_target_feature), &[]),
("mul", Unstable(sym::avr_target_feature), &[]),
("rmw", Unstable(sym::avr_target_feature), &[]),
("spm", Unstable(sym::avr_target_feature), &[]),
("spmx", Unstable(sym::avr_target_feature), &[]),
("sram", Forbidden { reason: "devices that have no SRAM are unsupported" }, &[]),
("tinyencoding", Unstable(sym::avr_target_feature), &[]),
// tidy-alphabetical-end
];
/// When rustdoc is running, provide a list of all known features so that all their respective
/// primitives may be documented.
///
@@ -919,6 +941,7 @@ pub fn all_rust_features() -> impl Iterator<Item = (&'static str, Stability)> {
.chain(IBMZ_FEATURES)
.chain(SPARC_FEATURES)
.chain(M68K_FEATURES)
.chain(AVR_FEATURES)
.cloned()
.map(|(f, s, _)| (f, s))
}
@@ -996,12 +1019,8 @@ pub fn rust_target_features(&self) -> &'static [(&'static str, Stability, Implie
Arch::S390x => IBMZ_FEATURES,
Arch::Sparc | Arch::Sparc64 => SPARC_FEATURES,
Arch::M68k => M68K_FEATURES,
Arch::AmdGpu
| Arch::Avr
| Arch::Msp430
| Arch::SpirV
| Arch::Xtensa
| Arch::Other(_) => &[],
Arch::Avr => AVR_FEATURES,
Arch::AmdGpu | Arch::Msp430 | Arch::SpirV | Arch::Xtensa | Arch::Other(_) => &[],
}
}
@@ -1023,11 +1042,11 @@ pub fn features_for_correct_fixed_length_vector_abi(&self) -> &'static [(u64, &'
MIPS_FEATURES_FOR_CORRECT_FIXED_LENGTH_VECTOR_ABI
}
Arch::AmdGpu => AMDGPU_FEATURES_FOR_CORRECT_FIXED_LENGTH_VECTOR_ABI,
Arch::Nvptx64 | Arch::Bpf | Arch::M68k => &[], // no vector ABI
Arch::Nvptx64 | Arch::Bpf | Arch::M68k | Arch::Avr => &[], // no vector ABI
Arch::CSky => CSKY_FEATURES_FOR_CORRECT_FIXED_LENGTH_VECTOR_ABI,
// FIXME: for some tier3 targets, we are overly cautious and always give warnings
// when passing args in vector registers.
Arch::Avr | Arch::Msp430 | Arch::SpirV | Arch::Xtensa | Arch::Other(_) => &[],
Arch::Msp430 | Arch::SpirV | Arch::Xtensa | Arch::Other(_) => &[],
}
}
@@ -1224,6 +1243,12 @@ pub fn abi_required_features(&self) -> FeatureConstraints {
// because the vector and float registers overlap.
FeatureConstraints { required: &[], incompatible: &["soft-float"] }
}
Arch::Avr => {
// SRAM is minimum requirement for C/C++ in both avr-gcc and Clang,
// and backends of them only support assembly for devices have no SRAM.
// See the discussion in https://github.com/rust-lang/rust/pull/146900 for more.
FeatureConstraints { required: &["sram"], incompatible: &[] }
}
_ => NOTHING,
}
}
@@ -68,6 +68,8 @@ the possible variants:
https://github.com/llvm/llvm-project/blob/093d4db2f3c874d4683fb01194b00dbb20e5c713/clang/lib/Basic/Targets/AVR.cpp#L32
Note that devices that have no SRAM are not supported, same as when compiling C/C++ programs with avr-gcc or Clang.
## Testing
You can use [`simavr`](https://github.com/buserror/simavr) to emulate the
-125
View File
@@ -1,125 +0,0 @@
//! Checks that all Flunt files have messages in alphabetical order
use std::collections::HashMap;
use std::fs::OpenOptions;
use std::io::Write;
use std::path::Path;
use fluent_syntax::ast::Entry;
use fluent_syntax::parser;
use regex::Regex;
use crate::diagnostics::{CheckId, RunningCheck, TidyCtx};
use crate::walk::{filter_dirs, walk};
fn message() -> &'static Regex {
static_regex!(r#"(?m)^([a-zA-Z0-9_]+)\s*=\s*"#)
}
fn is_fluent(path: &Path) -> bool {
path.extension().is_some_and(|ext| ext == "ftl")
}
fn check_alphabetic(
filename: &str,
fluent: &str,
check: &mut RunningCheck,
all_defined_msgs: &mut HashMap<String, String>,
) {
let Ok(resource) = parser::parse(fluent) else {
panic!("Errors encountered while parsing fluent file `{filename}`");
};
let mut prev: Option<&str> = None;
for entry in &resource.body {
if let Entry::Message(msg) = entry {
let name: &str = msg.id.name;
if let Some(defined_filename) = all_defined_msgs.get(name) {
check.error(format!(
"{filename}: message `{name}` is already defined in {defined_filename}",
));
} else {
all_defined_msgs.insert(name.to_string(), filename.to_owned());
}
if let Some(prev) = prev
&& prev > name
{
check.error(format!(
"{filename}: message `{prev}` appears before `{name}`, but is alphabetically \
later than it. Run `./x.py test tidy --bless` to sort the file correctly",
));
}
prev = Some(name);
}
}
}
fn sort_messages(
filename: &str,
fluent: &str,
check: &mut RunningCheck,
all_defined_msgs: &mut HashMap<String, String>,
) -> String {
let mut chunks = vec![];
let mut cur = String::new();
for line in fluent.lines() {
if let Some(name) = message().find(line) {
if let Some(defined_filename) = all_defined_msgs.get(name.as_str()) {
check.error(format!(
"{filename}: message `{}` is already defined in {defined_filename}",
name.as_str(),
));
}
all_defined_msgs.insert(name.as_str().to_owned(), filename.to_owned());
chunks.push(std::mem::take(&mut cur));
}
cur += line;
cur.push('\n');
}
chunks.push(cur);
chunks.sort();
let mut out = chunks.join("");
out = out.trim().to_string();
out.push('\n');
out
}
pub fn check(path: &Path, tidy_ctx: TidyCtx) {
let mut check = tidy_ctx.start_check(CheckId::new("fluent_alphabetical").path(path));
let bless = tidy_ctx.is_bless_enabled();
let mut all_defined_msgs = HashMap::new();
walk(
path,
|path, is_dir| filter_dirs(path) || (!is_dir && !is_fluent(path)),
&mut |ent, contents| {
if bless {
let sorted = sort_messages(
ent.path().to_str().unwrap(),
contents,
&mut check,
&mut all_defined_msgs,
);
if sorted != contents {
let mut f =
OpenOptions::new().write(true).truncate(true).open(ent.path()).unwrap();
f.write_all(sorted.as_bytes()).unwrap();
}
} else {
check_alphabetic(
ent.path().to_str().unwrap(),
contents,
&mut check,
&mut all_defined_msgs,
);
}
},
);
assert!(!all_defined_msgs.is_empty());
crate::fluent_used::check(path, all_defined_msgs, tidy_ctx);
}
-65
View File
@@ -1,65 +0,0 @@
//! Checks that the error messages start with a lowercased letter (except when allowed to).
use std::path::Path;
use fluent_syntax::ast::{Entry, Message, PatternElement};
use crate::diagnostics::{CheckId, RunningCheck, TidyCtx};
use crate::walk::{filter_dirs, walk};
#[rustfmt::skip]
const ALLOWED_CAPITALIZED_WORDS: &[&str] = &[
// tidy-alphabetical-start
"ABI",
"ABIs",
"ADT",
"C",
"CGU",
"Ferris",
"MIR",
"OK",
"Rust",
"VS", // VS Code
// tidy-alphabetical-end
];
fn filter_fluent(path: &Path) -> bool {
if let Some(ext) = path.extension() { ext.to_str() != Some("ftl") } else { true }
}
fn is_allowed_capitalized_word(msg: &str) -> bool {
ALLOWED_CAPITALIZED_WORDS.iter().any(|word| {
msg.strip_prefix(word)
.map(|tail| tail.chars().next().map(|c| c == '-' || c.is_whitespace()).unwrap_or(true))
.unwrap_or_default()
})
}
fn check_lowercase(filename: &str, contents: &str, check: &mut RunningCheck) {
let (Ok(parse) | Err((parse, _))) = fluent_syntax::parser::parse(contents);
for entry in &parse.body {
if let Entry::Message(msg) = entry
&& let Message { value: Some(pattern), .. } = msg
&& let [first_pattern, ..] = &pattern.elements[..]
&& let PatternElement::TextElement { value } = first_pattern
&& value.chars().next().is_some_and(char::is_uppercase)
&& !is_allowed_capitalized_word(value)
{
check.error(format!(
"{filename}: message `{value}` starts with an uppercase letter. Fix it or add it to `ALLOWED_CAPITALIZED_WORDS`"
));
}
}
}
pub fn check(path: &Path, tidy_ctx: TidyCtx) {
let mut check = tidy_ctx.start_check(CheckId::new("fluent_lowercase").path(path));
walk(
path,
|path, is_dir| filter_dirs(path) || (!is_dir && filter_fluent(path)),
&mut |ent, contents| {
check_lowercase(ent.path().to_str().unwrap(), contents, &mut check);
},
);
}
-88
View File
@@ -1,88 +0,0 @@
//! Checks that no Fluent messages or attributes end in periods (except ellipses)
use std::path::Path;
use fluent_syntax::ast::{Entry, PatternElement};
use crate::diagnostics::{CheckId, RunningCheck, TidyCtx};
use crate::walk::{filter_dirs, walk};
fn filter_fluent(path: &Path) -> bool {
if let Some(ext) = path.extension() { ext.to_str() != Some("ftl") } else { true }
}
/// Messages allowed to have `.` at their end.
///
/// These should probably be reworked eventually.
const ALLOWLIST: &[&str] = &[
"const_eval_long_running",
"const_eval_validation_failure_note",
"driver_impl_ice",
"incremental_corrupt_file",
];
fn check_period(filename: &str, contents: &str, check: &mut RunningCheck) {
if filename.contains("codegen") {
// FIXME: Too many codegen messages have periods right now...
return;
}
let (Ok(parse) | Err((parse, _))) = fluent_syntax::parser::parse(contents);
for entry in &parse.body {
if let Entry::Message(m) = entry {
if ALLOWLIST.contains(&m.id.name) {
continue;
}
if let Some(pat) = &m.value
&& let Some(PatternElement::TextElement { value }) = pat.elements.last()
{
// We don't care about ellipses.
if value.ends_with(".") && !value.ends_with("...") {
let ll = find_line(contents, value);
let name = m.id.name;
check.error(format!("{filename}:{ll}: message `{name}` ends in a period"));
}
}
for attr in &m.attributes {
// Teach notes usually have long messages.
if attr.id.name == "teach_note" {
continue;
}
if let Some(PatternElement::TextElement { value }) = attr.value.elements.last()
&& value.ends_with(".")
&& !value.ends_with("...")
{
let ll = find_line(contents, value);
let name = attr.id.name;
check.error(format!("{filename}:{ll}: attr `{name}` ends in a period"));
}
}
}
}
}
/// Evil cursed bad hack. Requires that `value` be a substr (in memory) of `contents`.
fn find_line(haystack: &str, needle: &str) -> usize {
for (ll, line) in haystack.lines().enumerate() {
if line.as_ptr() > needle.as_ptr() {
return ll;
}
}
1
}
pub fn check(path: &Path, tidy_ctx: TidyCtx) {
let mut check = tidy_ctx.start_check(CheckId::new("fluent_period").path(path));
walk(
path,
|path, is_dir| filter_dirs(path) || (!is_dir && filter_fluent(path)),
&mut |ent, contents| {
check_period(ent.path().to_str().unwrap(), contents, &mut check);
},
);
}
-42
View File
@@ -1,42 +0,0 @@
//! Checks that all Fluent messages appear at least twice
use std::collections::HashMap;
use std::path::Path;
use crate::diagnostics::{CheckId, TidyCtx};
use crate::walk::{filter_dirs, walk};
fn filter_used_messages(
contents: &str,
msgs_not_appeared_yet: &mut HashMap<String, String>,
msgs_appeared_only_once: &mut HashMap<String, String>,
) {
// we don't just check messages never appear in Rust files,
// because messages can be used as parts of other fluent messages in Fluent files,
// so we check messages appear only once in all Rust and Fluent files.
let matches = static_regex!(r"\w+").find_iter(contents);
for name in matches {
if let Some((name, filename)) = msgs_not_appeared_yet.remove_entry(name.as_str()) {
// if one msg appears for the first time,
// remove it from `msgs_not_appeared_yet` and insert it into `msgs_appeared_only_once`.
msgs_appeared_only_once.insert(name, filename);
} else {
// if one msg appears for the second time,
// remove it from `msgs_appeared_only_once`.
msgs_appeared_only_once.remove(name.as_str());
}
}
}
pub fn check(path: &Path, mut all_defined_msgs: HashMap<String, String>, tidy_ctx: TidyCtx) {
let mut check = tidy_ctx.start_check(CheckId::new("fluent_used").path(path));
let mut msgs_appear_only_once = HashMap::new();
walk(path, |path, _| filter_dirs(path), &mut |_, contents| {
filter_used_messages(contents, &mut all_defined_msgs, &mut msgs_appear_only_once);
});
for (name, filename) in msgs_appear_only_once {
check.error(format!("{filename}: message `{name}` is not used"));
}
}
-4
View File
@@ -168,10 +168,6 @@ pub fn files_modified(ci_info: &CiInfo, pred: impl Fn(&str) -> bool) -> bool {
pub mod extra_checks;
pub mod features;
pub mod filenames;
pub mod fluent_alphabetical;
pub mod fluent_lowercase;
pub mod fluent_period;
mod fluent_used;
pub mod gcc_submodule;
pub(crate) mod iter_header;
pub mod known_bug;
-3
View File
@@ -107,9 +107,6 @@ macro_rules! check {
// Checks that only make sense for the compiler.
check!(error_codes, &root_path, &[&compiler_path, &librustdoc_path], &ci_info);
check!(fluent_alphabetical, &compiler_path);
check!(fluent_period, &compiler_path);
check!(fluent_lowercase, &compiler_path);
check!(target_policy, &root_path);
check!(gcc_submodule, &root_path, &compiler_path);
+1 -1
View File
@@ -9,7 +9,7 @@ LL | fn wrong()
aborting due to `-Z treat-err-as-bug=1`
stack backtrace:
error: the compiler unexpectedly panicked. this is a bug.
error: the compiler unexpectedly panicked. This is a bug
note: we would appreciate a bug report: https://github.com/rust-lang/rust/issues/new?labels=C-bug%2C+I-ICE%2C+T-rustdoc&template=ice.md
+12
View File
@@ -0,0 +1,12 @@
warning: target feature `sram` cannot be disabled with `-Ctarget-feature`: devices that have no SRAM are unsupported
|
= note: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
= note: for more information, see issue #116344 <https://github.com/rust-lang/rust/issues/116344>
warning: target feature `sram` must be enabled to ensure that the ABI of the current target can be implemented correctly
|
= note: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
= note: for more information, see issue #116344 <https://github.com/rust-lang/rust/issues/116344>
warning: 2 warnings emitted
+7
View File
@@ -0,0 +1,7 @@
warning: target feature `sram` must be enabled to ensure that the ABI of the current target can be implemented correctly
|
= note: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
= note: for more information, see issue #116344 <https://github.com/rust-lang/rust/issues/116344>
warning: 1 warning emitted
+15
View File
@@ -0,0 +1,15 @@
//@ revisions: has_sram no_sram disable_sram
//@ build-pass
//@[has_sram] compile-flags: --target avr-none -C target-cpu=atmega328p
//@[has_sram] needs-llvm-components: avr
//@[no_sram] compile-flags: --target avr-none -C target-cpu=attiny11
//@[no_sram] needs-llvm-components: avr
//@[disable_sram] compile-flags: --target avr-none -C target-cpu=atmega328p -C target-feature=-sram
//@[disable_sram] needs-llvm-components: avr
//@ ignore-backends: gcc
//[no_sram,disable_sram]~? WARN target feature `sram` must be enabled
//[disable_sram]~? WARN target feature `sram` cannot be disabled with `-Ctarget-feature`
#![feature(no_core)]
#![no_core]
#![crate_type = "lib"]
+16
View File
@@ -14,6 +14,7 @@ LL | cfg!(target_feature = "_UNEXPECTED_VALUE");
`7e10`
`a`
`aclass`
`addsubiw`
`adx`
`aes`
`altivec`
@@ -57,6 +58,7 @@ LL | cfg!(target_feature = "_UNEXPECTED_VALUE");
`bf16`
`bmi1`
`bmi2`
`break`
`bti`
`bulk-memory`
`c`
@@ -83,6 +85,9 @@ LL | cfg!(target_feature = "_UNEXPECTED_VALUE");
`e2`
`ecv`
`edsp`
`eijmpcall`
`elpm`
`elpmx`
`elrw`
`enhanced-sort`
`ermsb`
@@ -148,6 +153,7 @@ LL | cfg!(target_feature = "_UNEXPECTED_VALUE");
`hvxv79`
`hwdiv`
`i8mm`
`ijmpcall`
`isa-68000`
`isa-68010`
`isa-68020`
@@ -156,6 +162,7 @@ LL | cfg!(target_feature = "_UNEXPECTED_VALUE");
`isa-68060`
`isa-68881`
`isa-68882`
`jmpcall`
`jsconv`
`kl`
`lahfsahf`
@@ -166,6 +173,9 @@ LL | cfg!(target_feature = "_UNEXPECTED_VALUE");
`ld-seq-sa`
`leoncasa`
`lor`
`lowbytefirst`
`lpm`
`lpmx`
`lse`
`lse128`
`lse2`
@@ -187,11 +197,13 @@ LL | cfg!(target_feature = "_UNEXPECTED_VALUE");
`mops`
`movbe`
`movrs`
`movw`
`mp`
`mp1e2`
`msa`
`msync`
`mte`
`mul`
`multivalue`
`mutable-globals`
`neon`
@@ -256,6 +268,7 @@ LL | cfg!(target_feature = "_UNEXPECTED_VALUE");
`reference-types`
`relax`
`relaxed-simd`
`rmw`
`rtm`
`rva23u64`
`sb`
@@ -308,6 +321,8 @@ LL | cfg!(target_feature = "_UNEXPECTED_VALUE");
`sme2p1`
`soft-float`
`spe`
`spm`
`spmx`
`ssbs`
`sse`
`sse2`
@@ -332,6 +347,7 @@ LL | cfg!(target_feature = "_UNEXPECTED_VALUE");
`tbm`
`thumb-mode`
`thumb2`
`tinyencoding`
`tme`
`transactional-execution`
`trust`
@@ -5,7 +5,7 @@ LL | [(); loop {}].field;
| ^^^^^^^
|
= note: this lint makes sure the compiler doesn't get stuck due to infinite loops in const eval.
If your compilation actually takes a long time, you can safely allow the lint.
If your compilation actually takes a long time, you can safely allow the lint
help: the constant being evaluated
--> $DIR/field-access-after-const-eval-fail-in-ty.rs:4:10
|
@@ -8,7 +8,7 @@ LL | | }
| |_________^
|
= note: this lint makes sure the compiler doesn't get stuck due to infinite loops in const eval.
If your compilation actually takes a long time, you can safely allow the lint.
If your compilation actually takes a long time, you can safely allow the lint
help: the constant being evaluated
--> $DIR/infinite_loop.rs:13:18
|
@@ -8,7 +8,7 @@ LL | | }
| |_________^
|
= note: this lint makes sure the compiler doesn't get stuck due to infinite loops in const eval.
If your compilation actually takes a long time, you can safely allow the lint.
If your compilation actually takes a long time, you can safely allow the lint
help: the constant being evaluated
--> $DIR/infinite_loop.rs:13:18
|
@@ -9,7 +9,7 @@ LL | | }
| |_________^
|
= note: this lint makes sure the compiler doesn't get stuck due to infinite loops in const eval.
If your compilation actually takes a long time, you can safely allow the lint.
If your compilation actually takes a long time, you can safely allow the lint
help: the constant being evaluated
--> $DIR/issue-52475.rs:2:18
|
@@ -5,7 +5,7 @@ LL | static _X: () = loop {};
| ^^^^^^^
|
= note: this lint makes sure the compiler doesn't get stuck due to infinite loops in const eval.
If your compilation actually takes a long time, you can safely allow the lint.
If your compilation actually takes a long time, you can safely allow the lint
help: the constant being evaluated
--> $DIR/issue-70723.rs:1:1
|
@@ -5,7 +5,7 @@ LL | foo();
| ^^^^^
|
= note: this lint makes sure the compiler doesn't get stuck due to infinite loops in const eval.
If your compilation actually takes a long time, you can safely allow the lint.
If your compilation actually takes a long time, you can safely allow the lint
help: the constant being evaluated
--> $DIR/ctfe-fn-call.rs:32:1
|
@@ -11,7 +11,7 @@ LL | | }
| |_____^
|
= note: this lint makes sure the compiler doesn't get stuck due to infinite loops in const eval.
If your compilation actually takes a long time, you can safely allow the lint.
If your compilation actually takes a long time, you can safely allow the lint
help: the constant being evaluated
--> $DIR/ctfe-labelled-loop.rs:16:1
|
@@ -5,7 +5,7 @@ LL | recurse(n - 1)
| ^^^^^^^^^^^^^^
|
= note: this lint makes sure the compiler doesn't get stuck due to infinite loops in const eval.
If your compilation actually takes a long time, you can safely allow the lint.
If your compilation actually takes a long time, you can safely allow the lint
help: the constant being evaluated
--> $DIR/ctfe-recursion.rs:13:1
|
@@ -7,7 +7,7 @@ LL | | }
| |_____^
|
= note: this lint makes sure the compiler doesn't get stuck due to infinite loops in const eval.
If your compilation actually takes a long time, you can safely allow the lint.
If your compilation actually takes a long time, you can safely allow the lint
help: the constant being evaluated
--> $DIR/ctfe-simple-loop.rs:19:1
|
@@ -28,7 +28,7 @@ LL | | }
| |_____^
|
= note: this lint makes sure the compiler doesn't get stuck due to infinite loops in const eval.
If your compilation actually takes a long time, you can safely allow the lint.
If your compilation actually takes a long time, you can safely allow the lint
help: the constant being evaluated
--> $DIR/ctfe-simple-loop.rs:20:1
|
@@ -5,7 +5,7 @@ LL | [(); loop {}];
| ^^^^^^^
|
= note: this lint makes sure the compiler doesn't get stuck due to infinite loops in const eval.
If your compilation actually takes a long time, you can safely allow the lint.
If your compilation actually takes a long time, you can safely allow the lint
help: the constant being evaluated
--> $DIR/do-not-ice-long-constant-evaluation-in-for-loop.rs:10:14
|
@@ -5,7 +5,7 @@ LL | let array = [(); { loop {} }];
| ^^^^^^^
|
= note: this lint makes sure the compiler doesn't get stuck due to infinite loops in const eval.
If your compilation actually takes a long time, you can safely allow the lint.
If your compilation actually takes a long time, you can safely allow the lint
help: the constant being evaluated
--> $DIR/do-not-ice-on-field-access-of-err-type.rs:5:22
|
+1 -1
View File
@@ -7,7 +7,7 @@ error: constant evaluation is taking a long time
= note: in this macro invocation
|
= note: this lint makes sure the compiler doesn't get stuck due to infinite loops in const eval.
If your compilation actually takes a long time, you can safely allow the lint.
If your compilation actually takes a long time, you can safely allow the lint
help: the constant being evaluated
--> $DIR/timeout.rs:7:1
|
+1 -1
View File
@@ -4,7 +4,7 @@ error[E0010]: allocations are not allowed in constants
LL | const CON: Vec<i32> = vec![1, 2, 3];
| ^^^^^^^^^^^^^ allocation not allowed in constants
|
= note: The runtime heap is not yet available at compile-time, so no runtime heap allocations can be created.
= note: the runtime heap is not yet available at compile-time, so no runtime heap allocations can be created
error[E0015]: cannot call non-const method `slice::<impl [i32]>::into_vec::<std::alloc::Global>` in constants
--> $DIR/E0010-teach.rs:5:23
+1 -1
View File
@@ -4,7 +4,7 @@ error[E0030]: lower bound for range pattern must be less than or equal to upper
LL | 1000 ..= 5 => {}
| ^^^^^^^^^^ lower bound larger than upper bound
|
= note: When matching against a range, the compiler verifies that the range is non-empty. Range patterns include both end-points, so this is equivalent to requiring the start of the range to be less than or equal to the end of the range.
= note: when matching against a range, the compiler verifies that the range is non-empty. Range patterns include both end-points, so this is equivalent to requiring the start of the range to be less than or equal to the end of the range
error: aborting due to 1 previous error
@@ -5,7 +5,7 @@ LL | become f();
| ^^^^^^^^^^
|
= note: this lint makes sure the compiler doesn't get stuck due to infinite loops in const eval.
If your compilation actually takes a long time, you can safely allow the lint.
If your compilation actually takes a long time, you can safely allow the lint
help: the constant being evaluated
--> $DIR/infinite-recursion-in-ctfe.rs:4:1
|
+1 -1
View File
@@ -1,6 +1,6 @@
257 > 255
error: the compiler unexpectedly panicked. this is a bug.
error: the compiler unexpectedly panicked. This is a bug
query stack during panic:
#0 [layout_of] computing layout of `Foo`
+1 -1
View File
@@ -13,7 +13,7 @@ LL | StorageLive(a);
aborting due to `-Z treat-err-as-bug=1`
error: the compiler unexpectedly panicked. this is a bug.
error: the compiler unexpectedly panicked. This is a bug
query stack during panic:
end of query stack
+1 -1
View File
@@ -13,7 +13,7 @@ stack backtrace:
(end_short_backtrace)
(begin_short_backtrace)
error: the compiler unexpectedly panicked. this is a bug.
error: the compiler unexpectedly panicked. This is a bug
@@ -8,7 +8,7 @@ LL | | }
| |_________^
|
= note: this lint makes sure the compiler doesn't get stuck due to infinite loops in const eval.
If your compilation actually takes a long time, you can safely allow the lint.
If your compilation actually takes a long time, you can safely allow the lint
help: the constant being evaluated
--> $DIR/no-ice-on-inference-failure.rs:2:22
|
@@ -5,7 +5,7 @@
//@ build-fail
//@ max-llvm-major-version: 20
//~? ERROR `-Zsanitizer-kcfi-arity` requires LLVM 21.0.0 or later.
//~? ERROR `-Zsanitizer-kcfi-arity` requires LLVM 21.0.0 or later
#![feature(no_core)]
#![no_core]
#![no_main]
@@ -1,4 +1,4 @@
error: `-Zsanitizer-kcfi-arity` requires LLVM 21.0.0 or later.
error: `-Zsanitizer-kcfi-arity` requires LLVM 21.0.0 or later
error: aborting due to 1 previous error
+1
View File
@@ -20,6 +20,7 @@
// gate-test-sparc_target_feature
// gate-test-x87_target_feature
// gate-test-m68k_target_feature
// gate-test-avr_target_feature
#[target_feature(enable = "x87")]
//~^ ERROR: currently unstable
+1 -1
View File
@@ -1,5 +1,5 @@
error[E0658]: the target feature `x87` is currently unstable
--> $DIR/gate.rs:24:18
--> $DIR/gate.rs:25:18
|
LL | #[target_feature(enable = "x87")]
| ^^^^^^^^^^^^^^
+1 -1
View File
@@ -5,7 +5,7 @@ LL | pub static C: u32 = 0 - 1;
| ^^^^^ evaluation of `C` failed here
error: the compiler unexpectedly panicked. this is a bug.
error: the compiler unexpectedly panicked. This is a bug
query stack during panic:
#0 [eval_static_initializer] evaluating initializer of static `C`
@@ -5,7 +5,7 @@ LL | fn main() {}
| ^^^^^^^^^
error: the compiler unexpectedly panicked. this is a bug.
error: the compiler unexpectedly panicked. This is a bug
query stack during panic:
#0 [trigger_delayed_bug] triggering a delayed bug for testing incremental