diff --git a/Cargo.lock b/Cargo.lock index 321e9cc35c583..368acc64af6f9 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3452,9 +3452,9 @@ dependencies = [ [[package]] name = "once_cell" -version = "1.16.0" +version = "1.17.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "86f0b0d4bf799edbc74508c1e8bf170ff5f41238e5f8225603ca7caaae2b7860" +checksum = "b7e5500299e16ebb147ae15a00a942af264cf3688f47923b8fc2cd5858f23ad3" [[package]] name = "opener" @@ -6101,6 +6101,15 @@ version = "2.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6bdef32e8150c2a081110b42772ffe7d7c9032b606bc226c8260fd97e0976601" +[[package]] +name = "suggest-tests" +version = "0.1.0" +dependencies = [ + "build_helper", + "glob", + "once_cell", +] + [[package]] name = "syn" version = "1.0.102" diff --git a/Cargo.toml b/Cargo.toml index 15cbb2659c9b3..1fcaaf6ddc4d0 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -44,6 +44,7 @@ members = [ "src/tools/lld-wrapper", "src/tools/collect-license-metadata", "src/tools/generate-copyright", + "src/tools/suggest-tests", ] exclude = [ diff --git a/compiler/rustc_codegen_gcc/example/alloc_system.rs b/compiler/rustc_codegen_gcc/example/alloc_system.rs index 9ec18da90d819..046903fe5aca4 100644 --- a/compiler/rustc_codegen_gcc/example/alloc_system.rs +++ b/compiler/rustc_codegen_gcc/example/alloc_system.rs @@ -15,6 +15,7 @@ const MIN_ALIGN: usize = 8; #[cfg(any(target_arch = "x86_64", target_arch = "aarch64", + target_arch = "loongarch64", target_arch = "mips64", target_arch = "s390x", target_arch = "sparc64"))] diff --git a/compiler/rustc_codegen_ssa/src/back/metadata.rs b/compiler/rustc_codegen_ssa/src/back/metadata.rs index 3e3fcc08bd644..d5d843702c003 100644 --- a/compiler/rustc_codegen_ssa/src/back/metadata.rs +++ b/compiler/rustc_codegen_ssa/src/back/metadata.rs @@ -127,6 +127,7 @@ pub(crate) fn create_object_file(sess: &Session) -> Option Architecture::Msp430, "hexagon" => Architecture::Hexagon, "bpf" => Architecture::Bpf, + "loongarch64" => Architecture::LoongArch64, // Unsupported architecture. _ => return None, }; @@ -190,6 +191,10 @@ pub(crate) fn create_object_file(sess: &Session) -> Option { + // Source: https://loongson.github.io/LoongArch-Documentation/LoongArch-ELF-ABI-EN.html#_e_flags_identifies_abi_type_and_version + elf::EF_LARCH_OBJABI_V1 | elf::EF_LARCH_ABI_DOUBLE_FLOAT + } _ => 0, }; // adapted from LLVM's `MCELFObjectTargetWriter::getOSABI` diff --git a/compiler/rustc_errors/src/lib.rs b/compiler/rustc_errors/src/lib.rs index 9866a9bffe0e1..17944044aae1f 100644 --- a/compiler/rustc_errors/src/lib.rs +++ b/compiler/rustc_errors/src/lib.rs @@ -473,8 +473,6 @@ pub enum StashKey { /// When an invalid lifetime e.g. `'2` should be reinterpreted /// as a char literal in the parser LifetimeIsChar, - /// When an invalid lifetime e.g. `'🐱` contains emoji. - LifetimeContainsEmoji, /// Maybe there was a typo where a comma was forgotten before /// FRU syntax MaybeFruTypo, diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs index fdf178c3ea79e..f736f7a96207e 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs @@ -578,7 +578,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { #[instrument(skip(self), level = "debug")] pub(in super::super) fn report_ambiguity_errors(&self) { - let mut errors = self.fulfillment_cx.borrow_mut().collect_remaining_errors(); + let mut errors = self.fulfillment_cx.borrow_mut().collect_remaining_errors(self); if !errors.is_empty() { self.adjust_fulfillment_errors_for_expr_obligation(&mut errors); diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/adjust_fulfillment_errors.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/adjust_fulfillment_errors.rs index 3e0c2bf2a5538..2899ba0b7e701 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/adjust_fulfillment_errors.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/adjust_fulfillment_errors.rs @@ -78,7 +78,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // Finally, for ambiguity-related errors, we actually want to look // for a parameter that is the source of the inference type left // over in this predicate. - if let traits::FulfillmentErrorCode::CodeAmbiguity = error.code { + if let traits::FulfillmentErrorCode::CodeAmbiguity { .. } = error.code { fallback_param_to_point_at = None; self_param_to_point_at = None; param_to_point_at = diff --git a/compiler/rustc_infer/src/traits/engine.rs b/compiler/rustc_infer/src/traits/engine.rs index f75344f20b6d9..2f0a19b46de93 100644 --- a/compiler/rustc_infer/src/traits/engine.rs +++ b/compiler/rustc_infer/src/traits/engine.rs @@ -38,7 +38,7 @@ pub trait TraitEngine<'tcx>: 'tcx { fn select_where_possible(&mut self, infcx: &InferCtxt<'tcx>) -> Vec>; - fn collect_remaining_errors(&mut self) -> Vec>; + fn collect_remaining_errors(&mut self, infcx: &InferCtxt<'tcx>) -> Vec>; fn pending_obligations(&self) -> Vec>; @@ -78,6 +78,6 @@ impl<'tcx, T: ?Sized + TraitEngine<'tcx>> TraitEngineExt<'tcx> for T { return errors; } - self.collect_remaining_errors() + self.collect_remaining_errors(infcx) } } diff --git a/compiler/rustc_infer/src/traits/mod.rs b/compiler/rustc_infer/src/traits/mod.rs index dd9b2e548c731..e01b6caf43064 100644 --- a/compiler/rustc_infer/src/traits/mod.rs +++ b/compiler/rustc_infer/src/traits/mod.rs @@ -128,7 +128,11 @@ pub enum FulfillmentErrorCode<'tcx> { CodeProjectionError(MismatchedProjectionTypes<'tcx>), CodeSubtypeError(ExpectedFound>, TypeError<'tcx>), // always comes from a SubtypePredicate CodeConstEquateError(ExpectedFound>, TypeError<'tcx>), - CodeAmbiguity, + CodeAmbiguity { + /// Overflow reported from the new solver `-Ztrait-solver=next`, which will + /// be reported as an regular error as opposed to a fatal error. + overflow: bool, + }, } impl<'tcx, O> Obligation<'tcx, O> { diff --git a/compiler/rustc_infer/src/traits/structural_impls.rs b/compiler/rustc_infer/src/traits/structural_impls.rs index 3a5273b0359e4..1563d92af0ea7 100644 --- a/compiler/rustc_infer/src/traits/structural_impls.rs +++ b/compiler/rustc_infer/src/traits/structural_impls.rs @@ -46,7 +46,8 @@ impl<'tcx> fmt::Debug for traits::FulfillmentErrorCode<'tcx> { super::CodeConstEquateError(ref a, ref b) => { write!(f, "CodeConstEquateError({:?}, {:?})", a, b) } - super::CodeAmbiguity => write!(f, "Ambiguity"), + super::CodeAmbiguity { overflow: false } => write!(f, "Ambiguity"), + super::CodeAmbiguity { overflow: true } => write!(f, "Overflow"), super::CodeCycle(ref cycle) => write!(f, "Cycle({:?})", cycle), } } diff --git a/compiler/rustc_lexer/src/lib.rs b/compiler/rustc_lexer/src/lib.rs index 322ec31fb2cff..b3f4b5cd5e5a0 100644 --- a/compiler/rustc_lexer/src/lib.rs +++ b/compiler/rustc_lexer/src/lib.rs @@ -95,7 +95,7 @@ pub enum TokenKind { Literal { kind: LiteralKind, suffix_start: u32 }, /// "'a" - Lifetime { starts_with_number: bool, contains_emoji: bool }, + Lifetime { starts_with_number: bool }, // One-char tokens: /// ";" @@ -632,13 +632,7 @@ impl Cursor<'_> { // If the first symbol is valid for identifier, it can be a lifetime. // Also check if it's a number for a better error reporting (so '0 will // be reported as invalid lifetime and not as unterminated char literal). - // We also have to account for potential `'🐱` emojis to avoid reporting - // it as an unterminated char literal. - is_id_start(self.first()) - || self.first().is_digit(10) - // FIXME(#108019): `unic-emoji-char` seems to have data tables only up to Unicode - // 5.0, but Unicode is already newer than this. - || unic_emoji_char::is_emoji(self.first()) + is_id_start(self.first()) || self.first().is_digit(10) }; if !can_be_a_lifetime { @@ -651,33 +645,16 @@ impl Cursor<'_> { return Literal { kind, suffix_start }; } - // Either a lifetime or a character literal. + // Either a lifetime or a character literal with + // length greater than 1. let starts_with_number = self.first().is_digit(10); - let mut contains_emoji = false; - // FIXME(#108019): `unic-emoji-char` seems to have data tables only up to Unicode - // 5.0, but Unicode is already newer than this. - if unic_emoji_char::is_emoji(self.first()) { - contains_emoji = true; - } else { - // Skip the literal contents. - // First symbol can be a number (which isn't a valid identifier start), - // so skip it without any checks. - self.bump(); - } - self.eat_while(|c| { - if is_id_continue(c) { - true - // FIXME(#108019): `unic-emoji-char` seems to have data tables only up to Unicode - // 5.0, but Unicode is already newer than this. - } else if unic_emoji_char::is_emoji(c) { - contains_emoji = true; - true - } else { - false - } - }); + // Skip the literal contents. + // First symbol can be a number (which isn't a valid identifier start), + // so skip it without any checks. + self.bump(); + self.eat_while(is_id_continue); // Check if after skipping literal contents we've met a closing // single quote (which means that user attempted to create a @@ -687,7 +664,7 @@ impl Cursor<'_> { let kind = Char { terminated: true }; Literal { kind, suffix_start: self.pos_within_token() } } else { - Lifetime { starts_with_number, contains_emoji } + Lifetime { starts_with_number } } } diff --git a/compiler/rustc_lexer/src/tests.rs b/compiler/rustc_lexer/src/tests.rs index 670d64fb983f5..e4c1787f2ccef 100644 --- a/compiler/rustc_lexer/src/tests.rs +++ b/compiler/rustc_lexer/src/tests.rs @@ -235,7 +235,7 @@ fn lifetime() { check_lexing( "'abc", expect![[r#" - Token { kind: Lifetime { starts_with_number: false, contains_emoji: false }, len: 4 } + Token { kind: Lifetime { starts_with_number: false }, len: 4 } "#]], ); } diff --git a/compiler/rustc_llvm/build.rs b/compiler/rustc_llvm/build.rs index f8e9ec535e456..b0783d75d4756 100644 --- a/compiler/rustc_llvm/build.rs +++ b/compiler/rustc_llvm/build.rs @@ -10,6 +10,7 @@ const OPTIONAL_COMPONENTS: &[&str] = &[ "aarch64", "amdgpu", "avr", + "loongarch", "m68k", "mips", "powerpc", diff --git a/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp index 736766e35bcc3..08e38b0c9d59e 100644 --- a/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp +++ b/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp @@ -146,6 +146,12 @@ extern "C" void LLVMTimeTraceProfilerFinish(const char* FileName) { #define SUBTARGET_HEXAGON #endif +#ifdef LLVM_COMPONENT_LOONGARCH +#define SUBTARGET_LOONGARCH SUBTARGET(LoongArch) +#else +#define SUBTARGET_LOONGARCH +#endif + #define GEN_SUBTARGETS \ SUBTARGET_X86 \ SUBTARGET_ARM \ @@ -159,6 +165,7 @@ extern "C" void LLVMTimeTraceProfilerFinish(const char* FileName) { SUBTARGET_SPARC \ SUBTARGET_HEXAGON \ SUBTARGET_RISCV \ + SUBTARGET_LOONGARCH \ #define SUBTARGET(x) \ namespace llvm { \ diff --git a/compiler/rustc_llvm/src/lib.rs b/compiler/rustc_llvm/src/lib.rs index ec3cf34d7109f..a49ded4fd7baa 100644 --- a/compiler/rustc_llvm/src/lib.rs +++ b/compiler/rustc_llvm/src/lib.rs @@ -102,6 +102,14 @@ pub fn initialize_available_targets() { LLVMInitializeM68kAsmPrinter, LLVMInitializeM68kAsmParser ); + init_target!( + llvm_component = "loongarch", + LLVMInitializeLoongArchTargetInfo, + LLVMInitializeLoongArchTarget, + LLVMInitializeLoongArchTargetMC, + LLVMInitializeLoongArchAsmPrinter, + LLVMInitializeLoongArchAsmParser + ); init_target!( llvm_component = "mips", LLVMInitializeMipsTargetInfo, diff --git a/compiler/rustc_parse/src/lexer/mod.rs b/compiler/rustc_parse/src/lexer/mod.rs index e41d0f7047b3b..9e856c9f2120c 100644 --- a/compiler/rustc_parse/src/lexer/mod.rs +++ b/compiler/rustc_parse/src/lexer/mod.rs @@ -223,21 +223,16 @@ impl<'a> StringReader<'a> { }; token::Literal(token::Lit { kind, symbol, suffix }) } - rustc_lexer::TokenKind::Lifetime { starts_with_number, contains_emoji } => { + rustc_lexer::TokenKind::Lifetime { starts_with_number } => { // Include the leading `'` in the real identifier, for macro // expansion purposes. See #12512 for the gory details of why // this is necessary. let lifetime_name = self.str_from(start); if starts_with_number { let span = self.mk_sp(start, self.pos); - let mut diag = self.sess.struct_err("lifetimes or labels cannot start with a number"); + let mut diag = self.sess.struct_err("lifetimes cannot start with a number"); diag.set_span(span); diag.stash(span, StashKey::LifetimeIsChar); - } else if contains_emoji { - let span = self.mk_sp(start, self.pos); - let mut diag = self.sess.struct_err("lifetimes or labels cannot contain emojis"); - diag.set_span(span); - diag.stash(span, StashKey::LifetimeContainsEmoji); } let ident = Symbol::intern(lifetime_name); token::Lifetime(ident) diff --git a/compiler/rustc_target/src/spec/loongarch64_unknown_linux_gnu.rs b/compiler/rustc_target/src/spec/loongarch64_unknown_linux_gnu.rs new file mode 100644 index 0000000000000..db8b9c70e6702 --- /dev/null +++ b/compiler/rustc_target/src/spec/loongarch64_unknown_linux_gnu.rs @@ -0,0 +1,17 @@ +use crate::spec::{Target, TargetOptions}; + +pub fn target() -> Target { + Target { + llvm_target: "loongarch64-unknown-linux-gnu".into(), + pointer_width: 64, + data_layout: "e-m:e-p:64:64-i64:64-i128:128-n64-S128".into(), + arch: "loongarch64".into(), + options: TargetOptions { + cpu: "generic".into(), + features: "+f,+d".into(), + llvm_abiname: "lp64d".into(), + max_atomic_width: Some(64), + ..super::linux_gnu_base::opts() + }, + } +} diff --git a/compiler/rustc_target/src/spec/mod.rs b/compiler/rustc_target/src/spec/mod.rs index 62c58c204e09a..192b2ab0ca275 100644 --- a/compiler/rustc_target/src/spec/mod.rs +++ b/compiler/rustc_target/src/spec/mod.rs @@ -1021,6 +1021,7 @@ supported_targets! { ("x86_64-unknown-linux-gnux32", x86_64_unknown_linux_gnux32), ("i686-unknown-linux-gnu", i686_unknown_linux_gnu), ("i586-unknown-linux-gnu", i586_unknown_linux_gnu), + ("loongarch64-unknown-linux-gnu", loongarch64_unknown_linux_gnu), ("m68k-unknown-linux-gnu", m68k_unknown_linux_gnu), ("mips-unknown-linux-gnu", mips_unknown_linux_gnu), ("mips64-unknown-linux-gnuabi64", mips64_unknown_linux_gnuabi64), diff --git a/compiler/rustc_trait_selection/src/solve/fulfill.rs b/compiler/rustc_trait_selection/src/solve/fulfill.rs index 76a2a5879114d..32bd10f0beba5 100644 --- a/compiler/rustc_trait_selection/src/solve/fulfill.rs +++ b/compiler/rustc_trait_selection/src/solve/fulfill.rs @@ -1,6 +1,7 @@ use std::mem; use rustc_infer::infer::InferCtxt; +use rustc_infer::traits::solve::MaybeCause; use rustc_infer::traits::Obligation; use rustc_infer::traits::{ query::NoSolution, FulfillmentError, FulfillmentErrorCode, MismatchedProjectionTypes, @@ -41,13 +42,31 @@ impl<'tcx> TraitEngine<'tcx> for FulfillmentCtxt<'tcx> { self.obligations.push(obligation); } - fn collect_remaining_errors(&mut self) -> Vec> { + fn collect_remaining_errors(&mut self, infcx: &InferCtxt<'tcx>) -> Vec> { self.obligations .drain(..) - .map(|obligation| FulfillmentError { - obligation: obligation.clone(), - code: FulfillmentErrorCode::CodeAmbiguity, - root_obligation: obligation, + .map(|obligation| { + let code = + infcx.probe(|_| match infcx.evaluate_root_goal(obligation.clone().into()) { + Ok((_, Certainty::Maybe(MaybeCause::Ambiguity), _)) => { + FulfillmentErrorCode::CodeAmbiguity { overflow: false } + } + Ok((_, Certainty::Maybe(MaybeCause::Overflow), _)) => { + FulfillmentErrorCode::CodeAmbiguity { overflow: true } + } + Ok((_, Certainty::Yes, _)) => { + bug!("did not expect successful goal when collecting ambiguity errors") + } + Err(_) => { + bug!("did not expect selection error when collecting ambiguity errors") + } + }); + + FulfillmentError { + obligation: obligation.clone(), + code, + root_obligation: obligation, + } }) .collect() } diff --git a/compiler/rustc_trait_selection/src/traits/chalk_fulfill.rs b/compiler/rustc_trait_selection/src/traits/chalk_fulfill.rs index b42a49eb47b90..28967e1cc55b2 100644 --- a/compiler/rustc_trait_selection/src/traits/chalk_fulfill.rs +++ b/compiler/rustc_trait_selection/src/traits/chalk_fulfill.rs @@ -40,13 +40,16 @@ impl<'tcx> TraitEngine<'tcx> for FulfillmentContext<'tcx> { self.obligations.insert(obligation); } - fn collect_remaining_errors(&mut self) -> Vec> { + fn collect_remaining_errors( + &mut self, + _infcx: &InferCtxt<'tcx>, + ) -> Vec> { // any remaining obligations are errors self.obligations .iter() .map(|obligation| FulfillmentError { obligation: obligation.clone(), - code: FulfillmentErrorCode::CodeAmbiguity, + code: FulfillmentErrorCode::CodeAmbiguity { overflow: false }, // FIXME - does Chalk have a notation of 'root obligation'? // This is just for diagnostics, so it's okay if this is wrong root_obligation: obligation.clone(), diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs index 6ebf056f0e837..5b49684cfcebc 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs @@ -125,6 +125,8 @@ pub trait TypeErrCtxtExt<'tcx> { + Print<'tcx, FmtPrinter<'tcx, 'tcx>, Output = FmtPrinter<'tcx, 'tcx>>, >>::Error: std::fmt::Debug; + fn report_overflow_no_abort(&self, obligation: PredicateObligation<'tcx>) -> ErrorGuaranteed; + fn report_fulfillment_errors(&self, errors: &[FulfillmentError<'tcx>]) -> ErrorGuaranteed; fn report_overflow_obligation( @@ -602,6 +604,14 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { ); } + fn report_overflow_no_abort(&self, obligation: PredicateObligation<'tcx>) -> ErrorGuaranteed { + let obligation = self.resolve_vars_if_possible(obligation); + let mut err = self.build_overflow_error(&obligation.predicate, obligation.cause.span, true); + self.note_obligation_cause(&mut err, &obligation); + self.point_at_returns_when_relevant(&mut err, &obligation); + err.emit() + } + fn report_selection_error( &self, mut obligation: PredicateObligation<'tcx>, @@ -1658,9 +1668,12 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> { FulfillmentErrorCode::CodeProjectionError(ref e) => { self.report_projection_error(&error.obligation, e); } - FulfillmentErrorCode::CodeAmbiguity => { + FulfillmentErrorCode::CodeAmbiguity { overflow: false } => { self.maybe_report_ambiguity(&error.obligation); } + FulfillmentErrorCode::CodeAmbiguity { overflow: true } => { + self.report_overflow_no_abort(error.obligation.clone()); + } FulfillmentErrorCode::CodeSubtypeError(ref expected_found, ref err) => { self.report_mismatched_types( &error.obligation.cause, diff --git a/compiler/rustc_trait_selection/src/traits/fulfill.rs b/compiler/rustc_trait_selection/src/traits/fulfill.rs index 07e31e87bfb46..26cadab3e9f1a 100644 --- a/compiler/rustc_trait_selection/src/traits/fulfill.rs +++ b/compiler/rustc_trait_selection/src/traits/fulfill.rs @@ -133,8 +133,15 @@ impl<'tcx> TraitEngine<'tcx> for FulfillmentContext<'tcx> { .register_obligation(PendingPredicateObligation { obligation, stalled_on: vec![] }); } - fn collect_remaining_errors(&mut self) -> Vec> { - self.predicates.to_errors(CodeAmbiguity).into_iter().map(to_fulfillment_error).collect() + fn collect_remaining_errors( + &mut self, + _infcx: &InferCtxt<'tcx>, + ) -> Vec> { + self.predicates + .to_errors(CodeAmbiguity { overflow: false }) + .into_iter() + .map(to_fulfillment_error) + .collect() } fn select_where_possible(&mut self, infcx: &InferCtxt<'tcx>) -> Vec> { diff --git a/config.example.toml b/config.example.toml index b27a34e61c545..6d9c762ceca1e 100644 --- a/config.example.toml +++ b/config.example.toml @@ -88,7 +88,7 @@ changelog-seen = 2 # the resulting rustc being unable to compile for the disabled architectures. # # To add support for new targets, see https://rustc-dev-guide.rust-lang.org/building/new-target.html. -#targets = "AArch64;ARM;BPF;Hexagon;MSP430;Mips;NVPTX;PowerPC;RISCV;Sparc;SystemZ;WebAssembly;X86" +#targets = "AArch64;ARM;BPF;Hexagon;LoongArch;MSP430;Mips;NVPTX;PowerPC;RISCV;Sparc;SystemZ;WebAssembly;X86" # LLVM experimental targets to build support for. These targets are specified in # the same format as above, but since these targets are experimental, they are @@ -257,7 +257,7 @@ changelog-seen = 2 #python = "python" # The path to the REUSE executable to use. Note that REUSE is not required in -# most cases, as our tooling relies on a cached (and shrinked) copy of the +# most cases, as our tooling relies on a cached (and shrunk) copy of the # REUSE output present in the git repository and in our source tarballs. # # REUSE is only needed if your changes caused the overall licensing of the diff --git a/library/std/src/env.rs b/library/std/src/env.rs index 183f9ab3b08f6..3014fe6e2fc2b 100644 --- a/library/std/src/env.rs +++ b/library/std/src/env.rs @@ -895,6 +895,7 @@ pub mod consts { /// - x86_64 /// - arm /// - aarch64 + /// - loongarch64 /// - m68k /// - mips /// - mips64 diff --git a/library/std/src/os/linux/raw.rs b/library/std/src/os/linux/raw.rs index f46028c3a96c9..c55ca8ba26e2f 100644 --- a/library/std/src/os/linux/raw.rs +++ b/library/std/src/os/linux/raw.rs @@ -231,6 +231,7 @@ mod arch { } #[cfg(any( + target_arch = "loongarch64", target_arch = "mips64", target_arch = "s390x", target_arch = "sparc64", diff --git a/library/std/src/personality/gcc.rs b/library/std/src/personality/gcc.rs index 41c0fe725a540..0421b47be024e 100644 --- a/library/std/src/personality/gcc.rs +++ b/library/std/src/personality/gcc.rs @@ -77,6 +77,9 @@ const UNWIND_DATA_REG: (i32, i32) = (0, 1); // R0, R1 #[cfg(any(target_arch = "riscv64", target_arch = "riscv32"))] const UNWIND_DATA_REG: (i32, i32) = (10, 11); // x10, x11 +#[cfg(target_arch = "loongarch64")] +const UNWIND_DATA_REG: (i32, i32) = (4, 5); // a0, a1 + // The following code is based on GCC's C and C++ personality routines. For reference, see: // https://github.com/gcc-mirror/gcc/blob/master/libstdc++-v3/libsupc++/eh_personality.cc // https://github.com/gcc-mirror/gcc/blob/trunk/libgcc/unwind-c.c diff --git a/library/std/src/sys/common/alloc.rs b/library/std/src/sys/common/alloc.rs index 403a5e627f1e7..a5fcbdf39c6c6 100644 --- a/library/std/src/sys/common/alloc.rs +++ b/library/std/src/sys/common/alloc.rs @@ -22,6 +22,7 @@ pub const MIN_ALIGN: usize = 8; #[cfg(any( target_arch = "x86_64", target_arch = "aarch64", + target_arch = "loongarch64", target_arch = "mips64", target_arch = "s390x", target_arch = "sparc64", diff --git a/library/unwind/src/libunwind.rs b/library/unwind/src/libunwind.rs index eeeed3afcd30c..f6a68073b2f7e 100644 --- a/library/unwind/src/libunwind.rs +++ b/library/unwind/src/libunwind.rs @@ -75,6 +75,9 @@ pub const unwinder_private_data_size: usize = 20; #[cfg(all(target_arch = "hexagon", target_os = "linux"))] pub const unwinder_private_data_size: usize = 35; +#[cfg(target_arch = "loongarch64")] +pub const unwinder_private_data_size: usize = 2; + #[repr(C)] pub struct _Unwind_Exception { pub exception_class: _Unwind_Exception_Class, diff --git a/src/bootstrap/bootstrap.py b/src/bootstrap/bootstrap.py index d12781cc33af0..025145244c491 100644 --- a/src/bootstrap/bootstrap.py +++ b/src/bootstrap/bootstrap.py @@ -304,6 +304,7 @@ def default_build_triple(verbose): 'i486': 'i686', 'i686': 'i686', 'i786': 'i686', + 'loongarch64': 'loongarch64', 'm68k': 'm68k', 'powerpc': 'powerpc', 'powerpc64': 'powerpc64', diff --git a/src/bootstrap/builder.rs b/src/bootstrap/builder.rs index ade8fa4c74dcb..e959ea06f8b69 100644 --- a/src/bootstrap/builder.rs +++ b/src/bootstrap/builder.rs @@ -591,6 +591,7 @@ pub enum Kind { Install, Run, Setup, + Suggest, } impl Kind { @@ -610,6 +611,7 @@ impl Kind { "install" => Kind::Install, "run" | "r" => Kind::Run, "setup" => Kind::Setup, + "suggest" => Kind::Suggest, _ => return None, }) } @@ -629,6 +631,7 @@ impl Kind { Kind::Install => "install", Kind::Run => "run", Kind::Setup => "setup", + Kind::Suggest => "suggest", } } } @@ -709,6 +712,7 @@ impl<'a> Builder<'a> { test::CrateRustdoc, test::CrateRustdocJsonTypes, test::CrateJsonDocLint, + test::SuggestTestsCrate, test::Linkcheck, test::TierCheck, test::ReplacePlaceholderTest, @@ -827,7 +831,7 @@ impl<'a> Builder<'a> { Kind::Setup => describe!(setup::Profile, setup::Hook, setup::Link, setup::Vscode), Kind::Clean => describe!(clean::CleanAll, clean::Rustc, clean::Std), // special-cased in Build::build() - Kind::Format => vec![], + Kind::Format | Kind::Suggest => vec![], } } @@ -891,6 +895,7 @@ impl<'a> Builder<'a> { Subcommand::Run { ref paths, .. } => (Kind::Run, &paths[..]), Subcommand::Clean { ref paths, .. } => (Kind::Clean, &paths[..]), Subcommand::Format { .. } => (Kind::Format, &[][..]), + Subcommand::Suggest { .. } => (Kind::Suggest, &[][..]), Subcommand::Setup { profile: ref path } => ( Kind::Setup, path.as_ref().map_or([].as_slice(), |path| std::slice::from_ref(path)), @@ -900,6 +905,21 @@ impl<'a> Builder<'a> { Self::new_internal(build, kind, paths.to_owned()) } + /// Creates a new standalone builder for use outside of the normal process + pub fn new_standalone( + build: &mut Build, + kind: Kind, + paths: Vec, + stage: Option, + ) -> Builder<'_> { + // FIXME: don't mutate `build` + if let Some(stage) = stage { + build.config.stage = stage; + } + + Self::new_internal(build, kind, paths.to_owned()) + } + pub fn execute_cli(&self) { self.run_step_descriptions(&Builder::get_step_descriptions(self.kind), &self.paths); } diff --git a/src/bootstrap/channel.rs b/src/bootstrap/channel.rs index 390047f6fdce1..c3e3fa009a677 100644 --- a/src/bootstrap/channel.rs +++ b/src/bootstrap/channel.rs @@ -139,7 +139,7 @@ pub fn read_commit_info_file(root: &Path) -> Option { sha: sha.to_owned(), short_sha: short_sha.to_owned(), }, - _ => panic!("the `git-comit-info` file is malformed"), + _ => panic!("the `git-commit-info` file is malformed"), }; Some(info) } else { diff --git a/src/bootstrap/compile.rs b/src/bootstrap/compile.rs index e3581943f2ca2..85d1c12cc6a09 100644 --- a/src/bootstrap/compile.rs +++ b/src/bootstrap/compile.rs @@ -83,11 +83,11 @@ impl Step for Std { let target = self.target; let compiler = self.compiler; - // These artifacts were already copied (in `impl Step for Sysroot`). - // Don't recompile them. + // When using `download-rustc`, we already have artifacts for the host available + // (they were copied in `impl Step for Sysroot`). Don't recompile them. // NOTE: the ABI of the beta compiler is different from the ABI of the downloaded compiler, // so its artifacts can't be reused. - if builder.download_rustc() && compiler.stage != 0 { + if builder.download_rustc() && compiler.stage != 0 && target == builder.build.build { return; } diff --git a/src/bootstrap/config.rs b/src/bootstrap/config.rs index dd65dc91c0cd3..cc3b3bc25f3d5 100644 --- a/src/bootstrap/config.rs +++ b/src/bootstrap/config.rs @@ -56,8 +56,7 @@ pub enum DryRun { /// filled out from the decoded forms of the structs below. For documentation /// each field, see the corresponding fields in /// `config.example.toml`. -#[derive(Default)] -#[cfg_attr(test, derive(Clone))] +#[derive(Default, Clone)] pub struct Config { pub changelog_seen: Option, pub ccache: Option, @@ -240,23 +239,20 @@ pub struct Config { pub initial_rustfmt: RefCell, } -#[derive(Default, Deserialize)] -#[cfg_attr(test, derive(Clone))] +#[derive(Default, Deserialize, Clone)] pub struct Stage0Metadata { pub compiler: CompilerMetadata, pub config: Stage0Config, pub checksums_sha256: HashMap, pub rustfmt: Option, } -#[derive(Default, Deserialize)] -#[cfg_attr(test, derive(Clone))] +#[derive(Default, Deserialize, Clone)] pub struct CompilerMetadata { pub date: String, pub version: String, } -#[derive(Default, Deserialize)] -#[cfg_attr(test, derive(Clone))] +#[derive(Default, Deserialize, Clone)] pub struct Stage0Config { pub dist_server: String, pub artifacts_server: String, @@ -264,8 +260,7 @@ pub struct Stage0Config { pub git_merge_commit_email: String, pub nightly_branch: String, } -#[derive(Default, Deserialize)] -#[cfg_attr(test, derive(Clone))] +#[derive(Default, Deserialize, Clone)] pub struct RustfmtMetadata { pub date: String, pub version: String, @@ -443,8 +438,7 @@ impl PartialEq<&str> for TargetSelection { } /// Per-target configuration stored in the global configuration structure. -#[derive(Default)] -#[cfg_attr(test, derive(Clone))] +#[derive(Default, Clone)] pub struct Target { /// Some(path to llvm-config) if using an external LLVM. pub llvm_config: Option, @@ -1396,7 +1390,8 @@ impl Config { | Subcommand::Fix { .. } | Subcommand::Run { .. } | Subcommand::Setup { .. } - | Subcommand::Format { .. } => flags.stage.unwrap_or(0), + | Subcommand::Format { .. } + | Subcommand::Suggest { .. } => flags.stage.unwrap_or(0), }; // CI should always run stage 2 builds, unless it specifically states otherwise @@ -1421,7 +1416,8 @@ impl Config { | Subcommand::Fix { .. } | Subcommand::Run { .. } | Subcommand::Setup { .. } - | Subcommand::Format { .. } => {} + | Subcommand::Format { .. } + | Subcommand::Suggest { .. } => {} } } diff --git a/src/bootstrap/flags.rs b/src/bootstrap/flags.rs index 2b0b772a61817..b6f5f31039838 100644 --- a/src/bootstrap/flags.rs +++ b/src/bootstrap/flags.rs @@ -84,8 +84,7 @@ pub struct Flags { pub free_args: Option>, } -#[derive(Debug)] -#[cfg_attr(test, derive(Clone))] +#[derive(Debug, Clone)] pub enum Subcommand { Build { paths: Vec, @@ -149,6 +148,9 @@ pub enum Subcommand { Setup { profile: Option, }, + Suggest { + run: bool, + }, } impl Default for Subcommand { @@ -183,6 +185,7 @@ Subcommands: install Install distribution artifacts run, r Run tools contained in this repository setup Create a config.toml (making it easier to use `x.py` itself) + suggest Suggest a subset of tests to run, based on modified files To learn more about a subcommand, run `./x.py -h`", ); @@ -349,6 +352,9 @@ To learn more about a subcommand, run `./x.py -h`", Kind::Run => { opts.optmulti("", "args", "arguments for the tool", "ARGS"); } + Kind::Suggest => { + opts.optflag("", "run", "run suggested tests"); + } _ => {} }; @@ -565,7 +571,7 @@ Arguments: Profile::all_for_help(" ").trim_end() )); } - Kind::Bench | Kind::Clean | Kind::Dist | Kind::Install => {} + Kind::Bench | Kind::Clean | Kind::Dist | Kind::Install | Kind::Suggest => {} }; // Get any optional paths which occur after the subcommand let mut paths = matches.free[1..].iter().map(|p| p.into()).collect::>(); @@ -626,6 +632,7 @@ Arguments: Kind::Format => Subcommand::Format { check: matches.opt_present("check"), paths }, Kind::Dist => Subcommand::Dist { paths }, Kind::Install => Subcommand::Install { paths }, + Kind::Suggest => Subcommand::Suggest { run: matches.opt_present("run") }, Kind::Run => { if paths.is_empty() { println!("\nrun requires at least a path!\n"); @@ -734,6 +741,7 @@ impl Subcommand { Subcommand::Install { .. } => Kind::Install, Subcommand::Run { .. } => Kind::Run, Subcommand::Setup { .. } => Kind::Setup, + Subcommand::Suggest { .. } => Kind::Suggest, } } diff --git a/src/bootstrap/lib.rs b/src/bootstrap/lib.rs index 5ee18cf641104..1aed07f4923ae 100644 --- a/src/bootstrap/lib.rs +++ b/src/bootstrap/lib.rs @@ -58,6 +58,7 @@ mod render_tests; mod run; mod sanity; mod setup; +mod suggest; mod tarball; mod test; mod tool; @@ -129,7 +130,8 @@ const EXTRA_CHECK_CFGS: &[(Option, &'static str, Option<&[&'static str]>)] /* Extra values not defined in the built-in targets yet, but used in std */ (Some(Mode::Std), "target_env", Some(&["libnx"])), // (Some(Mode::Std), "target_os", Some(&[])), - (Some(Mode::Std), "target_arch", Some(&["asmjs", "spirv", "nvptx", "xtensa"])), + // #[cfg(bootstrap)] loongarch64 + (Some(Mode::Std), "target_arch", Some(&["asmjs", "spirv", "nvptx", "xtensa", "loongarch64"])), /* Extra names used by dependencies */ // FIXME: Used by serde_json, but we should not be triggering on external dependencies. (Some(Mode::Rustc), "no_btreemap_remove_entry", None), @@ -189,6 +191,7 @@ pub enum GitRepo { /// although most functions are implemented as free functions rather than /// methods specifically on this structure itself (to make it easier to /// organize). +#[derive(Clone)] pub struct Build { /// User-specified configuration from `config.toml`. config: Config, @@ -242,7 +245,7 @@ pub struct Build { metrics: metrics::BuildMetrics, } -#[derive(Debug)] +#[derive(Debug, Clone)] struct Crate { name: Interned, deps: HashSet>, @@ -656,13 +659,20 @@ impl Build { job::setup(self); } - if let Subcommand::Format { check, paths } = &self.config.cmd { - return format::format(&builder::Builder::new(&self), *check, &paths); - } - // Download rustfmt early so that it can be used in rust-analyzer configs. let _ = &builder::Builder::new(&self).initial_rustfmt(); + // hardcoded subcommands + match &self.config.cmd { + Subcommand::Format { check, paths } => { + return format::format(&builder::Builder::new(&self), *check, &paths); + } + Subcommand::Suggest { run } => { + return suggest::suggest(&builder::Builder::new(&self), *run); + } + _ => (), + } + { let builder = builder::Builder::new(&self); if let Some(path) = builder.paths.get(0) { diff --git a/src/bootstrap/llvm.rs b/src/bootstrap/llvm.rs index cc2b45a9bdb5c..d123deec35454 100644 --- a/src/bootstrap/llvm.rs +++ b/src/bootstrap/llvm.rs @@ -291,7 +291,7 @@ impl Step for Llvm { let llvm_targets = match &builder.config.llvm_targets { Some(s) => s, None => { - "AArch64;ARM;BPF;Hexagon;MSP430;Mips;NVPTX;PowerPC;RISCV;\ + "AArch64;ARM;BPF;Hexagon;LoongArch;MSP430;Mips;NVPTX;PowerPC;RISCV;\ Sparc;SystemZ;WebAssembly;X86" } }; diff --git a/src/bootstrap/suggest.rs b/src/bootstrap/suggest.rs new file mode 100644 index 0000000000000..1a482e4165944 --- /dev/null +++ b/src/bootstrap/suggest.rs @@ -0,0 +1,72 @@ +use std::str::FromStr; + +use std::path::PathBuf; + +use crate::{ + builder::{Builder, Kind}, + tool::Tool, +}; + +/// Suggests a list of possible `x.py` commands to run based on modified files in branch. +pub fn suggest(builder: &Builder<'_>, run: bool) { + let suggestions = + builder.tool_cmd(Tool::SuggestTests).output().expect("failed to run `suggest-tests` tool"); + + if !suggestions.status.success() { + println!("failed to run `suggest-tests` tool ({})", suggestions.status); + println!( + "`suggest_tests` stdout:\n{}`suggest_tests` stderr:\n{}", + String::from_utf8(suggestions.stdout).unwrap(), + String::from_utf8(suggestions.stderr).unwrap() + ); + panic!("failed to run `suggest-tests`"); + } + + let suggestions = String::from_utf8(suggestions.stdout).unwrap(); + let suggestions = suggestions + .lines() + .map(|line| { + let mut sections = line.split_ascii_whitespace(); + + // this code expects one suggestion per line in the following format: + // {some number of flags} [optional stage number] + let cmd = sections.next().unwrap(); + let stage = sections.next_back().map(|s| str::parse(s).ok()).flatten(); + let paths: Vec = sections.map(|p| PathBuf::from_str(p).unwrap()).collect(); + + (cmd, stage, paths) + }) + .collect::>(); + + if !suggestions.is_empty() { + println!("==== SUGGESTIONS ===="); + for sug in &suggestions { + print!("x {} ", sug.0); + if let Some(stage) = sug.1 { + print!("--stage {stage} "); + } + + for path in &sug.2 { + print!("{} ", path.display()); + } + println!(); + } + println!("====================="); + } else { + println!("No suggestions found!"); + return; + } + + if run { + for sug in suggestions { + let mut build = builder.build.clone(); + + let builder = + Builder::new_standalone(&mut build, Kind::parse(&sug.0).unwrap(), sug.2, sug.1); + + builder.execute_cli() + } + } else { + println!("help: consider using the `--run` flag to automatically run suggested tests"); + } +} diff --git a/src/bootstrap/test.rs b/src/bootstrap/test.rs index 058ff429e80f1..1d55992446eb4 100644 --- a/src/bootstrap/test.rs +++ b/src/bootstrap/test.rs @@ -128,6 +128,42 @@ impl Step for CrateJsonDocLint { } } +#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] +pub struct SuggestTestsCrate { + host: TargetSelection, +} + +impl Step for SuggestTestsCrate { + type Output = (); + const ONLY_HOSTS: bool = true; + const DEFAULT: bool = true; + + fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { + run.path("src/tools/suggest-tests") + } + + fn make_run(run: RunConfig<'_>) { + run.builder.ensure(SuggestTestsCrate { host: run.target }); + } + + fn run(self, builder: &Builder<'_>) { + let bootstrap_host = builder.config.build; + let compiler = builder.compiler(0, bootstrap_host); + + let suggest_tests = tool::prepare_tool_cargo( + builder, + compiler, + Mode::ToolBootstrap, + bootstrap_host, + "test", + "src/tools/suggest-tests", + SourceType::InTree, + &[], + ); + add_flags_and_try_run_tests(builder, &mut suggest_tests.into()); + } +} + #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] pub struct Linkcheck { host: TargetSelection, diff --git a/src/bootstrap/tool.rs b/src/bootstrap/tool.rs index 6a687a7903e0f..d1fd2e8c42cb0 100644 --- a/src/bootstrap/tool.rs +++ b/src/bootstrap/tool.rs @@ -433,6 +433,7 @@ bootstrap_tool!( ReplaceVersionPlaceholder, "src/tools/replace-version-placeholder", "replace-version-placeholder"; CollectLicenseMetadata, "src/tools/collect-license-metadata", "collect-license-metadata"; GenerateCopyright, "src/tools/generate-copyright", "generate-copyright"; + SuggestTests, "src/tools/suggest-tests", "suggest-tests"; ); #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq, Ord, PartialOrd)] diff --git a/src/doc/rustc/src/SUMMARY.md b/src/doc/rustc/src/SUMMARY.md index 0452126cc3782..8ded2ee59dd20 100644 --- a/src/doc/rustc/src/SUMMARY.md +++ b/src/doc/rustc/src/SUMMARY.md @@ -29,6 +29,7 @@ - [\*-linux-ohos](platform-support/openharmony.md) - [\*-unknown-fuchsia](platform-support/fuchsia.md) - [\*-kmc-solid_\*](platform-support/kmc-solid.md) + - [loongarch\*-unknown-linux-\*](platform-support/loongarch-linux.md) - [m68k-unknown-linux-gnu](platform-support/m68k-unknown-linux-gnu.md) - [mips64-openwrt-linux-musl](platform-support/mips64-openwrt-linux-musl.md) - [mipsel-sony-psx](platform-support/mipsel-sony-psx.md) diff --git a/src/doc/rustc/src/platform-support.md b/src/doc/rustc/src/platform-support.md index 67fe2a610c22c..c378532dbf6c3 100644 --- a/src/doc/rustc/src/platform-support.md +++ b/src/doc/rustc/src/platform-support.md @@ -266,6 +266,7 @@ target | std | host | notes `i686-uwp-windows-gnu` | ? | | `i686-uwp-windows-msvc` | ? | | `i686-wrs-vxworks` | ? | | +[`loongarch64-unknown-linux-gnu`](platform-support/loongarch-linux.md) | ? | | LoongArch64 Linux (LP64D ABI) [`m68k-unknown-linux-gnu`](platform-support/m68k-unknown-linux-gnu.md) | ? | | Motorola 680x0 Linux `mips-unknown-linux-uclibc` | ✓ | | MIPS Linux with uClibc [`mips64-openwrt-linux-musl`](platform-support/mips64-openwrt-linux-musl.md) | ? | | MIPS64 for OpenWrt Linux MUSL diff --git a/src/doc/rustc/src/platform-support/loongarch-linux.md b/src/doc/rustc/src/platform-support/loongarch-linux.md new file mode 100644 index 0000000000000..e046ec244ece9 --- /dev/null +++ b/src/doc/rustc/src/platform-support/loongarch-linux.md @@ -0,0 +1,92 @@ +# loongarch\*-unknown-linux-\* + +**Tier: 3** + +[LoongArch] is a new RISC ISA developed by Loongson Technology Corporation Limited. + +[LoongArch]: https://loongson.github.io/LoongArch-Documentation/README-EN.html + +The target name follow this format: `--, where `` specifies the CPU family/model, `` specifies the vendor and `` the operating system name. +While the integer base ABI is implied by the machine field, the floating point base ABI type is encoded into the os field of the specifier using the string suffix ``. + +| `` | `Description` | +|------------------------|--------------------------------------------------------------------| +| f64 | The base ABI use 64-bits FPRs for parameter passing.(lp64d)| +| f32 | The base ABI uses 32-bit FPRs for parameter passing. (lp64f)| +| sf | The base ABI uses no FPR for parameter passing. (lp64s) | + +|`ABI type(Base ABI/ABI extension)`| `C library` | `kernel` | `target tuple` | +|----------------------------------|-------------|----------|----------------------------------| +| lp64d/base | glibc | linux | loongarch64-unknown-linux-gnu | +| lp64f/base | glibc | linux | loongarch64-unknown-linux-gnuf32 | +| lp64s/base | glibc | linux | loongarch64-unknown-linux-gnusf | +| lp64d/base | musl libc | linux | loongarch64-unknown-linux-musl| +| lp64f/base | musl libc | linux | loongarch64-unknown-linux-muslf32| +| lp64s/base | musl libc | linux | loongarch64-unknown-linux-muslsf | + +## Target maintainers + +- [ZHAI xiaojuan](https://github.com/zhaixiaojuan) `zhaixiaojuan@loongson.cn` +- [WANG rui](https://github.com/heiher) `wangrui@loongson.cn` +- [ZHAI xiang](https://github.com/xiangzhai) `zhaixiang@loongson.cn` +- [WANG Xuerui](https://github.com/xen0n) `git@xen0n.name` + +## Requirements + +This target is cross-compiled. +A GNU toolchain for LoongArch target is required. It can be downloaded from https://github.com/loongson/build-tools/releases, or built from the source code of GCC (12.1.0 or later) and Binutils (2.40 or later). + +## Building the target + +The target can be built by enabling it for a `rustc` build. + +```toml +[build] +target = ["loongarch64-unknown-linux-gnu"] +``` + +Make sure `loongarch64-unknown-linux-gnu-gcc` can be searched from the directories specified in`$PATH`. Alternatively, you can use GNU LoongArch Toolchain by adding the following to `config.toml`: + +```toml +[target.loongarch64-unknown-linux-gnu] +# ADJUST THIS PATH TO POINT AT YOUR TOOLCHAIN +cc = "/TOOLCHAIN_PATH/bin/loongarch64-unknown-linux-gnu-gcc" +cxx = "/TOOLCHAIN_PATH/bin/loongarch64-unknown-linux-gnu-g++" +ar = "/TOOLCHAIN_PATH/bin/loongarch64-unknown-linux-gnu-ar" +ranlib = "/TOOLCHAIN_PATH/bin/loongarch64-unknown-linux-gnu-ranlib" +linker = "/TOOLCHAIN_PATH/bin/loongarch64-unknown-linux-gnu-gcc" +``` + +## Cross-compilation + +This target can be cross-compiled on a `x86_64-unknown-linux-gnu` host. Cross-compilation on other hosts may work but is not tested. + +## Testing +To test a cross-compiled binary on your build system, install the qemu binary that supports the LoongArch architecture and execute the following commands. +```text +CC_loongarch64_unknown_linux_gnu=/TOOLCHAIN_PATH/bin/loongarch64-unknown-linux-gnu-gcc \ +CXX_loongarch64_unknown_linux_gnu=/TOOLCHAIN_PATH/bin/loongarch64-unknown-linux-gnu-g++ \ +AR_loongarch64_unknown_linux_gnu=/TOOLCHAIN_PATH/bin/loongarch64-unknown-linux-gnu-gcc-ar \ +CARGO_TARGET_LOONGARCH64_UNKNOWN_LINUX_GNUN_LINKER=/TOOLCHAIN_PATH/bin/loongarch64-unknown-linux-gnu-gcc \ +# SET TARGET SYSTEM LIBRARY PATH +CARGO_TARGET_LOONGARCH64_UNKNOWN_LINUX_GNUN_RUNNER="qemu-loongarch64 -L /TOOLCHAIN_PATH/TARGET_LIBRAY_PATH" \ +cargo run --target loongarch64-unknown-linux-gnu --release +``` +Tested on x86 architecture, other architectures not tested. + +## Building Rust programs + +Rust does not yet ship pre-compiled artifacts for this target. To compile for this target, you will either need to build Rust with the target enabled (see "Building the target" above), or build your own copy of `std` by using `build-std` or similar. + +If `rustc` has support for that target and the library artifacts are available, then Rust static libraries can be built for that target: + +```shell +$ rustc --target loongarch64-unknown-linux-gnu your-code.rs --crate-type staticlib +$ ls libyour_code.a +``` + +On Rust Nightly it's possible to build without the target artifacts available: + +```text +cargo build -Z build-std --target loongarch64-unknown-linux-gnu +``` diff --git a/src/doc/style-guide/src/expressions.md b/src/doc/style-guide/src/expressions.md index c7d0446dded19..96f66c89c259f 100644 --- a/src/doc/style-guide/src/expressions.md +++ b/src/doc/style-guide/src/expressions.md @@ -643,7 +643,7 @@ Examples: ```rust match foo { foo => bar, - a_very_long_patten | another_pattern if an_expression() => { + a_very_long_pattern | another_pattern if an_expression() => { no_room_for_this_expression() } foo => { diff --git a/src/doc/unstable-book/src/compiler-flags/dump-mono-stats-format.md b/src/doc/unstable-book/src/compiler-flags/dump-mono-stats-format.md index a497a75261fed..05ffdcf201c82 100644 --- a/src/doc/unstable-book/src/compiler-flags/dump-mono-stats-format.md +++ b/src/doc/unstable-book/src/compiler-flags/dump-mono-stats-format.md @@ -3,4 +3,4 @@ -------------------- The `-Z dump-mono-stats-format` compiler flag controls what file format to use for `-Z dump-mono-stats`. -The default is markdown; currently JSON is also supported. JSON can be useful for programatically manipulating the results (e.g. to find the item that took the longest to compile). +The default is markdown; currently JSON is also supported. JSON can be useful for programmatically manipulating the results (e.g. to find the item that took the longest to compile). diff --git a/src/etc/installer/msi/rust.wxs b/src/etc/installer/msi/rust.wxs index 9f4e4fd0611df..f29e1e4d27a27 100644 --- a/src/etc/installer/msi/rust.wxs +++ b/src/etc/installer/msi/rust.wxs @@ -119,7 +119,7 @@ NOT ALLUSERS - + NOT ALLUSERS diff --git a/src/librustdoc/clean/cfg.rs b/src/librustdoc/clean/cfg.rs index dd58a5b51fc1a..5177cffe6bae4 100644 --- a/src/librustdoc/clean/cfg.rs +++ b/src/librustdoc/clean/cfg.rs @@ -517,6 +517,7 @@ impl<'a> fmt::Display for Display<'a> { "aarch64" => "AArch64", "arm" => "ARM", "asmjs" => "JavaScript", + "loongarch64" => "LoongArch LA64", "m68k" => "M68k", "mips" => "MIPS", "mips64" => "MIPS-64", diff --git a/src/librustdoc/config.rs b/src/librustdoc/config.rs index ea8c7e9a67c32..c848089dad6b9 100644 --- a/src/librustdoc/config.rs +++ b/src/librustdoc/config.rs @@ -230,7 +230,7 @@ pub(crate) struct RenderOptions { pub(crate) extension_css: Option, /// A map of crate names to the URL to use instead of querying the crate's `html_root_url`. pub(crate) extern_html_root_urls: BTreeMap, - /// Whether to give precedence to `html_root_url` or `--exten-html-root-url`. + /// Whether to give precedence to `html_root_url` or `--extern-html-root-url`. pub(crate) extern_html_root_takes_precedence: bool, /// A map of the default settings (values are as for DOM storage API). Keys should lack the /// `rustdoc-` prefix. diff --git a/src/librustdoc/html/format.rs b/src/librustdoc/html/format.rs index 7a2449cbe9ace..1b445b8981e1a 100644 --- a/src/librustdoc/html/format.rs +++ b/src/librustdoc/html/format.rs @@ -349,10 +349,10 @@ pub(crate) fn print_where_clause<'a, 'tcx: 'a>( let mut br_with_padding = String::with_capacity(6 * indent + 28); br_with_padding.push_str("\n"); - let padding_amout = + let padding_amount = if ending == Ending::Newline { indent + 4 } else { indent + "fn where ".len() }; - for _ in 0..padding_amout { + for _ in 0..padding_amount { br_with_padding.push_str(" "); } let where_preds = where_preds.to_string().replace('\n', &br_with_padding); diff --git a/src/librustdoc/html/render/print_item.rs b/src/librustdoc/html/render/print_item.rs index 6bce57340040b..9a968e48b272f 100644 --- a/src/librustdoc/html/render/print_item.rs +++ b/src/librustdoc/html/render/print_item.rs @@ -1796,10 +1796,11 @@ fn render_struct( } match ty { None => { - let where_diplayed = g.map(|g| print_where_clause_and_check(w, g, cx)).unwrap_or(false); + let where_displayed = + g.map(|g| print_where_clause_and_check(w, g, cx)).unwrap_or(false); // If there wasn't a `where` clause, we add a whitespace. - if !where_diplayed { + if !where_displayed { w.write_str(" {"); } else { w.write_str("{"); diff --git a/src/rustdoc-json-types/lib.rs b/src/rustdoc-json-types/lib.rs index 4c210291b113b..3cf8ceed62036 100644 --- a/src/rustdoc-json-types/lib.rs +++ b/src/rustdoc-json-types/lib.rs @@ -550,7 +550,7 @@ pub enum Type { DynTrait(DynTrait), /// Parameterized types Generic(String), - /// Built in numberic (i*, u*, f*) types, bool, and char + /// Built in numeric (i*, u*, f*) types, bool, and char Primitive(String), /// `extern "ABI" fn` FunctionPointer(Box), diff --git a/src/tools/collect-license-metadata/src/path_tree.rs b/src/tools/collect-license-metadata/src/path_tree.rs index 7a2a440636d91..68b6cef643272 100644 --- a/src/tools/collect-license-metadata/src/path_tree.rs +++ b/src/tools/collect-license-metadata/src/path_tree.rs @@ -10,8 +10,8 @@ use std::path::{Path, PathBuf}; #[derive(serde::Serialize)] #[serde(rename_all = "kebab-case", tag = "type")] pub(crate) enum Node { - Root { childs: Vec> }, - Directory { name: PathBuf, childs: Vec>, license: Option }, + Root { children: Vec> }, + Directory { name: PathBuf, children: Vec>, license: Option }, File { name: PathBuf, license: L }, Group { files: Vec, directories: Vec, license: L }, Empty, @@ -48,14 +48,14 @@ impl Node { /// ``` fn merge_directories(&mut self) { match self { - Node::Root { childs } | Node::Directory { childs, license: None, .. } => { + Node::Root { children } | Node::Directory { children, license: None, .. } => { let mut directories = BTreeMap::new(); let mut files = Vec::new(); - for child in childs.drain(..) { + for child in children.drain(..) { match child { - Node::Directory { name, mut childs, license: None } => { - directories.entry(name).or_insert_with(Vec::new).append(&mut childs); + Node::Directory { name, mut children, license: None } => { + directories.entry(name).or_insert_with(Vec::new).append(&mut children); } file @ Node::File { .. } => { files.push(file); @@ -73,14 +73,14 @@ impl Node { } } - childs.extend(directories.into_iter().map(|(name, childs)| Node::Directory { + children.extend(directories.into_iter().map(|(name, children)| Node::Directory { name, - childs, + children, license: None, })); - childs.append(&mut files); + children.append(&mut files); - for child in &mut *childs { + for child in &mut *children { child.merge_directories(); } } @@ -105,13 +105,13 @@ impl Node { /// our inclusion of LLVM. fn collapse_in_licensed_directories(&mut self) { match self { - Node::Directory { childs, license, .. } => { - for child in &mut *childs { + Node::Directory { children, license, .. } => { + for child in &mut *children { child.collapse_in_licensed_directories(); } let mut licenses_count = BTreeMap::new(); - for child in &*childs { + for child in &*children { let Some(license) = child.license() else { continue }; *licenses_count.entry(license).or_insert(0) += 1; } @@ -122,12 +122,12 @@ impl Node { .map(|(license, _)| license); if let Some(most_popular_license) = most_popular_license { - childs.retain(|child| child.license() != Some(most_popular_license)); + children.retain(|child| child.license() != Some(most_popular_license)); *license = Some(most_popular_license); } } - Node::Root { childs } => { - for child in &mut *childs { + Node::Root { children } => { + for child in &mut *children { child.collapse_in_licensed_directories(); } } @@ -138,29 +138,29 @@ impl Node { } /// Reduce the depth of the tree by merging subdirectories with the same license as their - /// parent directory into their parent, and adjusting the paths of the childs accordingly. + /// parent directory into their parent, and adjusting the paths of the children accordingly. fn merge_directory_licenses(&mut self) { match self { - Node::Root { childs } => { - for child in &mut *childs { + Node::Root { children } => { + for child in &mut *children { child.merge_directory_licenses(); } } - Node::Directory { childs, license, .. } => { + Node::Directory { children, license, .. } => { let mut to_add = Vec::new(); - for child in &mut *childs { + for child in &mut *children { child.merge_directory_licenses(); let Node::Directory { name: child_name, - childs: child_childs, + children: child_children, license: child_license, } = child else { continue }; if child_license != license { continue; } - for mut child_child in child_childs.drain(..) { + for mut child_child in child_children.drain(..) { match &mut child_child { Node::Root { .. } => { panic!("can't have a root inside another element"); @@ -181,7 +181,7 @@ impl Node { *child = Node::Empty; } - childs.append(&mut to_add); + children.append(&mut to_add); } Node::Empty => {} Node::File { .. } => {} @@ -203,14 +203,14 @@ impl Node { directories: Vec, } match self { - Node::Root { childs } | Node::Directory { childs, .. } => { + Node::Root { children } | Node::Directory { children, .. } => { let mut grouped: BTreeMap = BTreeMap::new(); - for child in &mut *childs { + for child in &mut *children { child.merge_groups(); match child { - Node::Directory { name, childs, license: Some(license) } => { - if childs.is_empty() { + Node::Directory { name, children, license: Some(license) } => { + if children.is_empty() { grouped .entry(*license) .or_insert_with(Grouped::default) @@ -234,16 +234,16 @@ impl Node { for (license, mut grouped) in grouped.into_iter() { if grouped.files.len() + grouped.directories.len() <= 1 { if let Some(name) = grouped.files.pop() { - childs.push(Node::File { license, name }); + children.push(Node::File { license, name }); } else if let Some(name) = grouped.directories.pop() { - childs.push(Node::Directory { + children.push(Node::Directory { name, - childs: Vec::new(), + children: Vec::new(), license: Some(license), }); } } else { - childs.push(Node::Group { + children.push(Node::Group { license, files: grouped.files, directories: grouped.directories, @@ -261,11 +261,11 @@ impl Node { /// sure to remove them from the tree. fn remove_empty(&mut self) { match self { - Node::Root { childs } | Node::Directory { childs, .. } => { - for child in &mut *childs { + Node::Root { children } | Node::Directory { children, .. } => { + for child in &mut *children { child.remove_empty(); } - childs.retain(|child| !matches!(child, Node::Empty)); + children.retain(|child| !matches!(child, Node::Empty)); } Node::Group { .. } => {} Node::File { .. } => {} @@ -275,7 +275,7 @@ impl Node { fn license(&self) -> Option { match self { - Node::Directory { childs, license: Some(license), .. } if childs.is_empty() => { + Node::Directory { children, license: Some(license), .. } if children.is_empty() => { Some(*license) } Node::File { license, .. } => Some(*license), @@ -285,7 +285,7 @@ impl Node { } pub(crate) fn build(mut input: Vec<(PathBuf, LicenseId)>) -> Node { - let mut childs = Vec::new(); + let mut children = Vec::new(); // Ensure reproducibility of all future steps. input.sort(); @@ -295,15 +295,15 @@ pub(crate) fn build(mut input: Vec<(PathBuf, LicenseId)>) -> Node { for component in path.parent().unwrap_or_else(|| Path::new(".")).components().rev() { node = Node::Directory { name: component.as_os_str().into(), - childs: vec![node], + children: vec![node], license: None, }; } - childs.push(node); + children.push(node); } - Node::Root { childs } + Node::Root { children } } /// Convert a `Node` into a `Node<&License>`, expanding all interned license IDs with a @@ -313,14 +313,14 @@ pub(crate) fn expand_interned_licenses( interner: &LicensesInterner, ) -> Node<&License> { match node { - Node::Root { childs } => Node::Root { - childs: childs + Node::Root { children } => Node::Root { + children: children .into_iter() .map(|child| expand_interned_licenses(child, interner)) .collect(), }, - Node::Directory { name, childs, license } => Node::Directory { - childs: childs + Node::Directory { name, children, license } => Node::Directory { + children: children .into_iter() .map(|child| expand_interned_licenses(child, interner)) .collect(), diff --git a/src/tools/generate-copyright/src/main.rs b/src/tools/generate-copyright/src/main.rs index 4d116c7da653a..60c77167613db 100644 --- a/src/tools/generate-copyright/src/main.rs +++ b/src/tools/generate-copyright/src/main.rs @@ -20,17 +20,17 @@ fn render_recursive(node: &Node, buffer: &mut Vec, depth: usize) -> Result<( let prefix = std::iter::repeat("> ").take(depth + 1).collect::(); match node { - Node::Root { childs } => { - for child in childs { + Node::Root { children } => { + for child in children { render_recursive(child, buffer, depth)?; } } - Node::Directory { name, childs, license } => { + Node::Directory { name, children, license } => { render_license(&prefix, std::iter::once(name), license, buffer)?; - if !childs.is_empty() { + if !children.is_empty() { writeln!(buffer, "{prefix}")?; writeln!(buffer, "{prefix}*Exceptions:*")?; - for child in childs { + for child in children { writeln!(buffer, "{prefix}")?; render_recursive(child, buffer, depth + 1)?; } @@ -73,8 +73,8 @@ struct Metadata { #[derive(serde::Deserialize)] #[serde(rename_all = "kebab-case", tag = "type")] pub(crate) enum Node { - Root { childs: Vec }, - Directory { name: String, childs: Vec, license: License }, + Root { children: Vec }, + Directory { name: String, children: Vec, license: License }, File { name: String, license: License }, Group { files: Vec, directories: Vec, license: License }, } diff --git a/src/tools/jsondocck/src/main.rs b/src/tools/jsondocck/src/main.rs index 76770fe36a708..e3d05ec83159d 100644 --- a/src/tools/jsondocck/src/main.rs +++ b/src/tools/jsondocck/src/main.rs @@ -237,7 +237,7 @@ fn check_command(command: Command, cache: &mut Cache) -> Result<(), CkError> { // Serde json doesn't implement Ord or Hash for Value, so we must // use a Vec here. While in theory that makes setwize equality - // O(n^2), in practice n will never be large enought to matter. + // O(n^2), in practice n will never be large enough to matter. let expected_values = values.iter().map(|v| string_to_value(v, cache)).collect::>(); if expected_values.len() != got_values.len() { diff --git a/src/tools/jsondoclint/src/item_kind.rs b/src/tools/jsondoclint/src/item_kind.rs index b395c6e7d2d62..45a9c93ee0b54 100644 --- a/src/tools/jsondoclint/src/item_kind.rs +++ b/src/tools/jsondoclint/src/item_kind.rs @@ -1,6 +1,6 @@ use rustdoc_json_types::{Item, ItemEnum, ItemKind, ItemSummary}; -/// A univeral way to represent an [`ItemEnum`] or [`ItemKind`] +/// A universal way to represent an [`ItemEnum`] or [`ItemKind`] #[derive(Debug, Clone, Copy)] pub(crate) enum Kind { Module, @@ -53,7 +53,7 @@ impl Kind { Primitive => true, ForeignType => true, - // FIXME(adotinthevoid): I'm not sure if these are corrent + // FIXME(adotinthevoid): I'm not sure if these are correct Keyword => false, OpaqueTy => false, ProcAttribute => false, diff --git a/src/tools/jsondoclint/src/main.rs b/src/tools/jsondoclint/src/main.rs index 05e938f4f7df4..ee163ddfdd9a8 100644 --- a/src/tools/jsondoclint/src/main.rs +++ b/src/tools/jsondoclint/src/main.rs @@ -72,7 +72,7 @@ fn main() -> Result<()> { ) } [sel] => eprintln!( - "{} not in index or paths, but refered to at '{}'", + "{} not in index or paths, but referred to at '{}'", err.id.0, json_find::to_jsonpath(&sel) ), @@ -85,12 +85,12 @@ fn main() -> Result<()> { .collect::>() .join(", "); eprintln!( - "{} not in index or paths, but refered to at {sels}", + "{} not in index or paths, but referred to at {sels}", err.id.0 ); } else { eprintln!( - "{} not in index or paths, but refered to at '{}' and {} more", + "{} not in index or paths, but referred to at '{}' and {} more", err.id.0, json_find::to_jsonpath(&sel), sels.len() - 1, diff --git a/src/tools/publish_toolstate.py b/src/tools/publish_toolstate.py index 395bcc745f8dd..2018c239ba068 100755 --- a/src/tools/publish_toolstate.py +++ b/src/tools/publish_toolstate.py @@ -86,7 +86,7 @@ def gh_url(): return os.environ['TOOLSTATE_ISSUES_API_URL'] -def maybe_delink(message): +def maybe_remove_mention(message): # type: (str) -> str if os.environ.get('TOOLSTATE_SKIP_MENTIONS') is not None: return message.replace("@", "") @@ -109,7 +109,7 @@ def issue( else: status_description = 'no longer builds' request = json.dumps({ - 'body': maybe_delink(textwrap.dedent('''\ + 'body': maybe_remove_mention(textwrap.dedent('''\ Hello, this is your friendly neighborhood mergebot. After merging PR {}, I observed that the tool {} {}. A follow-up PR to the repository {} is needed to fix the fallout. @@ -285,7 +285,7 @@ def update_latest( issue_url = gh_url() + '/{}/comments'.format(number) response = urllib2.urlopen(urllib2.Request( issue_url, - json.dumps({'body': maybe_delink(message)}).encode(), + json.dumps({'body': maybe_remove_mention(message)}).encode(), { 'Authorization': 'token ' + github_token, 'Content-Type': 'application/json', diff --git a/src/tools/suggest-tests/Cargo.toml b/src/tools/suggest-tests/Cargo.toml new file mode 100644 index 0000000000000..f4f4d548bb79e --- /dev/null +++ b/src/tools/suggest-tests/Cargo.toml @@ -0,0 +1,9 @@ +[package] +name = "suggest-tests" +version = "0.1.0" +edition = "2021" + +[dependencies] +glob = "0.3.0" +build_helper = { version = "0.1.0", path = "../build_helper" } +once_cell = "1.17.1" diff --git a/src/tools/suggest-tests/src/dynamic_suggestions.rs b/src/tools/suggest-tests/src/dynamic_suggestions.rs new file mode 100644 index 0000000000000..2b0213cdc223c --- /dev/null +++ b/src/tools/suggest-tests/src/dynamic_suggestions.rs @@ -0,0 +1,23 @@ +use std::path::Path; + +use crate::Suggestion; + +type DynamicSuggestion = fn(&Path) -> Vec; + +pub(crate) const DYNAMIC_SUGGESTIONS: &[DynamicSuggestion] = &[|path: &Path| -> Vec { + if path.starts_with("compiler/") || path.starts_with("library/") { + let path = path.components().take(2).collect::>(); + + vec![Suggestion::with_single_path( + "test", + None, + &format!( + "{}/{}", + path[0].as_os_str().to_str().unwrap(), + path[1].as_os_str().to_str().unwrap() + ), + )] + } else { + Vec::new() + } +}]; diff --git a/src/tools/suggest-tests/src/lib.rs b/src/tools/suggest-tests/src/lib.rs new file mode 100644 index 0000000000000..44cd3c7f6a84d --- /dev/null +++ b/src/tools/suggest-tests/src/lib.rs @@ -0,0 +1,96 @@ +use std::{ + fmt::{self, Display}, + path::Path, +}; + +use dynamic_suggestions::DYNAMIC_SUGGESTIONS; +use glob::Pattern; +use static_suggestions::STATIC_SUGGESTIONS; + +mod dynamic_suggestions; +mod static_suggestions; + +#[cfg(test)] +mod tests; + +macro_rules! sug { + ($cmd:expr) => { + Suggestion::new($cmd, None, &[]) + }; + + ($cmd:expr, $paths:expr) => { + Suggestion::new($cmd, None, $paths.as_slice()) + }; + + ($cmd:expr, $stage:expr, $paths:expr) => { + Suggestion::new($cmd, Some($stage), $paths.as_slice()) + }; +} + +pub(crate) use sug; + +pub fn get_suggestions>(modified_files: &[T]) -> Vec { + let mut suggestions = Vec::new(); + + // static suggestions + for sug in STATIC_SUGGESTIONS.iter() { + let glob = Pattern::new(&sug.0).expect("Found invalid glob pattern!"); + + for file in modified_files { + if glob.matches(file.as_ref()) { + suggestions.extend_from_slice(&sug.1); + } + } + } + + // dynamic suggestions + for sug in DYNAMIC_SUGGESTIONS { + for file in modified_files { + let sugs = sug(Path::new(file.as_ref())); + + suggestions.extend_from_slice(&sugs); + } + } + + suggestions.sort(); + suggestions.dedup(); + + suggestions +} + +#[derive(Clone, PartialOrd, Ord, PartialEq, Eq, Debug)] +pub struct Suggestion { + pub cmd: String, + pub stage: Option, + pub paths: Vec, +} + +impl Suggestion { + pub fn new(cmd: &str, stage: Option, paths: &[&str]) -> Self { + Self { cmd: cmd.to_owned(), stage, paths: paths.iter().map(|p| p.to_string()).collect() } + } + + pub fn with_single_path(cmd: &str, stage: Option, path: &str) -> Self { + Self::new(cmd, stage, &[path]) + } +} + +impl Display for Suggestion { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> { + write!(f, "{} ", self.cmd)?; + + for path in &self.paths { + write!(f, "{} ", path)?; + } + + if let Some(stage) = self.stage { + write!(f, "{}", stage)?; + } else { + // write a sentinel value here (in place of a stage) to be consumed + // by the shim in bootstrap, it will be read and ignored. + write!(f, "N/A")?; + } + + Ok(()) + } +} diff --git a/src/tools/suggest-tests/src/main.rs b/src/tools/suggest-tests/src/main.rs new file mode 100644 index 0000000000000..0b541b60cba98 --- /dev/null +++ b/src/tools/suggest-tests/src/main.rs @@ -0,0 +1,27 @@ +use std::process::ExitCode; + +use build_helper::git::get_git_modified_files; +use suggest_tests::get_suggestions; + +fn main() -> ExitCode { + let modified_files = get_git_modified_files(None, &Vec::new()); + let modified_files = match modified_files { + Ok(Some(files)) => files, + Ok(None) => { + eprintln!("git error"); + return ExitCode::FAILURE; + } + Err(err) => { + eprintln!("Could not get modified files from git: \"{err}\""); + return ExitCode::FAILURE; + } + }; + + let suggestions = get_suggestions(&modified_files); + + for sug in &suggestions { + println!("{sug}"); + } + + ExitCode::SUCCESS +} diff --git a/src/tools/suggest-tests/src/static_suggestions.rs b/src/tools/suggest-tests/src/static_suggestions.rs new file mode 100644 index 0000000000000..d8166ead8c49d --- /dev/null +++ b/src/tools/suggest-tests/src/static_suggestions.rs @@ -0,0 +1,24 @@ +use crate::{sug, Suggestion}; + +// FIXME: perhaps this could use `std::lazy` when it is stablizied +macro_rules! static_suggestions { + ($( $glob:expr => [ $( $suggestion:expr ),* ] ),*) => { + pub(crate) const STATIC_SUGGESTIONS: ::once_cell::unsync::Lazy)>> + = ::once_cell::unsync::Lazy::new(|| vec![ $( ($glob, vec![ $($suggestion),* ]) ),*]); + } +} + +static_suggestions! { + "*.md" => [ + sug!("test", 0, ["linkchecker"]) + ], + + "compiler/*" => [ + sug!("check"), + sug!("test", 1, ["src/test/ui", "src/test/run-make"]) + ], + + "src/librustdoc/*" => [ + sug!("test", 1, ["rustdoc"]) + ] +} diff --git a/src/tools/suggest-tests/src/tests.rs b/src/tools/suggest-tests/src/tests.rs new file mode 100644 index 0000000000000..5bc1a7df7ca15 --- /dev/null +++ b/src/tools/suggest-tests/src/tests.rs @@ -0,0 +1,21 @@ +macro_rules! sugg_test { + ( $( $name:ident: $paths:expr => $suggestions:expr ),* ) => { + $( + #[test] + fn $name() { + let suggestions = crate::get_suggestions(&$paths).into_iter().map(|s| s.to_string()).collect::>(); + assert_eq!(suggestions, $suggestions); + } + )* + }; +} + +sugg_test! { + test_error_code_docs: ["compiler/rustc_error_codes/src/error_codes/E0000.md"] => + ["check N/A", "test compiler/rustc_error_codes N/A", "test linkchecker 0", "test src/test/ui src/test/run-make 1"], + + test_rustdoc: ["src/librustdoc/src/lib.rs"] => ["test rustdoc 1"], + + test_rustdoc_and_libstd: ["src/librustdoc/src/lib.rs", "library/std/src/lib.rs"] => + ["test library/std N/A", "test rustdoc 1"] +} diff --git a/tests/ui/check-cfg/compact-values.stderr b/tests/ui/check-cfg/compact-values.stderr index 9864aa385f99e..5ca4d3b3de741 100644 --- a/tests/ui/check-cfg/compact-values.stderr +++ b/tests/ui/check-cfg/compact-values.stderr @@ -4,7 +4,7 @@ warning: unexpected `cfg` condition value LL | #[cfg(target(os = "linux", arch = "X"))] | ^^^^^^^^^^ | - = note: expected values for `target_arch` are: aarch64, arm, avr, bpf, hexagon, m68k, mips, mips64, msp430, nvptx64, powerpc, powerpc64, riscv32, riscv64, s390x, sparc, sparc64, wasm32, wasm64, x86, x86_64 + = note: expected values for `target_arch` are: aarch64, arm, avr, bpf, hexagon, loongarch64, m68k, mips, mips64, msp430, nvptx64, powerpc, powerpc64, riscv32, riscv64, s390x, sparc, sparc64, wasm32, wasm64, x86, x86_64 = note: `#[warn(unexpected_cfgs)]` on by default warning: 1 warning emitted diff --git a/tests/ui/higher-rank-trait-bounds/issue-95230.new.stderr b/tests/ui/higher-rank-trait-bounds/issue-95230.new.stderr index bcb201bf0c379..d4bc5b67220a0 100644 --- a/tests/ui/higher-rank-trait-bounds/issue-95230.new.stderr +++ b/tests/ui/higher-rank-trait-bounds/issue-95230.new.stderr @@ -1,9 +1,10 @@ -error[E0282]: type annotations needed +error[E0275]: overflow evaluating the requirement `for<'a> &'a mut Bar well-formed` --> $DIR/issue-95230.rs:9:13 | LL | for<'a> &'a mut Self:; - | ^^^^^^^^^^^^ cannot infer type for mutable reference `&'a mut Bar` + | ^^^^^^^^^^^^ | + = help: consider increasing the recursion limit by adding a `#![recursion_limit = "256"]` attribute to your crate (`issue_95230`) note: required by a bound in `Bar` --> $DIR/issue-95230.rs:9:13 | @@ -15,4 +16,4 @@ LL | for<'a> &'a mut Self:; error: aborting due to previous error -For more information about this error, try `rustc --explain E0282`. +For more information about this error, try `rustc --explain E0275`. diff --git a/tests/ui/lexer/issue-108019-bad-emoji-recovery.rs b/tests/ui/lexer/issue-108019-bad-emoji-recovery.rs deleted file mode 100644 index f0f8622456010..0000000000000 --- a/tests/ui/lexer/issue-108019-bad-emoji-recovery.rs +++ /dev/null @@ -1,45 +0,0 @@ -#![allow(unused_labels)] - -// FIXME(#108019): outdated Unicode table -// fn foo() { -// '🥺 loop { -// break -// } -// } - -fn bar() { - '🐱 loop { - //~^ ERROR labeled expression must be followed by `:` - //~| ERROR lifetimes or labels cannot contain emojis - break - } -} - -fn qux() { - 'a🐱 loop { - //~^ ERROR labeled expression must be followed by `:` - //~| ERROR lifetimes or labels cannot contain emojis - break - } -} - -fn quux() { - '1🐱 loop { - //~^ ERROR labeled expression must be followed by `:` - //~| ERROR lifetimes or labels cannot start with a number - break - } -} - -fn x<'🐱>() -> &'🐱 () { - //~^ ERROR lifetimes or labels cannot contain emojis - //~| ERROR lifetimes or labels cannot contain emojis - &() -} - -fn y() { - 'a🐱: loop {} - //~^ ERROR lifetimes or labels cannot contain emojis -} - -fn main() {} diff --git a/tests/ui/lexer/issue-108019-bad-emoji-recovery.stderr b/tests/ui/lexer/issue-108019-bad-emoji-recovery.stderr deleted file mode 100644 index be77ffdea349f..0000000000000 --- a/tests/ui/lexer/issue-108019-bad-emoji-recovery.stderr +++ /dev/null @@ -1,86 +0,0 @@ -error: labeled expression must be followed by `:` - --> $DIR/issue-108019-bad-emoji-recovery.rs:11:5 - | -LL | '🐱 loop { - | ^--- help: add `:` after the label - | | - | _____the label - | | -LL | | -LL | | -LL | | break -LL | | } - | |_____^ - | - = note: labels are used before loops and blocks, allowing e.g., `break 'label` to them - -error: labeled expression must be followed by `:` - --> $DIR/issue-108019-bad-emoji-recovery.rs:19:5 - | -LL | 'a🐱 loop { - | ^---- help: add `:` after the label - | | - | _____the label - | | -LL | | -LL | | -LL | | break -LL | | } - | |_____^ - | - = note: labels are used before loops and blocks, allowing e.g., `break 'label` to them - -error: labeled expression must be followed by `:` - --> $DIR/issue-108019-bad-emoji-recovery.rs:27:5 - | -LL | '1🐱 loop { - | ^---- help: add `:` after the label - | | - | _____the label - | | -LL | | -LL | | -LL | | break -LL | | } - | |_____^ - | - = note: labels are used before loops and blocks, allowing e.g., `break 'label` to them - -error: lifetimes or labels cannot contain emojis - --> $DIR/issue-108019-bad-emoji-recovery.rs:11:5 - | -LL | '🐱 loop { - | ^^^ - -error: lifetimes or labels cannot contain emojis - --> $DIR/issue-108019-bad-emoji-recovery.rs:19:5 - | -LL | 'a🐱 loop { - | ^^^^ - -error: lifetimes or labels cannot start with a number - --> $DIR/issue-108019-bad-emoji-recovery.rs:27:5 - | -LL | '1🐱 loop { - | ^^^^ - -error: lifetimes or labels cannot contain emojis - --> $DIR/issue-108019-bad-emoji-recovery.rs:34:6 - | -LL | fn x<'🐱>() -> &'🐱 () { - | ^^^ - -error: lifetimes or labels cannot contain emojis - --> $DIR/issue-108019-bad-emoji-recovery.rs:34:16 - | -LL | fn x<'🐱>() -> &'🐱 () { - | ^^^ - -error: lifetimes or labels cannot contain emojis - --> $DIR/issue-108019-bad-emoji-recovery.rs:41:5 - | -LL | 'a🐱: loop {} - | ^^^^ - -error: aborting due to 9 previous errors - diff --git a/tests/ui/parser/numeric-lifetime.rs b/tests/ui/parser/numeric-lifetime.rs index a082a8a44df2a..2d82354c62cca 100644 --- a/tests/ui/parser/numeric-lifetime.rs +++ b/tests/ui/parser/numeric-lifetime.rs @@ -1,6 +1,6 @@ struct S<'1> { s: &'1 usize } -//~^ ERROR lifetimes or labels cannot start with a number -//~| ERROR lifetimes or labels cannot start with a number +//~^ ERROR lifetimes cannot start with a number +//~| ERROR lifetimes cannot start with a number fn main() { // verify that the parse error doesn't stop type checking let x: usize = ""; diff --git a/tests/ui/parser/numeric-lifetime.stderr b/tests/ui/parser/numeric-lifetime.stderr index 66e35dca92319..7c1bcb7263171 100644 --- a/tests/ui/parser/numeric-lifetime.stderr +++ b/tests/ui/parser/numeric-lifetime.stderr @@ -6,13 +6,13 @@ LL | let x: usize = ""; | | | expected due to this -error: lifetimes or labels cannot start with a number +error: lifetimes cannot start with a number --> $DIR/numeric-lifetime.rs:1:10 | LL | struct S<'1> { s: &'1 usize } | ^^ -error: lifetimes or labels cannot start with a number +error: lifetimes cannot start with a number --> $DIR/numeric-lifetime.rs:1:20 | LL | struct S<'1> { s: &'1 usize } diff --git a/tests/ui/traits/new-solver/recursive-self-normalization-2.rs b/tests/ui/traits/new-solver/recursive-self-normalization-2.rs index 7417d6018a131..8c029f5179d1f 100644 --- a/tests/ui/traits/new-solver/recursive-self-normalization-2.rs +++ b/tests/ui/traits/new-solver/recursive-self-normalization-2.rs @@ -13,7 +13,7 @@ fn needs_bar() {} fn test::Assoc2> + Foo2::Assoc1>>() { needs_bar::(); - //~^ ERROR type annotations needed + //~^ ERROR overflow evaluating the requirement `::Assoc1: Bar` } fn main() {} diff --git a/tests/ui/traits/new-solver/recursive-self-normalization-2.stderr b/tests/ui/traits/new-solver/recursive-self-normalization-2.stderr index e3a92e85e17e4..139b0a4568018 100644 --- a/tests/ui/traits/new-solver/recursive-self-normalization-2.stderr +++ b/tests/ui/traits/new-solver/recursive-self-normalization-2.stderr @@ -1,10 +1,10 @@ -error[E0283]: type annotations needed: cannot satisfy `::Assoc1: Bar` +error[E0275]: overflow evaluating the requirement `::Assoc1: Bar` --> $DIR/recursive-self-normalization-2.rs:15:5 | LL | needs_bar::(); | ^^^^^^^^^^^^^^^^^^^^^^ | - = note: cannot satisfy `::Assoc1: Bar` + = help: consider increasing the recursion limit by adding a `#![recursion_limit = "256"]` attribute to your crate (`recursive_self_normalization_2`) note: required by a bound in `needs_bar` --> $DIR/recursive-self-normalization-2.rs:12:17 | @@ -13,4 +13,4 @@ LL | fn needs_bar() {} error: aborting due to previous error -For more information about this error, try `rustc --explain E0283`. +For more information about this error, try `rustc --explain E0275`. diff --git a/tests/ui/traits/new-solver/recursive-self-normalization.rs b/tests/ui/traits/new-solver/recursive-self-normalization.rs index f3e3d71d813e4..06d187b5fdf73 100644 --- a/tests/ui/traits/new-solver/recursive-self-normalization.rs +++ b/tests/ui/traits/new-solver/recursive-self-normalization.rs @@ -9,7 +9,7 @@ fn needs_bar() {} fn test::Assoc>>() { needs_bar::(); - //~^ ERROR type annotations needed + //~^ ERROR overflow evaluating the requirement `::Assoc: Bar` } fn main() {} diff --git a/tests/ui/traits/new-solver/recursive-self-normalization.stderr b/tests/ui/traits/new-solver/recursive-self-normalization.stderr index 773007aebaa63..8e9b9b4b4cec3 100644 --- a/tests/ui/traits/new-solver/recursive-self-normalization.stderr +++ b/tests/ui/traits/new-solver/recursive-self-normalization.stderr @@ -1,10 +1,10 @@ -error[E0283]: type annotations needed: cannot satisfy `::Assoc: Bar` +error[E0275]: overflow evaluating the requirement `::Assoc: Bar` --> $DIR/recursive-self-normalization.rs:11:5 | LL | needs_bar::(); | ^^^^^^^^^^^^^^^^^^^^^ | - = note: cannot satisfy `::Assoc: Bar` + = help: consider increasing the recursion limit by adding a `#![recursion_limit = "256"]` attribute to your crate (`recursive_self_normalization`) note: required by a bound in `needs_bar` --> $DIR/recursive-self-normalization.rs:8:17 | @@ -13,4 +13,4 @@ LL | fn needs_bar() {} error: aborting due to previous error -For more information about this error, try `rustc --explain E0283`. +For more information about this error, try `rustc --explain E0275`. diff --git a/triagebot.toml b/triagebot.toml index 5f4de0562f89f..58f51959e1f81 100644 --- a/triagebot.toml +++ b/triagebot.toml @@ -344,11 +344,11 @@ message = "Some changes occurred in `const_evaluatable.rs`" cc = ["@BoxyUwU"] [mentions."compiler/rustc_middle/src/ty/abstract_const.rs"] -message = "Some changes occured in `abstract_const.rs`" +message = "Some changes occurred in `abstract_const.rs`" cc = ["@BoxyUwU"] [mentions."compiler/rustc_ty_utils/src/consts.rs"] -message = "Some changes occured in `rustc_ty_utils::consts.rs`" +message = "Some changes occurred in `rustc_ty_utils::consts.rs`" cc = ["@BoxyUwU"] [mentions."compiler/rustc_trait_selection/src/solve/"]