diff --git a/Cargo.lock b/Cargo.lock index a3f7b3a4367db..f035068a600d9 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -6070,6 +6070,7 @@ checksum = "f6ccf251212114b54433ec949fd6a7841275f9ada20dddd2f29e9ceea4501493" name = "unicode-table-generator" version = "0.1.0" dependencies = [ + "rustc-hash 2.1.1", "ucd-parse", ] diff --git a/compiler/rustc_abi/src/canon_abi.rs b/compiler/rustc_abi/src/canon_abi.rs index 316cb05ec1806..6b4963ae92461 100644 --- a/compiler/rustc_abi/src/canon_abi.rs +++ b/compiler/rustc_abi/src/canon_abi.rs @@ -28,6 +28,7 @@ pub enum CanonAbi { Rust, RustCold, RustPreserveNone, + RustTail, /// An ABI that rustc does not know how to call or define. Custom, @@ -59,7 +60,10 @@ pub enum CanonAbi { impl CanonAbi { pub fn is_rustic_abi(self) -> bool { match self { - CanonAbi::Rust | CanonAbi::RustCold | CanonAbi::RustPreserveNone => true, + CanonAbi::Rust + | CanonAbi::RustCold + | CanonAbi::RustPreserveNone + | CanonAbi::RustTail => true, CanonAbi::C | CanonAbi::Custom | CanonAbi::Swift @@ -81,6 +85,7 @@ impl fmt::Display for CanonAbi { CanonAbi::Rust => ExternAbi::Rust, CanonAbi::RustCold => ExternAbi::RustCold, CanonAbi::RustPreserveNone => ExternAbi::RustPreserveNone, + CanonAbi::RustTail => ExternAbi::RustTail, CanonAbi::Custom => ExternAbi::Custom, CanonAbi::Swift => ExternAbi::Swift, CanonAbi::Arm(arm_call) => match arm_call { diff --git a/compiler/rustc_abi/src/extern_abi.rs b/compiler/rustc_abi/src/extern_abi.rs index 3def8a8ccf0ba..f30b923eeed17 100644 --- a/compiler/rustc_abi/src/extern_abi.rs +++ b/compiler/rustc_abi/src/extern_abi.rs @@ -49,6 +49,11 @@ pub enum ExternAbi { /// forcing callers to save all registers. RustPreserveNone, + /// Ensures that calls in tail position can always be optimized into a jump. + /// + /// This ABI is not stable, and relies on LLVM implementation details. + RustTail, + /// Unstable impl detail that directly uses Rust types to describe the ABI to LLVM. /// Even normally-compatible Rust types can become ABI-incompatible with this ABI! Unadjusted, @@ -205,6 +210,7 @@ abi_impls! { System { unwind: true } =><= "system-unwind", SysV64 { unwind: false } =><= "sysv64", SysV64 { unwind: true } =><= "sysv64-unwind", + RustTail =><= "tail", Thiscall { unwind: false } =><= "thiscall", Thiscall { unwind: true } =><= "thiscall-unwind", Unadjusted =><= "unadjusted", @@ -280,7 +286,7 @@ impl ExternAbi { /// - are subject to change between compiler versions pub fn is_rustic_abi(self) -> bool { use ExternAbi::*; - matches!(self, Rust | RustCall | RustCold | RustPreserveNone) + matches!(self, Rust | RustCall | RustCold | RustPreserveNone | RustTail) } /// Returns whether the ABI supports C variadics. This only controls whether we allow *imports* @@ -354,6 +360,7 @@ impl ExternAbi { | Self::SysV64 { .. } | Self::Win64 { .. } | Self::RustPreserveNone + | Self::RustTail | Self::Swift => true, } } diff --git a/compiler/rustc_ast_lowering/src/asm.rs b/compiler/rustc_ast_lowering/src/asm.rs index e8df8ce6e6dc3..5628dffd51358 100644 --- a/compiler/rustc_ast_lowering/src/asm.rs +++ b/compiler/rustc_ast_lowering/src/asm.rs @@ -9,8 +9,7 @@ use rustc_session::errors::feature_err; use rustc_span::{Span, sym}; use rustc_target::asm; -use super::LoweringContext; -use super::errors::{ +use crate::diagnostics::{ AbiSpecifiedMultipleTimes, AttSyntaxOnlyX86, ClobberAbiNotSupported, InlineAsmUnsupportedTarget, InvalidAbiClobberAbi, InvalidAsmTemplateModifierConst, InvalidAsmTemplateModifierLabel, InvalidAsmTemplateModifierRegClass, @@ -18,7 +17,9 @@ use super::errors::{ InvalidRegisterClass, RegisterClassOnlyClobber, RegisterClassOnlyClobberStable, RegisterConflict, }; -use crate::{AllowReturnTypeNotation, ImplTraitContext, ImplTraitPosition, ParamMode}; +use crate::{ + AllowReturnTypeNotation, ImplTraitContext, ImplTraitPosition, LoweringContext, ParamMode, +}; impl<'hir> LoweringContext<'_, 'hir> { pub(crate) fn lower_inline_asm( diff --git a/compiler/rustc_ast_lowering/src/delegation.rs b/compiler/rustc_ast_lowering/src/delegation.rs index 5af13c70ef693..68ae9e68b029a 100644 --- a/compiler/rustc_ast_lowering/src/delegation.rs +++ b/compiler/rustc_ast_lowering/src/delegation.rs @@ -56,7 +56,7 @@ use rustc_span::symbol::kw; use rustc_span::{ErrorGuaranteed, Ident, Span, Symbol}; use crate::delegation::generics::{GenericsGenerationResult, GenericsGenerationResults}; -use crate::errors::{ +use crate::diagnostics::{ CycleInDelegationSignatureResolution, DelegationAttemptedBlockWithDefsDeletion, DelegationBlockSpecifiedWhenNoParams, UnresolvedDelegationCallee, }; diff --git a/compiler/rustc_ast_lowering/src/errors.rs b/compiler/rustc_ast_lowering/src/diagnostics.rs similarity index 100% rename from compiler/rustc_ast_lowering/src/errors.rs rename to compiler/rustc_ast_lowering/src/diagnostics.rs diff --git a/compiler/rustc_ast_lowering/src/expr.rs b/compiler/rustc_ast_lowering/src/expr.rs index ce20aaf4e0276..23c7159cb91fe 100644 --- a/compiler/rustc_ast_lowering/src/expr.rs +++ b/compiler/rustc_ast_lowering/src/expr.rs @@ -19,17 +19,17 @@ use visit::{Visitor, walk_expr}; mod closure; -use super::errors::{ +use crate::diagnostics::{ AsyncCoroutinesNotSupported, AwaitOnlyInAsyncFnAndBlocks, - FunctionalRecordUpdateDestructuringAssignment, InclusiveRangeWithNoEnd, MatchArmWithNoBody, - MoveExprOnlyInPlainClosures, NeverPatternWithBody, NeverPatternWithGuard, - UnderscoreExprLhsAssign, + FunctionalRecordUpdateDestructuringAssignment, InclusiveRangeWithNoEnd, + InvalidLegacyConstGenericArg, MatchArmWithNoBody, MoveExprOnlyInPlainClosures, + NeverPatternWithBody, NeverPatternWithGuard, UnderscoreExprLhsAssign, UseConstGenericArg, + YieldInClosure, }; -use super::{ - GenericArgsMode, ImplTraitContext, LoweringContext, ParamMode, ResolverAstLoweringExt, +use crate::{ + AllowReturnTypeNotation, GenericArgsMode, ImplTraitContext, ImplTraitPosition, LoweringContext, + ParamMode, ResolverAstLoweringExt, TryBlockScope, }; -use crate::errors::{InvalidLegacyConstGenericArg, UseConstGenericArg, YieldInClosure}; -use crate::{AllowReturnTypeNotation, ImplTraitPosition, TryBlockScope}; pub(super) struct WillCreateDefIdsVisitor; diff --git a/compiler/rustc_ast_lowering/src/expr/closure.rs b/compiler/rustc_ast_lowering/src/expr/closure.rs index 1c2a22e475232..cc2c6ae2879c1 100644 --- a/compiler/rustc_ast_lowering/src/expr/closure.rs +++ b/compiler/rustc_ast_lowering/src/expr/closure.rs @@ -7,7 +7,7 @@ use rustc_span::Span; use super::{LoweringContext, MoveExprInitializerFinder, MoveExprState}; use crate::FnDeclKind; -use crate::errors::{ClosureCannotBeStatic, CoroutineTooManyParameters}; +use crate::diagnostics::{ClosureCannotBeStatic, CoroutineTooManyParameters}; impl<'hir> LoweringContext<'_, 'hir> { // Entry point for `ExprKind::Closure`. Plain closures go through diff --git a/compiler/rustc_ast_lowering/src/item.rs b/compiler/rustc_ast_lowering/src/item.rs index 99c31551d234d..0e518c10e3bb7 100644 --- a/compiler/rustc_ast_lowering/src/item.rs +++ b/compiler/rustc_ast_lowering/src/item.rs @@ -19,7 +19,9 @@ use smallvec::{SmallVec, smallvec}; use thin_vec::ThinVec; use tracing::instrument; -use super::errors::{InvalidAbi, InvalidAbiSuggestion, TupleStructWithDefault, UnionWithDefault}; +use super::diagnostics::{ + InvalidAbi, InvalidAbiSuggestion, TupleStructWithDefault, UnionWithDefault, +}; use super::stability::{enabled_names, gate_unstable_abi}; use super::{ AstOwner, FnDeclKind, GenericArgsMode, ImplTraitContext, ImplTraitPosition, LoweringContext, diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index 6dc7de2911c0c..8b4a2795ec90c 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -70,7 +70,7 @@ use smallvec::SmallVec; use thin_vec::ThinVec; use tracing::{debug, instrument, trace}; -use crate::errors::{AssocTyParentheses, AssocTyParenthesesSub, MisplacedImplTrait}; +use crate::diagnostics::{AssocTyParentheses, AssocTyParenthesesSub, MisplacedImplTrait}; use crate::item::Owners; macro_rules! arena_vec { @@ -83,7 +83,7 @@ mod asm; mod block; mod contract; mod delegation; -mod errors; +mod diagnostics; mod expr; mod format; mod index; @@ -1145,17 +1145,21 @@ impl<'hir> LoweringContext<'_, 'hir> { { let err = match (&data.inputs[..], &data.output) { ([_, ..], FnRetTy::Default(_)) => { - errors::BadReturnTypeNotation::Inputs { span: data.inputs_span } + diagnostics::BadReturnTypeNotation::Inputs { + span: data.inputs_span, + } } ([], FnRetTy::Default(_)) => { - errors::BadReturnTypeNotation::NeedsDots { span: data.inputs_span } + diagnostics::BadReturnTypeNotation::NeedsDots { + span: data.inputs_span, + } } // The case `T: Trait Ret>` is handled in the parser. (_, FnRetTy::Ty(ty)) => { let span = data.inputs_span.shrink_to_hi().to(ty.span); - errors::BadReturnTypeNotation::Output { + diagnostics::BadReturnTypeNotation::Output { span, - suggestion: errors::RTNSuggestion { + suggestion: diagnostics::RTNSuggestion { output: span, input: data.inputs_span, }, @@ -1226,7 +1230,7 @@ impl<'hir> LoweringContext<'_, 'hir> { _ => None, }; - let guar = self.dcx().emit_err(errors::MisplacedAssocTyBinding { + let guar = self.dcx().emit_err(diagnostics::MisplacedAssocTyBinding { span: constraint.span, suggestion, }); @@ -1529,7 +1533,7 @@ impl<'hir> LoweringContext<'_, 'hir> { ast::GenericBound::Use(_, span) => Some(span), _ => None, }) { - self.tcx.dcx().emit_err(errors::NoPreciseCapturesOnApit { span }); + self.tcx.dcx().emit_err(diagnostics::NoPreciseCapturesOnApit { span }); } let def_id = self.local_def_id(*def_node_id); @@ -2123,7 +2127,7 @@ impl<'hir> LoweringContext<'_, 'hir> { .filter(|_| match source { hir::GenericParamSource::Generics => true, hir::GenericParamSource::Binder => { - self.dcx().emit_err(errors::GenericParamDefaultInBinder { + self.dcx().emit_err(diagnostics::GenericParamDefaultInBinder { span: param.span(), }); @@ -2154,7 +2158,8 @@ impl<'hir> LoweringContext<'_, 'hir> { .filter(|anon_const| match source { hir::GenericParamSource::Generics => true, hir::GenericParamSource::Binder => { - let err = errors::GenericParamDefaultInBinder { span: param.span() }; + let err = + diagnostics::GenericParamDefaultInBinder { span: param.span() }; if expr::WillCreateDefIdsVisitor .visit_expr(&anon_const.value) .is_break() diff --git a/compiler/rustc_ast_lowering/src/pat.rs b/compiler/rustc_ast_lowering/src/pat.rs index cf0615b8244e5..8780b70fadfa4 100644 --- a/compiler/rustc_ast_lowering/src/pat.rs +++ b/compiler/rustc_ast_lowering/src/pat.rs @@ -7,10 +7,10 @@ use rustc_hir::{self as hir, LangItem, Target}; use rustc_middle::span_bug; use rustc_span::{DesugaringKind, Ident, Span, Spanned, respan}; -use super::errors::{ +use crate::diagnostics::{ ArbitraryExpressionInPattern, ExtraDoubleDot, MisplacedDoubleDot, SubTupleBinding, }; -use super::{ +use crate::{ AllowReturnTypeNotation, ImplTraitContext, ImplTraitPosition, LoweringContext, ParamMode, }; diff --git a/compiler/rustc_ast_lowering/src/path.rs b/compiler/rustc_ast_lowering/src/path.rs index f5a306aa9140d..42c4af5add12d 100644 --- a/compiler/rustc_ast_lowering/src/path.rs +++ b/compiler/rustc_ast_lowering/src/path.rs @@ -11,11 +11,11 @@ use rustc_span::{BytePos, DUMMY_SP, DesugaringKind, Ident, Span, Symbol, sym}; use smallvec::smallvec; use tracing::{debug, instrument}; -use super::errors::{ +use crate::diagnostics::{ AsyncBoundNotOnTrait, AsyncBoundOnlyForFnTraits, BadReturnTypeNotation, GenericTypeWithParentheses, RTNSuggestion, UseAngleBrackets, }; -use super::{ +use crate::{ AllowReturnTypeNotation, GenericArgsCtor, GenericArgsMode, ImplTraitContext, ImplTraitPosition, LifetimeRes, LoweringContext, ParamMode, }; diff --git a/compiler/rustc_ast_lowering/src/stability.rs b/compiler/rustc_ast_lowering/src/stability.rs index 00b6a353d93f6..b58087e4aa3a6 100644 --- a/compiler/rustc_ast_lowering/src/stability.rs +++ b/compiler/rustc_ast_lowering/src/stability.rs @@ -100,6 +100,9 @@ pub fn extern_abi_stability(abi: ExternAbi) -> Result<(), UnstableAbi> { feature: sym::rust_preserve_none_cc, explain: GateReason::Experimental, }), + ExternAbi::RustTail => { + Err(UnstableAbi { abi, feature: sym::rust_tail_cc, explain: GateReason::Experimental }) + } ExternAbi::RustInvalid => { Err(UnstableAbi { abi, feature: sym::rustc_attrs, explain: GateReason::ImplDetail }) } diff --git a/compiler/rustc_ast_passes/src/ast_validation.rs b/compiler/rustc_ast_passes/src/ast_validation.rs index afaee6e542082..db0c5256184c5 100644 --- a/compiler/rustc_ast_passes/src/ast_validation.rs +++ b/compiler/rustc_ast_passes/src/ast_validation.rs @@ -39,7 +39,7 @@ use rustc_span::{Ident, Span, kw, sym}; use rustc_target::spec::{AbiMap, AbiMapping}; use thin_vec::thin_vec; -use crate::errors::{self, TildeConstReason}; +use crate::diagnostics::{self, TildeConstReason}; /// Is `self` allowed semantically as the first parameter in an `FnDecl`? enum SelfSemantic { @@ -161,7 +161,7 @@ impl<'a> AstValidator<'a> { fn check_type_alias_where_clause_location( &mut self, ty_alias: &TyAlias, - ) -> Result<(), errors::WhereClauseBeforeTypeAlias> { + ) -> Result<(), diagnostics::WhereClauseBeforeTypeAlias> { if ty_alias.ty.is_none() || !ty_alias.generics.where_clause.has_where_token { return Ok(()); } @@ -189,16 +189,16 @@ impl<'a> AstValidator<'a> { state.print_where_predicate(p); } - errors::WhereClauseBeforeTypeAliasSugg::Move { + diagnostics::WhereClauseBeforeTypeAliasSugg::Move { left: span, snippet: state.s.eof(), right: ty_alias.after_where_clause.span.shrink_to_hi(), } } else { - errors::WhereClauseBeforeTypeAliasSugg::Remove { span } + diagnostics::WhereClauseBeforeTypeAliasSugg::Remove { span } }; - Err(errors::WhereClauseBeforeTypeAlias { span, sugg }) + Err(diagnostics::WhereClauseBeforeTypeAlias { span, sugg }) } fn with_impl_trait(&mut self, outer_span: Option, f: impl FnOnce(&mut Self)) { @@ -226,7 +226,7 @@ impl<'a> AstValidator<'a> { if let Some(bound1) = use_bounds.next() && let Some(bound2) = use_bounds.next() { - self.dcx().emit_err(errors::DuplicatePreciseCapturing { bound1, bound2 }); + self.dcx().emit_err(diagnostics::DuplicatePreciseCapturing { bound1, bound2 }); } } TyKind::TraitObject(..) => self @@ -241,12 +241,16 @@ impl<'a> AstValidator<'a> { self.sess.dcx() } - fn visibility_not_permitted(&self, vis: &Visibility, note: errors::VisibilityNotPermittedNote) { + fn visibility_not_permitted( + &self, + vis: &Visibility, + note: diagnostics::VisibilityNotPermittedNote, + ) { if let VisibilityKind::Inherited = vis.kind { return; } - self.dcx().emit_err(errors::VisibilityNotPermitted { + self.dcx().emit_err(diagnostics::VisibilityNotPermitted { span: vis.span, note, remove_qualifier_sugg: vis.span, @@ -276,7 +280,7 @@ impl<'a> AstValidator<'a> { return; }; - self.dcx().emit_err(errors::ImplFnConst { span, parent_constness }); + self.dcx().emit_err(diagnostics::ImplFnConst { span, parent_constness }); } fn check_trait_fn_not_const(&self, constness: Const, parent: &TraitOrImpl) { @@ -309,7 +313,7 @@ impl<'a> AstValidator<'a> { }; let parent_constness = parent.constness(); - self.dcx().emit_err(errors::TraitFnConst { + self.dcx().emit_err(diagnostics::TraitFnConst { span, in_impl: matches!(parent, TraitOrImpl::TraitImpl { .. }), const_context_label: parent_constness, @@ -341,7 +345,7 @@ impl<'a> AstValidator<'a> { TraitOrImpl::Impl { .. } => "impl", }; - self.dcx().emit_err(errors::AsyncFnInConstTraitOrTraitImpl { + self.dcx().emit_err(diagnostics::AsyncFnInConstTraitOrTraitImpl { async_keyword, context, const_keyword, @@ -361,7 +365,7 @@ impl<'a> AstValidator<'a> { let max_num_args: usize = u16::MAX.into(); if fn_decl.inputs.len() > max_num_args { let Param { span, .. } = fn_decl.inputs[0]; - self.dcx().emit_fatal(errors::FnParamTooMany { span, max_num_args }); + self.dcx().emit_fatal(diagnostics::FnParamTooMany { span, max_num_args }); } } @@ -373,7 +377,7 @@ impl<'a> AstValidator<'a> { [ps @ .., _] => { for Param { ty, span, .. } in ps { if let TyKind::CVarArgs = ty.kind { - self.dcx().emit_err(errors::FnParamCVarArgsNotLast { span: *span }); + self.dcx().emit_err(diagnostics::FnParamCVarArgsNotLast { span: *span }); } } } @@ -400,9 +404,9 @@ impl<'a> AstValidator<'a> { }) .for_each(|attr| { if attr.is_doc_comment() { - self.dcx().emit_err(errors::FnParamDocComment { span: attr.span }); + self.dcx().emit_err(diagnostics::FnParamDocComment { span: attr.span }); } else { - self.dcx().emit_err(errors::FnParamForbiddenAttr { span: attr.span }); + self.dcx().emit_err(diagnostics::FnParamForbiddenAttr { span: attr.span }); } }); } @@ -410,7 +414,7 @@ impl<'a> AstValidator<'a> { fn check_decl_self_param(&self, fn_decl: &FnDecl, self_semantic: SelfSemantic) { if let (SelfSemantic::No, [param, ..]) = (self_semantic, &*fn_decl.inputs) { if param.is_self() { - self.dcx().emit_err(errors::FnParamForbiddenSelf { span: param.span }); + self.dcx().emit_err(diagnostics::FnParamForbiddenSelf { span: param.span }); } } } @@ -424,6 +428,7 @@ impl<'a> AstValidator<'a> { | CanonAbi::Rust | CanonAbi::RustCold | CanonAbi::RustPreserveNone + | CanonAbi::RustTail | CanonAbi::Swift | CanonAbi::Arm(_) | CanonAbi::X86(_) => { /* nothing to check */ } @@ -462,7 +467,8 @@ impl<'a> AstValidator<'a> { if spans.is_empty() { spans = vec![sig.span]; } - self.dcx().emit_err(errors::AbiX86Interrupt { spans, param_count }); + self.dcx() + .emit_err(diagnostics::AbiX86Interrupt { spans, param_count }); } self.reject_return(abi, sig); @@ -485,12 +491,15 @@ impl<'a> AstValidator<'a> { Safety::Safe(safe_span) => { let source_map = self.sess.psess.source_map(); let safe_span = source_map.span_until_non_whitespace(safe_span.to(sig.span)); - dcx.emit_err(errors::AbiCustomSafeForeignFunction { span: sig.span, safe_span }); + dcx.emit_err(diagnostics::AbiCustomSafeForeignFunction { + span: sig.span, + safe_span, + }); } Safety::Default => match ctxt { FnCtxt::Foreign => { /* all good */ } FnCtxt::Free | FnCtxt::Assoc(_) => { - dcx.emit_err(errors::AbiCustomSafeFunction { + dcx.emit_err(diagnostics::AbiCustomSafeFunction { span: sig.span, abi, unsafe_span: sig.span.shrink_to_lo(), @@ -508,7 +517,7 @@ impl<'a> AstValidator<'a> { .source_map() .span_until_non_whitespace(coroutine_kind.span().to(sig.span)); - self.dcx().emit_err(errors::AbiCannotBeCoroutine { + self.dcx().emit_err(diagnostics::AbiCannotBeCoroutine { span: sig.span, abi, coroutine_kind_span, @@ -525,7 +534,7 @@ impl<'a> AstValidator<'a> { _ => true, } { - self.dcx().emit_err(errors::AbiMustNotHaveReturnType { span: ret_ty.span, abi }); + self.dcx().emit_err(diagnostics::AbiMustNotHaveReturnType { span: ret_ty.span, abi }); } } @@ -546,7 +555,7 @@ impl<'a> AstValidator<'a> { let suggestion_span = header_span.shrink_to_hi().to(sig.decl.output.span()); let padding = if header_span.is_empty() { "" } else { " " }; - self.dcx().emit_err(errors::AbiMustNotHaveParametersOrReturnType { + self.dcx().emit_err(diagnostics::AbiMustNotHaveParametersOrReturnType { spans, symbol: ident.name, suggestion_span, @@ -567,7 +576,7 @@ impl<'a> AstValidator<'a> { if matches!(safety, Safety::Unsafe(_) | Safety::Safe(_)) && extern_safety == Safety::Default { - self.dcx().emit_err(errors::InvalidSafetyOnExtern { + self.dcx().emit_err(diagnostics::InvalidSafetyOnExtern { item_span: span, block: Some(self.current_extern_span().shrink_to_lo()), }); @@ -575,7 +584,7 @@ impl<'a> AstValidator<'a> { } None => { if matches!(safety, Safety::Safe(_)) { - self.dcx().emit_err(errors::InvalidSafetyOnItem { span }); + self.dcx().emit_err(diagnostics::InvalidSafetyOnItem { span }); } } } @@ -583,7 +592,7 @@ impl<'a> AstValidator<'a> { fn check_fn_ptr_safety(&self, span: Span, safety: Safety) { if matches!(safety, Safety::Safe(_)) { - self.dcx().emit_err(errors::InvalidSafetyOnFnPtr { span }); + self.dcx().emit_err(diagnostics::InvalidSafetyOnFnPtr { span }); } } @@ -597,11 +606,11 @@ impl<'a> AstValidator<'a> { match defaultness { Defaultness::Default(def_span) if matches!(allow_default, AllowDefault::No) => { let span = self.sess.source_map().guess_head_span(span); - self.dcx().emit_err(errors::ForbiddenDefault { span, def_span }); + self.dcx().emit_err(diagnostics::ForbiddenDefault { span, def_span }); } Defaultness::Final(def_span) if matches!(allow_final, AllowFinal::No) => { let span = self.sess.source_map().guess_head_span(span); - self.dcx().emit_err(errors::ForbiddenFinal { span, def_span }); + self.dcx().emit_err(diagnostics::ForbiddenFinal { span, def_span }); } _ => (), } @@ -612,7 +621,7 @@ impl<'a> AstValidator<'a> { && let Defaultness::Final(def_span) = defaultness { let span = self.sess.source_map().guess_head_span(item.span); - self.dcx().emit_err(errors::ForbiddenFinalWithoutBody { span, def_span }); + self.dcx().emit_err(diagnostics::ForbiddenFinalWithoutBody { span, def_span }); } } @@ -635,12 +644,12 @@ impl<'a> AstValidator<'a> { [b0] => b0.span(), [b0, .., bl] => b0.span().to(bl.span()), }; - self.dcx().emit_err(errors::BoundInContext { span, ctx }); + self.dcx().emit_err(diagnostics::BoundInContext { span, ctx }); } fn check_foreign_ty_genericless(&self, generics: &Generics, after_where_clause: &WhereClause) { let cannot_have = |span, descr, remove_descr| { - self.dcx().emit_err(errors::ExternTypesCannotHave { + self.dcx().emit_err(diagnostics::ExternTypesCannotHave { span, descr, remove_descr, @@ -666,7 +675,7 @@ impl<'a> AstValidator<'a> { let Some(body_span) = body_span else { return; }; - self.dcx().emit_err(errors::BodyInExtern { + self.dcx().emit_err(diagnostics::BodyInExtern { span: ident.span, body: body_span, block: self.current_extern_span(), @@ -679,7 +688,7 @@ impl<'a> AstValidator<'a> { let Some(body) = body else { return; }; - self.dcx().emit_err(errors::FnBodyInExtern { + self.dcx().emit_err(diagnostics::FnBodyInExtern { span: ident.span, body: body.span, block: self.current_extern_span(), @@ -697,7 +706,7 @@ impl<'a> AstValidator<'a> { FnHeader { safety: _, coroutine_kind, constness, ext }: FnHeader, ) { let report_err = |span, kw| { - self.dcx().emit_err(errors::FnQualifierInExtern { + self.dcx().emit_err(diagnostics::FnQualifierInExtern { span, kw, block: self.current_extern_span(), @@ -720,7 +729,7 @@ impl<'a> AstValidator<'a> { /// An item in `extern { ... }` cannot use non-ascii identifier. fn check_foreign_item_ascii_only(&self, ident: Ident) { if !ident.as_str().is_ascii() { - self.dcx().emit_err(errors::ExternItemAscii { + self.dcx().emit_err(diagnostics::ExternItemAscii { span: ident.span, block: self.current_extern_span(), }); @@ -752,7 +761,7 @@ impl<'a> AstValidator<'a> { } if let Some(coroutine_kind) = sig.header.coroutine_kind { - self.dcx().emit_err(errors::CoroutineAndCVariadic { + self.dcx().emit_err(diagnostics::CoroutineAndCVariadic { spans: vec![coroutine_kind.span(), variadic_param.span], coroutine_kind: coroutine_kind.as_str(), coroutine_span: coroutine_kind.span(), @@ -765,7 +774,7 @@ impl<'a> AstValidator<'a> { FnCtxt::Free | FnCtxt::Assoc(_) => { match self.sess.target.supports_c_variadic_definitions() { CVariadicStatus::NotSupported => { - self.dcx().emit_err(errors::CVariadicNotSupported { + self.dcx().emit_err(diagnostics::CVariadicNotSupported { variadic_span: variadic_param.span, target: &*self.sess.target.llvm_target, }); @@ -785,7 +794,7 @@ impl<'a> AstValidator<'a> { match sig.header.ext { Extern::Implicit(_) => { if !matches!(sig.header.safety, Safety::Unsafe(_)) { - self.dcx().emit_err(errors::CVariadicMustBeUnsafe { + self.dcx().emit_err(diagnostics::CVariadicMustBeUnsafe { span: variadic_param.span, unsafe_span: sig.safety_span(), }); @@ -800,14 +809,14 @@ impl<'a> AstValidator<'a> { self.check_c_variadic_abi(abi, attrs, variadic_param.span, sig); if !matches!(sig.header.safety, Safety::Unsafe(_)) { - self.dcx().emit_err(errors::CVariadicMustBeUnsafe { + self.dcx().emit_err(diagnostics::CVariadicMustBeUnsafe { span: variadic_param.span, unsafe_span: sig.safety_span(), }); } } Extern::None => { - let err = errors::CVariadicNoExtern { span: variadic_param.span }; + let err = diagnostics::CVariadicNoExtern { span: variadic_param.span }; self.dcx().emit_err(err); } } @@ -854,7 +863,7 @@ impl<'a> AstValidator<'a> { } CVariadicStatus::NotSupported => { // Some ABIs, e.g. `extern "Rust"`, never support c-variadic functions. - self.dcx().emit_err(errors::CVariadicBadNakedExtern { + self.dcx().emit_err(diagnostics::CVariadicBadNakedExtern { span: dotdotdot_span, abi: abi.as_str(), extern_span: sig.extern_span(), @@ -862,7 +871,7 @@ impl<'a> AstValidator<'a> { } } } else if !matches!(abi, ExternAbi::C { .. }) { - self.dcx().emit_err(errors::CVariadicBadExtern { + self.dcx().emit_err(diagnostics::CVariadicBadExtern { span: dotdotdot_span, abi: abi.as_str(), extern_span: sig.extern_span(), @@ -874,7 +883,7 @@ impl<'a> AstValidator<'a> { if ident.name != kw::Underscore { return; } - self.dcx().emit_err(errors::ItemUnderscore { span: ident.span, kind }); + self.dcx().emit_err(diagnostics::ItemUnderscore { span: ident.span, kind }); } fn check_nomangle_item_asciionly(&self, ident: Ident, item_span: Span) { @@ -882,26 +891,26 @@ impl<'a> AstValidator<'a> { return; } let span = self.sess.source_map().guess_head_span(item_span); - self.dcx().emit_err(errors::NoMangleAscii { span }); + self.dcx().emit_err(diagnostics::NoMangleAscii { span }); } fn check_mod_file_item_asciionly(&self, ident: Ident) { if ident.name.as_str().is_ascii() { return; } - self.dcx().emit_err(errors::ModuleNonAscii { span: ident.span, name: ident.name }); + self.dcx().emit_err(diagnostics::ModuleNonAscii { span: ident.span, name: ident.name }); } fn deny_const_auto_traits(&self, constness: Const) { if let Const::Yes(span) = constness { - self.dcx().emit_err(errors::ConstAutoTrait { span }); + self.dcx().emit_err(diagnostics::ConstAutoTrait { span }); } } fn deny_generic_params(&self, generics: &Generics, ident_span: Span) { if !generics.params.is_empty() { self.dcx() - .emit_err(errors::AutoTraitGeneric { span: generics.span, ident: ident_span }); + .emit_err(diagnostics::AutoTraitGeneric { span: generics.span, ident: ident_span }); } } @@ -909,7 +918,7 @@ impl<'a> AstValidator<'a> { if let [.., last] = &bounds[..] { let span = bounds.iter().map(|b| b.span()).collect(); let removal = ident.shrink_to_hi().to(last.span()); - self.dcx().emit_err(errors::AutoTraitBounds { span, removal, ident }); + self.dcx().emit_err(diagnostics::AutoTraitBounds { span, removal, ident }); } } @@ -917,7 +926,7 @@ impl<'a> AstValidator<'a> { if !where_clause.predicates.is_empty() { // FIXME: The current diagnostic is misleading since it only talks about // super trait and lifetime bounds while we should just say “bounds”. - self.dcx().emit_err(errors::AutoTraitBounds { + self.dcx().emit_err(diagnostics::AutoTraitBounds { span: vec![where_clause.span], removal: where_clause.span, ident, @@ -929,7 +938,7 @@ impl<'a> AstValidator<'a> { if !trait_items.is_empty() { let spans: Vec<_> = trait_items.iter().map(|i| i.kind.ident().unwrap().span).collect(); let total = trait_items.first().unwrap().span.to(trait_items.last().unwrap().span); - self.dcx().emit_err(errors::AutoTraitItems { spans, total, ident: ident_span }); + self.dcx().emit_err(diagnostics::AutoTraitItems { spans, total, ident: ident_span }); } } @@ -975,13 +984,13 @@ impl<'a> AstValidator<'a> { let args_len = arg_spans.len(); let constraint_len = constraint_spans.len(); // ...and then error: - self.dcx().emit_err(errors::ArgsBeforeConstraint { + self.dcx().emit_err(diagnostics::ArgsBeforeConstraint { arg_spans: arg_spans.clone(), constraints: constraint_spans[0], args: *arg_spans.iter().last().unwrap(), data: data.span, - constraint_spans: errors::EmptyLabelManySpans(constraint_spans), - arg_spans2: errors::EmptyLabelManySpans(arg_spans), + constraint_spans: diagnostics::EmptyLabelManySpans(constraint_spans), + arg_spans2: diagnostics::EmptyLabelManySpans(arg_spans), suggestion: self.correct_generic_order_suggestion(data), constraint_len, args_len, @@ -994,7 +1003,7 @@ impl<'a> AstValidator<'a> { self.check_fn_ptr_safety(bfty.decl_span, bfty.safety); self.check_fn_decl(&bfty.decl, SelfSemantic::No); Self::check_decl_no_pat(&bfty.decl, |span, _, _| { - self.dcx().emit_err(errors::PatternFnPointer { span }); + self.dcx().emit_err(diagnostics::PatternFnPointer { span }); }); if let Extern::Implicit(extern_span) = bfty.ext { self.handle_missing_abi(extern_span, ty.id); @@ -1005,8 +1014,9 @@ impl<'a> AstValidator<'a> { for bound in bounds { if let GenericBound::Outlives(lifetime) = bound { if any_lifetime_bounds { - self.dcx() - .emit_err(errors::TraitObjectBound { span: lifetime.ident.span }); + self.dcx().emit_err(diagnostics::TraitObjectBound { + span: lifetime.ident.span, + }); break; } any_lifetime_bounds = true; @@ -1015,7 +1025,7 @@ impl<'a> AstValidator<'a> { } TyKind::ImplTrait(_, bounds) => { if let Some(outer_impl_trait_sp) = self.outer_impl_trait_span { - self.dcx().emit_err(errors::NestedImplTrait { + self.dcx().emit_err(diagnostics::NestedImplTrait { span: ty.span, outer: outer_impl_trait_sp, inner: ty.span, @@ -1023,7 +1033,7 @@ impl<'a> AstValidator<'a> { } if !bounds.iter().any(|b| matches!(b, GenericBound::Trait(..))) { - self.dcx().emit_err(errors::AtLeastOneTrait { span: ty.span }); + self.dcx().emit_err(diagnostics::AtLeastOneTrait { span: ty.span }); } } _ => {} @@ -1034,7 +1044,7 @@ impl<'a> AstValidator<'a> { // FIXME(davidtwco): This is a hack to detect macros which produce spans of the // call site which do not have a macro backtrace. See #61963. if span.edition().at_least_edition_future() && self.features.explicit_extern_abis() { - self.dcx().emit_err(errors::MissingAbi { span }); + self.dcx().emit_err(diagnostics::MissingAbi { span }); } else if self .sess .source_map() @@ -1045,7 +1055,7 @@ impl<'a> AstValidator<'a> { MISSING_ABI, id, span, - errors::MissingAbiSugg { span, default_abi: ExternAbi::FALLBACK }, + diagnostics::MissingAbiSugg { span, default_abi: ExternAbi::FALLBACK }, ) } } @@ -1126,7 +1136,7 @@ fn validate_generic_param_order(dcx: DiagCtxtHandle<'_>, generics: &[GenericPara ordered_params += ">"; for (param_ord, (max_param, spans)) in &out_of_order { - dcx.emit_err(errors::OutOfOrderParams { + dcx.emit_err(diagnostics::OutOfOrderParams { spans: spans.clone(), sugg_span: span, param_ord: param_ord.to_string(), @@ -1171,15 +1181,15 @@ impl Visitor<'_> for AstValidator<'_> { self.visit_attrs_vis(&item.attrs, &item.vis); self.visibility_not_permitted( &item.vis, - errors::VisibilityNotPermittedNote::TraitImpl, + diagnostics::VisibilityNotPermittedNote::TraitImpl, ); if let TyKind::Dummy = self_ty.kind { // Abort immediately otherwise the `TyKind::Dummy` will reach HIR lowering, // which isn't allowed. Not a problem for this obscure, obsolete syntax. - self.dcx().emit_fatal(errors::ObsoleteAuto { span: item.span }); + self.dcx().emit_fatal(diagnostics::ObsoleteAuto { span: item.span }); } if let (&Safety::Unsafe(span), &ImplPolarity::Negative(sp)) = (safety, polarity) { - self.dcx().emit_err(errors::UnsafeNegativeImpl { + self.dcx().emit_err(diagnostics::UnsafeNegativeImpl { span: sp.to(t.path.span), negative: sp, r#unsafe: span, @@ -1212,7 +1222,7 @@ impl Visitor<'_> for AstValidator<'_> { self.visit_attrs_vis(&item.attrs, &item.vis); self.visibility_not_permitted( &item.vis, - errors::VisibilityNotPermittedNote::IndividualImplItems, + diagnostics::VisibilityNotPermittedNote::IndividualImplItems, ); let disallowed = matches!(constness, ast::Const::No) @@ -1254,19 +1264,19 @@ impl Visitor<'_> for AstValidator<'_> { let is_intrinsic = item.attrs.iter().any(|a| a.has_name(sym::rustc_intrinsic)); if body.is_none() && !is_intrinsic && !self.is_sdylib_interface { - self.dcx().emit_err(errors::FnWithoutBody { + self.dcx().emit_err(diagnostics::FnWithoutBody { span: item.span, replace_span: self.ending_semi_or_hi(item.span), extern_block_suggestion: match sig.header.ext { Extern::None => None, Extern::Implicit(start_span) => { - Some(errors::ExternBlockSuggestion::Implicit { + Some(diagnostics::ExternBlockSuggestion::Implicit { start_span, end_span: item.span.shrink_to_hi(), }) } Extern::Explicit(abi, start_span) => { - Some(errors::ExternBlockSuggestion::Explicit { + Some(diagnostics::ExternBlockSuggestion::Explicit { start_span, end_span: item.span.shrink_to_hi(), abi: abi.symbol_unescaped, @@ -1283,18 +1293,18 @@ impl Visitor<'_> for AstValidator<'_> { let old_item = mem::replace(&mut self.extern_mod_span, Some(item.span)); self.visibility_not_permitted( &item.vis, - errors::VisibilityNotPermittedNote::IndividualForeignItems, + diagnostics::VisibilityNotPermittedNote::IndividualForeignItems, ); if &Safety::Default == safety { if item.span.at_least_rust_2024() { - self.dcx().emit_err(errors::MissingUnsafeOnExtern { span: item.span }); + self.dcx().emit_err(diagnostics::MissingUnsafeOnExtern { span: item.span }); } else { self.lint_buffer.buffer_lint( MISSING_UNSAFE_ON_EXTERN, item.id, item.span, - errors::MissingUnsafeOnExternLint { + diagnostics::MissingUnsafeOnExternLint { suggestion: item.span.shrink_to_lo(), }, ); @@ -1315,12 +1325,12 @@ impl Visitor<'_> for AstValidator<'_> { for variant in &def.variants { self.visibility_not_permitted( &variant.vis, - errors::VisibilityNotPermittedNote::EnumVariant, + diagnostics::VisibilityNotPermittedNote::EnumVariant, ); for field in variant.data.fields() { self.visibility_not_permitted( &field.vis, - errors::VisibilityNotPermittedNote::EnumVariant, + diagnostics::VisibilityNotPermittedNote::EnumVariant, ); } } @@ -1364,7 +1374,7 @@ impl Visitor<'_> for AstValidator<'_> { } ItemKind::Mod(safety, ident, mod_kind) => { if let &Safety::Unsafe(span) = safety { - self.dcx().emit_err(errors::UnsafeItem { span, kind: "module" }); + self.dcx().emit_err(diagnostics::UnsafeItem { span, kind: "module" }); } // Ensure that `path` attributes on modules are recorded as used (cf. issue #35584). if !matches!(mod_kind, ModKind::Loaded(_, Inline::Yes, _)) @@ -1381,13 +1391,15 @@ impl Visitor<'_> for AstValidator<'_> { item.attrs.iter().find(|attr| attr.has_name(sym::rustc_scalable_vector)); if let Some(attr) = scalable_vector_attr { if !matches!(vdata, VariantData::Tuple(..)) { - this.dcx() - .emit_err(errors::ScalableVectorNotTupleStruct { span: item.span }); + this.dcx().emit_err(diagnostics::ScalableVectorNotTupleStruct { + span: item.span, + }); } if !self.sess.target.arch.supports_scalable_vectors() && !self.sess.opts.actually_rustdoc { - this.dcx().emit_err(errors::ScalableVectorBadArch { span: attr.span }); + this.dcx() + .emit_err(diagnostics::ScalableVectorBadArch { span: attr.span }); } } @@ -1403,7 +1415,7 @@ impl Visitor<'_> for AstValidator<'_> { } ItemKind::Union(ident, generics, vdata) => { if vdata.fields().is_empty() { - self.dcx().emit_err(errors::FieldlessUnion { span: item.span }); + self.dcx().emit_err(diagnostics::FieldlessUnion { span: item.span }); } self.with_tilde_const(Some(TildeConstReason::Union { span: item.span }), |this| { match vdata { @@ -1419,7 +1431,7 @@ impl Visitor<'_> for AstValidator<'_> { ItemKind::Const(ConstItem { defaultness, ident, rhs_kind, .. }) => { self.check_defaultness(item.span, *defaultness, AllowDefault::No, AllowFinal::No); if !rhs_kind.has_expr() { - self.dcx().emit_err(errors::ConstWithoutBody { + self.dcx().emit_err(diagnostics::ConstWithoutBody { span: item.span, replace_span: self.ending_semi_or_hi(item.span), }); @@ -1432,7 +1444,7 @@ impl Visitor<'_> for AstValidator<'_> { UNUSED_VISIBILITIES, item.id, item.vis.span, - errors::UnusedVisibility { span: item.vis.span }, + diagnostics::UnusedVisibility { span: item.vis.span }, ) } @@ -1441,11 +1453,11 @@ impl Visitor<'_> for AstValidator<'_> { ItemKind::Static(StaticItem { expr, safety, .. }) => { self.check_item_safety(item.span, *safety); if matches!(safety, Safety::Unsafe(_)) { - self.dcx().emit_err(errors::UnsafeStatic { span: item.span }); + self.dcx().emit_err(diagnostics::UnsafeStatic { span: item.span }); } if expr.is_none() { - self.dcx().emit_err(errors::StaticWithoutBody { + self.dcx().emit_err(diagnostics::StaticWithoutBody { span: item.span, replace_span: self.ending_semi_or_hi(item.span), }); @@ -1457,7 +1469,7 @@ impl Visitor<'_> for AstValidator<'_> { ) => { self.check_defaultness(item.span, *defaultness, AllowDefault::No, AllowFinal::No); if ty.is_none() { - self.dcx().emit_err(errors::TyAliasWithoutBody { + self.dcx().emit_err(diagnostics::TyAliasWithoutBody { span: item.span, replace_span: self.ending_semi_or_hi(item.span), }); @@ -1469,7 +1481,7 @@ impl Visitor<'_> for AstValidator<'_> { self.dcx().emit_err(err); } } else if after_where_clause.has_where_token { - self.dcx().emit_err(errors::WhereClauseAfterTypeAlias { + self.dcx().emit_err(diagnostics::WhereClauseAfterTypeAlias { span: after_where_clause.span, help: self.sess.is_nightly_build(), }); @@ -1499,7 +1511,7 @@ impl Visitor<'_> for AstValidator<'_> { if let Some(attr) = attr::find_by_name(fi.attrs(), sym::track_caller) && self.extern_mod_abi != Some(ExternAbi::Rust) { - self.dcx().emit_err(errors::RequiresRustAbi { + self.dcx().emit_err(diagnostics::RequiresRustAbi { track_caller_span: attr.span, extern_abi_span: self.current_extern_span(), }); @@ -1573,7 +1585,7 @@ impl Visitor<'_> for AstValidator<'_> { } GenericParamKind::Type { .. } | GenericParamKind::Const { .. } => { if let Some(span) = prev_param_default { - self.dcx().emit_err(errors::GenericDefaultTrailing { span }); + self.dcx().emit_err(diagnostics::GenericDefaultTrailing { span }); break; } } @@ -1602,8 +1614,9 @@ impl Visitor<'_> for AstValidator<'_> { match bound { GenericBound::Trait(t) => { if !t.bound_generic_params.is_empty() { - self.dcx() - .emit_err(errors::NestedLifetimes { span: t.span }); + self.dcx().emit_err(diagnostics::NestedLifetimes { + span: t.span, + }); } } GenericBound::Outlives(_) => {} @@ -1627,12 +1640,13 @@ impl Visitor<'_> for AstValidator<'_> { BoundConstness::Always(_), BoundPolarity::Positive, ) => { - self.dcx().emit_err(errors::ConstBoundTraitObject { span: trait_ref.span }); + self.dcx() + .emit_err(diagnostics::ConstBoundTraitObject { span: trait_ref.span }); } (_, BoundConstness::Maybe(span), BoundPolarity::Positive) if let Some(reason) = self.disallow_tilde_const => { - self.dcx().emit_err(errors::TildeConstDisallowed { span, reason }); + self.dcx().emit_err(diagnostics::TildeConstDisallowed { span, reason }); } _ => {} } @@ -1645,7 +1659,7 @@ impl Visitor<'_> for AstValidator<'_> { Some(ast::GenericArgs::AngleBracketed(args)) => { for arg in &args.args { if let ast::AngleBracketedArg::Constraint(constraint) = arg { - self.dcx().emit_err(errors::ConstraintOnNegativeBound { + self.dcx().emit_err(diagnostics::ConstraintOnNegativeBound { span: constraint.span, }); } @@ -1653,9 +1667,11 @@ impl Visitor<'_> for AstValidator<'_> { } // The lowered form of parenthesized generic args contains an associated type binding. Some(ast::GenericArgs::Parenthesized(args)) => { - self.dcx().emit_err(errors::NegativeBoundWithParentheticalNotation { - span: args.span, - }); + self.dcx().emit_err( + diagnostics::NegativeBoundWithParentheticalNotation { + span: args.span, + }, + ); } Some(ast::GenericArgs::ParenthesizedElided(_)) | None => {} } @@ -1665,7 +1681,7 @@ impl Visitor<'_> for AstValidator<'_> { GenericBound::Use(_, span) => match ctxt { BoundKind::Impl => {} BoundKind::Bound | BoundKind::TraitObject | BoundKind::SuperTraits => { - self.dcx().emit_err(errors::PreciseCapturingNotAllowedHere { + self.dcx().emit_err(diagnostics::PreciseCapturingNotAllowedHere { loc: ctxt.descr(), span: *span, }); @@ -1705,7 +1721,7 @@ impl Visitor<'_> for AstValidator<'_> { if let Some(attr) = attr::find_by_name(attrs, sym::track_caller) && extern_abi != ExternAbi::Rust { - self.dcx().emit_err(errors::RequiresRustAbi { + self.dcx().emit_err(diagnostics::RequiresRustAbi { track_caller_span: attr.span, extern_abi_span, }); @@ -1722,7 +1738,7 @@ impl Visitor<'_> for AstValidator<'_> { .. }) = fk.header() { - self.dcx().emit_err(errors::ConstAndCoroutine { + self.dcx().emit_err(diagnostics::ConstAndCoroutine { spans: vec![coroutine_kind.span(), const_span], const_span, coroutine_span: coroutine_kind.span(), @@ -1754,11 +1770,11 @@ impl Visitor<'_> for AstValidator<'_> { id, span, move |dcx, level| { - let sub = errors::PatternsInFnsWithoutBodySub { ident, span }; + let sub = diagnostics::PatternsInFnsWithoutBodySub { ident, span }; if is_foreign { - errors::PatternsInFnsWithoutBody::Foreign { sub } + diagnostics::PatternsInFnsWithoutBody::Foreign { sub } } else { - errors::PatternsInFnsWithoutBody::Bodiless { sub } + diagnostics::PatternsInFnsWithoutBody::Bodiless { sub } } .into_diag(dcx, level) }, @@ -1766,8 +1782,10 @@ impl Visitor<'_> for AstValidator<'_> { } } else { match ctxt { - FnCtxt::Foreign => self.dcx().emit_err(errors::PatternInForeign { span }), - _ => self.dcx().emit_err(errors::PatternInBodiless { span }), + FnCtxt::Foreign => { + self.dcx().emit_err(diagnostics::PatternInForeign { span }) + } + _ => self.dcx().emit_err(diagnostics::PatternInBodiless { span }), }; } }); @@ -1814,7 +1832,7 @@ impl Visitor<'_> for AstValidator<'_> { match &item.kind { AssocItemKind::Const(ConstItem { rhs_kind, .. }) => { if !rhs_kind.has_expr() { - self.dcx().emit_err(errors::AssocConstWithoutBody { + self.dcx().emit_err(diagnostics::AssocConstWithoutBody { span: item.span, replace_span: self.ending_semi_or_hi(item.span), }); @@ -1822,7 +1840,7 @@ impl Visitor<'_> for AstValidator<'_> { } AssocItemKind::Fn(Fn { body, .. }) => { if body.is_none() && !self.is_sdylib_interface { - self.dcx().emit_err(errors::AssocFnWithoutBody { + self.dcx().emit_err(diagnostics::AssocFnWithoutBody { span: item.span, replace_span: self.ending_semi_or_hi(item.span), }); @@ -1830,7 +1848,7 @@ impl Visitor<'_> for AstValidator<'_> { } AssocItemKind::Type(TyAlias { bounds, ty, .. }) => { if ty.is_none() { - self.dcx().emit_err(errors::AssocTypeWithoutBody { + self.dcx().emit_err(diagnostics::AssocTypeWithoutBody { span: item.span, replace_span: self.ending_semi_or_hi(item.span), }); @@ -1845,8 +1863,8 @@ impl Visitor<'_> for AstValidator<'_> { && let Err(err) = self.check_type_alias_where_clause_location(ty_alias) { let sugg = match err.sugg { - errors::WhereClauseBeforeTypeAliasSugg::Remove { .. } => None, - errors::WhereClauseBeforeTypeAliasSugg::Move { snippet, right, .. } => { + diagnostics::WhereClauseBeforeTypeAliasSugg::Remove { .. } => None, + diagnostics::WhereClauseBeforeTypeAliasSugg::Move { snippet, right, .. } => { Some((right, snippet)) } }; @@ -1862,17 +1880,17 @@ impl Visitor<'_> for AstValidator<'_> { move |dcx, level| { let suggestion = match sugg { Some((right_sp, sugg)) => { - errors::DeprecatedWhereClauseLocationSugg::MoveToEnd { + diagnostics::DeprecatedWhereClauseLocationSugg::MoveToEnd { left: left_sp, right: right_sp, sugg, } } - None => errors::DeprecatedWhereClauseLocationSugg::RemoveWhere { + None => diagnostics::DeprecatedWhereClauseLocationSugg::RemoveWhere { span: err.span, }, }; - errors::DeprecatedWhereClauseLocation { suggestion }.into_diag(dcx, level) + diagnostics::DeprecatedWhereClauseLocation { suggestion }.into_diag(dcx, level) }, ); } @@ -1881,7 +1899,7 @@ impl Visitor<'_> for AstValidator<'_> { Some(parent @ (TraitOrImpl::Trait { .. } | TraitOrImpl::TraitImpl { .. })) => { self.visibility_not_permitted( &item.vis, - errors::VisibilityNotPermittedNote::TraitImpl, + diagnostics::VisibilityNotPermittedNote::TraitImpl, ); if let AssocItemKind::Fn(Fn { sig, .. }) = &item.kind { self.check_trait_fn_not_const(sig.header.constness, parent); @@ -1952,7 +1970,7 @@ fn deny_equality_constraints( predicate_span: Span, generics: &Generics, ) { - let mut err = errors::EqualityInWhere { span: predicate_span, assoc: None, assoc2: None }; + let mut err = diagnostics::EqualityInWhere { span: predicate_span, assoc: None, assoc2: None }; // Given `::Bar = RhsTy`, suggest `A: Foo`. if let TyKind::Path(Some(qself), full_path) = &predicate.lhs_ty.kind @@ -1995,7 +2013,7 @@ fn deny_equality_constraints( ); } } - err.assoc = Some(errors::AssociatedSuggestion { + err.assoc = Some(diagnostics::AssociatedSuggestion { span: predicate_span, ident: *ident, param: param.ident, @@ -2046,7 +2064,7 @@ fn deny_equality_constraints( } span }; - err.assoc2 = Some(errors::AssociatedSuggestion2 { + err.assoc2 = Some(diagnostics::AssociatedSuggestion2 { span, args, predicate: removal_span, diff --git a/compiler/rustc_ast_passes/src/errors.rs b/compiler/rustc_ast_passes/src/diagnostics.rs similarity index 100% rename from compiler/rustc_ast_passes/src/errors.rs rename to compiler/rustc_ast_passes/src/diagnostics.rs diff --git a/compiler/rustc_ast_passes/src/feature_gate.rs b/compiler/rustc_ast_passes/src/feature_gate.rs index fd0070bd9c529..09672d1e69f11 100644 --- a/compiler/rustc_ast_passes/src/feature_gate.rs +++ b/compiler/rustc_ast_passes/src/feature_gate.rs @@ -10,7 +10,7 @@ use rustc_session::errors::{feature_err, feature_warn}; use rustc_span::{Span, Spanned, Symbol, sym}; use thin_vec::ThinVec; -use crate::errors; +use crate::diagnostics; /// The common case. macro_rules! gate { @@ -133,7 +133,7 @@ impl<'a> PostExpansionVisitor<'a> { .collect(); if !const_param_spans.is_empty() { - self.sess.dcx().emit_err(errors::ForbiddenConstParam { const_param_spans }); + self.sess.dcx().emit_err(diagnostics::ForbiddenConstParam { const_param_spans }); } } @@ -144,9 +144,9 @@ impl<'a> PostExpansionVisitor<'a> { // Issue #149695 // Abort immediately otherwise items defined in complex bounds will be lowered into HIR, // which will cause ICEs when errors of the items visit unlowered parents. - self.sess.dcx().emit_fatal(errors::ForbiddenBound { spans }); + self.sess.dcx().emit_fatal(diagnostics::ForbiddenBound { spans }); } else { - self.sess.dcx().emit_err(errors::ForbiddenBound { spans }); + self.sess.dcx().emit_err(diagnostics::ForbiddenBound { spans }); } } } @@ -553,7 +553,7 @@ pub fn check_crate(krate: &ast::Crate, sess: &Session, features: &Features) { // Under no circumstances do we want to advertise the feature name to users! if !visitor.features.negative_bounds() { for &span in spans.get(&sym::negative_bounds).into_iter().flatten() { - sess.dcx().emit_err(errors::NegativeBoundUnsupported { span }); + sess.dcx().emit_err(diagnostics::NegativeBoundUnsupported { span }); } } @@ -570,7 +570,7 @@ pub fn check_crate(krate: &ast::Crate, sess: &Session, features: &Features) { .emit(); } else { let suggestion = span.shrink_to_hi(); - sess.dcx().emit_err(errors::MatchArmWithNoBody { span, suggestion }); + sess.dcx().emit_err(diagnostics::MatchArmWithNoBody { span, suggestion }); } } } @@ -645,7 +645,7 @@ fn maybe_stage_features(sess: &Session, features: &Features, krate: &ast::Crate) AttributeParser::parse_limited(sess, &krate.attrs, &[sym::feature]) { // `feature(...)` used on non-nightly. This is definitely an error. - let mut err = errors::FeatureOnNonNightly { + let mut err = diagnostics::FeatureOnNonNightly { span: first_span, channel: option_env!("CFG_RELEASE_CHANNEL").unwrap_or("(unknown)"), stable_features: vec![], @@ -662,7 +662,7 @@ fn maybe_stage_features(sess: &Session, features: &Features, krate: &ast::Crate) .map(|feat| feat.stable_since) .flatten(); if let Some(since) = stable_since { - err.stable_features.push(errors::StableFeature { name, since }); + err.stable_features.push(diagnostics::StableFeature { name, since }); } else { all_stable = false; } @@ -688,7 +688,11 @@ fn check_incompatible_features(sess: &Session, features: &Features) { && let Some((f2_name, f2_span)) = enabled_features.clone().find(|(name, _)| name == f2) { let spans = vec![f1_span, f2_span]; - sess.dcx().emit_err(errors::IncompatibleFeatures { spans, f1: f1_name, f2: f2_name }); + sess.dcx().emit_err(diagnostics::IncompatibleFeatures { + spans, + f1: f1_name, + f2: f2_name, + }); } } } @@ -709,7 +713,11 @@ fn check_dependent_features(sess: &Session, features: &Features) { .map(|s| format!("`{}`", s.as_str())) .intersperse(String::from(", ")) .collect(); - sess.dcx().emit_err(errors::MissingDependentFeatures { parent_span, parent, missing }); + sess.dcx().emit_err(diagnostics::MissingDependentFeatures { + parent_span, + parent, + missing, + }); } } } @@ -727,7 +735,7 @@ fn check_new_solver_banned_features(sess: &Session, features: &Features) { .map(|feat| feat.attr_sp) { #[allow(rustc::symbol_intern_string_literal)] - sess.dcx().emit_err(errors::IncompatibleFeatures { + sess.dcx().emit_err(diagnostics::IncompatibleFeatures { spans: vec![gce_span], f1: Symbol::intern("-Znext-solver=globally"), f2: sym::generic_const_exprs, @@ -749,7 +757,7 @@ fn check_features_requiring_new_solver(sess: &Session, features: &Features) { .map(|feat| feat.attr_sp) { #[allow(rustc::symbol_intern_string_literal)] - sess.dcx().emit_err(errors::MissingDependentFeatures { + sess.dcx().emit_err(diagnostics::MissingDependentFeatures { parent_span: gca_span, parent: sym::generic_const_args, missing: String::from("-Znext-solver=globally"), diff --git a/compiler/rustc_ast_passes/src/lib.rs b/compiler/rustc_ast_passes/src/lib.rs index 8bf51dd10a844..86ad758807584 100644 --- a/compiler/rustc_ast_passes/src/lib.rs +++ b/compiler/rustc_ast_passes/src/lib.rs @@ -9,5 +9,5 @@ // tidy-alphabetical-end pub mod ast_validation; -mod errors; +mod diagnostics; pub mod feature_gate; diff --git a/compiler/rustc_attr_parsing/src/interface.rs b/compiler/rustc_attr_parsing/src/interface.rs index cf5a722f0529e..27960e96bc111 100644 --- a/compiler/rustc_attr_parsing/src/interface.rs +++ b/compiler/rustc_attr_parsing/src/interface.rs @@ -8,7 +8,7 @@ use rustc_ast::token::DocFragmentKind; use rustc_ast::{AttrItemKind, AttrStyle, CRATE_NODE_ID, NodeId, Safety}; use rustc_data_structures::sync::{DynSend, DynSync}; use rustc_errors::{Diag, DiagCtxtHandle, Diagnostic, Level, MultiSpan}; -use rustc_feature::{AttributeTemplate, Features}; +use rustc_feature::{AttributeTemplate, BUILTIN_ATTRIBUTE_MAP, Features}; use rustc_hir::attrs::AttributeKind; use rustc_hir::{AttrArgs, AttrItem, AttrPath, Attribute, HashIgnoredAttrId, Target}; use rustc_lint_defs::RegisteredTools; @@ -355,6 +355,9 @@ impl<'sess> AttributeParser<'sess> { &mut emit_lint, ); self.check_attribute_stability(&attr_path, attr_span, accept.stability); + if let [part] = parts.as_slice() { + debug_assert!(BUILTIN_ATTRIBUTE_MAP.contains(&part)); + } let Some(args) = ArgParser::from_attr_args( args, diff --git a/compiler/rustc_borrowck/src/type_check/constraint_conversion.rs b/compiler/rustc_borrowck/src/type_check/constraint_conversion.rs index bca2de041b657..4d93fa08fe0bd 100644 --- a/compiler/rustc_borrowck/src/type_check/constraint_conversion.rs +++ b/compiler/rustc_borrowck/src/type_check/constraint_conversion.rs @@ -1,7 +1,7 @@ use rustc_data_structures::fx::FxHashSet; use rustc_hir::def_id::LocalDefId; use rustc_infer::infer::SubregionOrigin; -use rustc_infer::infer::canonical::QueryRegionConstraints; +use rustc_infer::infer::canonical::{QueryRegionConstraint, QueryRegionConstraints}; use rustc_infer::infer::outlives::env::RegionBoundPairs; use rustc_infer::infer::outlives::obligations::{TypeOutlives, TypeOutlivesDelegate}; use rustc_infer::infer::region_constraints::{GenericKind, VerifyBound}; @@ -74,9 +74,9 @@ impl<'a, 'tcx> ConstraintConversion<'a, 'tcx> { let assumptions = elaborate::elaborate_outlives_assumptions(self.infcx.tcx, assumptions.iter().copied()); - for &(constraint, constraint_category, _) in constraints { + for &QueryRegionConstraint { constraint, category, .. } in constraints { constraint.iter_outlives().for_each(|predicate| { - self.convert(predicate, constraint_category, &assumptions); + self.convert(predicate, category, &assumptions); }); } } @@ -296,7 +296,7 @@ impl<'a, 'tcx> ConstraintConversion<'a, 'tcx> { // FIXME(higher_ranked_auto): What should we do with the assumptions here? if let Some(QueryRegionConstraints { constraints, assumptions: _ }) = constraints { next_outlives_predicates.extend(constraints.iter().flat_map( - |(constraint, category, _)| { + |QueryRegionConstraint { constraint, category, .. }| { constraint.iter_outlives().map(|outlives| (outlives, *category)) }, )); diff --git a/compiler/rustc_builtin_macros/src/alloc_error_handler.rs b/compiler/rustc_builtin_macros/src/alloc_error_handler.rs index 5f78758513e17..544ad86120356 100644 --- a/compiler/rustc_builtin_macros/src/alloc_error_handler.rs +++ b/compiler/rustc_builtin_macros/src/alloc_error_handler.rs @@ -6,7 +6,7 @@ use rustc_expand::base::{Annotatable, ExtCtxt}; use rustc_span::{Ident, Span, kw, sym}; use thin_vec::{ThinVec, thin_vec}; -use crate::errors; +use crate::diagnostics; use crate::util::check_builtin_macro_attribute; pub(crate) fn expand( @@ -31,7 +31,7 @@ pub(crate) fn expand( { (item, fn_kind.ident, true, ecx.with_def_site_ctxt(fn_kind.sig.span)) } else { - ecx.dcx().emit_err(errors::AllocErrorMustBeFn { span: item.span() }); + ecx.dcx().emit_err(diagnostics::AllocErrorMustBeFn { span: item.span() }); return vec![orig_item]; }; diff --git a/compiler/rustc_builtin_macros/src/asm.rs b/compiler/rustc_builtin_macros/src/asm.rs index a1e14b5245137..b67b1fdb42048 100644 --- a/compiler/rustc_builtin_macros/src/asm.rs +++ b/compiler/rustc_builtin_macros/src/asm.rs @@ -12,7 +12,7 @@ use rustc_span::{ErrorGuaranteed, InnerSpan, Span, Symbol, sym}; use rustc_target::asm::InlineAsmArch; use smallvec::smallvec; -use crate::errors; +use crate::diagnostics; use crate::util::{ExprToSpannedString, expr_to_spanned_string}; /// Validated assembly arguments, ready for macro expansion. @@ -65,7 +65,7 @@ fn validate_asm_args<'a>( for arg in args { for attr in arg.attributes.0.iter() { if !matches!(attr.name(), Some(sym::cfg | sym::cfg_attr)) { - ecx.dcx().emit_err(errors::AsmAttributeNotSupported { span: attr.span() }); + ecx.dcx().emit_err(diagnostics::AsmAttributeNotSupported { span: attr.span() }); } } @@ -86,7 +86,7 @@ fn validate_asm_args<'a>( ) => {} ast::ExprKind::MacCall(..) => {} _ => { - let err = dcx.create_err(errors::AsmExpectedOther { + let err = dcx.create_err(diagnostics::AsmExpectedOther { span: template.span, is_inline_asm: matches!(asm_macro, AsmMacro::Asm), }); @@ -111,12 +111,12 @@ fn validate_asm_args<'a>( if explicit_reg { if name.is_some() { - dcx.emit_err(errors::AsmExplicitRegisterName { span }); + dcx.emit_err(diagnostics::AsmExplicitRegisterName { span }); } validated.reg_args.insert(slot); } else if let Some(name) = name { if let Some(&prev) = validated.named_args.get(&name) { - dcx.emit_err(errors::AsmDuplicateArg { + dcx.emit_err(diagnostics::AsmDuplicateArg { span, name, prev: validated.operands[prev].1, @@ -130,7 +130,7 @@ fn validate_asm_args<'a>( let explicit = validated.reg_args.iter().map(|p| validated.operands[p].1).collect(); - dcx.emit_err(errors::AsmPositionalAfter { span, named, explicit }); + dcx.emit_err(diagnostics::AsmPositionalAfter { span, named, explicit }); } } AsmArgKind::Options(new_options) => { @@ -141,7 +141,7 @@ fn validate_asm_args<'a>( if !asm_macro.is_supported_option(options) { // Tool-only output. - dcx.emit_err(errors::AsmUnsupportedOption { + dcx.emit_err(diagnostics::AsmUnsupportedOption { span, symbol, span_with_comma, @@ -149,7 +149,7 @@ fn validate_asm_args<'a>( }); } else if validated.options.contains(options) { // Tool-only output. - dcx.emit_err(errors::AsmOptAlreadyprovided { + dcx.emit_err(diagnostics::AsmOptAlreadyprovided { span, symbol, span_with_comma, @@ -178,13 +178,13 @@ fn validate_asm_args<'a>( && validated.options.contains(ast::InlineAsmOptions::READONLY) { let spans = validated.options_spans.clone(); - dcx.emit_err(errors::AsmMutuallyExclusive { spans, opt1: "nomem", opt2: "readonly" }); + dcx.emit_err(diagnostics::AsmMutuallyExclusive { spans, opt1: "nomem", opt2: "readonly" }); } if validated.options.contains(ast::InlineAsmOptions::PURE) && validated.options.contains(ast::InlineAsmOptions::NORETURN) { let spans = validated.options_spans.clone(); - dcx.emit_err(errors::AsmMutuallyExclusive { spans, opt1: "pure", opt2: "noreturn" }); + dcx.emit_err(diagnostics::AsmMutuallyExclusive { spans, opt1: "pure", opt2: "noreturn" }); } if validated.options.contains(ast::InlineAsmOptions::PURE) && !validated @@ -192,7 +192,7 @@ fn validate_asm_args<'a>( .intersects(ast::InlineAsmOptions::NOMEM | ast::InlineAsmOptions::READONLY) { let spans = validated.options_spans.clone(); - dcx.emit_err(errors::AsmPureCombine { spans }); + dcx.emit_err(diagnostics::AsmPureCombine { spans }); } let mut have_real_output = false; @@ -223,24 +223,24 @@ fn validate_asm_args<'a>( } } if validated.options.contains(ast::InlineAsmOptions::PURE) && !have_real_output { - dcx.emit_err(errors::AsmPureNoOutput { spans: validated.options_spans.clone() }); + dcx.emit_err(diagnostics::AsmPureNoOutput { spans: validated.options_spans.clone() }); } if validated.options.contains(ast::InlineAsmOptions::NORETURN) && !outputs_sp.is_empty() && labels_sp.is_empty() { - let err = dcx.create_err(errors::AsmNoReturn { outputs_sp }); + let err = dcx.create_err(diagnostics::AsmNoReturn { outputs_sp }); // Bail out now since this is likely to confuse MIR return Err(err); } if validated.options.contains(ast::InlineAsmOptions::MAY_UNWIND) && !labels_sp.is_empty() { - dcx.emit_err(errors::AsmMayUnwind { labels_sp }); + dcx.emit_err(diagnostics::AsmMayUnwind { labels_sp }); } if !validated.clobber_abis.is_empty() { match asm_macro { AsmMacro::GlobalAsm | AsmMacro::NakedAsm => { - let err = dcx.create_err(errors::AsmUnsupportedClobberAbi { + let err = dcx.create_err(diagnostics::AsmUnsupportedClobberAbi { spans: validated.clobber_abis.iter().map(|(_, span)| *span).collect(), macro_name: asm_macro.macro_name(), }); @@ -250,7 +250,7 @@ fn validate_asm_args<'a>( } AsmMacro::Asm => { if !regclass_outputs.is_empty() { - dcx.emit_err(errors::AsmClobberNoReg { + dcx.emit_err(diagnostics::AsmClobberNoReg { spans: regclass_outputs, clobbers: validated.clobber_abis.iter().map(|(_, span)| *span).collect(), }); @@ -354,7 +354,7 @@ fn expand_preparsed_asm( lint::builtin::BAD_ASM_STYLE, find_span(".intel_syntax"), ecx.current_expansion.lint_node_id, - errors::AvoidIntelSyntax, + diagnostics::AvoidIntelSyntax, ); } if template_str.contains(".att_syntax") { @@ -362,7 +362,7 @@ fn expand_preparsed_asm( lint::builtin::BAD_ASM_STYLE, find_span(".att_syntax"), ecx.current_expansion.lint_node_id, - errors::AvoidAttSyntax, + diagnostics::AvoidAttSyntax, ); } } @@ -482,7 +482,7 @@ fn expand_preparsed_asm( None => { let span = arg.position_span; ecx.dcx() - .create_err(errors::AsmNoMatchedArgumentName { + .create_err(diagnostics::AsmNoMatchedArgumentName { name: name.to_owned(), span: span_in_template(span), }) @@ -497,7 +497,7 @@ fn expand_preparsed_asm( let mut modifier = chars.next(); if chars.next().is_some() { let span = arg.format.ty_span.map(span_in_template).unwrap_or(template_sp); - ecx.dcx().emit_err(errors::AsmModifierInvalid { span }); + ecx.dcx().emit_err(diagnostics::AsmModifierInvalid { span }); modifier = None; } diff --git a/compiler/rustc_builtin_macros/src/assert.rs b/compiler/rustc_builtin_macros/src/assert.rs index 855da5caa312c..444510ee50572 100644 --- a/compiler/rustc_builtin_macros/src/assert.rs +++ b/compiler/rustc_builtin_macros/src/assert.rs @@ -11,8 +11,8 @@ use rustc_parse::parser::Parser; use rustc_span::{DUMMY_SP, Ident, Span, Symbol, sym}; use thin_vec::thin_vec; +use crate::diagnostics; use crate::edition_panic::use_panic_2021; -use crate::errors; pub(crate) fn expand_assert<'cx>( cx: &'cx mut ExtCtxt<'_>, @@ -114,7 +114,7 @@ fn parse_assert<'a>(cx: &ExtCtxt<'a>, sp: Span, stream: TokenStream) -> PResult< let mut parser = cx.new_parser_from_tts(stream); if parser.token == token::Eof { - return Err(cx.dcx().create_err(errors::AssertRequiresBoolean { span: sp })); + return Err(cx.dcx().create_err(diagnostics::AssertRequiresBoolean { span: sp })); } let cond_expr = parser.parse_expr()?; @@ -127,7 +127,8 @@ fn parse_assert<'a>(cx: &ExtCtxt<'a>, sp: Span, stream: TokenStream) -> PResult< // // Emit an error about semicolon and suggest removing it. if parser.token == token::Semi { - cx.dcx().emit_err(errors::AssertRequiresExpression { span: sp, token: parser.token.span }); + cx.dcx() + .emit_err(diagnostics::AssertRequiresExpression { span: sp, token: parser.token.span }); parser.bump(); } @@ -140,7 +141,7 @@ fn parse_assert<'a>(cx: &ExtCtxt<'a>, sp: Span, stream: TokenStream) -> PResult< let custom_message = if let token::Literal(token::Lit { kind: token::Str, .. }) = parser.token.kind { let comma = parser.prev_token.span.shrink_to_hi(); - cx.dcx().emit_err(errors::AssertMissingComma { span: parser.token.span, comma }); + cx.dcx().emit_err(diagnostics::AssertMissingComma { span: parser.token.span, comma }); parse_custom_message(&mut parser) } else if parser.eat(exp!(Comma)) { diff --git a/compiler/rustc_builtin_macros/src/autodiff.rs b/compiler/rustc_builtin_macros/src/autodiff.rs index 76c43e0df1a24..595a8b1fecb87 100644 --- a/compiler/rustc_builtin_macros/src/autodiff.rs +++ b/compiler/rustc_builtin_macros/src/autodiff.rs @@ -24,7 +24,7 @@ mod llvm_enzyme { use thin_vec::{ThinVec, thin_vec}; use tracing::{debug, trace}; - use crate::errors; + use crate::diagnostics; pub(crate) fn outer_normal_attr( kind: &Box, @@ -101,7 +101,7 @@ mod llvm_enzyme { match x.try_into() { Ok(x) => x, Err(_) => { - dcx.emit_err(errors::AutoDiffInvalidWidth { + dcx.emit_err(diagnostics::AutoDiffInvalidWidth { span: meta_item[1].span(), width: x, }); @@ -120,7 +120,7 @@ mod llvm_enzyme { match res { Ok(x) => activities.push(x), Err(_) => { - dcx.emit_err(errors::AutoDiffUnknownActivity { + dcx.emit_err(diagnostics::AutoDiffUnknownActivity { span: x.span(), act: activity_str, }); @@ -238,14 +238,14 @@ mod llvm_enzyme { } _ => None, }) else { - dcx.emit_err(errors::AutoDiffInvalidApplication { span: item.span() }); + dcx.emit_err(diagnostics::AutoDiffInvalidApplication { span: item.span() }); return vec![item]; }; let meta_item_vec: ThinVec = match meta_item.kind { ast::MetaItemKind::List(ref vec) => vec.clone(), _ => { - dcx.emit_err(errors::AutoDiffMissingConfig { span: item.span() }); + dcx.emit_err(diagnostics::AutoDiffMissingConfig { span: item.span() }); return vec![item]; } }; @@ -257,7 +257,7 @@ mod llvm_enzyme { let mut ts: Vec = vec![]; if meta_item_vec.len() < 1 { // At the bare minimum, we need a fnc name. - dcx.emit_err(errors::AutoDiffMissingConfig { span: item.span() }); + dcx.emit_err(diagnostics::AutoDiffMissingConfig { span: item.span() }); return vec![item]; } @@ -658,7 +658,7 @@ mod llvm_enzyme { let sig_args = sig.decl.inputs.len() + if has_ret { 1 } else { 0 }; let num_activities = x.input_activity.len() + if x.has_ret_activity() { 1 } else { 0 }; if sig_args != num_activities { - dcx.emit_err(errors::AutoDiffInvalidNumberActivities { + dcx.emit_err(diagnostics::AutoDiffInvalidNumberActivities { span, expected: sig_args, found: num_activities, @@ -679,7 +679,7 @@ mod llvm_enzyme { let mut errors = false; for (arg, activity) in sig.decl.inputs.iter().zip(x.input_activity.iter()) { if !valid_input_activity(x.mode, *activity) { - dcx.emit_err(errors::AutoDiffInvalidApplicationModeAct { + dcx.emit_err(diagnostics::AutoDiffInvalidApplicationModeAct { span, mode: x.mode.to_string(), act: activity.to_string(), @@ -687,7 +687,7 @@ mod llvm_enzyme { errors = true; } if !valid_ty_for_activity(&arg.ty, *activity) { - dcx.emit_err(errors::AutoDiffInvalidTypeForActivity { + dcx.emit_err(diagnostics::AutoDiffInvalidTypeForActivity { span: arg.ty.span, act: activity.to_string(), }); @@ -696,7 +696,7 @@ mod llvm_enzyme { } if has_ret && !valid_ret_activity(x.mode, x.ret_activity) { - dcx.emit_err(errors::AutoDiffInvalidRetAct { + dcx.emit_err(diagnostics::AutoDiffInvalidRetAct { span, mode: x.mode.to_string(), act: x.ret_activity.to_string(), diff --git a/compiler/rustc_builtin_macros/src/cfg.rs b/compiler/rustc_builtin_macros/src/cfg.rs index 2872cff0fdc7a..f2771f125ff54 100644 --- a/compiler/rustc_builtin_macros/src/cfg.rs +++ b/compiler/rustc_builtin_macros/src/cfg.rs @@ -16,7 +16,7 @@ use rustc_parse::exp; use rustc_parse::parser::Recovery; use rustc_span::{ErrorGuaranteed, Span, sym}; -use crate::errors; +use crate::diagnostics; pub(crate) fn expand_cfg( cx: &mut ExtCtxt<'_>, @@ -38,7 +38,7 @@ pub(crate) fn expand_cfg( fn parse_cfg(cx: &ExtCtxt<'_>, span: Span, tts: TokenStream) -> Result { let mut parser = cx.new_parser_from_tts(tts); if parser.token == token::Eof { - return Err(cx.dcx().emit_err(errors::RequiresCfgPattern { span })); + return Err(cx.dcx().emit_err(diagnostics::RequiresCfgPattern { span })); } let meta = MetaItemOrLitParser::parse_single( @@ -70,7 +70,7 @@ fn parse_cfg(cx: &ExtCtxt<'_>, span: Span, tts: TokenStream) -> Result(ecx: &ExtCtxt<'_>, mi: &'a ast::MetaItem) -> Option<&'a ast::Path> { - use errors::CfgAccessibleInvalid::*; + use diagnostics::CfgAccessibleInvalid::*; match mi.meta_item_list() { None => {} Some([]) => { @@ -62,7 +62,7 @@ impl MultiItemModifier for Expander { Ok(true) => ExpandResult::Ready(vec![item]), Ok(false) => ExpandResult::Ready(Vec::new()), Err(Indeterminate) if ecx.force_mode => { - ecx.dcx().emit_err(errors::CfgAccessibleIndeterminate { span }); + ecx.dcx().emit_err(diagnostics::CfgAccessibleIndeterminate { span }); ExpandResult::Ready(vec![item]) } Err(Indeterminate) => ExpandResult::Retry(item), diff --git a/compiler/rustc_builtin_macros/src/cfg_select.rs b/compiler/rustc_builtin_macros/src/cfg_select.rs index 35098722a910e..526ddd6a3811d 100644 --- a/compiler/rustc_builtin_macros/src/cfg_select.rs +++ b/compiler/rustc_builtin_macros/src/cfg_select.rs @@ -6,7 +6,7 @@ use rustc_expand::base::{DummyResult, ExpandResult, ExtCtxt, MacResult, MacroExp use rustc_span::{Ident, Span, sym}; use smallvec::SmallVec; -use crate::errors::CfgSelectNoMatches; +use crate::diagnostics::CfgSelectNoMatches; /// This intermediate structure is used to emit parse errors for the branches that are not chosen. /// The `MacResult` instance below parses all branches, emitting any errors it encounters, but only diff --git a/compiler/rustc_builtin_macros/src/concat.rs b/compiler/rustc_builtin_macros/src/concat.rs index c200539e12872..f359b8336dbd5 100644 --- a/compiler/rustc_builtin_macros/src/concat.rs +++ b/compiler/rustc_builtin_macros/src/concat.rs @@ -4,7 +4,7 @@ use rustc_expand::base::{DummyResult, ExpandResult, ExtCtxt, MacEager, MacroExpa use rustc_session::errors::report_lit_error; use rustc_span::Symbol; -use crate::errors; +use crate::diagnostics; use crate::util::get_exprs_from_tts; pub(crate) fn expand_concat( @@ -38,10 +38,10 @@ pub(crate) fn expand_concat( accumulator.push_str(&b.to_string()); } Ok(LitKind::CStr(..)) => { - guar = Some(cx.dcx().emit_err(errors::ConcatCStrLit { span: e.span })); + guar = Some(cx.dcx().emit_err(diagnostics::ConcatCStrLit { span: e.span })); } Ok(LitKind::Byte(..) | LitKind::ByteStr(..)) => { - guar = Some(cx.dcx().emit_err(errors::ConcatBytestr { span: e.span })); + guar = Some(cx.dcx().emit_err(diagnostics::ConcatBytestr { span: e.span })); } Ok(LitKind::Err(guarantee)) => { guar = Some(guarantee); @@ -62,7 +62,7 @@ pub(crate) fn expand_concat( } } ExprKind::IncludedBytes(..) => { - cx.dcx().emit_err(errors::ConcatBytestr { span: e.span }); + cx.dcx().emit_err(diagnostics::ConcatBytestr { span: e.span }); } ExprKind::Err(guarantee) => { guar = Some(guarantee); @@ -75,7 +75,7 @@ pub(crate) fn expand_concat( } ExpandResult::Ready(if !missing_literal.is_empty() { - let guar = cx.dcx().emit_err(errors::ConcatMissingLiteral { spans: missing_literal }); + let guar = cx.dcx().emit_err(diagnostics::ConcatMissingLiteral { spans: missing_literal }); DummyResult::any(sp, guar) } else if let Some(guar) = guar { DummyResult::any(sp, guar) diff --git a/compiler/rustc_builtin_macros/src/concat_bytes.rs b/compiler/rustc_builtin_macros/src/concat_bytes.rs index 8885017b930d9..f86b1daa13d2d 100644 --- a/compiler/rustc_builtin_macros/src/concat_bytes.rs +++ b/compiler/rustc_builtin_macros/src/concat_bytes.rs @@ -4,7 +4,7 @@ use rustc_expand::base::{DummyResult, ExpandResult, ExtCtxt, MacEager, MacroExpa use rustc_session::errors::report_lit_error; use rustc_span::{ErrorGuaranteed, Span}; -use crate::errors; +use crate::diagnostics; use crate::util::get_exprs_from_tts; /// Emits errors for literal expressions that are invalid inside and outside of an array. @@ -14,7 +14,7 @@ fn invalid_type_err( span: Span, is_nested: bool, ) -> ErrorGuaranteed { - use errors::{ + use diagnostics::{ ConcatBytesInvalid, ConcatBytesInvalidSuggestion, ConcatBytesNonU8, ConcatBytesOob, }; let snippet = cx.sess.source_map().span_to_snippet(span).ok(); @@ -105,7 +105,10 @@ fn handle_array_element( Ok(LitKind::Byte(val)) => return Some(val), Ok(LitKind::ByteStr(..)) => { guar.get_or_insert_with(|| { - dcx.emit_err(errors::ConcatBytesArray { span: expr.span, bytestr: true }) + dcx.emit_err(diagnostics::ConcatBytesArray { + span: expr.span, + bytestr: true, + }) }); } _ => { @@ -115,12 +118,12 @@ fn handle_array_element( } ExprKind::Array(_) | ExprKind::Repeat(_, _) => { guar.get_or_insert_with(|| { - dcx.emit_err(errors::ConcatBytesArray { span: expr.span, bytestr: false }) + dcx.emit_err(diagnostics::ConcatBytesArray { span: expr.span, bytestr: false }) }); } ExprKind::IncludedBytes(..) => { guar.get_or_insert_with(|| { - dcx.emit_err(errors::ConcatBytesArray { span: expr.span, bytestr: false }) + dcx.emit_err(diagnostics::ConcatBytesArray { span: expr.span, bytestr: false }) }); } _ => missing_literals.push(expr.span), @@ -167,9 +170,10 @@ pub(crate) fn expand_concat_bytes( } } } else { - guar = Some( - cx.dcx().emit_err(errors::ConcatBytesBadRepeat { span: count.value.span }), - ); + guar = + Some(cx.dcx().emit_err(diagnostics::ConcatBytesBadRepeat { + span: count.value.span, + })); } } &ExprKind::Lit(token_lit) => match LitKind::from_token_lit(token_lit) { @@ -196,7 +200,8 @@ pub(crate) fn expand_concat_bytes( } } ExpandResult::Ready(if !missing_literals.is_empty() { - let guar = cx.dcx().emit_err(errors::ConcatBytesMissingLiteral { spans: missing_literals }); + let guar = + cx.dcx().emit_err(diagnostics::ConcatBytesMissingLiteral { spans: missing_literals }); MacEager::expr(DummyResult::raw_expr(sp, Some(guar))) } else if let Some(guar) = guar { MacEager::expr(DummyResult::raw_expr(sp, Some(guar))) diff --git a/compiler/rustc_builtin_macros/src/derive.rs b/compiler/rustc_builtin_macros/src/derive.rs index 09d827b0635e6..79c0563b9d183 100644 --- a/compiler/rustc_builtin_macros/src/derive.rs +++ b/compiler/rustc_builtin_macros/src/derive.rs @@ -9,7 +9,7 @@ use rustc_session::Session; use rustc_span::{ErrorGuaranteed, Ident, Span, sym}; use crate::cfg_eval::cfg_eval; -use crate::errors; +use crate::diagnostics; pub(crate) struct Expander { pub is_const: bool, @@ -131,7 +131,7 @@ fn report_bad_target( let bad_target = !matches!(item_kind, Some(ItemKind::Struct(..) | ItemKind::Enum(..) | ItemKind::Union(..))); if bad_target { - return Err(sess.dcx().emit_err(errors::BadDeriveTarget { span, item: item.span() })); + return Err(sess.dcx().emit_err(diagnostics::BadDeriveTarget { span, item: item.span() })); } Ok(()) } @@ -141,11 +141,11 @@ fn report_unexpected_meta_item_lit(sess: &Session, lit: &ast::MetaItemLit) { ast::LitKind::Str(_, ast::StrStyle::Cooked) if rustc_lexer::is_ident(lit.symbol.as_str()) => { - errors::BadDeriveLitHelp::StrLit { sym: lit.symbol } + diagnostics::BadDeriveLitHelp::StrLit { sym: lit.symbol } } - _ => errors::BadDeriveLitHelp::Other, + _ => diagnostics::BadDeriveLitHelp::Other, }; - sess.dcx().emit_err(errors::BadDeriveLit { span: lit.span, help }); + sess.dcx().emit_err(diagnostics::BadDeriveLit { span: lit.span, help }); } fn report_path_args(sess: &Session, meta: &ast::MetaItem) { @@ -154,10 +154,10 @@ fn report_path_args(sess: &Session, meta: &ast::MetaItem) { match meta.kind { MetaItemKind::Word => {} MetaItemKind::List(..) => { - sess.dcx().emit_err(errors::DerivePathArgsList { span }); + sess.dcx().emit_err(diagnostics::DerivePathArgsList { span }); } MetaItemKind::NameValue(..) => { - sess.dcx().emit_err(errors::DerivePathArgsValue { span }); + sess.dcx().emit_err(diagnostics::DerivePathArgsValue { span }); } } } diff --git a/compiler/rustc_builtin_macros/src/deriving/coerce_pointee.rs b/compiler/rustc_builtin_macros/src/deriving/coerce_pointee.rs index 1d9551f93a14c..43399b614b50a 100644 --- a/compiler/rustc_builtin_macros/src/deriving/coerce_pointee.rs +++ b/compiler/rustc_builtin_macros/src/deriving/coerce_pointee.rs @@ -12,7 +12,7 @@ use rustc_macros::Diagnostic; use rustc_span::{Ident, Span, Symbol, sym}; use thin_vec::{ThinVec, thin_vec}; -use crate::errors; +use crate::diagnostics; macro_rules! path { ($span:expr, $($part:ident)::*) => { vec![$(Ident::new(sym::$part, $span),)*] } @@ -409,7 +409,7 @@ struct DetectNonGenericPointeeAttr<'a, 'b> { impl<'a, 'b> rustc_ast::visit::Visitor<'a> for DetectNonGenericPointeeAttr<'a, 'b> { fn visit_attribute(&mut self, attr: &'a rustc_ast::Attribute) -> Self::Result { if attr.has_name(sym::pointee) { - self.cx.dcx().emit_err(errors::NonGenericPointee { span: attr.span }); + self.cx.dcx().emit_err(diagnostics::NonGenericPointee { span: attr.span }); } } @@ -457,7 +457,7 @@ struct AlwaysErrorOnGenericParam<'a, 'b> { impl<'a, 'b> rustc_ast::visit::Visitor<'a> for AlwaysErrorOnGenericParam<'a, 'b> { fn visit_attribute(&mut self, attr: &'a rustc_ast::Attribute) -> Self::Result { if attr.has_name(sym::pointee) { - self.cx.dcx().emit_err(errors::NonGenericPointee { span: attr.span }); + self.cx.dcx().emit_err(diagnostics::NonGenericPointee { span: attr.span }); } } } diff --git a/compiler/rustc_builtin_macros/src/deriving/default.rs b/compiler/rustc_builtin_macros/src/deriving/default.rs index 263ba2968eab4..cf48ff96aed1e 100644 --- a/compiler/rustc_builtin_macros/src/deriving/default.rs +++ b/compiler/rustc_builtin_macros/src/deriving/default.rs @@ -9,7 +9,7 @@ use thin_vec::{ThinVec, thin_vec}; use crate::deriving::generic::ty::*; use crate::deriving::generic::*; -use crate::errors; +use crate::diagnostics; pub(crate) fn expand_deriving_default( cx: &ExtCtxt<'_>, @@ -177,10 +177,13 @@ fn extract_default_variant<'a>( .filter(|variant| !attr::contains_name(&variant.attrs, sym::non_exhaustive)); let suggs = possible_defaults - .map(|v| errors::NoDefaultVariantSugg { span: v.span.shrink_to_lo() }) + .map(|v| diagnostics::NoDefaultVariantSugg { span: v.span.shrink_to_lo() }) .collect(); - let guar = - cx.dcx().emit_err(errors::NoDefaultVariant { span: trait_span, item_span, suggs }); + let guar = cx.dcx().emit_err(diagnostics::NoDefaultVariant { + span: trait_span, + item_span, + suggs, + }); return Err(guar); } @@ -196,11 +199,13 @@ fn extract_default_variant<'a>( .filter_map(|attr| (attr.span != keep).then_some(attr.span)) }) .collect(); - (!spans.is_empty()) - .then_some(errors::MultipleDefaultsSugg { spans, ident: variant.ident }) + (!spans.is_empty()).then_some(diagnostics::MultipleDefaultsSugg { + spans, + ident: variant.ident, + }) }) .collect(); - let guar = cx.dcx().emit_err(errors::MultipleDefaults { + let guar = cx.dcx().emit_err(diagnostics::MultipleDefaults { span: trait_span, first: first.span, additional: rest.iter().map(|v| v.span).collect(), @@ -223,12 +228,13 @@ fn extract_default_variant<'a>( } else { "" }; - let guar = cx.dcx().emit_err(errors::NonUnitDefault { span: variant.ident.span, post }); + let guar = + cx.dcx().emit_err(diagnostics::NonUnitDefault { span: variant.ident.span, post }); return Err(guar); } if let Some(non_exhaustive_attr) = attr::find_by_name(&variant.attrs, sym::non_exhaustive) { - let guar = cx.dcx().emit_err(errors::NonExhaustiveDefault { + let guar = cx.dcx().emit_err(diagnostics::NonExhaustiveDefault { span: variant.ident.span, non_exhaustive: non_exhaustive_attr.span, }); @@ -252,10 +258,10 @@ fn validate_default_attribute( "this method must only be called with a variant that has a `#[default]` attribute", ), [first, rest @ ..] => { - let sugg = errors::MultipleDefaultAttrsSugg { + let sugg = diagnostics::MultipleDefaultAttrsSugg { spans: rest.iter().map(|attr| attr.span).collect(), }; - let guar = cx.dcx().emit_err(errors::MultipleDefaultAttrs { + let guar = cx.dcx().emit_err(diagnostics::MultipleDefaultAttrs { span: default_variant.ident.span, first: first.span, first_rest: rest[0].span, @@ -268,7 +274,7 @@ fn validate_default_attribute( } }; if !attr.is_word() { - let guar = cx.dcx().emit_err(errors::DefaultHasArg { span: attr.span }); + let guar = cx.dcx().emit_err(diagnostics::DefaultHasArg { span: attr.span }); return Err(guar); } @@ -287,7 +293,7 @@ impl<'a, 'b> rustc_ast::visit::Visitor<'a> for DetectNonVariantDefaultAttr<'a, ' } else { "" }; - self.cx.dcx().emit_err(errors::NonUnitDefault { span: attr.span, post }); + self.cx.dcx().emit_err(diagnostics::NonUnitDefault { span: attr.span, post }); } rustc_ast::visit::walk_attribute(self, attr); diff --git a/compiler/rustc_builtin_macros/src/deriving/from.rs b/compiler/rustc_builtin_macros/src/deriving/from.rs index 2e4369f3bb1c8..c5fd0d87251f6 100644 --- a/compiler/rustc_builtin_macros/src/deriving/from.rs +++ b/compiler/rustc_builtin_macros/src/deriving/from.rs @@ -11,7 +11,7 @@ use crate::deriving::generic::{ combine_substructure, }; use crate::deriving::pathvec_std; -use crate::errors; +use crate::diagnostics; /// Generate an implementation of the `From` trait, provided that `item` /// is a struct or a tuple struct with exactly one field. @@ -38,7 +38,7 @@ pub(crate) fn expand_deriving_from( if let [field] = data.fields() { Ok(field.clone()) } else { - let guar = cx.dcx().emit_err(errors::DeriveFromWrongFieldCount { + let guar = cx.dcx().emit_err(diagnostics::DeriveFromWrongFieldCount { span: err_span(), multiple_fields: data.fields().len() > 1, }); @@ -46,7 +46,7 @@ pub(crate) fn expand_deriving_from( } } ItemKind::Enum(_, _, _) | ItemKind::Union(_, _, _) => { - let guar = cx.dcx().emit_err(errors::DeriveFromWrongTarget { + let guar = cx.dcx().emit_err(diagnostics::DeriveFromWrongTarget { span: err_span(), kind: &format!("{} {}", item.kind.article(), item.kind.descr()), }); diff --git a/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs b/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs index 8b8af1685287c..ff6b15b173ed1 100644 --- a/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs +++ b/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs @@ -194,7 +194,7 @@ use rustc_span::{DUMMY_SP, Ident, Span, Symbol, kw, sym}; use thin_vec::{ThinVec, thin_vec}; use ty::{Bounds, Path, Ref, Self_, Ty}; -use crate::{deriving, errors}; +use crate::{deriving, diagnostics}; pub(crate) mod ty; @@ -456,7 +456,7 @@ fn find_type_parameters( } fn visit_mac_call(&mut self, mac: &ast::MacCall) { - self.cx.dcx().emit_err(errors::DeriveMacroCall { span: mac.span() }); + self.cx.dcx().emit_err(diagnostics::DeriveMacroCall { span: mac.span() }); } } @@ -525,7 +525,7 @@ impl<'a> TraitDef<'a> { is_packed, ) } else { - cx.dcx().emit_err(errors::DeriveUnion { span: mitem.span }); + cx.dcx().emit_err(diagnostics::DeriveUnion { span: mitem.span }); return; } } diff --git a/compiler/rustc_builtin_macros/src/errors.rs b/compiler/rustc_builtin_macros/src/diagnostics.rs similarity index 100% rename from compiler/rustc_builtin_macros/src/errors.rs rename to compiler/rustc_builtin_macros/src/diagnostics.rs diff --git a/compiler/rustc_builtin_macros/src/eii.rs b/compiler/rustc_builtin_macros/src/eii.rs index d8d749cd35c4b..9bb34cdd642a0 100644 --- a/compiler/rustc_builtin_macros/src/eii.rs +++ b/compiler/rustc_builtin_macros/src/eii.rs @@ -9,7 +9,7 @@ use rustc_expand::base::{Annotatable, ExtCtxt}; use rustc_span::{ErrorGuaranteed, Ident, Span, kw, sym}; use thin_vec::{ThinVec, thin_vec}; -use crate::errors::{ +use crate::diagnostics::{ EiiAttributeNotSupported, EiiExternTargetExpectedList, EiiExternTargetExpectedMacro, EiiExternTargetExpectedUnsafe, EiiMacroExpectedMaxOneArgument, EiiOnlyOnce, EiiSharedMacroInStatementPosition, EiiSharedMacroTarget, EiiStaticArgumentRequired, diff --git a/compiler/rustc_builtin_macros/src/env.rs b/compiler/rustc_builtin_macros/src/env.rs index d9af43fcd1c3d..aaa9117bb092b 100644 --- a/compiler/rustc_builtin_macros/src/env.rs +++ b/compiler/rustc_builtin_macros/src/env.rs @@ -15,7 +15,7 @@ use rustc_span::edit_distance::edit_distance; use rustc_span::{Ident, Span, Symbol, kw, sym}; use thin_vec::thin_vec; -use crate::errors; +use crate::diagnostics; use crate::util::{expr_to_string, get_exprs_from_tts, get_single_expr_from_tts}; fn lookup_env<'cx>(cx: &'cx ExtCtxt<'_>, var: Symbol) -> Result { @@ -76,7 +76,7 @@ pub(crate) fn expand_option_env<'cx>( unreachable!("`expr_to_string` ensures this is a string lit") }; - let guar = cx.dcx().emit_err(errors::EnvNotUnicode { span: sp, var: *symbol }); + let guar = cx.dcx().emit_err(diagnostics::EnvNotUnicode { span: sp, var: *symbol }); return ExpandResult::Ready(DummyResult::any(sp, guar)); } Ok(value) => cx.expr_call_global( @@ -98,7 +98,7 @@ pub(crate) fn expand_env<'cx>( }; let mut exprs = match mac { Ok(exprs) if exprs.is_empty() || exprs.len() > 2 => { - let guar = cx.dcx().emit_err(errors::EnvTakesArgs { span: sp }); + let guar = cx.dcx().emit_err(diagnostics::EnvTakesArgs { span: sp }); return ExpandResult::Ready(DummyResult::any(sp, guar)); } Err(guar) => return ExpandResult::Ready(DummyResult::any(sp, guar)), @@ -145,24 +145,26 @@ pub(crate) fn expand_env<'cx>( let guar = match err { VarError::NotPresent => { if let Some(msg_from_user) = custom_msg { - cx.dcx() - .emit_err(errors::EnvNotDefinedWithUserMessage { span, msg_from_user }) + cx.dcx().emit_err(diagnostics::EnvNotDefinedWithUserMessage { + span, + msg_from_user, + }) } else if let Some(suggested_var) = find_similar_cargo_var(var) && suggested_var != var { - cx.dcx().emit_err(errors::EnvNotDefined::CargoEnvVarTypo { + cx.dcx().emit_err(diagnostics::EnvNotDefined::CargoEnvVarTypo { span, var: *symbol, suggested_var: Symbol::intern(suggested_var), }) } else if is_cargo_env_var(var) { - cx.dcx().emit_err(errors::EnvNotDefined::CargoEnvVar { + cx.dcx().emit_err(diagnostics::EnvNotDefined::CargoEnvVar { span, var: *symbol, var_expr: pprust::expr_to_string(&var_expr), }) } else { - cx.dcx().emit_err(errors::EnvNotDefined::CustomEnvVar { + cx.dcx().emit_err(diagnostics::EnvNotDefined::CustomEnvVar { span, var: *symbol, var_expr: pprust::expr_to_string(&var_expr), @@ -170,7 +172,7 @@ pub(crate) fn expand_env<'cx>( } } VarError::NotUnicode(_) => { - cx.dcx().emit_err(errors::EnvNotUnicode { span, var: *symbol }) + cx.dcx().emit_err(diagnostics::EnvNotUnicode { span, var: *symbol }) } }; diff --git a/compiler/rustc_builtin_macros/src/format.rs b/compiler/rustc_builtin_macros/src/format.rs index 6bb3fa884027e..007251ff3df05 100644 --- a/compiler/rustc_builtin_macros/src/format.rs +++ b/compiler/rustc_builtin_macros/src/format.rs @@ -20,7 +20,7 @@ use rustc_parse::exp; use rustc_parse_format as parse; use rustc_span::{BytePos, ErrorGuaranteed, Ident, InnerSpan, Span, Symbol}; -use crate::errors; +use crate::diagnostics; use crate::util::{ExprToSpannedString, expr_to_spanned_string}; // The format_args!() macro is expanded in three steps: @@ -73,7 +73,9 @@ fn parse_args<'a>(ecx: &ExtCtxt<'a>, sp: Span, tts: TokenStream) -> PResult<'a, // parse the format string let fmtstr = match p.token.kind { - token::Eof => return Err(ecx.dcx().create_err(errors::FormatRequiresString { span: sp })), + token::Eof => { + return Err(ecx.dcx().create_err(diagnostics::FormatRequiresString { span: sp })); + } // This allows us to properly handle cases when the first comma // after the format string is mistakenly replaced with any operator, // which cause the expression parser to eat too much tokens. @@ -122,7 +124,7 @@ fn parse_args<'a>(ecx: &ExtCtxt<'a>, sp: Span, tts: TokenStream) -> PResult<'a, p.expect(exp!(Eq))?; let expr = p.parse_expr()?; if let Some((_, prev)) = args.by_name(ident.name) { - ecx.dcx().emit_err(errors::FormatDuplicateArg { + ecx.dcx().emit_err(diagnostics::FormatDuplicateArg { span: ident.span, prev: prev.kind.ident().unwrap().span, duplicate: ident.span, @@ -135,7 +137,7 @@ fn parse_args<'a>(ecx: &ExtCtxt<'a>, sp: Span, tts: TokenStream) -> PResult<'a, _ => { let expr = p.parse_expr()?; if !args.named_args().is_empty() { - return Err(ecx.dcx().create_err(errors::PositionalAfterNamed { + return Err(ecx.dcx().create_err(diagnostics::PositionalAfterNamed { span: expr.span, args: args .named_args() @@ -304,7 +306,7 @@ fn make_format_args( // argument span here. fmt_span }; - let mut e = errors::InvalidFormatString { + let mut e = diagnostics::InvalidFormatString { span: sp, note_: None, label_: None, @@ -313,12 +315,12 @@ fn make_format_args( label1: err.label, }; if let Some(note) = err.note { - e.note_ = Some(errors::InvalidFormatStringNote { note }); + e.note_ = Some(diagnostics::InvalidFormatStringNote { note }); } if let Some((label, span)) = err.secondary_label && is_source_literal { - e.label_ = Some(errors::InvalidFormatStringLabel { + e.label_ = Some(diagnostics::InvalidFormatStringLabel { span: fmt_span.from_inner(InnerSpan::new(span.start, span.end)), label, }); @@ -333,7 +335,7 @@ fn make_format_args( Some(arg) => arg.expr.span, None => fmt_span, }; - e.sugg_ = Some(errors::InvalidFormatStringSuggestion::UsePositional { + e.sugg_ = Some(diagnostics::InvalidFormatStringSuggestion::UsePositional { captured: captured_arg_span, len: args.unnamed_args().len().to_string(), span: span.shrink_to_hi(), @@ -344,19 +346,22 @@ fn make_format_args( parse::Suggestion::RemoveRawIdent(span) => { if is_source_literal { let span = fmt_span.from_inner(InnerSpan::new(span.start, span.end)); - e.sugg_ = Some(errors::InvalidFormatStringSuggestion::RemoveRawIdent { span }) + e.sugg_ = + Some(diagnostics::InvalidFormatStringSuggestion::RemoveRawIdent { span }) } } parse::Suggestion::ReorderFormatParameter(span, replacement) => { let span = fmt_span.from_inner(InnerSpan::new(span.start, span.end)); - e.sugg_ = Some(errors::InvalidFormatStringSuggestion::ReorderFormatParameter { - span, - replacement, - }); + e.sugg_ = + Some(diagnostics::InvalidFormatStringSuggestion::ReorderFormatParameter { + span, + replacement, + }); } parse::Suggestion::AddMissingColon(span) => { let span = fmt_span.from_inner(InnerSpan::new(span.start, span.end)); - e.sugg_ = Some(errors::InvalidFormatStringSuggestion::AddMissingColon { span }); + e.sugg_ = + Some(diagnostics::InvalidFormatStringSuggestion::AddMissingColon { span }); } parse::Suggestion::UseRustDebugPrintingMacro => { // This targets `println!("{=}", x);` and `println!("{0=}", x);` @@ -367,7 +372,7 @@ fn make_format_args( let call_span = macro_span.source_callsite(); e.sugg_ = Some( - errors::InvalidFormatStringSuggestion::UseRustDebugPrintingMacro { + diagnostics::InvalidFormatStringSuggestion::UseRustDebugPrintingMacro { macro_span: call_span, replacement, }, @@ -436,7 +441,7 @@ fn make_format_args( } else { // For the moment capturing variables from format strings expanded from macros is // disabled (see RFC #2795) - let guar = ecx.dcx().emit_err(errors::FormatNoArgNamed { span, name }); + let guar = ecx.dcx().emit_err(diagnostics::FormatNoArgNamed { span, name }); unnamed_arg_after_named_arg = true; DummyResult::raw_expr(span, Some(guar)) }; @@ -659,7 +664,7 @@ fn make_format_args( (None, String::new()) }; - errors::NamedArgumentUsedPositionally { + diagnostics::NamedArgumentUsedPositionally { named_arg_sp: arg_name.span, position_label_sp: position_sp_for_msg, suggestion, @@ -701,12 +706,12 @@ fn invalid_placeholder_type_error( ("X", "UpperHex"), ] .into_iter() - .map(|(fmt, trait_name)| errors::FormatUnknownTraitSugg { span: sp, fmt, trait_name }) + .map(|(fmt, trait_name)| diagnostics::FormatUnknownTraitSugg { span: sp, fmt, trait_name }) .collect() } else { vec![] }; - ecx.dcx().emit_err(errors::FormatUnknownTrait { span: sp.unwrap_or(fmt_span), ty, suggs }); + ecx.dcx().emit_err(diagnostics::FormatUnknownTrait { span: sp.unwrap_or(fmt_span), ty, suggs }); } fn report_missing_placeholders( @@ -723,12 +728,14 @@ fn report_missing_placeholders( fmt_span: Span, ) { let mut diag = if let &[(span, named)] = &unused[..] { - ecx.dcx().create_err(errors::FormatUnusedArg { span, named }) + ecx.dcx().create_err(diagnostics::FormatUnusedArg { span, named }) } else { - let unused_labels = - unused.iter().map(|&(span, named)| errors::FormatUnusedArg { span, named }).collect(); + let unused_labels = unused + .iter() + .map(|&(span, named)| diagnostics::FormatUnusedArg { span, named }) + .collect(); let unused_spans = unused.iter().map(|&(span, _)| span).collect(); - ecx.dcx().create_err(errors::FormatUnusedArgs { + ecx.dcx().create_err(diagnostics::FormatUnusedArgs { fmt: fmt_span, unused: unused_spans, unused_labels, @@ -920,12 +927,12 @@ fn report_redundant_format_arguments<'a>( } let sugg = if args.named_args().len() == 0 { - Some(errors::FormatRedundantArgsSugg { spans: suggestion_spans }) + Some(diagnostics::FormatRedundantArgsSugg { spans: suggestion_spans }) } else { None }; - return Some(ecx.dcx().create_err(errors::FormatRedundantArgs { + return Some(ecx.dcx().create_err(diagnostics::FormatRedundantArgs { n: args_spans.len(), span: MultiSpan::from(args_spans), note: multispan, @@ -1034,7 +1041,7 @@ fn report_invalid_references( } else { MultiSpan::from_spans(spans) }; - e = ecx.dcx().create_err(errors::FormatPositionalMismatch { + e = ecx.dcx().create_err(diagnostics::FormatPositionalMismatch { span, n: num_placeholders, desc: num_args_desc, diff --git a/compiler/rustc_builtin_macros/src/global_allocator.rs b/compiler/rustc_builtin_macros/src/global_allocator.rs index 684411d64d943..db034f6fb7011 100644 --- a/compiler/rustc_builtin_macros/src/global_allocator.rs +++ b/compiler/rustc_builtin_macros/src/global_allocator.rs @@ -9,7 +9,7 @@ use rustc_expand::base::{Annotatable, ExtCtxt}; use rustc_span::{Ident, Span, Symbol, kw, sym}; use thin_vec::{ThinVec, thin_vec}; -use crate::errors; +use crate::diagnostics; use crate::util::check_builtin_macro_attribute; pub(crate) fn expand( @@ -34,13 +34,14 @@ pub(crate) fn expand( { (item, *ident, true, ecx.with_def_site_ctxt(ty.span)) } else { - ecx.dcx().emit_err(errors::AllocMustStatics { span: item.span() }); + ecx.dcx().emit_err(diagnostics::AllocMustStatics { span: item.span() }); return vec![orig_item]; }; // Forbid `#[thread_local]` attributes on the item if let Some(attr) = item.attrs.iter().find(|x| x.has_name(sym::thread_local)) { - ecx.dcx().emit_err(errors::AllocCannotThreadLocal { span: item.span, attr: attr.span }); + ecx.dcx() + .emit_err(diagnostics::AllocCannotThreadLocal { span: item.span, attr: attr.span }); return vec![orig_item]; } diff --git a/compiler/rustc_builtin_macros/src/lib.rs b/compiler/rustc_builtin_macros/src/lib.rs index 9e29262042f21..4a5ff44c402ab 100644 --- a/compiler/rustc_builtin_macros/src/lib.rs +++ b/compiler/rustc_builtin_macros/src/lib.rs @@ -33,10 +33,10 @@ mod concat_bytes; mod define_opaque; mod derive; mod deriving; +mod diagnostics; mod edition_panic; mod eii; mod env; -mod errors; mod format; mod format_foreign; mod global_allocator; diff --git a/compiler/rustc_builtin_macros/src/offload.rs b/compiler/rustc_builtin_macros/src/offload.rs index 9dbd2d45a93af..d20c07f8619dc 100644 --- a/compiler/rustc_builtin_macros/src/offload.rs +++ b/compiler/rustc_builtin_macros/src/offload.rs @@ -6,7 +6,7 @@ use rustc_session::config::Offload; use rustc_span::{Ident, Span, sym}; use thin_vec::thin_vec; -use crate::errors; +use crate::diagnostics; fn compile_for_device(ecx: &mut ExtCtxt<'_>) -> bool { ecx.sess.opts.unstable_opts.offload.contains(&Offload::Device) @@ -74,7 +74,7 @@ pub(crate) fn expand_kernel( let dcx = ecx.sess.dcx(); let Some((vis, sig, ident, generics, body)) = extract_fn(&item) else { - dcx.emit_err(errors::AutoDiffInvalidApplication { span: item.span() }); + dcx.emit_err(diagnostics::AutoDiffInvalidApplication { span: item.span() }); return vec![item]; }; diff --git a/compiler/rustc_builtin_macros/src/proc_macro_harness.rs b/compiler/rustc_builtin_macros/src/proc_macro_harness.rs index aa936b46eec20..df9cebb8f7c03 100644 --- a/compiler/rustc_builtin_macros/src/proc_macro_harness.rs +++ b/compiler/rustc_builtin_macros/src/proc_macro_harness.rs @@ -16,7 +16,7 @@ use rustc_span::{DUMMY_SP, Ident, Span, Symbol, kw, sym}; use smallvec::smallvec; use thin_vec::{ThinVec, thin_vec}; -use crate::errors; +use crate::diagnostics; struct ProcMacroDerive { id: NodeId, @@ -91,7 +91,7 @@ pub fn inject( impl<'a> CollectProcMacros<'a> { fn check_not_pub_in_root(&self, vis: &ast::Visibility, sp: Span) { if self.is_proc_macro_crate && self.in_root && vis.kind.is_pub() { - self.dcx.emit_err(errors::ProcMacro { span: sp }); + self.dcx.emit_err(diagnostics::ProcMacro { span: sp }); } } @@ -174,7 +174,7 @@ impl<'a> Visitor<'a> for CollectProcMacros<'a> { fn visit_item(&mut self, item: &'a ast::Item) { if let ast::ItemKind::MacroDef(..) = item.kind { if self.is_proc_macro_crate && attr::contains_name(&item.attrs, sym::macro_export) { - self.dcx.emit_err(errors::ExportMacroRules { + self.dcx.emit_err(diagnostics::ExportMacroRules { span: self.source_map.guess_head_span(item.span), }); } @@ -238,7 +238,7 @@ impl<'a> Visitor<'a> for CollectProcMacros<'a> { if !self.is_proc_macro_crate { self.dcx - .create_err(errors::AttributeOnlyUsableWithCrateType { + .create_err(diagnostics::AttributeOnlyUsableWithCrateType { span: attr.span, path: &pprust::path_to_string(&attr.get_normal_item().path), }) diff --git a/compiler/rustc_builtin_macros/src/source_util.rs b/compiler/rustc_builtin_macros/src/source_util.rs index ab7a9c3bccb38..fe2b5e1a45920 100644 --- a/compiler/rustc_builtin_macros/src/source_util.rs +++ b/compiler/rustc_builtin_macros/src/source_util.rs @@ -21,7 +21,7 @@ use rustc_span::source_map::SourceMap; use rustc_span::{ByteSymbol, Pos, Span, Symbol}; use smallvec::SmallVec; -use crate::errors; +use crate::diagnostics; use crate::util::{ check_zero_tts, get_single_str_from_tts, get_single_str_spanned_from_tts, parse_expr, }; @@ -153,7 +153,7 @@ pub(crate) fn expand_include<'cx>( INCOMPLETE_INCLUDE, p.token.span, self.node_id, - errors::IncompleteInclude, + diagnostics::IncompleteInclude, ); } Some(expr) @@ -176,7 +176,7 @@ pub(crate) fn expand_include<'cx>( Ok(Some(item)) => ret.push(item), Ok(None) => { if p.token != token::Eof { - p.dcx().emit_err(errors::ExpectedItem { + p.dcx().emit_err(diagnostics::ExpectedItem { span: p.token.span, token: &pprust::token_to_string(&p.token), }); diff --git a/compiler/rustc_builtin_macros/src/test.rs b/compiler/rustc_builtin_macros/src/test.rs index ac865958011a6..fda0660c48403 100644 --- a/compiler/rustc_builtin_macros/src/test.rs +++ b/compiler/rustc_builtin_macros/src/test.rs @@ -14,7 +14,7 @@ use rustc_span::{ErrorGuaranteed, Ident, RemapPathScopeComponents, Span, Symbol, use thin_vec::{ThinVec, thin_vec}; use tracing::debug; -use crate::errors; +use crate::diagnostics; use crate::util::{check_builtin_macro_attribute, warn_on_duplicate_attribute}; /// #[test_case] is used by custom test authors to mark tests @@ -44,7 +44,7 @@ pub(crate) fn expand_test_case( } } _ => { - ecx.dcx().emit_err(errors::TestCaseNonItem { span: anno_item.span() }); + ecx.dcx().emit_err(diagnostics::TestCaseNonItem { span: anno_item.span() }); return vec![]; } }; @@ -136,7 +136,7 @@ pub(crate) fn expand_test_or_bench( } if let Some(attr) = attr::find_by_name(&item.attrs, sym::naked) { - cx.dcx().emit_err(errors::NakedFunctionTestingAttribute { + cx.dcx().emit_err(diagnostics::NakedFunctionTestingAttribute { testing_span: attr_sp, naked_span: attr.span, }); @@ -525,27 +525,31 @@ fn check_test_signature( let dcx = cx.dcx(); if let ast::Safety::Unsafe(span) = f.sig.header.safety { - return Err(dcx.emit_err(errors::TestBadFn { span: i.span, cause: span, kind: "unsafe" })); + return Err(dcx.emit_err(diagnostics::TestBadFn { + span: i.span, + cause: span, + kind: "unsafe", + })); } if let Some(coroutine_kind) = f.sig.header.coroutine_kind { match coroutine_kind { ast::CoroutineKind::Async { span, .. } => { - return Err(dcx.emit_err(errors::TestBadFn { + return Err(dcx.emit_err(diagnostics::TestBadFn { span: i.span, cause: span, kind: "async", })); } ast::CoroutineKind::Gen { span, .. } => { - return Err(dcx.emit_err(errors::TestBadFn { + return Err(dcx.emit_err(diagnostics::TestBadFn { span: i.span, cause: span, kind: "gen", })); } ast::CoroutineKind::AsyncGen { span, .. } => { - return Err(dcx.emit_err(errors::TestBadFn { + return Err(dcx.emit_err(diagnostics::TestBadFn { span: i.span, cause: span, kind: "async gen", @@ -588,7 +592,7 @@ fn check_bench_signature( // N.B., inadequate check, but we're running // well before resolve, can't get too deep. if f.sig.decl.inputs.len() != 1 { - return Err(cx.dcx().emit_err(errors::BenchSig { span: i.span })); + return Err(cx.dcx().emit_err(diagnostics::BenchSig { span: i.span })); } Ok(()) } diff --git a/compiler/rustc_builtin_macros/src/test_harness.rs b/compiler/rustc_builtin_macros/src/test_harness.rs index db5aecde3472c..0b68b44769987 100644 --- a/compiler/rustc_builtin_macros/src/test_harness.rs +++ b/compiler/rustc_builtin_macros/src/test_harness.rs @@ -22,7 +22,7 @@ use smallvec::smallvec; use thin_vec::{ThinVec, thin_vec}; use tracing::debug; -use crate::errors; +use crate::diagnostics; #[derive(Clone)] struct Test { @@ -71,7 +71,7 @@ pub fn inject( // Silently allow compiling with panic=abort on these platforms, // but with old behavior (abort if a test fails). } else { - dcx.emit_err(errors::TestsNotSupport {}); + dcx.emit_err(diagnostics::TestsNotSupport {}); } PanicStrategy::Unwind } @@ -166,7 +166,7 @@ impl<'a> Visitor<'a> for InnerItemLinter<'_> { UNNAMEABLE_TEST_ITEMS, attr.span, i.id, - errors::UnnameableTestItems, + diagnostics::UnnameableTestItems, ); } } diff --git a/compiler/rustc_builtin_macros/src/trace_macros.rs b/compiler/rustc_builtin_macros/src/trace_macros.rs index 8264c17b4d171..88837e01a9407 100644 --- a/compiler/rustc_builtin_macros/src/trace_macros.rs +++ b/compiler/rustc_builtin_macros/src/trace_macros.rs @@ -2,7 +2,7 @@ use rustc_ast::tokenstream::{TokenStream, TokenTree}; use rustc_expand::base::{DummyResult, ExpandResult, ExtCtxt, MacroExpanderResult}; use rustc_span::{Span, kw}; -use crate::errors; +use crate::diagnostics; pub(crate) fn expand_trace_macros( cx: &mut ExtCtxt<'_>, @@ -21,7 +21,7 @@ pub(crate) fn expand_trace_macros( }; err |= iter.next().is_some(); if err { - cx.dcx().emit_err(errors::TraceMacros { span: sp }); + cx.dcx().emit_err(diagnostics::TraceMacros { span: sp }); } else { cx.set_trace_macros(value); } diff --git a/compiler/rustc_builtin_macros/src/util.rs b/compiler/rustc_builtin_macros/src/util.rs index 9ac3d0e7eac12..769016ecac2a7 100644 --- a/compiler/rustc_builtin_macros/src/util.rs +++ b/compiler/rustc_builtin_macros/src/util.rs @@ -10,7 +10,7 @@ use rustc_parse::{exp, parser}; use rustc_session::errors::report_lit_error; use rustc_span::{BytePos, Span, Symbol}; -use crate::errors; +use crate::diagnostics; pub(crate) fn check_builtin_macro_attribute(ecx: &ExtCtxt<'_>, meta_item: &MetaItem, name: Symbol) { // All the built-in macro attributes are "words" at the moment. @@ -48,7 +48,7 @@ pub(crate) fn warn_on_duplicate_attribute(ecx: &ExtCtxt<'_>, item: &Annotatable, DUPLICATE_MACRO_ATTRIBUTES, attr.span, ecx.current_expansion.lint_node_id, - errors::DuplicateMacroAttribute, + diagnostics::DuplicateMacroAttribute, ); } } @@ -150,7 +150,7 @@ pub(crate) fn expr_to_string( /// (this should be done as rarely as possible). pub(crate) fn check_zero_tts(cx: &ExtCtxt<'_>, span: Span, tts: TokenStream, name: &str) { if !tts.is_empty() { - cx.dcx().emit_err(errors::TakesNoArguments { span, name }); + cx.dcx().emit_err(diagnostics::TakesNoArguments { span, name }); } } @@ -209,7 +209,7 @@ pub(crate) fn get_single_expr_from_tts( ) -> ExpandResult, ErrorGuaranteed>, ()> { let mut p = cx.new_parser_from_tts(tts); if p.token == token::Eof { - let guar = cx.dcx().emit_err(errors::OnlyOneArgument { span, name }); + let guar = cx.dcx().emit_err(diagnostics::OnlyOneArgument { span, name }); return ExpandResult::Ready(Err(guar)); } let ret = match parse_expr(&mut p) { @@ -219,7 +219,7 @@ pub(crate) fn get_single_expr_from_tts( let _ = p.eat(exp!(Comma)); if p.token != token::Eof { - cx.dcx().emit_err(errors::OnlyOneArgument { span, name }); + cx.dcx().emit_err(diagnostics::OnlyOneArgument { span, name }); } ExpandResult::Ready(Ok(ret)) } @@ -253,7 +253,7 @@ pub(crate) fn get_exprs_from_tts( continue; } if p.token != token::Eof { - let guar = cx.dcx().emit_err(errors::ExpectedCommaInList { span: p.token.span }); + let guar = cx.dcx().emit_err(diagnostics::ExpectedCommaInList { span: p.token.span }); return ExpandResult::Ready(Err(guar)); } } diff --git a/compiler/rustc_codegen_cranelift/.github/workflows/cranelift-release-branch.yml b/compiler/rustc_codegen_cranelift/.github/workflows/cranelift-release-branch.yml new file mode 100644 index 0000000000000..5cfdc3e8f2936 --- /dev/null +++ b/compiler/rustc_codegen_cranelift/.github/workflows/cranelift-release-branch.yml @@ -0,0 +1,64 @@ +name: Test upcoming Cranelift release branch + +on: + schedule: + - cron: "0 3 6 * *" + workflow_dispatch: {} + +permissions: {} + +env: + CARGO_BUILD_INCREMENTAL: false + RUSTFLAGS: "-Dwarnings" + +jobs: + test_upcoming_cranelift_release: + runs-on: ubuntu-latest + timeout-minutes: 90 + + steps: + - uses: actions/checkout@v6 + + - name: Determine latest Wasmtime release branch + id: wasmtime_release_branch + run: | + branches="$( + git ls-remote --heads https://github.com/bytecodealliance/wasmtime.git "refs/heads/release-*" \ + | awk '{print $2}' \ + | sed 's#refs/heads/##' \ + | sort -V + )" + if [[ -z "${branches}" ]]; then + echo "No wasmtime release branches found" + exit 1 + fi + latest="$(echo "${branches}" | tail -n 1)" + echo "Latest release branch: ${latest}" + echo "branch=${latest}" >> "$GITHUB_OUTPUT" + + - name: Patch Cargo.toml to use release branch Cranelift + run: | + cat >>Cargo.toml <", ); diff --git a/compiler/rustc_codegen_cranelift/build_system/build_sysroot.rs b/compiler/rustc_codegen_cranelift/build_system/build_sysroot.rs index 216c87f095533..5c8b719ad5404 100644 --- a/compiler/rustc_codegen_cranelift/build_system/build_sysroot.rs +++ b/compiler/rustc_codegen_cranelift/build_system/build_sysroot.rs @@ -231,6 +231,8 @@ fn build_clif_sysroot_for_triple( // inlining. rustflags.push("-Zinline-mir".to_owned()); + rustflags.push("-Zdisable-incr-comp-backend-caching".to_owned()); + if let Some(prefix) = env::var_os("CG_CLIF_STDLIB_REMAP_PATH_PREFIX") { rustflags.push("--remap-path-prefix".to_owned()); rustflags.push(format!("library/={}/library", prefix.to_str().unwrap())); diff --git a/compiler/rustc_codegen_cranelift/build_system/main.rs b/compiler/rustc_codegen_cranelift/build_system/main.rs index 0720d72c6d7cb..852fda950d88b 100644 --- a/compiler/rustc_codegen_cranelift/build_system/main.rs +++ b/compiler/rustc_codegen_cranelift/build_system/main.rs @@ -59,7 +59,6 @@ fn main() { if env::var_os("RUST_BACKTRACE").is_none() { env::set_var("RUST_BACKTRACE", "1"); } - env::set_var("CG_CLIF_DISABLE_INCR_CACHE", "1"); let mut args = env::args().skip(1); let command = match args.next().as_deref() { diff --git a/compiler/rustc_codegen_cranelift/build_system/prepare.rs b/compiler/rustc_codegen_cranelift/build_system/prepare.rs index ba5cc9a29f599..1bc56e311ec7d 100644 --- a/compiler/rustc_codegen_cranelift/build_system/prepare.rs +++ b/compiler/rustc_codegen_cranelift/build_system/prepare.rs @@ -11,11 +11,13 @@ pub(crate) fn prepare(dirs: &Dirs) { std::fs::create_dir_all(&dirs.download_dir).unwrap(); crate::tests::RAND_REPO.fetch(dirs); crate::tests::REGEX_REPO.fetch(dirs); + crate::tests::GRAVIOLA_REPO.fetch(dirs); } pub(crate) struct GitRepo { url: GitRepoUrl, rev: &'static str, + submodules: &'static [&'static str], content_hash: &'static str, patch_name: &'static str, } @@ -71,10 +73,17 @@ impl GitRepo { user: &'static str, repo: &'static str, rev: &'static str, + submodules: &'static [&'static str], content_hash: &'static str, patch_name: &'static str, ) -> GitRepo { - GitRepo { url: GitRepoUrl::Github { user, repo }, rev, content_hash, patch_name } + GitRepo { + url: GitRepoUrl::Github { user, repo }, + rev, + submodules, + content_hash, + patch_name, + } } fn download_dir(&self, dirs: &Dirs) -> PathBuf { @@ -132,6 +141,7 @@ impl GitRepo { &download_dir, &format!("https://github.com/{}/{}.git", user, repo), self.rev, + self.submodules, ); } } @@ -160,7 +170,7 @@ impl GitRepo { } } -fn clone_repo(download_dir: &Path, repo: &str, rev: &str) { +fn clone_repo(download_dir: &Path, repo: &str, rev: &str, submodules: &[&str]) { eprintln!("[CLONE] {}", repo); match fs::remove_dir_all(download_dir) { @@ -180,6 +190,13 @@ fn clone_repo(download_dir: &Path, repo: &str, rev: &str) { checkout_cmd.arg("-q").arg(rev); spawn_and_wait(checkout_cmd); + if !submodules.is_empty() { + let mut submodule_cmd = git_command(download_dir, "submodule"); + submodule_cmd.arg("update").arg("--init"); + submodule_cmd.args(submodules); + spawn_and_wait(submodule_cmd); + } + std::fs::remove_dir_all(download_dir.join(".git")).unwrap(); } diff --git a/compiler/rustc_codegen_cranelift/build_system/tests.rs b/compiler/rustc_codegen_cranelift/build_system/tests.rs index 3b6a2e7a055cb..685bf8ce9a891 100644 --- a/compiler/rustc_codegen_cranelift/build_system/tests.rs +++ b/compiler/rustc_codegen_cranelift/build_system/tests.rs @@ -125,6 +125,7 @@ pub(crate) static RAND_REPO: GitRepo = GitRepo::github( "rust-random", "rand", "1f4507a8e1cf8050e4ceef95eeda8f64645b6719", + &[], "981f8bf489338978", "rand", ); @@ -135,12 +136,24 @@ pub(crate) static REGEX_REPO: GitRepo = GitRepo::github( "rust-lang", "regex", "061ee815ef2c44101dba7b0b124600fcb03c1912", + &[], "dc26aefbeeac03ca", "regex", ); static REGEX: CargoProject = CargoProject::new(REGEX_REPO.source_dir(), "regex_target"); +pub(crate) static GRAVIOLA_REPO: GitRepo = GitRepo::github( + "ctz", + "graviola", + "c779b83cfd7114c4802293700c92cfb5e05cb4b7", + &["thirdparty/cavp", "thirdparty/wycheproof"], + "e0925ceb21a56101", + "graviola", +); + +static GRAVIOLA: CargoProject = CargoProject::new(GRAVIOLA_REPO.source_dir(), "graviola_target"); + static PORTABLE_SIMD_SRC: RelPath = RelPath::build("portable-simd"); static PORTABLE_SIMD: CargoProject = CargoProject::new(PORTABLE_SIMD_SRC, "portable-simd_target"); @@ -199,6 +212,43 @@ const EXTENDED_SYSROOT_SUITE: &[TestCase] = &[ spawn_and_wait(build_cmd); } }), + TestCase::custom("test.graviola", &|runner| { + let (arch, _) = runner.target_compiler.triple.split_once('-').unwrap(); + + if !["aarch64", "x86_64"].contains(&arch) { + eprintln!("Skipping `graviola` tests: unsupported target"); + return; + } + + GRAVIOLA_REPO.patch(&runner.dirs); + GRAVIOLA.clean(&runner.dirs); + + if runner.is_native { + let mut test_cmd = GRAVIOLA.test(&runner.target_compiler, &runner.dirs); + + // FIXME: Disable AVX-512 until intrinsics are supported. + test_cmd.env("GRAVIOLA_CPU_DISABLE_avx512f", "1"); + test_cmd.env("GRAVIOLA_CPU_DISABLE_avx512bw", "1"); + test_cmd.env("GRAVIOLA_CPU_DISABLE_avx512vl", "1"); + + test_cmd.args([ + "-p", + "graviola", + "--lib", + "--", + "-q", + // FIXME: Disable AVX-512 until intrinsics are supported. + "--skip", + "check_counter512", + ]); + spawn_and_wait(test_cmd); + } else { + eprintln!("Cross-Compiling: Not running tests"); + let mut build_cmd = GRAVIOLA.build(&runner.target_compiler, &runner.dirs); + build_cmd.args(["-p", "graviola", "--lib"]); + spawn_and_wait(build_cmd); + } + }), TestCase::custom("test.portable-simd", &|runner| { apply_patches( &runner.dirs, diff --git a/compiler/rustc_codegen_cranelift/config.txt b/compiler/rustc_codegen_cranelift/config.txt index 72631355733c4..7c516e2164b40 100644 --- a/compiler/rustc_codegen_cranelift/config.txt +++ b/compiler/rustc_codegen_cranelift/config.txt @@ -20,7 +20,7 @@ aot.mini_core_hello_world testsuite.base_sysroot aot.arbitrary_self_types_pointers_and_wrappers -#jit.std_example # FIXME(#1619) broken for some reason +jit.std_example aot.std_example aot.dst_field_align aot.subslice-patterns-const-eval @@ -36,4 +36,5 @@ test.sysroot testsuite.extended_sysroot test.rust-random/rand test.regex +test.graviola test.portable-simd diff --git a/compiler/rustc_codegen_cranelift/example/neon.rs b/compiler/rustc_codegen_cranelift/example/neon.rs index 98a2a7af38f6b..1aec5badcbc26 100644 --- a/compiler/rustc_codegen_cranelift/example/neon.rs +++ b/compiler/rustc_codegen_cranelift/example/neon.rs @@ -9,6 +9,25 @@ use std::mem::transmute; #[cfg(target_arch = "aarch64")] use std::simd::*; +#[cfg(target_arch = "aarch64")] +#[target_feature(enable = "crc")] +unsafe fn test_crc32() { + assert!(std::arch::is_aarch64_feature_detected!("crc")); + + let a: u32 = 42; + let b: u64 = 0xdeadbeef; + + assert_eq!(__crc32b(a, b as u8), 0xEB0E363F); + assert_eq!(__crc32h(a, b as u16), 0x9A54BD80); + assert_eq!(__crc32w(a, b as u32), 0xF491F059); + assert_eq!(__crc32d(a, b as u64), 0xD14BBEA6); + + assert_eq!(__crc32cb(a, b as u8), 0xF67C32D8); + assert_eq!(__crc32ch(a, b as u16), 0x479108B8); + assert_eq!(__crc32cw(a, b as u32), 0x979F49F8); + assert_eq!(__crc32cd(a, b as u64), 0x0E6BE593); +} + #[cfg(target_arch = "aarch64")] unsafe fn test_vpmin_s8() { let a = i8x8::from([1, -2, 3, -4, 5, 6, 7, 8]); @@ -240,6 +259,272 @@ unsafe fn test_vrndnq_f32() { assert_eq!(r, e); } +#[cfg(target_arch = "aarch64")] +#[target_feature(enable = "aes")] +unsafe fn test_vaeseq_u8() { + // AArch64 llvm intrinsic: llvm.aarch64.crypto.aese + let a = u8x16::from([0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]); + let b = u8x16::from([16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31]); + let e = u8x16::from([ + 0xca, 0xca, 0xca, 0xca, 0xca, 0xca, 0xca, 0xca, 0xca, 0xca, 0xca, 0xca, 0xca, 0xca, 0xca, + 0xca, + ]); + let r: u8x16 = unsafe { transmute(vaeseq_u8(transmute(a), transmute(b))) }; + assert_eq!(r, e); +} + +#[cfg(target_arch = "aarch64")] +#[target_feature(enable = "aes")] +unsafe fn test_vaesdq_u8() { + // AArch64 llvm intrinsic: llvm.aarch64.crypto.aesd + let a = u8x16::from([0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]); + let b = u8x16::from([16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31]); + let e = u8x16::from([ + 0x7c, 0x7c, 0x7c, 0x7c, 0x7c, 0x7c, 0x7c, 0x7c, 0x7c, 0x7c, 0x7c, 0x7c, 0x7c, 0x7c, 0x7c, + 0x7c, + ]); + let r: u8x16 = unsafe { transmute(vaesdq_u8(transmute(a), transmute(b))) }; + assert_eq!(r, e); +} + +#[cfg(target_arch = "aarch64")] +#[target_feature(enable = "aes")] +unsafe fn test_vaesmcq_u8() { + // AArch64 llvm intrinsic: llvm.aarch64.crypto.aesmc + let a = u8x16::from([0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]); + let e = u8x16::from([2, 7, 0, 5, 6, 3, 4, 1, 10, 15, 8, 13, 14, 11, 12, 9]); + let r: u8x16 = unsafe { transmute(vaesmcq_u8(transmute(a))) }; + assert_eq!(r, e); +} + +#[cfg(target_arch = "aarch64")] +#[target_feature(enable = "aes")] +unsafe fn test_vaesimcq_u8() { + // AArch64 llvm intrinsic: llvm.aarch64.crypto.aesimc + let a = u8x16::from([0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]); + let e = u8x16::from([10, 15, 8, 13, 14, 11, 12, 9, 2, 7, 0, 5, 6, 3, 4, 1]); + let r: u8x16 = unsafe { transmute(vaesimcq_u8(transmute(a))) }; + assert_eq!(r, e); +} + +#[cfg(target_arch = "aarch64")] +#[target_feature(enable = "sha2")] +unsafe fn test_vsha256hq_u32() { + // AArch64 llvm intrinsic: llvm.aarch64.crypto.sha256h + let a = u32x4::from([0, 1, 2, 3]); + let b = u32x4::from([4, 5, 6, 7]); + let c = u32x4::from([8, 9, 10, 11]); + let e = u32x4::from([0x27bb4ae0, 0xd8f61f7c, 0xb7c1ecdc, 0x10800215]); + let r: u32x4 = unsafe { transmute(vsha256hq_u32(transmute(a), transmute(b), transmute(c))) }; + assert_eq!(r, e); +} + +#[cfg(target_arch = "aarch64")] +#[target_feature(enable = "sha2")] +unsafe fn test_vsha256h2q_u32() { + // AArch64 llvm intrinsic: llvm.aarch64.crypto.sha256h2 + let a = u32x4::from([0, 1, 2, 3]); + let b = u32x4::from([4, 5, 6, 7]); + let c = u32x4::from([8, 9, 10, 11]); + let e = u32x4::from([0x6989ee0d, 0x4b055920, 0x52800a12, 0x00000014]); + let r: u32x4 = unsafe { transmute(vsha256h2q_u32(transmute(a), transmute(b), transmute(c))) }; + assert_eq!(r, e); +} + +#[cfg(target_arch = "aarch64")] +#[target_feature(enable = "sha2")] +unsafe fn test_vsha256su0q_u32() { + // AArch64 llvm intrinsic: llvm.aarch64.crypto.sha256su0 + let a = u32x4::from([0, 1, 2, 3]); + let b = u32x4::from([4, 5, 6, 7]); + let e = u32x4::from([0x02004000, 0x04008001, 0x0600c002, 0x08010003]); + let r: u32x4 = unsafe { transmute(vsha256su0q_u32(transmute(a), transmute(b))) }; + assert_eq!(r, e); +} + +#[cfg(target_arch = "aarch64")] +#[target_feature(enable = "sha2")] +unsafe fn test_vsha256su1q_u32() { + // AArch64 llvm intrinsic: llvm.aarch64.crypto.sha256su1 + let a = u32x4::from([0, 1, 2, 3]); + let b = u32x4::from([4, 5, 6, 7]); + let c = u32x4::from([8, 9, 10, 11]); + let e = u32x4::from([0x00044005, 0x0004e007, 0xa802211b, 0xec036145]); + let r: u32x4 = unsafe { transmute(vsha256su1q_u32(transmute(a), transmute(b), transmute(c))) }; + assert_eq!(r, e); +} + +#[cfg(target_arch = "aarch64")] +#[target_feature(enable = "aes")] +fn test_vmull_p64() { + // AArch64 llvm intrinsic: llvm.aarch64.neon.pmull64 + let a: u64 = 3; + let b: u64 = 6; + let e: u128 = 10; + let r: u128 = vmull_p64(a, b); + assert_eq!(r, e); +} + +#[cfg(target_arch = "aarch64")] +unsafe fn test_vmull_p8() { + // AArch64 llvm intrinsic: llvm.aarch64.neon.pmull.v8i16 + let a = u8x8::from([0, 1, 2, 3, 4, 5, 6, 7]); + let b = u8x8::from([8, 9, 10, 11, 12, 13, 14, 15]); + let e = u16x8::from([0x0000, 0x0009, 0x0014, 0x001d, 0x0030, 0x0039, 0x0024, 0x002d]); + let r: u16x8 = unsafe { transmute(vmull_p8(transmute(a), transmute(b))) }; + assert_eq!(r, e); +} + +#[cfg(target_arch = "aarch64")] +unsafe fn test_vqdmulh_s16() { + // AArch64 llvm intrinsic: llvm.aarch64.neon.sqdmulh.v4i16 + let a = i16x4::from([1, 2, 4, 8]); + let b = i16x4::from([16384, 16384, 16384, 16384]); + let e = i16x4::from([0, 1, 2, 4]); + let r: i16x4 = unsafe { transmute(vqdmulh_s16(transmute(a), transmute(b))) }; + assert_eq!(r, e); +} + +#[cfg(target_arch = "aarch64")] +unsafe fn test_vqdmulh_s32() { + // AArch64 llvm intrinsic: llvm.aarch64.neon.sqdmulh.v2i32 + let a = i32x2::from([1, 2]); + let b = i32x2::from([1073741824, 1073741824]); + let e = i32x2::from([0, 1]); + let r: i32x2 = unsafe { transmute(vqdmulh_s32(transmute(a), transmute(b))) }; + assert_eq!(r, e); +} + +#[cfg(target_arch = "aarch64")] +unsafe fn test_vqdmulhq_s16() { + // AArch64 llvm intrinsic: llvm.aarch64.neon.sqdmulh.v8i16 + let a = i16x8::from([1, 2, 4, 8, 16, 32, 64, 128]); + let b = i16x8::from([16384, 16384, 16384, 16384, 16384, 16384, 16384, 16384]); + let e = i16x8::from([0, 1, 2, 4, 8, 16, 32, 64]); + let r: i16x8 = unsafe { transmute(vqdmulhq_s16(transmute(a), transmute(b))) }; + assert_eq!(r, e); +} + +#[cfg(target_arch = "aarch64")] +unsafe fn test_vqdmulhq_s32() { + // AArch64 llvm intrinsic: llvm.aarch64.neon.sqdmulh.v4i32 + let a = i32x4::from([1, 2, 4, 8]); + let b = i32x4::from([1073741824, 1073741824, 1073741824, 1073741824]); + let e = i32x4::from([0, 1, 2, 4]); + let r: i32x4 = unsafe { transmute(vqdmulhq_s32(transmute(a), transmute(b))) }; + assert_eq!(r, e); +} + +#[cfg(target_arch = "aarch64")] +unsafe fn test_vpaddl_s8() { + // AArch64 llvm intrinsic: llvm.aarch64.neon.saddlp.v4i16.v8i8 + let a = i8x8::from([1, 2, 3, 4, -5, -6, -7, -8]); + let e = i16x4::from([3, 7, -11, -15]); + let r: i16x4 = unsafe { transmute(vpaddl_s8(transmute(a))) }; + assert_eq!(r, e); +} + +#[cfg(target_arch = "aarch64")] +unsafe fn test_vpaddl_s16() { + // AArch64 llvm intrinsic: llvm.aarch64.neon.saddlp.v2i32.v4i16 + let a = i16x4::from([1, 2, -3, -4]); + let e = i32x2::from([3, -7]); + let r: i32x2 = unsafe { transmute(vpaddl_s16(transmute(a))) }; + assert_eq!(r, e); +} + +#[cfg(target_arch = "aarch64")] +unsafe fn test_vpaddl_s32() { + // AArch64 llvm intrinsic: llvm.aarch64.neon.saddlp.v1i64.v2i32 + let a = i32x2::from([1, -2]); + let e = i64x1::from([-1]); + let r: i64x1 = unsafe { transmute(vpaddl_s32(transmute(a))) }; + assert_eq!(r, e); +} + +#[cfg(target_arch = "aarch64")] +unsafe fn test_vpaddlq_s8() { + // AArch64 llvm intrinsic: llvm.aarch64.neon.saddlp.v8i16.v16i8 + let a = i8x16::from([1, 2, 3, 4, 5, 6, 7, 8, -9, -10, -11, -12, -13, -14, -15, -16]); + let e = i16x8::from([3, 7, 11, 15, -19, -23, -27, -31]); + let r: i16x8 = unsafe { transmute(vpaddlq_s8(transmute(a))) }; + assert_eq!(r, e); +} + +#[cfg(target_arch = "aarch64")] +unsafe fn test_vpaddlq_s16() { + // AArch64 llvm intrinsic: llvm.aarch64.neon.saddlp.v4i32.v8i16 + let a = i16x8::from([1, 2, 3, 4, -5, -6, -7, -8]); + let e = i32x4::from([3, 7, -11, -15]); + let r: i32x4 = unsafe { transmute(vpaddlq_s16(transmute(a))) }; + assert_eq!(r, e); +} + +#[cfg(target_arch = "aarch64")] +unsafe fn test_vpaddlq_s32() { + // AArch64 llvm intrinsic: llvm.aarch64.neon.saddlp.v2i64.v4i32 + let a = i32x4::from([1, 2, -3, -4]); + let e = i64x2::from([3, -7]); + let r: i64x2 = unsafe { transmute(vpaddlq_s32(transmute(a))) }; + assert_eq!(r, e); +} + +#[cfg(target_arch = "aarch64")] +unsafe fn test_vpaddl_u8() { + // AArch64 llvm intrinsic: llvm.aarch64.neon.uaddlp.v4i16.v8i8 + let a = u8x8::from([255, 254, 253, 252, 251, 250, 249, 248]); + let e = u16x4::from([509, 505, 501, 497]); + let r: u16x4 = unsafe { transmute(vpaddl_u8(transmute(a))) }; + assert_eq!(r, e); +} + +#[cfg(target_arch = "aarch64")] +unsafe fn test_vpaddl_u16() { + // AArch64 llvm intrinsic: llvm.aarch64.neon.uaddlp.v2i32.v4i16 + let a = u16x4::from([65535, 65534, 65533, 65532]); + let e = u32x2::from([131069, 131065]); + let r: u32x2 = unsafe { transmute(vpaddl_u16(transmute(a))) }; + assert_eq!(r, e); +} + +#[cfg(target_arch = "aarch64")] +unsafe fn test_vpaddl_u32() { + // AArch64 llvm intrinsic: llvm.aarch64.neon.uaddlp.v1i64.v2i32 + let a = u32x2::from([4294967295, 4294967294]); + let e = u64x1::from([8589934589]); + let r: u64x1 = unsafe { transmute(vpaddl_u32(transmute(a))) }; + assert_eq!(r, e); +} + +#[cfg(target_arch = "aarch64")] +unsafe fn test_vpaddlq_u8() { + // AArch64 llvm intrinsic: llvm.aarch64.neon.uaddlp.v8i16.v16i8 + let a = u8x16::from([ + 255, 254, 253, 252, 251, 250, 249, 248, 247, 246, 245, 244, 243, 242, 241, 240, + ]); + let e = u16x8::from([509, 505, 501, 497, 493, 489, 485, 481]); + let r: u16x8 = unsafe { transmute(vpaddlq_u8(transmute(a))) }; + assert_eq!(r, e); +} + +#[cfg(target_arch = "aarch64")] +unsafe fn test_vpaddlq_u16() { + // AArch64 llvm intrinsic: llvm.aarch64.neon.uaddlp.v4i32.v8i16 + let a = u16x8::from([65535, 65534, 65533, 65532, 65531, 65530, 65529, 65528]); + let e = u32x4::from([131069, 131065, 131061, 131057]); + let r: u32x4 = unsafe { transmute(vpaddlq_u16(transmute(a))) }; + assert_eq!(r, e); +} + +#[cfg(target_arch = "aarch64")] +unsafe fn test_vpaddlq_u32() { + // AArch64 llvm intrinsic: llvm.aarch64.neon.uaddlp.v2i64.v4i32 + let a = u32x4::from([4294967295, 4294967294, 4294967293, 4294967292]); + let e = u64x2::from([8589934589, 8589934585]); + let r: u64x2 = unsafe { transmute(vpaddlq_u32(transmute(a))) }; + assert_eq!(r, e); +} + #[cfg(target_arch = "aarch64")] fn main() { unsafe { @@ -272,6 +557,40 @@ fn main() { test_vminq_f32(); test_vaddvq_f32(); test_vrndnq_f32(); + + test_crc32(); + + test_vaeseq_u8(); + test_vaesdq_u8(); + test_vaesmcq_u8(); + test_vaesimcq_u8(); + + test_vsha256hq_u32(); + test_vsha256h2q_u32(); + test_vsha256su0q_u32(); + test_vsha256su1q_u32(); + + test_vmull_p64(); + test_vmull_p8(); + + test_vqdmulh_s16(); + test_vqdmulh_s32(); + test_vqdmulhq_s16(); + test_vqdmulhq_s32(); + + test_vpaddl_s8(); + test_vpaddl_s16(); + test_vpaddl_s32(); + test_vpaddlq_s8(); + test_vpaddlq_s16(); + test_vpaddlq_s32(); + + test_vpaddl_u8(); + test_vpaddl_u16(); + test_vpaddl_u32(); + test_vpaddlq_u8(); + test_vpaddlq_u16(); + test_vpaddlq_u32(); } } diff --git a/compiler/rustc_codegen_cranelift/example/std_example.rs b/compiler/rustc_codegen_cranelift/example/std_example.rs index f0e38ae0610c9..252344b378e8a 100644 --- a/compiler/rustc_codegen_cranelift/example/std_example.rs +++ b/compiler/rustc_codegen_cranelift/example/std_example.rs @@ -1,8 +1,6 @@ #![feature(core_intrinsics, coroutines, coroutine_trait, repr_simd, tuple_trait, unboxed_closures)] #![allow(internal_features)] -#[cfg(target_arch = "x86_64")] -use std::arch::asm; #[cfg(target_arch = "x86_64")] use std::arch::x86_64::*; use std::hint::black_box; @@ -591,7 +589,7 @@ unsafe fn test_xmm_roundtrip() { let input = [1u8; 16]; let mut output = [0u8; 16]; - asm!( + std::arch::asm!( "movups {xmm}, [{input}]", "movups [{output}], {xmm}", input = in(reg) input.as_ptr(), @@ -611,7 +609,7 @@ unsafe fn test_ymm_roundtrip() { let input = [1u8; 32]; let mut output = [0u8; 32]; - asm!( + std::arch::asm!( "vmovups {ymm}, [{input}]", "vmovups [{output}], {ymm}", input = in(reg) input.as_ptr(), @@ -631,7 +629,7 @@ unsafe fn test_zmm_roundtrip() { let input = [1u8; 64]; let mut output = [0u8; 64]; - asm!( + std::arch::asm!( "vmovups {zmm}, [{input}]", "vmovups [{output}], {zmm}", input = in(reg) input.as_ptr(), diff --git a/compiler/rustc_codegen_cranelift/patches/0001-portable-simd-Disable-f16-usage-in-portable-simd.patch b/compiler/rustc_codegen_cranelift/patches/0001-portable-simd-Disable-f16-usage-in-portable-simd.patch index 029e493227cd1..a2fcd97349e2b 100644 --- a/compiler/rustc_codegen_cranelift/patches/0001-portable-simd-Disable-f16-usage-in-portable-simd.patch +++ b/compiler/rustc_codegen_cranelift/patches/0001-portable-simd-Disable-f16-usage-in-portable-simd.patch @@ -154,6 +154,21 @@ index 510f4c9..175cbce 100644 -impl_trait! { f16 { bits: u16, mask: i16 }, f32 { bits: u32, mask: i32 }, f64 { bits: u64, mask: i64 } } +impl_trait! { f32 { bits: u32, mask: i32 }, f64 { bits: u64, mask: i64 } } +diff --git a/crates/core_simd/src/simd/prelude.rs b/crates/core_simd/src/simd/prelude.rs +index 51b8def..6e93f16 100644 +--- a/crates/core_simd/src/simd/prelude.rs ++++ b/crates/core_simd/src/simd/prelude.rs +@@ -14,10 +14,6 @@ pub use super::{ + simd_swizzle, + }; + +-#[rustfmt::skip] +-#[doc(no_inline)] +-pub use super::{f16x1, f16x2, f16x4, f16x8, f16x16, f16x32, f16x64}; +- + #[rustfmt::skip] + #[doc(no_inline)] + pub use super::{f32x1, f32x2, f32x4, f32x8, f32x16, f32x32, f32x64}; diff --git a/crates/core_simd/src/vector.rs b/crates/core_simd/src/vector.rs index fbef69f..c8e0b8c 100644 --- a/crates/core_simd/src/vector.rs diff --git a/compiler/rustc_codegen_cranelift/patches/0027-stdlib-128bit-atomic-operations.patch b/compiler/rustc_codegen_cranelift/patches/0027-stdlib-128bit-atomic-operations.patch index b7276e43153bc..717495cbcdf33 100644 --- a/compiler/rustc_codegen_cranelift/patches/0027-stdlib-128bit-atomic-operations.patch +++ b/compiler/rustc_codegen_cranelift/patches/0027-stdlib-128bit-atomic-operations.patch @@ -34,17 +34,17 @@ index a60f0799c0e..af056fbf41f 100644 #[cfg(target_has_atomic_load_store = "8")] #[stable(feature = "unwind_safe_atomic_refs", since = "1.14.0")] diff --git a/library/core/src/sync/atomic.rs b/library/core/src/sync/atomic.rs -index bf2b6d59f88..d5ccce03bbf 100644 +index 8a9a0b5..92ed9a6 100644 --- a/library/core/src/sync/atomic.rs +++ b/library/core/src/sync/atomic.rs -@@ -3585,42 +3585,6 @@ pub const fn as_ptr(&self) -> *mut $int_type { +@@ -3762,42 +3757,6 @@ atomic_int! { 8, u64 AtomicU64 } -#[cfg(target_has_atomic_load_store = "128")] -atomic_int! { - cfg(target_has_atomic = "128"), -- cfg(target_has_atomic_equal_alignment = "128"), +- cfg(target_has_atomic_primitive_alignment = "128"), - unstable(feature = "integer_atomics", issue = "99069"), - unstable(feature = "integer_atomics", issue = "99069"), - unstable(feature = "integer_atomics", issue = "99069"), @@ -62,7 +62,7 @@ index bf2b6d59f88..d5ccce03bbf 100644 -#[cfg(target_has_atomic_load_store = "128")] -atomic_int! { - cfg(target_has_atomic = "128"), -- cfg(target_has_atomic_equal_alignment = "128"), +- cfg(target_has_atomic_primitive_alignment = "128"), - unstable(feature = "integer_atomics", issue = "99069"), - unstable(feature = "integer_atomics", issue = "99069"), - unstable(feature = "integer_atomics", issue = "99069"), diff --git a/compiler/rustc_codegen_cranelift/patches/0029-sysroot_tests-disable-f16-math.patch b/compiler/rustc_codegen_cranelift/patches/0029-sysroot_tests-disable-f16-math.patch index 2aeb4a8a1874c..8d21359aa0043 100644 --- a/compiler/rustc_codegen_cranelift/patches/0029-sysroot_tests-disable-f16-math.patch +++ b/compiler/rustc_codegen_cranelift/patches/0029-sysroot_tests-disable-f16-math.patch @@ -7,11 +7,389 @@ Subject: [PATCH] Disable f16 math tests for cranelift coretests/tests/num/floats.rs | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) -diff --git a/coretests/tests/floats/mod.rs b/coretests/tests/floats/mod.rs -index c61961f8584..d7b4fa20322 100644 +diff --git a/coretests/tests/num/floats.rs b/coretests/tests/num/floats.rs +index 1d7956b..01e4caa 100644 --- a/coretests/tests/num/floats.rs +++ b/coretests/tests/num/floats.rs -@@ -1534,7 +1534,7 @@ fn s_nan() -> Float { +@@ -444,7 +444,7 @@ pub(crate) use float_test; + float_test! { + name: num, + attrs: { +- f16: #[cfg(target_has_reliable_f16)], ++ f16: #[cfg(false)], + f128: #[cfg(target_has_reliable_f128)], + }, + test { +@@ -463,7 +463,7 @@ float_test! { + name: num_rem, + attrs: { + // Miri only uses softfloats here, so that always works +- f16: #[cfg(any(miri, target_has_reliable_f16_math))], ++ f16: #[cfg(false)], + f128: #[cfg(any(miri, target_has_reliable_f128_math))], + }, + test { +@@ -476,7 +476,7 @@ float_test! { + float_test! { + name: nan, + attrs: { +- f16: #[cfg(target_has_reliable_f16)], ++ f16: #[cfg(false)], + f128: #[cfg(target_has_reliable_f128)], + }, + test { +@@ -496,7 +496,7 @@ float_test! { + float_test! { + name: infinity, + attrs: { +- f16: #[cfg(target_has_reliable_f16)], ++ f16: #[cfg(false)], + f128: #[cfg(target_has_reliable_f128)], + }, + test { +@@ -514,7 +514,7 @@ float_test! { + float_test! { + name: neg_infinity, + attrs: { +- f16: #[cfg(target_has_reliable_f16)], ++ f16: #[cfg(false)], + f128: #[cfg(target_has_reliable_f128)], + }, + test { +@@ -532,7 +532,7 @@ float_test! { + float_test! { + name: zero, + attrs: { +- f16: #[cfg(target_has_reliable_f16)], ++ f16: #[cfg(false)], + f128: #[cfg(target_has_reliable_f128)], + }, + test { +@@ -550,7 +550,7 @@ float_test! { + float_test! { + name: neg_zero, + attrs: { +- f16: #[cfg(target_has_reliable_f16)], ++ f16: #[cfg(false)], + f128: #[cfg(target_has_reliable_f128)], + }, + test { +@@ -570,7 +570,7 @@ float_test! { + float_test! { + name: one, + attrs: { +- f16: #[cfg(target_has_reliable_f16)], ++ f16: #[cfg(false)], + f128: #[cfg(target_has_reliable_f128)], + }, + test { +@@ -588,7 +588,7 @@ float_test! { + float_test! { + name: is_nan, + attrs: { +- f16: #[cfg(target_has_reliable_f16)], ++ f16: #[cfg(false)], + f128: #[cfg(target_has_reliable_f128)], + }, + test { +@@ -609,7 +609,7 @@ float_test! { + float_test! { + name: is_infinite, + attrs: { +- f16: #[cfg(target_has_reliable_f16)], ++ f16: #[cfg(false)], + f128: #[cfg(target_has_reliable_f128)], + }, + test { +@@ -630,7 +630,7 @@ float_test! { + float_test! { + name: is_finite, + attrs: { +- f16: #[cfg(target_has_reliable_f16)], ++ f16: #[cfg(false)], + f128: #[cfg(target_has_reliable_f128)], + }, + test { +@@ -651,7 +651,7 @@ float_test! { + float_test! { + name: is_normal, + attrs: { +- f16: #[cfg(target_has_reliable_f16)], ++ f16: #[cfg(false)], + f128: #[cfg(target_has_reliable_f128)], + }, + test { +@@ -673,7 +673,7 @@ float_test! { + float_test! { + name: classify, + attrs: { +- f16: #[cfg(target_has_reliable_f16)], ++ f16: #[cfg(false)], + }, + test { + let nan: Float = Float::NAN; +@@ -695,7 +695,7 @@ float_test! { + name: min, + attrs: { + // Miri only uses softfloats here, so that always works +- f16: #[cfg(any(miri, target_has_reliable_f16_math))], ++ f16: #[cfg(false)], + f128: #[cfg(any(miri, target_has_reliable_f128_math))], + }, + test { +@@ -737,7 +737,7 @@ float_test! { + name: max, + attrs: { + // Miri only uses softfloats here, so that always works +- f16: #[cfg(any(miri, target_has_reliable_f16_math))], ++ f16: #[cfg(false)], + f128: #[cfg(any(miri, target_has_reliable_f128_math))], + }, + test { +@@ -780,7 +780,7 @@ float_test! { + name: minimum, + attrs: { + // Miri only uses softfloats here, so that always works +- f16: #[cfg(any(miri, target_has_reliable_f16_math))], ++ f16: #[cfg(false)], + f128: #[cfg(any(miri, target_has_reliable_f128_math))], + }, + test { +@@ -812,7 +812,7 @@ float_test! { + name: maximum, + attrs: { + // Miri only uses softfloats here, so that always works +- f16: #[cfg(any(miri, target_has_reliable_f16_math))], ++ f16: #[cfg(false)], + f128: #[cfg(any(miri, target_has_reliable_f128_math))], + }, + test { +@@ -845,7 +845,7 @@ float_test! { + name: midpoint, + attrs: { + // Miri only uses softfloats here, so that always works +- f16: #[cfg(any(miri, target_has_reliable_f16_math))], ++ f16: #[cfg(false)], + f128: #[cfg(any(miri, target_has_reliable_f128_math))], + }, + test { +@@ -898,7 +898,7 @@ float_test! { + attrs: { + const: #[cfg(false)], + // Needs powi +- f16: #[cfg(target_has_reliable_f16_math)], ++ f16: #[cfg(false)], + f128: #[cfg(target_has_reliable_f128_math)], + }, + test { +@@ -929,7 +929,7 @@ float_test! { + name: abs, + attrs: { + // Miri only uses softfloats here, so that always works +- f16: #[cfg(any(miri, target_has_reliable_f16_math))], ++ f16: #[cfg(false)], + f128: #[cfg(any(miri, target_has_reliable_f128_math))], + }, + test { +@@ -948,7 +948,7 @@ float_test! { + name: copysign, + attrs: { + // Miri only uses softfloats here, so that always works +- f16: #[cfg(any(miri, target_has_reliable_f16_math))], ++ f16: #[cfg(false)], + f128: #[cfg(any(miri, target_has_reliable_f128_math))], + }, + test { +@@ -964,7 +964,7 @@ float_test! { + attrs: { + const: #[cfg(false)], + // Miri only uses softfloats here, so that always works +- f16: #[cfg(any(miri, target_has_reliable_f16_math))], ++ f16: #[cfg(false)], + f128: #[cfg(any(miri, target_has_reliable_f128_math))], + }, + test { +@@ -982,7 +982,7 @@ float_test! { + attrs: { + const: #[cfg(false)], + // Miri only uses softfloats here, so that always works +- f16: #[cfg(any(miri, target_has_reliable_f16_math))], ++ f16: #[cfg(false)], + f128: #[cfg(any(miri, target_has_reliable_f128_math))], + }, + test { +@@ -998,7 +998,7 @@ float_test! { + name: floor, + attrs: { + // Miri only uses softfloats here, so that always works +- f16: #[cfg(any(miri, target_has_reliable_f16_math))], ++ f16: #[cfg(false)], + f128: #[cfg(any(miri, target_has_reliable_f128_math))], + }, + test { +@@ -1028,7 +1028,7 @@ float_test! { + name: ceil, + attrs: { + // Miri only uses softfloats here, so that always works +- f16: #[cfg(any(miri, target_has_reliable_f16_math))], ++ f16: #[cfg(false)], + f128: #[cfg(any(miri, target_has_reliable_f128_math))], + }, + test { +@@ -1058,7 +1058,7 @@ float_test! { + name: round, + attrs: { + // Miri only uses softfloats here, so that always works +- f16: #[cfg(any(miri, target_has_reliable_f16_math))], ++ f16: #[cfg(false)], + f128: #[cfg(any(miri, target_has_reliable_f128_math))], + }, + test { +@@ -1089,7 +1089,7 @@ float_test! { + name: round_ties_even, + attrs: { + // Miri only uses softfloats here, so that always works +- f16: #[cfg(any(miri, target_has_reliable_f16_math))], ++ f16: #[cfg(false)], + f128: #[cfg(any(miri, target_has_reliable_f128_math))], + }, + test { +@@ -1120,7 +1120,7 @@ float_test! { + name: trunc, + attrs: { + // Miri only uses softfloats here, so that always works +- f16: #[cfg(any(miri, target_has_reliable_f16_math))], ++ f16: #[cfg(false)], + f128: #[cfg(any(miri, target_has_reliable_f128_math))], + }, + test { +@@ -1150,7 +1150,7 @@ float_test! { + name: fract, + attrs: { + // Miri only uses softfloats here, so that always works +- f16: #[cfg(any(miri, target_has_reliable_f16_math))], ++ f16: #[cfg(false)], + f128: #[cfg(any(miri, target_has_reliable_f128_math))], + }, + test { +@@ -1182,7 +1182,7 @@ float_test! { + name: signum, + attrs: { + // Miri only uses softfloats here, so that always works +- f16: #[cfg(any(miri, target_has_reliable_f16_math))], ++ f16: #[cfg(false)], + f128: #[cfg(any(miri, target_has_reliable_f128_math))], + }, + test { +@@ -1200,7 +1200,7 @@ float_test! { + float_test! { + name: is_sign_positive, + attrs: { +- f16: #[cfg(target_has_reliable_f16)], ++ f16: #[cfg(false)], + f128: #[cfg(target_has_reliable_f128)], + }, + test { +@@ -1219,7 +1219,7 @@ float_test! { + float_test! { + name: is_sign_negative, + attrs: { +- f16: #[cfg(target_has_reliable_f16)], ++ f16: #[cfg(false)], + f128: #[cfg(target_has_reliable_f128)], + }, + test { +@@ -1238,7 +1238,7 @@ float_test! { + float_test! { + name: next_up, + attrs: { +- f16: #[cfg(target_has_reliable_f16)], ++ f16: #[cfg(false)], + f128: #[cfg(target_has_reliable_f128)], + }, + test { +@@ -1269,7 +1269,7 @@ float_test! { + float_test! { + name: next_down, + attrs: { +- f16: #[cfg(target_has_reliable_f16)], ++ f16: #[cfg(false)], + f128: #[cfg(target_has_reliable_f128)], + }, + test { +@@ -1303,7 +1303,7 @@ float_test! { + attrs: { + const: #[cfg(false)], + // Miri only uses softfloats here, so that always works +- f16: #[cfg(any(miri, target_has_reliable_f16_math))], ++ f16: #[cfg(false)], + f128: #[cfg(any(miri, target_has_reliable_f128_math))], + }, + test { +@@ -1321,7 +1321,7 @@ float_test! { + name: clamp_min_greater_than_max, + attrs: { + const: #[cfg(false)], +- f16: #[should_panic, cfg(target_has_reliable_f16)], ++ f16: #[should_panic, cfg(false)], + f32: #[should_panic], + f64: #[should_panic], + f128: #[should_panic, cfg(target_has_reliable_f128)], +@@ -1335,7 +1335,7 @@ float_test! { + name: clamp_min_is_nan, + attrs: { + const: #[cfg(false)], +- f16: #[should_panic, cfg(target_has_reliable_f16)], ++ f16: #[should_panic, cfg(false)], + f32: #[should_panic], + f64: #[should_panic], + f128: #[should_panic, cfg(target_has_reliable_f128)], +@@ -1349,7 +1349,7 @@ float_test! { + name: clamp_max_is_nan, + attrs: { + const: #[cfg(false)], +- f16: #[should_panic, cfg(target_has_reliable_f16)], ++ f16: #[should_panic, cfg(false)], + f32: #[should_panic], + f64: #[should_panic], + f128: #[should_panic, cfg(target_has_reliable_f128)], +@@ -1363,7 +1363,7 @@ float_test! { + name: total_cmp, + attrs: { + // Miri only uses softfloats here, so that always works +- f16: #[cfg(any(miri, target_has_reliable_f16_math))], ++ f16: #[cfg(false)], + f128: #[cfg(any(miri, target_has_reliable_f128_math))], + }, + test { +@@ -1469,7 +1469,7 @@ float_test! { + attrs: { + const: #[cfg(false)], + // Miri only uses softfloats here, so that always works +- f16: #[cfg(any(miri, target_has_reliable_f16_math))], ++ f16: #[cfg(false)], + f128: #[cfg(any(miri, target_has_reliable_f128_math))], + }, + test { +@@ -1526,7 +1526,7 @@ float_test! { + name: recip, + attrs: { + // Miri only uses softfloats here, so that always works +- f16: #[cfg(any(miri, target_has_reliable_f16_math))], ++ f16: #[cfg(false)], + f128: #[cfg(any(miri, target_has_reliable_f128_math))], + }, + test { +@@ -1549,7 +1549,7 @@ float_test! { + name: powi, + attrs: { + const: #[cfg(false)], +- f16: #[cfg(target_has_reliable_f16_math)], ++ f16: #[cfg(false)], + f128: #[cfg(target_has_reliable_f128_math)], + }, + test { +@@ -1570,7 +1570,7 @@ float_test! { name: powf, attrs: { const: #[cfg(false)], @@ -20,7 +398,7 @@ index c61961f8584..d7b4fa20322 100644 f128: #[cfg(target_has_reliable_f128_math)], }, test { -@@ -1557,7 +1557,7 @@ fn s_nan() -> Float { +@@ -1593,7 +1593,7 @@ float_test! { name: exp, attrs: { const: #[cfg(false)], @@ -29,7 +407,7 @@ index c61961f8584..d7b4fa20322 100644 f128: #[cfg(target_has_reliable_f128_math)], }, test { -@@ -1578,7 +1578,7 @@ fn s_nan() -> Float { +@@ -1614,7 +1614,7 @@ float_test! { name: exp2, attrs: { const: #[cfg(false)], @@ -38,7 +416,7 @@ index c61961f8584..d7b4fa20322 100644 f128: #[cfg(target_has_reliable_f128_math)], }, test { -@@ -1598,7 +1598,7 @@ fn s_nan() -> Float { +@@ -1634,7 +1634,7 @@ float_test! { name: ln, attrs: { const: #[cfg(false)], @@ -47,7 +425,7 @@ index c61961f8584..d7b4fa20322 100644 f128: #[cfg(target_has_reliable_f128_math)], }, test { -@@ -1620,7 +1620,7 @@ fn s_nan() -> Float { +@@ -1656,7 +1656,7 @@ float_test! { name: log, attrs: { const: #[cfg(false)], @@ -56,7 +434,7 @@ index c61961f8584..d7b4fa20322 100644 f128: #[cfg(target_has_reliable_f128_math)], }, test { -@@ -1645,7 +1645,7 @@ fn s_nan() -> Float { +@@ -1681,7 +1681,7 @@ float_test! { name: log2, attrs: { const: #[cfg(false)], @@ -65,7 +443,7 @@ index c61961f8584..d7b4fa20322 100644 f128: #[cfg(target_has_reliable_f128_math)], }, test { -@@ -1668,7 +1668,7 @@ fn s_nan() -> Float { +@@ -1704,7 +1704,7 @@ float_test! { name: log10, attrs: { const: #[cfg(false)], @@ -74,7 +452,7 @@ index c61961f8584..d7b4fa20322 100644 f128: #[cfg(target_has_reliable_f128_math)], }, test { -@@ -1692,7 +1692,7 @@ fn s_nan() -> Float { +@@ -1728,7 +1728,7 @@ float_test! { name: asinh, attrs: { const: #[cfg(false)], @@ -83,7 +461,7 @@ index c61961f8584..d7b4fa20322 100644 f128: #[cfg(target_has_reliable_f128_math)], }, test { -@@ -1725,7 +1725,7 @@ fn s_nan() -> Float { +@@ -1764,7 +1764,7 @@ float_test! { name: acosh, attrs: { const: #[cfg(false)], @@ -92,7 +470,7 @@ index c61961f8584..d7b4fa20322 100644 f128: #[cfg(target_has_reliable_f128_math)], }, test { -@@ -1753,7 +1753,7 @@ fn s_nan() -> Float { +@@ -1795,7 +1795,7 @@ float_test! { name: atanh, attrs: { const: #[cfg(false)], @@ -101,7 +479,7 @@ index c61961f8584..d7b4fa20322 100644 f128: #[cfg(target_has_reliable_f128_math)], }, test { -@@ -1779,7 +1779,7 @@ fn s_nan() -> Float { +@@ -1821,7 +1821,7 @@ float_test! { name: gamma, attrs: { const: #[cfg(false)], @@ -110,7 +488,7 @@ index c61961f8584..d7b4fa20322 100644 f128: #[cfg(target_has_reliable_f128_math)], }, test { -@@ -1814,7 +1814,7 @@ fn s_nan() -> Float { +@@ -1856,7 +1856,7 @@ float_test! { name: ln_gamma, attrs: { const: #[cfg(false)], @@ -119,7 +497,79 @@ index c61961f8584..d7b4fa20322 100644 f128: #[cfg(target_has_reliable_f128_math)], }, test { -@@ -2027,7 +2027,7 @@ fn s_nan() -> Float { +@@ -1874,7 +1874,7 @@ float_test! { + float_test! { + name: to_degrees, + attrs: { +- f16: #[cfg(target_has_reliable_f16)], ++ f16: #[cfg(false)], + f128: #[cfg(target_has_reliable_f128)], + }, + test { +@@ -1895,7 +1895,7 @@ float_test! { + float_test! { + name: to_radians, + attrs: { +- f16: #[cfg(target_has_reliable_f16)], ++ f16: #[cfg(false)], + f128: #[cfg(target_has_reliable_f128)], + }, + test { +@@ -1916,7 +1916,7 @@ float_test! { + float_test! { + name: to_algebraic, + attrs: { +- f16: #[cfg(target_has_reliable_f16)], ++ f16: #[cfg(false)], + f128: #[cfg(target_has_reliable_f128)], + }, + test { +@@ -1940,7 +1940,7 @@ float_test! { + float_test! { + name: to_bits_conv, + attrs: { +- f16: #[cfg(target_has_reliable_f16)], ++ f16: #[cfg(false)], + f128: #[cfg(target_has_reliable_f128)], + }, + test { +@@ -1967,7 +1967,7 @@ float_test! { + float_test! { + name: mul_add, + attrs: { +- f16: #[cfg(target_has_reliable_f16)], ++ f16: #[cfg(false)], + // FIXME(#140515): mingw has an incorrect fma https://sourceforge.net/p/mingw-w64/bugs/848/ + f32: #[cfg_attr(all(target_os = "windows", target_env = "gnu", not(target_abi = "llvm")), ignore)], + f64: #[cfg_attr(all(target_os = "windows", target_env = "gnu", not(target_abi = "llvm")), ignore)], +@@ -1992,7 +1992,7 @@ float_test! { + float_test! { + name: from, + attrs: { +- f16: #[cfg(target_has_reliable_f16)], ++ f16: #[cfg(false)], + f128: #[cfg(target_has_reliable_f128)], + }, + test { +@@ -2049,7 +2049,7 @@ float_test! { + float_test! { + name: max_exact_integer_constant, + attrs: { +- f16: #[cfg(target_has_reliable_f16)], ++ f16: #[cfg(false)], + f128: #[cfg(target_has_reliable_f128)], + }, + test { +@@ -2091,7 +2091,7 @@ float_test! { + float_test! { + name: min_exact_integer_constant, + attrs: { +- f16: #[cfg(target_has_reliable_f16)], ++ f16: #[cfg(false)], + f128: #[cfg(target_has_reliable_f128)], + }, + test { +@@ -2156,7 +2156,7 @@ float_test! { attrs: { // FIXME(f16_f128): add math tests when available const: #[cfg(false)], diff --git a/compiler/rustc_codegen_cranelift/rust-toolchain.toml b/compiler/rustc_codegen_cranelift/rust-toolchain.toml index 486078185db84..faadf08929557 100644 --- a/compiler/rustc_codegen_cranelift/rust-toolchain.toml +++ b/compiler/rustc_codegen_cranelift/rust-toolchain.toml @@ -1,4 +1,4 @@ [toolchain] -channel = "nightly-2026-04-28" +channel = "nightly-2026-06-06" components = ["rust-src", "rustc-dev", "llvm-tools", "rustfmt"] profile = "minimal" diff --git a/compiler/rustc_codegen_cranelift/scripts/setup_rust_fork.sh b/compiler/rustc_codegen_cranelift/scripts/setup_rust_fork.sh index 7ce54a45e2ce6..ab31c43fb1b12 100644 --- a/compiler/rustc_codegen_cranelift/scripts/setup_rust_fork.sh +++ b/compiler/rustc_codegen_cranelift/scripts/setup_rust_fork.sh @@ -54,7 +54,7 @@ index 2e16f2cf27..3ac3df99a8 100644 --- a/src/bootstrap/bootstrap.py +++ b/src/bootstrap/bootstrap.py @@ -1147,6 +1147,8 @@ class RustBuild(object): - args += ["-Zwarnings"] + if deny_warnings: env["CARGO_BUILD_WARNINGS"] = "deny" + env["RUSTFLAGS"] += " -Zbinary-dep-depinfo" diff --git a/compiler/rustc_codegen_cranelift/scripts/test_rustc_tests.sh b/compiler/rustc_codegen_cranelift/scripts/test_rustc_tests.sh index 4a663c48c0aff..683adeb49edd1 100755 --- a/compiler/rustc_codegen_cranelift/scripts/test_rustc_tests.sh +++ b/compiler/rustc_codegen_cranelift/scripts/test_rustc_tests.sh @@ -88,6 +88,8 @@ rm -r tests/run-make/reproducible-build-2 rm -r tests/run-make/no-builtins-lto rm -r tests/run-make/reachable-extern-fn-available-lto rm -r tests/run-make/no-builtins-linker-plugin-lto +rm -r tests/run-make/fat-then-thin-lto +rm -r tests/run-make/cross-lang-lto-upstream-rlibs # coverage instrumentation rm tests/ui/consts/precise-drop-with-coverage.rs @@ -146,6 +148,7 @@ rm tests/ui/consts/const-mut-refs-crate.rs # same rm tests/ui/abi/large-byval-align.rs # exceeds implementation limit of Cranelift rm -r tests/run-make/short-ice # ICE backtrace begin/end marker mismatch rm -r tests/run-make/naked-dead-code-elimination # function not eliminated +rm tests/ui/codegen/huge-stacks.rs # Cranelift doesn't allow stack frames to exceed 4GB # doesn't work due to the way the rustc test suite is invoked. # should work when using ./x.py test the way it is intended diff --git a/compiler/rustc_codegen_cranelift/src/abi/mod.rs b/compiler/rustc_codegen_cranelift/src/abi/mod.rs index a8b179f169bf6..0eb493036ce51 100644 --- a/compiler/rustc_codegen_cranelift/src/abi/mod.rs +++ b/compiler/rustc_codegen_cranelift/src/abi/mod.rs @@ -31,6 +31,11 @@ use crate::base::codegen_unwind_terminate; use crate::debuginfo::EXCEPTION_HANDLER_CLEANUP; use crate::prelude::*; +struct ArgValue<'tcx> { + value: CValue<'tcx>, + is_underaligned_pointee: bool, +} + fn clif_sig_from_fn_abi<'tcx>( tcx: TyCtxt<'tcx>, default_call_conv: CallConv, @@ -55,8 +60,9 @@ pub(crate) fn conv_to_call_conv( match c { CanonAbi::Rust | CanonAbi::RustCold | CanonAbi::C => default_call_conv, - // Cranelift doesn't currently have anything for this. - CanonAbi::RustPreserveNone => default_call_conv, + CanonAbi::RustPreserveNone | CanonAbi::RustTail => { + sess.dcx().fatal(format!("call conv {c:?} is LLVM-specific")) + } // Functions with this calling convention can only be called from assembly, but it is // possible to declare an `extern "custom"` block, so the backend still needs a calling @@ -71,7 +77,7 @@ pub(crate) fn conv_to_call_conv( }, CanonAbi::Interrupt(_) | CanonAbi::Arm(_) | CanonAbi::Swift => { - sess.dcx().fatal("call conv {c:?} is not yet implemented") + sess.dcx().fatal(format!("call conv {c:?} is not yet implemented")) } CanonAbi::GpuKernel => { unreachable!("tried to use {c:?} call conv which only exists on an unsupported target") @@ -245,8 +251,8 @@ pub(crate) fn codegen_fn_prelude<'tcx>(fx: &mut FunctionCx<'_, '_, 'tcx>, start_ // None means pass_mode == NoPass enum ArgKind<'tcx> { - Normal(Option>), - Spread(Vec>>), + Normal(Option>), + Spread(Vec>>), } // FIXME implement variadics in cranelift @@ -299,8 +305,12 @@ pub(crate) fn codegen_fn_prelude<'tcx>(fx: &mut FunctionCx<'_, '_, 'tcx>, start_ if fx.instance.def.requires_caller_location(fx.tcx) { // Store caller location for `#[track_caller]`. let arg_abi = arg_abis_iter.next().unwrap(); - fx.caller_location = - Some(cvalue_for_param(fx, None, None, arg_abi, &mut block_params_iter).unwrap()); + let param = cvalue_for_param(fx, None, None, arg_abi, &mut block_params_iter).unwrap(); + assert!( + !param.is_underaligned_pointee, + "caller location argument should not be underaligned", + ); + fx.caller_location = Some(param.value); } assert_eq!(arg_abis_iter.next(), None, "ArgAbi left behind for {:?}", fx.fn_abi); @@ -311,23 +321,24 @@ pub(crate) fn codegen_fn_prelude<'tcx>(fx: &mut FunctionCx<'_, '_, 'tcx>, start_ for (local, arg_kind, ty) in func_params { // While this is normally an optimization to prevent an unnecessary copy when an argument is // not mutated by the current function, this is necessary to support unsized arguments. - if let ArgKind::Normal(Some(val)) = arg_kind { - if let Some((addr, meta)) = val.try_to_ptr() { - // Ownership of the value at the backing storage for an argument is passed to the - // callee per the ABI, so it is fine to borrow the backing storage of this argument - // to prevent a copy. - - let place = if let Some(meta) = meta { - CPlace::for_ptr_with_extra(addr, meta, val.layout()) - } else { - CPlace::for_ptr(addr, val.layout()) - }; + if let ArgKind::Normal(Some(ArgValue { value: val, is_underaligned_pointee: false })) = + arg_kind + && let Some((addr, meta)) = val.try_to_ptr() + { + // Ownership of the value at the backing storage for an argument is passed to the + // callee per the ABI, so it is fine to borrow the backing storage of this argument + // to prevent a copy. + + let place = if let Some(meta) = meta { + CPlace::for_ptr_with_extra(addr, meta, val.layout()) + } else { + CPlace::for_ptr(addr, val.layout()) + }; - self::comments::add_local_place_comments(fx, place, local); + self::comments::add_local_place_comments(fx, place, local); - assert_eq!(fx.local_map.push(place), local); - continue; - } + assert_eq!(fx.local_map.push(place), local); + continue; } let layout = fx.layout_of(ty); @@ -338,13 +349,22 @@ pub(crate) fn codegen_fn_prelude<'tcx>(fx: &mut FunctionCx<'_, '_, 'tcx>, start_ match arg_kind { ArgKind::Normal(param) => { if let Some(param) = param { - place.write_cvalue(fx, param); + if param.is_underaligned_pointee { + place.write_cvalue_transmute(fx, param.value); + } else { + place.write_cvalue(fx, param.value); + } } } ArgKind::Spread(params) => { for (i, param) in params.into_iter().enumerate() { if let Some(param) = param { - place.place_field(fx, FieldIdx::new(i)).write_cvalue(fx, param); + let field_place = place.place_field(fx, FieldIdx::new(i)); + if param.is_underaligned_pointee { + field_place.write_cvalue_transmute(fx, param.value); + } else { + field_place.write_cvalue(fx, param.value); + } } } } diff --git a/compiler/rustc_codegen_cranelift/src/abi/pass_mode.rs b/compiler/rustc_codegen_cranelift/src/abi/pass_mode.rs index edbee60471830..612f89e6a4217 100644 --- a/compiler/rustc_codegen_cranelift/src/abi/pass_mode.rs +++ b/compiler/rustc_codegen_cranelift/src/abi/pass_mode.rs @@ -7,6 +7,7 @@ use rustc_target::callconv::{ }; use smallvec::{SmallVec, smallvec}; +use super::ArgValue; use crate::prelude::*; use crate::value_and_place::assert_assignable; @@ -285,7 +286,7 @@ pub(super) fn cvalue_for_param<'tcx>( local_field: Option, arg_abi: &ArgAbi<'tcx, Ty<'tcx>>, block_params_iter: &mut impl Iterator, -) -> Option> { +) -> Option> { let block_params = arg_abi .get_abi_param(fx.tcx) .into_iter() @@ -306,30 +307,42 @@ pub(super) fn cvalue_for_param<'tcx>( arg_abi.layout, ); - match arg_abi.mode { - PassMode::Ignore => None, + let value = match arg_abi.mode { + PassMode::Ignore => return None, PassMode::Direct(_) => { assert_eq!(block_params.len(), 1, "{:?}", block_params); - Some(CValue::by_val(block_params[0], arg_abi.layout)) + CValue::by_val(block_params[0], arg_abi.layout) } PassMode::Pair(_, _) => { assert_eq!(block_params.len(), 2, "{:?}", block_params); - Some(CValue::by_val_pair(block_params[0], block_params[1], arg_abi.layout)) + CValue::by_val_pair(block_params[0], block_params[1], arg_abi.layout) } PassMode::Cast { ref cast, .. } => { - Some(from_casted_value(fx, &block_params, arg_abi.layout, cast)) + from_casted_value(fx, &block_params, arg_abi.layout, cast) } - PassMode::Indirect { attrs: _, meta_attrs: None, on_stack: _ } => { + PassMode::Indirect { attrs, meta_attrs: None, on_stack: _ } => { assert_eq!(block_params.len(), 1, "{:?}", block_params); - Some(CValue::by_ref(Pointer::new(block_params[0]), arg_abi.layout)) + if let Some(pointee_align) = attrs.pointee_align + && pointee_align < arg_abi.layout.align.abi + && arg_abi.layout.is_sized() + && arg_abi.layout.size != Size::ZERO + { + // Underaligned pointer: treat as `[u8; size]` and transmute-copy into the real type. + let bytes_ty = Ty::new_array(fx.tcx, fx.tcx.types.u8, arg_abi.layout.size.bytes()); + let bytes_layout = fx.layout_of(bytes_ty); + return Some(ArgValue { + value: CValue::by_ref(Pointer::new(block_params[0]), bytes_layout), + is_underaligned_pointee: true, + }); + } else { + CValue::by_ref(Pointer::new(block_params[0]), arg_abi.layout) + } } PassMode::Indirect { attrs: _, meta_attrs: Some(_), on_stack: _ } => { assert_eq!(block_params.len(), 2, "{:?}", block_params); - Some(CValue::by_ref_unsized( - Pointer::new(block_params[0]), - block_params[1], - arg_abi.layout, - )) + CValue::by_ref_unsized(Pointer::new(block_params[0]), block_params[1], arg_abi.layout) } - } + }; + + Some(ArgValue { value, is_underaligned_pointee: false }) } diff --git a/compiler/rustc_codegen_cranelift/src/allocator.rs b/compiler/rustc_codegen_cranelift/src/allocator.rs index 4a9b0c0952ff3..3c18748ee24b4 100644 --- a/compiler/rustc_codegen_cranelift/src/allocator.rs +++ b/compiler/rustc_codegen_cranelift/src/allocator.rs @@ -5,20 +5,11 @@ use cranelift_frontend::{FunctionBuilder, FunctionBuilderContext}; use rustc_ast::expand::allocator::{ AllocatorMethod, AllocatorTy, NO_ALLOC_SHIM_IS_UNSTABLE, default_fn_name, global_fn_name, }; -use rustc_codegen_ssa::base::{allocator_kind_for_codegen, allocator_shim_contents}; use rustc_symbol_mangling::mangle_internal_symbol; use crate::prelude::*; -/// Returns whether an allocator shim was created -pub(crate) fn codegen(tcx: TyCtxt<'_>, module: &mut dyn Module) -> bool { - let Some(kind) = allocator_kind_for_codegen(tcx) else { return false }; - let methods = allocator_shim_contents(tcx, kind); - codegen_inner(tcx, module, &methods); - true -} - -fn codegen_inner(tcx: TyCtxt<'_>, module: &mut dyn Module, methods: &[AllocatorMethod]) { +pub(crate) fn codegen(tcx: TyCtxt<'_>, module: &mut dyn Module, methods: &[AllocatorMethod]) { let usize_ty = module.target_config().pointer_type(); for method in methods { diff --git a/compiler/rustc_codegen_cranelift/src/analyze.rs b/compiler/rustc_codegen_cranelift/src/analyze.rs index 72380f50385a1..c4a31cabcf385 100644 --- a/compiler/rustc_codegen_cranelift/src/analyze.rs +++ b/compiler/rustc_codegen_cranelift/src/analyze.rs @@ -23,14 +23,10 @@ pub(crate) fn analyze(fx: &FunctionCx<'_, '_, '_>) -> IndexVec { for bb in fx.mir.basic_blocks.iter() { for stmt in bb.statements.iter() { - match &stmt.kind { - Assign(place_and_rval) => match &place_and_rval.1 { - Rvalue::Ref(_, _, place) | Rvalue::RawPtr(_, place) => { - flag_map[place.local] = SsaKind::NotSsa; - } - _ => {} - }, - _ => {} + if let Assign(place_and_rval) = &stmt.kind + && let Rvalue::Ref(_, _, place) | Rvalue::RawPtr(_, place) = &place_and_rval.1 + { + flag_map[place.local] = SsaKind::NotSsa; } } } diff --git a/compiler/rustc_codegen_cranelift/src/base.rs b/compiler/rustc_codegen_cranelift/src/base.rs index 2edbdb560f52b..467eceea221c8 100644 --- a/compiler/rustc_codegen_cranelift/src/base.rs +++ b/compiler/rustc_codegen_cranelift/src/base.rs @@ -147,7 +147,7 @@ pub(crate) fn codegen_fn<'tcx>( } pub(crate) fn compile_fn( - profiler: &SelfProfilerRef, + prof: &SelfProfilerRef, output_filenames: &OutputFilenames, should_write_ir: bool, cached_context: &mut Context, @@ -156,8 +156,7 @@ pub(crate) fn compile_fn( global_asm: &mut String, codegened_func: CodegenedFunction, ) { - let _timer = - profiler.generic_activity_with_arg("compile function", &*codegened_func.symbol_name); + let _timer = prof.generic_activity_with_arg("compile function", &*codegened_func.symbol_name); let clif_comments = codegened_func.clif_comments; global_asm.push_str(&codegened_func.inline_asm); @@ -196,7 +195,7 @@ pub(crate) fn compile_fn( }; // Define function - profiler.generic_activity("define function").run(|| { + prof.generic_activity("define function").run(|| { context.want_disasm = should_write_ir; match module.define_function(codegened_func.func_id, context) { Ok(()) => {} @@ -248,7 +247,7 @@ pub(crate) fn compile_fn( } // Define debuginfo for function - profiler.generic_activity("generate debug info").run(|| { + prof.generic_activity("generate debug info").run(|| { if let Some(debug_context) = debug_context { codegened_func.func_debug_cx.unwrap().finalize( debug_context, @@ -1052,7 +1051,7 @@ pub(crate) fn codegen_operand<'tcx>( Operand::RuntimeChecks(checks) => { let val = checks.value(fx.tcx.sess); let layout = fx.layout_of(fx.tcx.types.bool); - return CValue::const_val(fx, layout, val.into()); + CValue::const_val(fx, layout, val.into()) } } } diff --git a/compiler/rustc_codegen_cranelift/src/concurrency_limiter.rs b/compiler/rustc_codegen_cranelift/src/concurrency_limiter.rs deleted file mode 100644 index b5a81fc11d57b..0000000000000 --- a/compiler/rustc_codegen_cranelift/src/concurrency_limiter.rs +++ /dev/null @@ -1,205 +0,0 @@ -use std::sync::{Arc, Condvar, Mutex}; - -use rustc_data_structures::jobserver::{self, HelperThread}; -use rustc_errors::DiagCtxtHandle; - -// FIXME don't panic when a worker thread panics - -pub(super) struct ConcurrencyLimiter { - helper_thread: Option>, - state: Arc>, - available_token_condvar: Arc, - finished: bool, -} - -impl ConcurrencyLimiter { - pub(super) fn new(pending_jobs: usize) -> Self { - let state = Arc::new(Mutex::new(state::ConcurrencyLimiterState::new(pending_jobs))); - let available_token_condvar = Arc::new(Condvar::new()); - - let state_helper = state.clone(); - let available_token_condvar_helper = available_token_condvar.clone(); - let helper_thread = jobserver::client() - .clone() - .into_helper_thread(move |token| { - let mut state = state_helper.lock().unwrap(); - match token { - Ok(token) => { - state.add_new_token(token); - available_token_condvar_helper.notify_one(); - } - Err(err) => { - state.poison(format!("failed to acquire jobserver token: {}", err)); - // Notify all threads waiting for a token to give them a chance to - // gracefully exit. - available_token_condvar_helper.notify_all(); - } - } - }) - .unwrap(); - ConcurrencyLimiter { - helper_thread: Some(Mutex::new(helper_thread)), - state, - available_token_condvar, - finished: false, - } - } - - pub(super) fn acquire(&self, dcx: DiagCtxtHandle<'_>) -> ConcurrencyLimiterToken { - let mut state = self.state.lock().unwrap(); - loop { - state.assert_invariants(); - - match state.try_start_job() { - Ok(true) => { - return ConcurrencyLimiterToken { - state: self.state.clone(), - available_token_condvar: self.available_token_condvar.clone(), - }; - } - Ok(false) => {} - Err(err) => { - // An error happened when acquiring the token. Raise it as fatal error. - // Make sure to drop the mutex guard first to prevent poisoning the mutex. - drop(state); - if let Some(err) = err { - dcx.fatal(err); - } else { - // The error was already emitted, but compilation continued. Raise a silent - // fatal error. - rustc_errors::FatalError.raise(); - } - } - } - - self.helper_thread.as_ref().unwrap().lock().unwrap().request_token(); - state = self.available_token_condvar.wait(state).unwrap(); - } - } - - pub(crate) fn finished(mut self) { - self.helper_thread.take(); - - // Assert that all jobs have finished - let state = Mutex::get_mut(Arc::get_mut(&mut self.state).unwrap()).unwrap(); - state.assert_done(); - - self.finished = true; - } -} - -impl Drop for ConcurrencyLimiter { - fn drop(&mut self) { - if !self.finished && !std::thread::panicking() { - panic!("Forgot to call finished() on ConcurrencyLimiter"); - } - } -} - -#[derive(Debug)] -pub(super) struct ConcurrencyLimiterToken { - state: Arc>, - available_token_condvar: Arc, -} - -impl Drop for ConcurrencyLimiterToken { - fn drop(&mut self) { - let mut state = self.state.lock().unwrap(); - state.job_finished(); - self.available_token_condvar.notify_one(); - } -} - -mod state { - use rustc_data_structures::jobserver::Acquired; - - #[derive(Debug)] - pub(super) struct ConcurrencyLimiterState { - pending_jobs: usize, - active_jobs: usize, - - poisoned: bool, - stored_error: Option, - - // None is used to represent the implicit token, Some to represent explicit tokens - tokens: Vec>, - } - - impl ConcurrencyLimiterState { - pub(super) fn new(pending_jobs: usize) -> Self { - ConcurrencyLimiterState { - pending_jobs, - active_jobs: 0, - poisoned: false, - stored_error: None, - tokens: vec![None], - } - } - - pub(super) fn assert_invariants(&self) { - // There must be no excess active jobs - assert!(self.active_jobs <= self.pending_jobs); - - // There may not be more active jobs than there are tokens - assert!(self.active_jobs <= self.tokens.len()); - } - - pub(super) fn assert_done(&self) { - assert_eq!(self.pending_jobs, 0); - assert_eq!(self.active_jobs, 0); - } - - pub(super) fn add_new_token(&mut self, token: Acquired) { - self.tokens.push(Some(token)); - self.drop_excess_capacity(); - } - - pub(super) fn try_start_job(&mut self) -> Result> { - if self.poisoned { - return Err(self.stored_error.take()); - } - - if self.active_jobs < self.tokens.len() { - // Using existing token - self.job_started(); - return Ok(true); - } - - Ok(false) - } - - pub(super) fn job_started(&mut self) { - self.assert_invariants(); - self.active_jobs += 1; - self.drop_excess_capacity(); - self.assert_invariants(); - } - - pub(super) fn job_finished(&mut self) { - self.assert_invariants(); - self.pending_jobs -= 1; - self.active_jobs -= 1; - self.assert_invariants(); - self.drop_excess_capacity(); - self.assert_invariants(); - } - - pub(super) fn poison(&mut self, error: String) { - self.poisoned = true; - self.stored_error = Some(error); - } - - fn drop_excess_capacity(&mut self) { - self.assert_invariants(); - - // Drop all tokens that can never be used anymore - self.tokens.truncate(std::cmp::max(self.pending_jobs, 1)); - - // Keep some excess tokens to satisfy requests faster - const MAX_EXTRA_CAPACITY: usize = 2; - self.tokens.truncate(std::cmp::max(self.active_jobs + MAX_EXTRA_CAPACITY, 1)); - - self.assert_invariants(); - } - } -} diff --git a/compiler/rustc_codegen_cranelift/src/constant.rs b/compiler/rustc_codegen_cranelift/src/constant.rs index f85d21db11fb2..c986666f9c46e 100644 --- a/compiler/rustc_codegen_cranelift/src/constant.rs +++ b/compiler/rustc_codegen_cranelift/src/constant.rs @@ -455,7 +455,8 @@ fn define_all_allocs(tcx: TyCtxt<'_>, module: &mut dyn Module, cx: &mut Constant } else { ("", section_name.as_str()) }; - data.set_segment_section(segment_name, section_name); + // FIXME pass correct section flags on Mach-O + data.set_segment_section(segment_name, section_name, 0); } let bytes = alloc.inspect_with_uninit_and_ptr_outside_interpreter(0..alloc.len()).to_vec(); diff --git a/compiler/rustc_codegen_cranelift/src/debuginfo/unwind.rs b/compiler/rustc_codegen_cranelift/src/debuginfo/unwind.rs index 1ce424332db20..4b0260a8abc74 100644 --- a/compiler/rustc_codegen_cranelift/src/debuginfo/unwind.rs +++ b/compiler/rustc_codegen_cranelift/src/debuginfo/unwind.rs @@ -204,7 +204,7 @@ impl UnwindContext { let mut data = DataDescription::new(); data.define(gcc_except_table.writer.into_vec().into_boxed_slice()); - data.set_segment_section("", ".gcc_except_table"); + data.set_segment_section("", ".gcc_except_table", 0); for reloc in &gcc_except_table.relocs { match reloc.name { diff --git a/compiler/rustc_codegen_cranelift/src/driver/aot.rs b/compiler/rustc_codegen_cranelift/src/driver/aot.rs index 323fec06bcc58..fcaf80d968a49 100644 --- a/compiler/rustc_codegen_cranelift/src/driver/aot.rs +++ b/compiler/rustc_codegen_cranelift/src/driver/aot.rs @@ -1,184 +1,103 @@ //! The AOT driver uses [`cranelift_object`] to write object files suitable for linking into a //! standalone executable. -use std::env; +use std::convert::Infallible; use std::fs::File; use std::io::BufWriter; use std::path::PathBuf; use std::sync::Arc; -use std::thread::JoinHandle; +use std::time::Instant; use cranelift_object::{ObjectBuilder, ObjectModule}; -use rustc_codegen_ssa::assert_module_sources::CguReuse; -use rustc_codegen_ssa::back::write::produce_final_output_artifacts; -use rustc_codegen_ssa::base::determine_cgu_reuse; -use rustc_codegen_ssa::{CompiledModule, CompiledModules, ModuleKind}; +use rustc_ast::expand::allocator::AllocatorMethod; +use rustc_codegen_ssa::back::lto::ThinModule; +use rustc_codegen_ssa::back::write::{ + CodegenContext, FatLtoInput, ModuleConfig, SharedEmitter, TargetMachineFactoryFn, ThinLtoInput, +}; +use rustc_codegen_ssa::traits::{ExtraBackendMethods, WriteBackendMethods}; +use rustc_codegen_ssa::{CompiledModule, ModuleCodegen, ModuleKind}; use rustc_data_structures::profiling::SelfProfilerRef; -use rustc_data_structures::stable_hash::{StableHash, StableHashCtxt, StableHasher}; -use rustc_data_structures::sync::{IntoDynSyncSend, par_map}; +use rustc_errors::DiagCtxt; use rustc_hir::attrs::Linkage as RLinkage; -use rustc_middle::dep_graph::{WorkProduct, WorkProductId}; +use rustc_middle::dep_graph::WorkProduct; use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags; -use rustc_middle::mono::{CodegenUnit, MonoItem, MonoItemData, Visibility}; +use rustc_middle::mono::{MonoItem, MonoItemData, Visibility}; use rustc_session::Session; -use rustc_session::config::{OutputFilenames, OutputType}; +use rustc_session::config::{OptLevel, OutputFilenames, OutputType}; +use rustc_span::Symbol; use crate::base::CodegenedFunction; -use crate::concurrency_limiter::{ConcurrencyLimiter, ConcurrencyLimiterToken}; use crate::debuginfo::TypeDebugContext; use crate::global_asm::{GlobalAsmConfig, GlobalAsmContext}; use crate::prelude::*; use crate::unwind_module::UnwindModule; -fn disable_incr_cache() -> bool { - env::var("CG_CLIF_DISABLE_INCR_CACHE").as_deref() == Ok("1") -} - -struct ModuleCodegenResult { - module: CompiledModule, - existing_work_product: Option<(WorkProductId, WorkProduct)>, -} - -enum OngoingModuleCodegen { - Sync(Result), - Async(JoinHandle>), -} - -impl StableHash for OngoingModuleCodegen { - fn stable_hash(&self, _: &mut Hcx, _: &mut StableHasher) { - // do nothing - } -} - -pub(crate) struct OngoingCodegen { - modules: Vec, - allocator_module: Option, - concurrency_limiter: ConcurrencyLimiter, -} - -impl OngoingCodegen { - pub(crate) fn join( - self, - sess: &Session, - outputs: &OutputFilenames, - ) -> (CompiledModules, FxIndexMap) { - let mut work_products = FxIndexMap::default(); - let mut modules = vec![]; - let disable_incr_cache = disable_incr_cache(); - - for module_codegen in self.modules { - let module_codegen_result = match module_codegen { - OngoingModuleCodegen::Sync(module_codegen_result) => module_codegen_result, - OngoingModuleCodegen::Async(join_handle) => match join_handle.join() { - Ok(module_codegen_result) => module_codegen_result, - Err(panic) => std::panic::resume_unwind(panic), - }, - }; - - let module_codegen_result = match module_codegen_result { - Ok(module_codegen_result) => module_codegen_result, - Err(err) => sess.dcx().fatal(err), - }; - let ModuleCodegenResult { module, existing_work_product } = module_codegen_result; - - if let Some((work_product_id, work_product)) = existing_work_product { - work_products.insert(work_product_id, work_product); - } else { - let work_product = if disable_incr_cache { - None - } else if let Some(global_asm_object) = &module.global_asm_object { - rustc_incremental::copy_cgu_workproduct_to_incr_comp_cache_dir( - sess, - &module.name, - &[("o", module.object.as_ref().unwrap()), ("asm.o", global_asm_object)], - &[], - ) - } else { - rustc_incremental::copy_cgu_workproduct_to_incr_comp_cache_dir( - sess, - &module.name, - &[("o", module.object.as_ref().unwrap())], - &[], - ) - }; - if let Some((work_product_id, work_product)) = work_product { - work_products.insert(work_product_id, work_product); - } - } - - modules.push(module); - } - - self.concurrency_limiter.finished(); - - sess.dcx().abort_if_errors(); - - let compiled_modules = CompiledModules { modules, allocator_module: self.allocator_module }; - - produce_final_output_artifacts(sess, &compiled_modules, outputs); - - (compiled_modules, work_products) - } +pub(crate) struct AotModule { + producer: String, + global_asm_config: GlobalAsmConfig, + module: UnwindModule, + debug_context: Option, + codegened_functions: Vec, + global_asm: String, } -fn make_module(sess: &Session, name: String) -> UnwindModule { - let isa = crate::build_isa(sess, false); +fn make_module(tcx: TyCtxt<'_>, cgu_name: &str) -> AotModule { + let isa = crate::build_isa(tcx.sess, false); - let mut builder = - ObjectBuilder::new(isa, name + ".o", cranelift_module::default_libcall_names()).unwrap(); + let mut builder = ObjectBuilder::new( + isa, + cgu_name.to_owned() + ".o", + cranelift_module::default_libcall_names(), + ) + .unwrap(); // Disable function sections by default on MSVC as it causes significant slowdowns with link.exe. // Maybe link.exe has exponential behavior when there are many sections with the same name? Also // explicitly disable it on MinGW as rustc already disables it by default on MinGW and as such // isn't tested. If rustc enables it in the future on MinGW, we can re-enable it too once it has // been on MinGW. - let default_function_sections = sess.target.function_sections && !sess.target.is_like_windows; + let default_function_sections = + tcx.sess.target.function_sections && !tcx.sess.target.is_like_windows; builder.per_function_section( - sess.opts.unstable_opts.function_sections.unwrap_or(default_function_sections), + tcx.sess.opts.unstable_opts.function_sections.unwrap_or(default_function_sections), ); - UnwindModule::new(ObjectModule::new(builder), true) -} + let module = UnwindModule::new(ObjectModule::new(builder), true); -fn emit_cgu( - output_filenames: &OutputFilenames, - prof: &SelfProfilerRef, - name: String, - module: UnwindModule, - debug: Option, - global_asm_object_file: Option, - producer: &str, -) -> Result { - let mut product = module.finish(); - - if let Some(mut debug) = debug { - debug.emit(&mut product); - } + let producer = crate::debuginfo::producer(tcx.sess); + let global_asm_config = GlobalAsmConfig::new(tcx.sess); + let debug_context = DebugContext::new(tcx, module.isa(), false, cgu_name); + let codegened_functions = vec![]; + let global_asm = String::new(); - let module = emit_module( - output_filenames, - prof, - product.object, - ModuleKind::Regular, - name.clone(), - global_asm_object_file, + AotModule { producer, - )?; - - Ok(ModuleCodegenResult { module, existing_work_product: None }) + global_asm_config, + module, + debug_context, + codegened_functions, + global_asm, + } } fn emit_module( output_filenames: &OutputFilenames, prof: &SelfProfilerRef, - mut object: cranelift_object::object::write::Object<'_>, + module: UnwindModule, + debug: Option, kind: ModuleKind, name: String, global_asm_object: Option, producer_str: &str, ) -> Result { - if object.format() == cranelift_object::object::BinaryFormat::Elf { - let comment_section = object.add_section( + let mut product = module.finish(); + + if let Some(mut debug) = debug { + debug.emit(&mut product); + } + + if product.object.format() == cranelift_object::object::BinaryFormat::Elf { + let comment_section = product.object.add_section( Vec::new(), b".comment".to_vec(), cranelift_object::object::SectionKind::OtherString, @@ -186,7 +105,7 @@ fn emit_module( let mut producer = vec![0]; producer.extend(producer_str.as_bytes()); producer.push(0); - object.set_section_data(comment_section, producer, 1); + product.object.set_section_data(comment_section, producer, 1); } let tmp_file = output_filenames.temp_path_for_cgu(OutputType::Object, &name); @@ -196,7 +115,7 @@ fn emit_module( }; let mut file = BufWriter::new(file); - if let Err(err) = object.write_stream(&mut file) { + if let Err(err) = product.object.write_stream(&mut file) { return Err(format!("error writing object file: {}", err)); } let file = match file.into_inner() { @@ -225,87 +144,22 @@ fn emit_module( }) } -fn reuse_workproduct_for_cgu( - tcx: TyCtxt<'_>, - cgu: &CodegenUnit<'_>, -) -> Result { - let work_product = cgu.previous_work_product(tcx); - let obj_out_regular = - tcx.output_filenames(()).temp_path_for_cgu(OutputType::Object, cgu.name().as_str()); - let source_file_regular = rustc_incremental::in_incr_comp_dir_sess( - tcx.sess, - work_product.saved_files.get("o").expect("no saved object file in work product"), - ); - - if let Err(err) = rustc_fs_util::link_or_copy(&source_file_regular, &obj_out_regular) { - return Err(format!( - "unable to copy {} to {}: {}", - source_file_regular.display(), - obj_out_regular.display(), - err - )); - } - - let obj_out_global_asm = - tcx.output_filenames(()).temp_path_ext_for_cgu("asm.o", cgu.name().as_str()); - let source_file_global_asm = if let Some(asm_o) = work_product.saved_files.get("asm.o") { - let source_file_global_asm = rustc_incremental::in_incr_comp_dir_sess(tcx.sess, asm_o); - if let Err(err) = rustc_fs_util::link_or_copy(&source_file_global_asm, &obj_out_global_asm) - { - return Err(format!( - "unable to copy {} to {}: {}", - source_file_global_asm.display(), - obj_out_global_asm.display(), - err - )); - } - Some(source_file_global_asm) - } else { - None - }; - - Ok(ModuleCodegenResult { - module: CompiledModule { - name: cgu.name().to_string(), - kind: ModuleKind::Regular, - object: Some(obj_out_regular), - global_asm_object: source_file_global_asm.as_ref().map(|_| obj_out_global_asm), - dwarf_object: None, - bytecode: None, - assembly: None, - llvm_ir: None, - links_from_incr_cache: if let Some(source_file_global_asm) = source_file_global_asm { - vec![source_file_regular, source_file_global_asm] - } else { - vec![source_file_regular] - }, - }, - existing_work_product: Some((cgu.work_product_id(), work_product)), - }) -} - -fn codegen_cgu_content( - tcx: TyCtxt<'_>, - module: &mut dyn Module, - cgu_name: rustc_span::Symbol, -) -> (Option, Vec, String) { +fn codegen_cgu(tcx: TyCtxt<'_>, cgu_name: Symbol) -> AotModule { let _timer = tcx.prof.generic_activity_with_arg("codegen cgu", cgu_name.as_str()); let cgu = tcx.codegen_unit(cgu_name); let mono_items = cgu.items_in_deterministic_order(tcx); - let mut debug_context = DebugContext::new(tcx, module.isa(), false, cgu_name.as_str()); - let mut global_asm = String::new(); + let mut module = make_module(tcx, cgu_name.as_str()); let mut type_dbg = TypeDebugContext::default(); - super::predefine_mono_items(tcx, module, &mono_items); - let mut codegened_functions = vec![]; + super::predefine_mono_items(tcx, &mut module.module, &mono_items); for (mono_item, item_data) in mono_items { match mono_item { MonoItem::Fn(instance) => { let flags = tcx.codegen_instance_attrs(instance.def).flags; if flags.contains(CodegenFnAttrFlags::NAKED) { rustc_codegen_ssa::mir::naked_asm::codegen_naked_asm( - &mut GlobalAsmContext { tcx, global_asm: &mut global_asm }, + &mut GlobalAsmContext { tcx, global_asm: &mut module.global_asm }, instance, MonoItemData { linkage: RLinkage::External, @@ -321,186 +175,219 @@ fn codegen_cgu_content( } let codegened_function = crate::base::codegen_fn( tcx, - cgu_name, - debug_context.as_mut(), + cgu.name(), + module.debug_context.as_mut(), &mut type_dbg, Function::new(), - module, + &mut module.module, instance, ); - codegened_functions.push(codegened_function); + module.codegened_functions.push(codegened_function); } MonoItem::Static(def_id) => { - let data_id = crate::constant::codegen_static(tcx, module, def_id); - if let Some(debug_context) = debug_context.as_mut() { + let data_id = crate::constant::codegen_static(tcx, &mut module.module, def_id); + if let Some(debug_context) = module.debug_context.as_mut() { debug_context.define_static(tcx, &mut type_dbg, def_id, data_id); } } MonoItem::GlobalAsm(item_id) => { rustc_codegen_ssa::base::codegen_global_asm( - &mut GlobalAsmContext { tcx, global_asm: &mut global_asm }, + &mut GlobalAsmContext { tcx, global_asm: &mut module.global_asm }, item_id, ); } } } - crate::main_shim::maybe_create_entry_wrapper(tcx, module, false, cgu.is_primary()); + crate::main_shim::maybe_create_entry_wrapper(tcx, &mut module.module, false, cgu.is_primary()); - (debug_context, codegened_functions, global_asm) + module } -fn module_codegen( - tcx: TyCtxt<'_>, - global_asm_config: Arc, - cgu_name: rustc_span::Symbol, - token: ConcurrencyLimiterToken, -) -> OngoingModuleCodegen { - let mut module = make_module(tcx.sess, cgu_name.as_str().to_string()); +fn compile_cgu( + prof: &SelfProfilerRef, + output_filenames: &OutputFilenames, + should_write_ir: bool, + mut aot_module: AotModule, + cgu_name: String, + kind: ModuleKind, +) -> Result { + prof.generic_activity_with_arg("compile functions", &*cgu_name).run(|| { + cranelift_codegen::timing::set_thread_profiler(Box::new(super::MeasuremeProfiler( + prof.clone(), + ))); + + let mut cached_context = Context::new(); + for codegened_func in aot_module.codegened_functions { + crate::base::compile_fn( + &prof, + &output_filenames, + should_write_ir, + &mut cached_context, + &mut aot_module.module, + aot_module.debug_context.as_mut(), + &mut aot_module.global_asm, + codegened_func, + ); + } + }); - let (mut debug_context, codegened_functions, mut global_asm) = - codegen_cgu_content(tcx, &mut module, cgu_name); + let global_asm_object_file = + prof.generic_activity_with_arg("compile assembly", &*cgu_name).run(|| { + if aot_module.global_asm.is_empty() { + return Ok::<_, String>(None); + } - let cgu_name = cgu_name.as_str().to_owned(); + let global_asm_object_file = output_filenames.temp_path_ext_for_cgu("asm.o", &cgu_name); + crate::global_asm::compile_global_asm( + &aot_module.global_asm_config, + aot_module.global_asm, + &global_asm_object_file, + )?; + + Ok(Some(global_asm_object_file)) + })?; + + prof.generic_activity_with_arg("write object file", &*cgu_name).run(|| { + emit_module( + output_filenames, + prof, + aot_module.module, + aot_module.debug_context, + kind, + cgu_name.clone(), + global_asm_object_file, + &aot_module.producer, + ) + }) +} - let producer = crate::debuginfo::producer(tcx.sess); +#[derive(Copy, Clone)] +pub(crate) struct AotDriver; + +impl ExtraBackendMethods for AotDriver { + type Module = AotModule; + + fn codegen_allocator<'tcx>( + &self, + tcx: TyCtxt<'tcx>, + module_name: &str, + methods: &[AllocatorMethod], + ) -> Self::Module { + let mut allocator_module = make_module(tcx, module_name); + crate::allocator::codegen(tcx, &mut allocator_module.module, methods); + allocator_module + } - let profiler = tcx.prof.clone(); - let output_filenames = tcx.output_filenames(()).clone(); - let should_write_ir = crate::pretty_clif::should_write_ir(tcx.sess); - - OngoingModuleCodegen::Async(std::thread::spawn(move || { - profiler.clone().generic_activity_with_arg("compile functions", &*cgu_name).run(|| { - cranelift_codegen::timing::set_thread_profiler(Box::new(super::MeasuremeProfiler( - profiler.clone(), - ))); - - let mut cached_context = Context::new(); - for codegened_func in codegened_functions { - crate::base::compile_fn( - &profiler, - &output_filenames, - should_write_ir, - &mut cached_context, - &mut module, - debug_context.as_mut(), - &mut global_asm, - codegened_func, - ); - } - }); - - let global_asm_object_file = - profiler.generic_activity_with_arg("compile assembly", &*cgu_name).run(|| { - crate::global_asm::compile_global_asm(&global_asm_config, &cgu_name, global_asm) - })?; - - let codegen_result = - profiler.generic_activity_with_arg("write object file", &*cgu_name).run(|| { - emit_cgu( - &global_asm_config.output_filenames, - &profiler, - cgu_name, - module, - debug_context, - global_asm_object_file, - &producer, - ) - }); - std::mem::drop(token); - codegen_result - })) -} + fn compile_codegen_unit( + &self, + tcx: TyCtxt<'_>, + cgu_name: Symbol, + ) -> (ModuleCodegen, u64) { + let start_time = Instant::now(); + + let dep_node = tcx.codegen_unit(cgu_name).codegen_dep_node(tcx); + let (module, _) = tcx.dep_graph.with_task( + dep_node, + tcx, + || { + let aot_module = codegen_cgu(tcx, cgu_name); + ModuleCodegen::new_regular(cgu_name.as_str().to_owned(), aot_module) + }, + Some(rustc_middle::dep_graph::hash_result), + ); -fn emit_allocator_module(tcx: TyCtxt<'_>) -> Option { - let mut allocator_module = make_module(tcx.sess, "allocator_shim".to_string()); - let created_alloc_shim = crate::allocator::codegen(tcx, &mut allocator_module); - - if created_alloc_shim { - let product = allocator_module.finish(); - - match emit_module( - tcx.output_filenames(()), - &tcx.sess.prof, - product.object, - ModuleKind::Allocator, - "allocator_shim".to_owned(), - None, - &crate::debuginfo::producer(tcx.sess), - ) { - Ok(allocator_module) => Some(allocator_module), - Err(err) => tcx.dcx().fatal(err), - } - } else { - None + let time_to_codegen = start_time.elapsed(); + + // We assume that the cost to run LLVM on a CGU is proportional to + // the time we needed for codegenning it. + let cost = time_to_codegen.as_nanos() as u64; + + (module, cost) } } -pub(crate) fn run_aot(tcx: TyCtxt<'_>) -> Box { - let cgus = tcx.collect_and_partition_mono_items(()).codegen_units; +impl WriteBackendMethods for AotDriver { + type Module = AotModule; - if tcx.dep_graph.is_fully_enabled() { - for cgu in cgus { - tcx.ensure_ok().codegen_unit(cgu.name()); - } + type TargetMachine = (); + + type ModuleBuffer = Infallible; + + type ThinData = Infallible; + + fn target_machine_factory( + &self, + _sess: &Session, + _opt_level: OptLevel, + _target_features: &[String], + ) -> TargetMachineFactoryFn { + Arc::new(|_, _| ()) } - // Calculate the CGU reuse - let cgu_reuse = tcx.sess.time("find_cgu_reuse", || { - cgus.iter().map(|cgu| determine_cgu_reuse(tcx, cgu)).collect::>() - }); + fn optimize_and_codegen_fat_lto( + _sess: &Session, + _cgcx: &CodegenContext, + _shared_emitter: &SharedEmitter, + _tm_factory: TargetMachineFactoryFn, + _exported_symbols_for_lto: &[String], + _each_linked_rlib_for_lto: &[PathBuf], + _modules: Vec>, + ) -> CompiledModule { + unreachable!() + } - rustc_codegen_ssa::assert_module_sources::assert_module_sources(tcx, &|cgu_reuse_tracker| { - for (i, cgu) in cgus.iter().enumerate() { - let cgu_reuse = cgu_reuse[i]; - cgu_reuse_tracker.set_actual_reuse(cgu.name().as_str(), cgu_reuse); - } - }); + fn run_thin_lto( + _cgcx: &CodegenContext, + _prof: &SelfProfilerRef, + _dcx: rustc_errors::DiagCtxtHandle<'_>, + _exported_symbols_for_lto: &[String], + _each_linked_rlib_for_lto: &[PathBuf], + _modules: Vec>, + ) -> (Vec>, Vec) { + unreachable!() + } - let global_asm_config = Arc::new(crate::global_asm::GlobalAsmConfig::new(tcx)); + fn optimize( + _cgcx: &CodegenContext, + _prof: &SelfProfilerRef, + _shared_emitter: &SharedEmitter, + _module: &mut ModuleCodegen, + _config: &ModuleConfig, + ) { + } - let disable_incr_cache = disable_incr_cache(); - let (todo_cgus, done_cgus) = - cgus.iter().enumerate().partition::, _>(|&(i, _)| match cgu_reuse[i] { - _ if disable_incr_cache => true, - CguReuse::No => true, - CguReuse::PreLto | CguReuse::PostLto => false, - }); + fn optimize_and_codegen_thin( + _cgcx: &CodegenContext, + _prof: &SelfProfilerRef, + _shared_emitter: &SharedEmitter, + _tm_factory: TargetMachineFactoryFn, + _thin: ThinModule, + ) -> CompiledModule { + unreachable!() + } - let concurrency_limiter = IntoDynSyncSend(ConcurrencyLimiter::new(todo_cgus.len())); + fn codegen( + cgcx: &CodegenContext, + prof: &SelfProfilerRef, + shared_emitter: &SharedEmitter, + module: ModuleCodegen, + config: &ModuleConfig, + ) -> CompiledModule { + compile_cgu( + prof, + &cgcx.output_filenames, + config.emit_ir, + module.module_llvm, + module.name, + module.kind, + ) + .unwrap_or_else(|err| { + let dcx = DiagCtxt::new(Box::new(shared_emitter.clone())); + dcx.handle().fatal(err) + }) + } - let modules: Vec<_> = - tcx.sess.time("codegen mono items", || { - let modules: Vec<_> = par_map(todo_cgus, |(_, cgu)| { - let dep_node = cgu.codegen_dep_node(tcx); - let (module, _) = tcx.dep_graph.with_task( - dep_node, - tcx, - || { - module_codegen( - tcx, - global_asm_config.clone(), - cgu.name(), - concurrency_limiter.acquire(tcx.dcx()), - ) - }, - Some(rustc_middle::dep_graph::hash_result), - ); - IntoDynSyncSend(module) - }); - modules - .into_iter() - .map(|module| module.0) - .chain(done_cgus.into_iter().map(|(_, cgu)| { - OngoingModuleCodegen::Sync(reuse_workproduct_for_cgu(tcx, cgu)) - })) - .collect() - }); - - let allocator_module = emit_allocator_module(tcx); - - Box::new(OngoingCodegen { - modules, - allocator_module, - concurrency_limiter: concurrency_limiter.0, - }) + fn serialize_module(_module: Self::Module, _is_thin: bool) -> Self::ModuleBuffer { + unreachable!() + } } diff --git a/compiler/rustc_codegen_cranelift/src/driver/jit.rs b/compiler/rustc_codegen_cranelift/src/driver/jit.rs index 33b88d70d6f8d..7d6ece02e4a62 100644 --- a/compiler/rustc_codegen_cranelift/src/driver/jit.rs +++ b/compiler/rustc_codegen_cranelift/src/driver/jit.rs @@ -6,6 +6,7 @@ use std::os::raw::{c_char, c_int}; use cranelift_jit::{JITBuilder, JITModule}; use rustc_codegen_ssa::CrateInfo; +use rustc_codegen_ssa::base::{allocator_kind_for_codegen, allocator_shim_contents}; use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags; use rustc_middle::mono::MonoItem; use rustc_session::Session; @@ -28,7 +29,9 @@ fn create_jit_module( let cx = DebugContext::new(tcx, jit_module.isa(), false, "dummy_cgu_name"); - crate::allocator::codegen(tcx, &mut jit_module); + if let Some(kind) = allocator_kind_for_codegen(tcx) { + crate::allocator::codegen(tcx, &mut jit_module, &allocator_shim_contents(tcx, kind)); + } (jit_module, cx) } diff --git a/compiler/rustc_codegen_cranelift/src/global_asm.rs b/compiler/rustc_codegen_cranelift/src/global_asm.rs index ee7e6732e6a77..769c008c13f75 100644 --- a/compiler/rustc_codegen_cranelift/src/global_asm.rs +++ b/compiler/rustc_codegen_cranelift/src/global_asm.rs @@ -2,9 +2,8 @@ //! standalone executable. use std::io::Write; -use std::path::PathBuf; +use std::path::{Path, PathBuf}; use std::process::{Command, Stdio}; -use std::sync::Arc; use rustc_ast::{InlineAsmOptions, InlineAsmTemplatePiece}; use rustc_codegen_ssa::traits::{AsmCodegenMethods, GlobalAsmOperandRef}; @@ -12,7 +11,7 @@ use rustc_middle::ty::TyCtxt; use rustc_middle::ty::layout::{ FnAbiError, FnAbiOfHelpers, FnAbiRequest, HasTyCtxt, HasTypingEnv, LayoutError, LayoutOfHelpers, }; -use rustc_session::config::OutputFilenames; +use rustc_session::Session; use rustc_target::asm::InlineAsmArch; use crate::prelude::*; @@ -163,32 +162,28 @@ fn codegen_global_asm_inner<'tcx>( pub(crate) struct GlobalAsmConfig { assembler: PathBuf, target: String, - pub(crate) output_filenames: Arc, } impl GlobalAsmConfig { - pub(crate) fn new(tcx: TyCtxt<'_>) -> Self { + pub(crate) fn new(sess: &Session) -> Self { GlobalAsmConfig { - assembler: crate::toolchain::get_toolchain_binary(tcx.sess, "as"), - target: match &tcx.sess.opts.target_triple { + assembler: crate::toolchain::get_toolchain_binary(sess, "as"), + target: match &sess.opts.target_triple { rustc_target::spec::TargetTuple::TargetTuple(triple) => triple.clone(), rustc_target::spec::TargetTuple::TargetJson { path_for_rustdoc, .. } => { path_for_rustdoc.to_str().unwrap().to_owned() } }, - output_filenames: tcx.output_filenames(()).clone(), } } } pub(crate) fn compile_global_asm( config: &GlobalAsmConfig, - cgu_name: &str, global_asm: String, -) -> Result, String> { - if global_asm.is_empty() { - return Ok(None); - } + global_asm_object_file: &Path, +) -> Result<(), String> { + assert!(!global_asm.is_empty()); // Remove all LLVM style comments let mut global_asm = global_asm @@ -198,8 +193,6 @@ pub(crate) fn compile_global_asm( .join("\n"); global_asm.push('\n'); - let global_asm_object_file = config.output_filenames.temp_path_ext_for_cgu("asm.o", cgu_name); - // Assemble `global_asm` if option_env!("CG_CLIF_FORCE_GNU_AS").is_some() { let mut child = Command::new(&config.assembler) @@ -266,5 +259,5 @@ pub(crate) fn compile_global_asm( } } - Ok(Some(global_asm_object_file)) + Ok(()) } diff --git a/compiler/rustc_codegen_cranelift/src/inline_asm.rs b/compiler/rustc_codegen_cranelift/src/inline_asm.rs index 8100d565b3974..f9fc7002be87b 100644 --- a/compiler/rustc_codegen_cranelift/src/inline_asm.rs +++ b/compiler/rustc_codegen_cranelift/src/inline_asm.rs @@ -424,13 +424,10 @@ impl<'tcx> InlineAssemblyGenerator<'_, 'tcx> { // Allocate stack slots for inout for (i, operand) in self.operands.iter().enumerate() { - match *operand { - CInlineAsmOperand::InOut { reg, out_place: Some(_), .. } => { - let slot = new_slot(reg.reg_class()); - slots_input[i] = Some(slot); - slots_output[i] = Some(slot); - } - _ => (), + if let CInlineAsmOperand::InOut { reg, out_place: Some(_), .. } = *operand { + let slot = new_slot(reg.reg_class()); + slots_input[i] = Some(slot); + slots_output[i] = Some(slot); } } @@ -456,11 +453,8 @@ impl<'tcx> InlineAssemblyGenerator<'_, 'tcx> { // Allocate stack slots for output for (i, operand) in self.operands.iter().enumerate() { - match *operand { - CInlineAsmOperand::Out { reg, place: Some(_), .. } => { - slots_output[i] = Some(new_slot(reg.reg_class())); - } - _ => (), + if let CInlineAsmOperand::Out { reg, place: Some(_), .. } = *operand { + slots_output[i] = Some(new_slot(reg.reg_class())); } } diff --git a/compiler/rustc_codegen_cranelift/src/intrinsics/llvm_aarch64.rs b/compiler/rustc_codegen_cranelift/src/intrinsics/llvm_aarch64.rs index 3cd7ebb88f447..9da87a5774e8f 100644 --- a/compiler/rustc_codegen_cranelift/src/intrinsics/llvm_aarch64.rs +++ b/compiler/rustc_codegen_cranelift/src/intrinsics/llvm_aarch64.rs @@ -494,6 +494,385 @@ pub(super) fn codegen_aarch64_llvm_intrinsic_call<'tcx>( }); } */ + "llvm.aarch64.crc32b" + | "llvm.aarch64.crc32h" + | "llvm.aarch64.crc32w" + | "llvm.aarch64.crc32x" + | "llvm.aarch64.crc32cb" + | "llvm.aarch64.crc32ch" + | "llvm.aarch64.crc32cw" + | "llvm.aarch64.crc32cx" => { + // ARM ARM v8-A: CRC32{,C}{B,H,W,X}. + // Backs core::arch::aarch64::__crc32{,c}{b,h,w,d}. + intrinsic_args!(fx, args => (crc, v); intrinsic); + + let crc = crc.load_scalar(fx); + let v = v.load_scalar(fx); + + let asm = match intrinsic { + "llvm.aarch64.crc32b" => "crc32b w0, w0, w1", + "llvm.aarch64.crc32h" => "crc32h w0, w0, w1", + "llvm.aarch64.crc32w" => "crc32w w0, w0, w1", + "llvm.aarch64.crc32x" => "crc32x w0, w0, x1", + "llvm.aarch64.crc32cb" => "crc32cb w0, w0, w1", + "llvm.aarch64.crc32ch" => "crc32ch w0, w0, w1", + "llvm.aarch64.crc32cw" => "crc32cw w0, w0, w1", + "llvm.aarch64.crc32cx" => "crc32cx w0, w0, x1", + _ => unreachable!(), + }; + + codegen_inline_asm_inner( + fx, + &[InlineAsmTemplatePiece::String(asm.into())], + &[ + CInlineAsmOperand::InOut { + reg: InlineAsmRegOrRegClass::Reg(InlineAsmReg::AArch64( + AArch64InlineAsmReg::x0, + )), + _late: true, + in_value: crc, + out_place: Some(ret), + }, + CInlineAsmOperand::In { + reg: InlineAsmRegOrRegClass::Reg(InlineAsmReg::AArch64( + AArch64InlineAsmReg::x1, + )), + value: v, + }, + ], + InlineAsmOptions::NOSTACK | InlineAsmOptions::PURE | InlineAsmOptions::NOMEM, + ); + } + + "llvm.aarch64.crypto.aese" | "llvm.aarch64.crypto.aesd" => { + intrinsic_args!(fx, args => (a, b); intrinsic); + + let a = a.load_scalar(fx); + let b = b.load_scalar(fx); + + let asm = match intrinsic { + "llvm.aarch64.crypto.aese" => "aese v0.16b, v1.16b", + "llvm.aarch64.crypto.aesd" => "aesd v0.16b, v1.16b", + _ => unreachable!(), + }; + + codegen_inline_asm_inner( + fx, + &[InlineAsmTemplatePiece::String(asm.into())], + &[ + CInlineAsmOperand::InOut { + reg: InlineAsmRegOrRegClass::Reg(InlineAsmReg::AArch64( + AArch64InlineAsmReg::v0, + )), + _late: true, + in_value: a, + out_place: Some(ret), + }, + CInlineAsmOperand::In { + reg: InlineAsmRegOrRegClass::Reg(InlineAsmReg::AArch64( + AArch64InlineAsmReg::v1, + )), + value: b, + }, + ], + InlineAsmOptions::NOSTACK | InlineAsmOptions::PURE | InlineAsmOptions::NOMEM, + ); + } + + "llvm.aarch64.crypto.aesmc" | "llvm.aarch64.crypto.aesimc" => { + intrinsic_args!(fx, args => (a); intrinsic); + + let a = a.load_scalar(fx); + + let asm = match intrinsic { + "llvm.aarch64.crypto.aesmc" => "aesmc v0.16b, v0.16b", + "llvm.aarch64.crypto.aesimc" => "aesimc v0.16b, v0.16b", + _ => unreachable!(), + }; + + codegen_inline_asm_inner( + fx, + &[InlineAsmTemplatePiece::String(asm.into())], + &[CInlineAsmOperand::InOut { + reg: InlineAsmRegOrRegClass::Reg(InlineAsmReg::AArch64( + AArch64InlineAsmReg::v0, + )), + _late: true, + in_value: a, + out_place: Some(ret), + }], + InlineAsmOptions::NOSTACK | InlineAsmOptions::PURE | InlineAsmOptions::NOMEM, + ); + } + + "llvm.aarch64.crypto.sha256h" | "llvm.aarch64.crypto.sha256h2" => { + intrinsic_args!(fx, args => (a, b, c); intrinsic); + + let a = a.load_scalar(fx); + let b = b.load_scalar(fx); + let c = c.load_scalar(fx); + + let asm = match intrinsic { + "llvm.aarch64.crypto.sha256h" => "sha256h q0, q1, v2.4s", + "llvm.aarch64.crypto.sha256h2" => "sha256h2 q0, q1, v2.4s", + _ => unreachable!(), + }; + + codegen_inline_asm_inner( + fx, + &[InlineAsmTemplatePiece::String(asm.into())], + &[ + CInlineAsmOperand::InOut { + reg: InlineAsmRegOrRegClass::Reg(InlineAsmReg::AArch64( + AArch64InlineAsmReg::v0, + )), + _late: true, + in_value: a, + out_place: Some(ret), + }, + CInlineAsmOperand::In { + reg: InlineAsmRegOrRegClass::Reg(InlineAsmReg::AArch64( + AArch64InlineAsmReg::v1, + )), + value: b, + }, + CInlineAsmOperand::In { + reg: InlineAsmRegOrRegClass::Reg(InlineAsmReg::AArch64( + AArch64InlineAsmReg::v2, + )), + value: c, + }, + ], + InlineAsmOptions::NOSTACK | InlineAsmOptions::PURE | InlineAsmOptions::NOMEM, + ); + } + + "llvm.aarch64.crypto.sha256su0" => { + intrinsic_args!(fx, args => (a, b); intrinsic); + + let a = a.load_scalar(fx); + let b = b.load_scalar(fx); + + codegen_inline_asm_inner( + fx, + &[InlineAsmTemplatePiece::String("sha256su0 v0.4s, v1.4s".into())], + &[ + CInlineAsmOperand::InOut { + reg: InlineAsmRegOrRegClass::Reg(InlineAsmReg::AArch64( + AArch64InlineAsmReg::v0, + )), + _late: true, + in_value: a, + out_place: Some(ret), + }, + CInlineAsmOperand::In { + reg: InlineAsmRegOrRegClass::Reg(InlineAsmReg::AArch64( + AArch64InlineAsmReg::v1, + )), + value: b, + }, + ], + InlineAsmOptions::NOSTACK | InlineAsmOptions::PURE | InlineAsmOptions::NOMEM, + ); + } + + "llvm.aarch64.crypto.sha256su1" => { + intrinsic_args!(fx, args => (a, b, c); intrinsic); + + let a = a.load_scalar(fx); + let b = b.load_scalar(fx); + let c = c.load_scalar(fx); + + codegen_inline_asm_inner( + fx, + &[InlineAsmTemplatePiece::String("sha256su1 v0.4s, v1.4s, v2.4s".into())], + &[ + CInlineAsmOperand::InOut { + reg: InlineAsmRegOrRegClass::Reg(InlineAsmReg::AArch64( + AArch64InlineAsmReg::v0, + )), + _late: true, + in_value: a, + out_place: Some(ret), + }, + CInlineAsmOperand::In { + reg: InlineAsmRegOrRegClass::Reg(InlineAsmReg::AArch64( + AArch64InlineAsmReg::v1, + )), + value: b, + }, + CInlineAsmOperand::In { + reg: InlineAsmRegOrRegClass::Reg(InlineAsmReg::AArch64( + AArch64InlineAsmReg::v2, + )), + value: c, + }, + ], + InlineAsmOptions::NOSTACK | InlineAsmOptions::PURE | InlineAsmOptions::NOMEM, + ); + } + + "llvm.aarch64.neon.pmull64" => { + intrinsic_args!(fx, args => (a, b); intrinsic); + + let a = a.load_scalar(fx); + let b = b.load_scalar(fx); + + codegen_inline_asm_inner( + fx, + &[InlineAsmTemplatePiece::String( + "fmov d0, x0 + fmov d1, x1 + pmull v0.1q, v0.1d, v1.1d" + .into(), + )], + &[ + CInlineAsmOperand::Out { + reg: InlineAsmRegOrRegClass::Reg(InlineAsmReg::AArch64( + AArch64InlineAsmReg::v0, + )), + late: true, + place: Some(ret), + }, + CInlineAsmOperand::In { + reg: InlineAsmRegOrRegClass::Reg(InlineAsmReg::AArch64( + AArch64InlineAsmReg::x0, + )), + value: a, + }, + CInlineAsmOperand::In { + reg: InlineAsmRegOrRegClass::Reg(InlineAsmReg::AArch64( + AArch64InlineAsmReg::x1, + )), + value: b, + }, + CInlineAsmOperand::Out { + reg: InlineAsmRegOrRegClass::Reg(InlineAsmReg::AArch64( + AArch64InlineAsmReg::v1, + )), + late: true, + place: None, + }, + ], + InlineAsmOptions::NOSTACK | InlineAsmOptions::PURE | InlineAsmOptions::NOMEM, + ); + } + + "llvm.aarch64.neon.pmull.v8i16" => { + intrinsic_args!(fx, args => (a, b); intrinsic); + + let a = a.load_scalar(fx); + let b = b.load_scalar(fx); + + codegen_inline_asm_inner( + fx, + &[InlineAsmTemplatePiece::String("pmull v0.8h, v0.8b, v1.8b".into())], + &[ + CInlineAsmOperand::InOut { + reg: InlineAsmRegOrRegClass::Reg(InlineAsmReg::AArch64( + AArch64InlineAsmReg::v0, + )), + _late: true, + in_value: a, + out_place: Some(ret), + }, + CInlineAsmOperand::In { + reg: InlineAsmRegOrRegClass::Reg(InlineAsmReg::AArch64( + AArch64InlineAsmReg::v1, + )), + value: b, + }, + ], + InlineAsmOptions::NOSTACK | InlineAsmOptions::PURE | InlineAsmOptions::NOMEM, + ); + } + + "llvm.aarch64.neon.sqdmulh.v2i32" + | "llvm.aarch64.neon.sqdmulh.v4i16" + | "llvm.aarch64.neon.sqdmulh.v4i32" + | "llvm.aarch64.neon.sqdmulh.v8i16" => { + // https://developer.arm.com/documentation/ddi0602/2026-03/SIMD-FP-Instructions/SQDMULH--vector---Signed-saturating-doubling-multiply-returning-high-half- + intrinsic_args!(fx, args => (a, b); intrinsic); + + // Simplify the "double and shift by esize" into "shift by esize - 1". + // https://github.com/qemu/qemu/blob/81cc5f39aa3042e9c0b2ea772b42a2c8b1488e76/target/arm/tcg/mve_helper.c#L1267-L1283 + let (result_ty, product_ty, shift, max) = match intrinsic { + "llvm.aarch64.neon.sqdmulh.v4i16" | "llvm.aarch64.neon.sqdmulh.v8i16" => { + (types::I16, types::I32, 15, i64::from(i16::MAX)) + } + "llvm.aarch64.neon.sqdmulh.v2i32" | "llvm.aarch64.neon.sqdmulh.v4i32" => { + (types::I32, types::I64, 31, i64::from(i32::MAX)) + } + _ => unreachable!(), + }; + + simd_pair_for_each_lane( + fx, + a, + b, + ret, + &|fx, _lane_ty, _res_lane_ty, a_lane, b_lane| { + let a_lane = fx.bcx.ins().sextend(product_ty, a_lane); + let b_lane = fx.bcx.ins().sextend(product_ty, b_lane); + let product = fx.bcx.ins().imul(a_lane, b_lane); + let product = fx.bcx.ins().sshr_imm(product, shift); + let max = fx.bcx.ins().iconst(product_ty, max); + let result = fx.bcx.ins().smin(product, max); + fx.bcx.ins().ireduce(result_ty, result) + }, + ); + } + + "llvm.aarch64.neon.saddlp.v1i64.v2i32" + | "llvm.aarch64.neon.saddlp.v2i32.v4i16" + | "llvm.aarch64.neon.saddlp.v2i64.v4i32" + | "llvm.aarch64.neon.saddlp.v4i16.v8i8" + | "llvm.aarch64.neon.saddlp.v4i32.v8i16" + | "llvm.aarch64.neon.saddlp.v8i16.v16i8" => { + // https://developer.arm.com/documentation/ddi0602/2026-03/SIMD-FP-Instructions/SADDLP--Signed-add-long-pairwise- + intrinsic_args!(fx, args => (a); intrinsic); + + let (ret_lane_count, ret_lane_ty) = ret.layout().ty.simd_size_and_type(fx.tcx); + let ret_lane_layout = fx.layout_of(ret_lane_ty); + let wide_ty = fx.clif_type(ret_lane_ty).unwrap(); + + for lane_idx in 0..ret_lane_count { + let base = lane_idx * 2; + let a_lane0 = a.value_lane(fx, base).load_scalar(fx); + let a_lane1 = a.value_lane(fx, base + 1).load_scalar(fx); + let a_lane0 = fx.bcx.ins().sextend(wide_ty, a_lane0); + let a_lane1 = fx.bcx.ins().sextend(wide_ty, a_lane1); + let sum = fx.bcx.ins().iadd(a_lane0, a_lane1); + let res_lane = CValue::by_val(sum, ret_lane_layout); + ret.place_lane(fx, lane_idx).write_cvalue(fx, res_lane); + } + } + + "llvm.aarch64.neon.uaddlp.v1i64.v2i32" + | "llvm.aarch64.neon.uaddlp.v2i32.v4i16" + | "llvm.aarch64.neon.uaddlp.v2i64.v4i32" + | "llvm.aarch64.neon.uaddlp.v4i16.v8i8" + | "llvm.aarch64.neon.uaddlp.v4i32.v8i16" + | "llvm.aarch64.neon.uaddlp.v8i16.v16i8" => { + // https://developer.arm.com/documentation/ddi0602/2026-03/SIMD-FP-Instructions/UADDLP--Unsigned-add-long-pairwise- + intrinsic_args!(fx, args => (a); intrinsic); + + let (ret_lane_count, ret_lane_ty) = ret.layout().ty.simd_size_and_type(fx.tcx); + let ret_lane_layout = fx.layout_of(ret_lane_ty); + let wide_ty = fx.clif_type(ret_lane_ty).unwrap(); + + for lane_idx in 0..ret_lane_count { + let base = lane_idx * 2; + let a_lane0 = a.value_lane(fx, base).load_scalar(fx); + let a_lane1 = a.value_lane(fx, base + 1).load_scalar(fx); + let a_lane0 = fx.bcx.ins().uextend(wide_ty, a_lane0); + let a_lane1 = fx.bcx.ins().uextend(wide_ty, a_lane1); + let sum = fx.bcx.ins().iadd(a_lane0, a_lane1); + let res_lane = CValue::by_val(sum, ret_lane_layout); + ret.place_lane(fx, lane_idx).write_cvalue(fx, res_lane); + } + } + _ => { fx.tcx.dcx().warn(format!( "unsupported AArch64 llvm intrinsic {}; replacing with trap", diff --git a/compiler/rustc_codegen_cranelift/src/intrinsics/simd.rs b/compiler/rustc_codegen_cranelift/src/intrinsics/simd.rs index b8e1886b2d3c1..5d7e457b8e1ba 100644 --- a/compiler/rustc_codegen_cranelift/src/intrinsics/simd.rs +++ b/compiler/rustc_codegen_cranelift/src/intrinsics/simd.rs @@ -371,7 +371,7 @@ pub(super) fn codegen_simd_intrinsic_call<'tcx>( } for i in 0..lane_count { - let ret_lane = ret.place_lane(fx, i.into()); + let ret_lane = ret.place_lane(fx, i); ret_lane.write_cvalue(fx, value); } } diff --git a/compiler/rustc_codegen_cranelift/src/lib.rs b/compiler/rustc_codegen_cranelift/src/lib.rs index 48858e20381dd..38cb986034859 100644 --- a/compiler/rustc_codegen_cranelift/src/lib.rs +++ b/compiler/rustc_codegen_cranelift/src/lib.rs @@ -18,9 +18,7 @@ extern crate rustc_codegen_ssa; extern crate rustc_const_eval; extern crate rustc_data_structures; extern crate rustc_errors; -extern crate rustc_fs_util; extern crate rustc_hir; -extern crate rustc_incremental; extern crate rustc_index; extern crate rustc_log; extern crate rustc_session; @@ -40,7 +38,7 @@ use std::sync::Arc; use cranelift_codegen::isa::TargetIsa; use cranelift_codegen::settings::{self, Configurable}; use rustc_codegen_ssa::traits::CodegenBackend; -use rustc_codegen_ssa::{CompiledModules, CrateInfo, TargetConfig}; +use rustc_codegen_ssa::{CompiledModules, CrateInfo, TargetConfig, back}; use rustc_log::tracing::info; use rustc_middle::dep_graph::{WorkProduct, WorkProductId}; use rustc_session::Session; @@ -60,7 +58,6 @@ mod codegen_f16_f128; mod codegen_i128; mod common; mod compiler_builtins; -mod concurrency_limiter; mod config; mod constant; mod debuginfo; @@ -133,7 +130,7 @@ impl CodegenBackend for CraneliftCodegenBackend { match sess.lto() { Lto::No | Lto::ThinLocal => {} Lto::Thin | Lto::Fat => { - sess.dcx().warn("LTO is not supported. You may get a linker error.") + sess.dcx().fatal("LTO is not supported by rustc_codegen_cranelift"); } } @@ -152,6 +149,10 @@ impl CodegenBackend for CraneliftCodegenBackend { } } + fn thin_lto_supported(&self) -> bool { + false + } + fn target_config(&self, sess: &Session) -> TargetConfig { // FIXME return the actually used target features. this is necessary for #[cfg(target_feature)] let target_features = match sess.target.arch { @@ -224,7 +225,7 @@ impl CodegenBackend for CraneliftCodegenBackend { #[cfg(not(feature = "jit"))] tcx.dcx().fatal("jit support was disabled when compiling rustc_codegen_cranelift"); } else { - driver::aot::run_aot(tcx) + Box::new(rustc_codegen_ssa::base::codegen_crate(driver::aot::AotDriver, tcx)) } } @@ -232,10 +233,13 @@ impl CodegenBackend for CraneliftCodegenBackend { &self, ongoing_codegen: Box, sess: &Session, - outputs: &OutputFilenames, - _crate_info: &CrateInfo, + _outputs: &OutputFilenames, + crate_info: &CrateInfo, ) -> (CompiledModules, FxIndexMap) { - ongoing_codegen.downcast::().unwrap().join(sess, outputs) + ongoing_codegen + .downcast::>() + .unwrap() + .join(sess, crate_info) } fn fallback_intrinsics(&self) -> Vec { @@ -254,7 +258,9 @@ fn enable_verifier(sess: &Session) -> bool { } fn target_triple(sess: &Session) -> target_lexicon::Triple { - match sess.target.llvm_target.parse() { + // Use versioned target triple to make `OperatingSystem::MacOSX(...)` + // contain a value, which we use when emitting `LC_BUILD_VERSION`. + match back::versioned_llvm_target(sess).parse() { Ok(triple) => triple, Err(err) => sess.dcx().fatal(format!("target not recognized: {}", err)), } diff --git a/compiler/rustc_codegen_cranelift/src/value_and_place.rs b/compiler/rustc_codegen_cranelift/src/value_and_place.rs index 1d9dcdab4ced9..a2a2cac3faaa8 100644 --- a/compiler/rustc_codegen_cranelift/src/value_and_place.rs +++ b/compiler/rustc_codegen_cranelift/src/value_and_place.rs @@ -686,17 +686,14 @@ impl<'tcx> CPlace<'tcx> { ) -> CPlace<'tcx> { let layout = self.layout(); - match self.inner { - CPlaceInner::VarPair(local, var1, var2) => { - let layout = layout.field(&*fx, field.index()); + if let CPlaceInner::VarPair(local, var1, var2) = self.inner { + let layout = layout.field(&*fx, field.index()); - match field.as_u32() { - 0 => return CPlace { inner: CPlaceInner::Var(local, var1), layout }, - 1 => return CPlace { inner: CPlaceInner::Var(local, var2), layout }, - _ => unreachable!("field should be 0 or 1"), - } + match field.as_u32() { + 0 => return CPlace { inner: CPlaceInner::Var(local, var1), layout }, + 1 => return CPlace { inner: CPlaceInner::Var(local, var2), layout }, + _ => unreachable!("field should be 0 or 1"), } - _ => {} } let (base, extra) = match self.inner { diff --git a/compiler/rustc_codegen_gcc/src/abi.rs b/compiler/rustc_codegen_gcc/src/abi.rs index fb243ff842c83..1b7bb8c907735 100644 --- a/compiler/rustc_codegen_gcc/src/abi.rs +++ b/compiler/rustc_codegen_gcc/src/abi.rs @@ -10,7 +10,7 @@ use rustc_middle::bug; use rustc_middle::ty::Ty; use rustc_middle::ty::layout::LayoutOf; #[cfg(feature = "master")] -use rustc_session::config; +use rustc_session::{Session, config}; use rustc_target::callconv::{ArgAttributes, CastTarget, FnAbi, PassMode}; #[cfg(feature = "master")] use rustc_target::spec::Arch; @@ -230,32 +230,43 @@ impl<'gcc, 'tcx> FnAbiGccExt<'gcc, 'tcx> for FnAbi<'tcx, Ty<'tcx>> { #[cfg(feature = "master")] fn gcc_cconv(&self, cx: &CodegenCx<'gcc, 'tcx>) -> Option> { - conv_to_fn_attribute(self.conv, &cx.tcx.sess.target.arch) + conv_to_fn_attribute(cx.sess(), self.conv) } } #[cfg(feature = "master")] -pub fn conv_to_fn_attribute<'gcc>(conv: CanonAbi, arch: &Arch) -> Option> { +pub fn conv_to_fn_attribute<'gcc>(sess: &Session, conv: CanonAbi) -> Option> { let attribute = match conv { CanonAbi::C | CanonAbi::Rust => return None, - // gcc/gccjit does not have anything for this. - CanonAbi::RustPreserveNone => return None, + CanonAbi::RustPreserveNone => { + // This calling convention is LLVM-specific and unspecified. + sess.dcx() + .fatal("gcc/gccjit backend does not support RustPreserveNone calling convention") + } + CanonAbi::RustTail => { + // This calling convention is LLVM-specific and unspecified. + sess.dcx().fatal("gcc/gccjit backend does not support RustTail calling convention") + } CanonAbi::RustCold => FnAttribute::Cold, // Functions with this calling convention can only be called from assembly, but it is // possible to declare an `extern "custom"` block, so the backend still needs a calling // convention for declaring foreign functions. CanonAbi::Custom => return None, - // gcc/gccjit does not have anything for Swift's calling convention. - CanonAbi::Swift => panic!("gcc/gccjit backend does not support Swift calling convention"), + CanonAbi::Swift => { + // gcc/gccjit does not have anything for Swift's calling convention. + sess.dcx().fatal("gcc/gccjit backend does not support Swift calling convention") + } CanonAbi::Arm(arm_call) => match arm_call { ArmCall::CCmseNonSecureCall => FnAttribute::ArmCmseNonsecureCall, ArmCall::CCmseNonSecureEntry => FnAttribute::ArmCmseNonsecureEntry, ArmCall::Aapcs => FnAttribute::ArmPcs("aapcs"), }, - CanonAbi::GpuKernel => match arch { + CanonAbi::GpuKernel => match &sess.target.arch { &Arch::AmdGpu => FnAttribute::GcnAmdGpuHsaKernel, &Arch::Nvptx64 => FnAttribute::NvptxKernel, - arch => panic!("Arch {arch} does not support GpuKernel calling convention"), + arch => sess + .dcx() + .fatal(format!("Arch {arch} does not support GpuKernel calling convention")), }, // FIXME(antoyo): check if those AVR attributes are mapped correctly. CanonAbi::Interrupt(interrupt_kind) => match interrupt_kind { diff --git a/compiler/rustc_codegen_gcc/src/context.rs b/compiler/rustc_codegen_gcc/src/context.rs index ed313859aeafa..ea71546ea1c0e 100644 --- a/compiler/rustc_codegen_gcc/src/context.rs +++ b/compiler/rustc_codegen_gcc/src/context.rs @@ -486,10 +486,10 @@ impl<'gcc, 'tcx> MiscCodegenMethods<'tcx> for CodegenCx<'gcc, 'tcx> { fn declare_c_main(&self, fn_type: Self::Type) -> Option { let entry_name = self.sess().target.entry_name.as_ref(); if !self.functions.borrow().contains_key(entry_name) { - #[cfg(feature = "master")] - let conv = conv_to_fn_attribute(self.sess().target.entry_abi, &self.sess().target.arch); - #[cfg(not(feature = "master"))] - let conv = None; + let conv = cfg_select! { + feature = "master" => conv_to_fn_attribute(self.sess(), self.sess().target.entry_abi), + _ => None, + }; Some(self.declare_entry_fn(entry_name, fn_type, conv)) } else { // If the symbol already exists, it is an error: for example, the user wrote diff --git a/compiler/rustc_codegen_llvm/src/abi.rs b/compiler/rustc_codegen_llvm/src/abi.rs index 3f6010e55928d..4d18818bbe7bd 100644 --- a/compiler/rustc_codegen_llvm/src/abi.rs +++ b/compiler/rustc_codegen_llvm/src/abi.rs @@ -723,6 +723,10 @@ pub(crate) fn to_llvm_calling_convention(sess: &Session, abi: CanonAbi) -> llvm: Arch::X86_64 | Arch::AArch64 => llvm::PreserveNone, _ => llvm::CCallConv, }, + CanonAbi::RustTail => match &sess.target.arch { + Arch::X86 | Arch::X86_64 | Arch::AArch64 => llvm::Tail, + _ => sess.dcx().fatal("extern \"tail\" is only supported on x86_64 and aarch64"), + }, // Functions with this calling convention can only be called from assembly, but it is // possible to declare an `extern "custom"` block, so the backend still needs a calling // convention for declaring foreign functions. diff --git a/compiler/rustc_feature/src/unstable.rs b/compiler/rustc_feature/src/unstable.rs index be98544d89ecd..693326e198721 100644 --- a/compiler/rustc_feature/src/unstable.rs +++ b/compiler/rustc_feature/src/unstable.rs @@ -709,6 +709,8 @@ declare_features! ( (unstable, rust_cold_cc, "1.63.0", Some(97544)), /// Allows `extern "rust-preserve-none"`. (unstable, rust_preserve_none_cc, "1.95.0", Some(151401)), + /// Allows `extern "tail"`. + (unstable, rust_tail_cc, "CURRENT_RUSTC_VERSION", Some(157427)), /// Target features on s390x. (unstable, s390x_target_feature, "1.82.0", Some(150259)), /// Allows the use of the `sanitize` attribute. diff --git a/compiler/rustc_hir_typeck/src/callee.rs b/compiler/rustc_hir_typeck/src/callee.rs index 7d687099f9715..e70936972e7c7 100644 --- a/compiler/rustc_hir_typeck/src/callee.rs +++ b/compiler/rustc_hir_typeck/src/callee.rs @@ -205,6 +205,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { | CanonAbi::Rust | CanonAbi::RustCold | CanonAbi::RustPreserveNone + | CanonAbi::RustTail | CanonAbi::Swift | CanonAbi::Arm(_) | CanonAbi::X86(_) => {} diff --git a/compiler/rustc_hir_typeck/src/method/suggest.rs b/compiler/rustc_hir_typeck/src/method/suggest.rs index c9ec32159f476..48e1f553900b0 100644 --- a/compiler/rustc_hir_typeck/src/method/suggest.rs +++ b/compiler/rustc_hir_typeck/src/method/suggest.rs @@ -4796,7 +4796,24 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let hir::Node::Expr(rcvr) = self.tcx.hir_node(hir_id) else { return false; }; - let trait_ref = ty::TraitRef::new(self.tcx, trait_def_id, rcvr_ty.into_iter()); + // The trait may have generic parameters beyond `Self` (e.g. `Borrow`), and + // `rcvr_ty` may even be unknown. We only ever know the receiver type (the `Self` arg), + // so fill `Self` from `rcvr_ty` when available and the remaining parameters with fresh + // inference variables; building a `TraitRef` with a partial arg list would otherwise trip + // `debug_assert_args_compatible` and ICE. See #157189. + let trait_ref = ty::TraitRef::new_from_args( + self.tcx, + trait_def_id, + ty::GenericArgs::for_item(self.tcx, trait_def_id, |param, _| { + if param.index == 0 + && let Some(rcvr_ty) = rcvr_ty + { + rcvr_ty.into() + } else { + self.var_for_def(rcvr.span, param) + } + }), + ); let trait_pred = ty::Binder::dummy(ty::TraitPredicate { trait_ref, polarity: ty::PredicatePolarity::Positive, diff --git a/compiler/rustc_infer/src/infer/canonical/query_response.rs b/compiler/rustc_infer/src/infer/canonical/query_response.rs index 98763ff742f25..5641523c304c9 100644 --- a/compiler/rustc_infer/src/infer/canonical/query_response.rs +++ b/compiler/rustc_infer/src/infer/canonical/query_response.rs @@ -13,7 +13,7 @@ use std::iter; use rustc_index::{Idx, IndexVec}; use rustc_middle::arena::ArenaAllocatable; use rustc_middle::bug; -use rustc_middle::infer::canonical::CanonicalVarKind; +use rustc_middle::infer::canonical::{CanonicalVarKind, QueryRegionConstraint}; use rustc_middle::ty::{self, BoundVar, GenericArg, GenericArgKind, Ty, TyCtxt, TypeFoldable}; use tracing::{debug, instrument}; @@ -188,7 +188,9 @@ impl<'tcx> InferCtxt<'tcx> { let InferOk { value: result_args, obligations } = self.query_response_instantiation(cause, param_env, original_values, query_response)?; - for (constraint, _category, vis) in &query_response.value.region_constraints.constraints { + for QueryRegionConstraint { constraint, visible_for_leak_check: vis, .. } in + &query_response.value.region_constraints.constraints + { let constraint = instantiate_value(self.tcx, &result_args, *constraint); match constraint { ty::RegionConstraint::Outlives(predicate) => { @@ -285,11 +287,12 @@ impl<'tcx> InferCtxt<'tcx> { (GenericArgKind::Lifetime(v_o), GenericArgKind::Lifetime(v_r)) => { if v_o != v_r { - output_query_region_constraints.constraints.push(( - ty::RegionEqPredicate(v_o, v_r).into(), - constraint_category, - ty::VisibleForLeakCheck::Yes, - )); + let constraint = QueryRegionConstraint { + constraint: ty::RegionEqPredicate(v_o, v_r).into(), + category: constraint_category, + visible_for_leak_check: ty::VisibleForLeakCheck::Yes, + }; + output_query_region_constraints.constraints.push(constraint); } } @@ -321,7 +324,7 @@ impl<'tcx> InferCtxt<'tcx> { let r_c = instantiate_value(self.tcx, &result_args, r_c); // Screen out `'a: 'a` or `'a == 'a` cases. - if r_c.0.is_trivial() { None } else { Some(r_c) } + if r_c.constraint.is_trivial() { None } else { Some(r_c) } }), ); @@ -616,7 +619,7 @@ pub fn make_query_region_constraints<'tcx>( debug!(?constraints); - let constraints: Vec<_> = constraints + let constraints: Vec> = constraints .iter() .map(|(c, origin)| match c.kind { ConstraintKind::VarSubVar @@ -625,22 +628,30 @@ pub fn make_query_region_constraints<'tcx>( | ConstraintKind::RegSubReg => { // Swap regions because we are going from sub (<=) to outlives (>=). let constraint = ty::OutlivesPredicate(c.sup.into(), c.sub).into(); - (constraint, origin.to_constraint_category(), c.visible_for_leak_check) + QueryRegionConstraint { + constraint, + category: origin.to_constraint_category(), + visible_for_leak_check: c.visible_for_leak_check, + } } ConstraintKind::VarEqVar | ConstraintKind::VarEqReg | ConstraintKind::RegEqReg => { let constraint = ty::RegionEqPredicate(c.sup, c.sub).into(); - (constraint, origin.to_constraint_category(), c.visible_for_leak_check) + QueryRegionConstraint { + constraint, + category: origin.to_constraint_category(), + visible_for_leak_check: c.visible_for_leak_check, + } } }) .chain(outlives_obligations.into_iter().map( |TypeOutlivesConstraint { sub_region, sup_type, origin }| { - ( - ty::OutlivesPredicate(sup_type.into(), sub_region).into(), - origin.to_constraint_category(), + QueryRegionConstraint { + constraint: ty::OutlivesPredicate(sup_type.into(), sub_region).into(), + category: origin.to_constraint_category(), // We don't do leak checks for type outlives - ty::VisibleForLeakCheck::Unreachable, - ) + visible_for_leak_check: ty::VisibleForLeakCheck::Unreachable, + } }, )) .collect(); diff --git a/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp index 8a6caa9b10854..b03a07538ccd8 100644 --- a/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp +++ b/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp @@ -49,9 +49,6 @@ #include "llvm/Transforms/Instrumentation/RealtimeSanitizer.h" #include "llvm/Transforms/Instrumentation/ThreadSanitizer.h" #include "llvm/Transforms/Scalar/AnnotationRemarks.h" -#if LLVM_VERSION_GE(23, 0) -#include "llvm/Transforms/Utils/AssignGUID.h" -#endif #include "llvm/Transforms/Utils/CanonicalizeAliases.h" #include "llvm/Transforms/Utils/FunctionImportUtils.h" #include "llvm/Transforms/Utils/NameAnonGlobals.h" @@ -918,9 +915,6 @@ extern "C" LLVMRustResult LLVMRustOptimize( if (NeedThinLTOBufferPasses) { MPM.addPass(CanonicalizeAliasesPass()); MPM.addPass(NameAnonGlobalPass()); -#if LLVM_VERSION_GE(23, 0) - MPM.addPass(AssignGUIDPass()); -#endif } // For `-Copt-level=0`, and the pre-link fat/thin LTO stages. if (ThinLTOBufferRef && *ThinLTOBufferRef == nullptr) { @@ -1460,9 +1454,6 @@ extern "C" LLVMRustBuffer *LLVMRustModuleSerialize(LLVMModuleRef M, PB.registerLoopAnalyses(LAM); PB.crossRegisterProxies(LAM, FAM, CGAM, MAM); ModulePassManager MPM; -#if LLVM_VERSION_GE(23, 0) - MPM.addPass(AssignGUIDPass()); -#endif MPM.addPass(ThinLTOBitcodeWriterPass(OS, nullptr)); MPM.run(*unwrap(M), MAM); } else { diff --git a/compiler/rustc_middle/src/infer/canonical.rs b/compiler/rustc_middle/src/infer/canonical.rs index ee8ab8a2ff931..8f182d096e759 100644 --- a/compiler/rustc_middle/src/infer/canonical.rs +++ b/compiler/rustc_middle/src/infer/canonical.rs @@ -135,9 +135,12 @@ impl<'tcx, R> QueryResponse<'tcx, R> { } } -// FIXME: Convert this into a struct -pub type QueryRegionConstraint<'tcx> = - (ty::RegionConstraint<'tcx>, ConstraintCategory<'tcx>, ty::VisibleForLeakCheck); +#[derive(Debug, StableHash, Hash, Eq, PartialEq, TypeVisitable, Clone, TypeFoldable, Copy)] +pub struct QueryRegionConstraint<'tcx> { + pub constraint: ty::RegionConstraint<'tcx>, + pub category: ConstraintCategory<'tcx>, + pub visible_for_leak_check: ty::VisibleForLeakCheck, +} #[derive(Default)] pub struct CanonicalParamEnvCache<'tcx> { diff --git a/compiler/rustc_middle/src/thir.rs b/compiler/rustc_middle/src/thir.rs index 0cc57e5021f86..838dbdcbff58f 100644 --- a/compiler/rustc_middle/src/thir.rs +++ b/compiler/rustc_middle/src/thir.rs @@ -729,23 +729,6 @@ impl<'tcx> Pat<'tcx> { true }) } - - /// Whether this a never pattern. - pub fn is_never_pattern(&self) -> bool { - let mut is_never_pattern = false; - self.walk(|pat| match &pat.kind { - PatKind::Never => { - is_never_pattern = true; - false - } - PatKind::Or { pats } => { - is_never_pattern = pats.iter().all(|p| p.is_never_pattern()); - false - } - _ => true, - }); - is_never_pattern - } } #[derive(Clone, Debug, StableHash, TypeVisitable)] diff --git a/compiler/rustc_middle/src/ty/layout.rs b/compiler/rustc_middle/src/ty/layout.rs index 682bec55b4a38..a0dd7b5c5cb5e 100644 --- a/compiler/rustc_middle/src/ty/layout.rs +++ b/compiler/rustc_middle/src/ty/layout.rs @@ -1305,7 +1305,9 @@ pub fn fn_can_unwind(tcx: TyCtxt<'_>, fn_def_id: Option, abi: ExternAbi) | RustInvalid | Swift | Unadjusted => false, - Rust | RustCall | RustCold | RustPreserveNone => tcx.sess.panic_strategy().unwinds(), + Rust | RustCall | RustCold | RustPreserveNone | RustTail => { + tcx.sess.panic_strategy().unwinds() + } } } diff --git a/compiler/rustc_mir_build/src/builder/matches/match_pair.rs b/compiler/rustc_mir_build/src/builder/matches/match_pair.rs index e2d00238e2d59..b4ce8149f5e4d 100644 --- a/compiler/rustc_mir_build/src/builder/matches/match_pair.rs +++ b/compiler/rustc_mir_build/src/builder/matches/match_pair.rs @@ -1,10 +1,11 @@ use std::sync::Arc; use rustc_abi::FieldIdx; -use rustc_middle::mir::*; +use rustc_middle::mir::{Pinnedness, Place, PlaceElem, ProjectionElem}; use rustc_middle::span_bug; -use rustc_middle::thir::*; +use rustc_middle::thir::{Ascription, DerefPatBorrowMode, FieldPat, Pat, PatKind}; use rustc_middle::ty::{self, Ty, TypeVisitableExt}; +use rustc_span::Span; use crate::builder::Builder; use crate::builder::expr::as_place::{PlaceBase, PlaceBuilder}; @@ -66,16 +67,166 @@ fn prefix_slice_suffix<'a, 'tcx>( output_pairs } -impl<'tcx> MatchPairTree<'tcx> { - /// Recursively builds a match pair tree for the given pattern and its - /// subpatterns. - pub(super) fn for_pattern( - mut place_builder: PlaceBuilder<'tcx>, +impl<'tcx> FlatPat<'tcx> { + /// Creates a `FlatPat` containing a simplified [`MatchPairTree`] list/forest + /// for the given pattern. + pub(crate) fn new( + place: PlaceBuilder<'tcx>, pattern: &Pat<'tcx>, cx: &mut Builder<'_, 'tcx>, - match_pairs: &mut Vec, // Newly-created nodes are added to this vector - extra_data: &mut PatternExtraData<'tcx>, // Bindings/ascriptions are added here - ) { + ) -> Self { + // Recursively lower the THIR pattern into an intermediate form, + // then flatten into a `FlatPat`. + let inter_pat = InterPat::lower_thir_pat(cx, place, pattern); + FlatPat::from_inter_pat(inter_pat) + } + + /// Squashes an [`InterPat`] into a [`FlatPat`]. + /// + /// This is a separate function because it also needs to be called recursively + /// when squashing any or-patterns. + fn from_inter_pat(inter_pat: InterPat<'tcx>) -> Self { + let mut match_pairs = vec![]; + let mut extra_data = PatternExtraData { + span: inter_pat.pattern_span, + bindings: vec![], + ascriptions: vec![], + is_never: inter_pat.is_never, + }; + squash_inter_pat(inter_pat, &mut match_pairs, &mut extra_data); + + FlatPat { match_pairs, extra_data } + } +} + +/// Recursively squashes an [`InterPat`] into a forest of refutable [`MatchPairTree`] +/// nodes, while accumulating ascriptions and bindings. +fn squash_inter_pat<'tcx>( + inter_pat: InterPat<'tcx>, + match_pairs: &mut Vec>, // Newly-created nodes are added to this vector + extra_data: &mut PatternExtraData<'tcx>, // Bindings/ascriptions are added here +) { + // Destructure exhaustively to make sure we don't miss any fields. + let InterPat { + place, + testable_case, + subpats, + or_subpats, + ascriptions, + binding, + pattern_span, + is_never: _, // Not needed by `MatchPairTree` forests. + } = inter_pat; + + // Type ascriptions can appear regardless of whether the node is an or-pattern. + extra_data.ascriptions.extend(ascriptions); + + // Or and non-or patterns have very different handling. + if let Some(or_subpats) = or_subpats { + // We're dealing with an or-pattern node. + assert!(testable_case.is_none()); + assert!(subpats.is_empty()); + assert!(binding.is_none()); + + let or_subpats = or_subpats + .into_iter() + .map(|subpat| FlatPat::from_inter_pat(subpat)) + .collect::>(); + + if !or_subpats[0].extra_data.bindings.is_empty() { + // Hold a place for any bindings established in (possibly-nested) or-patterns. + // By only holding a place when bindings are present, we skip over any + // or-patterns that will be simplified by `merge_trivial_subcandidates`. In + // other words, we can assume this expands into subcandidates. + // FIXME(@dianne): this needs updating/removing if we always merge or-patterns + extra_data.bindings.push(super::SubpatternBindings::FromOrPattern); + } + + match_pairs.push(MatchPairTree { + // Or-patterns never need a place during MIR building. + place: None, + testable_case: TestableCase::Or { pats: or_subpats }, + subpairs: vec![], + pattern_span, + }); + } else { + // We're dealing with a node that isn't an or-pattern. + + // Recursively squash any subpatterns into refutable `MatchPairTree` forests. + // This must happen _before_ pushing the binding, as described by the binding step. + let mut subpairs = vec![]; + for subpat in subpats { + squash_inter_pat(subpat, &mut subpairs, extra_data); + } + + if let Some(testable_case) = testable_case { + // This pattern is refutable, so push a new match-pair node. + // + // If this match is inside a closure, it's essential that the place + // we're testing was actually captured! Be sure to keep `ExprUseVisitor` + // in sync with the refutability checks in this module. + assert!(place.is_some()); + assert!(!matches!(testable_case, TestableCase::Or { .. })); + match_pairs.push(MatchPairTree { place, testable_case, subpairs, pattern_span }); + } else { + // This pattern is irrefutable, so it doesn't need its own match-pair node. + // Just push its refutable subpatterns instead, if any. + match_pairs.extend(subpairs); + } + + // If present, the binding must be pushed _after_ traversing subpatterns. + // This is so that when lowering something like `x @ NonCopy { copy_field }`, + // the binding to `copy_field` will occur before the binding for `x`. + // See for more background. + if let Some(binding) = binding { + extra_data.bindings.push(super::SubpatternBindings::One(binding)); + } + } +} + +/// "Intermediate pattern", a partly-lowered THIR [`Pat`] that has not yet been +/// squashed into a forest of refutable [`MatchPairTree`] nodes. +/// +/// FIXME(Zalathar): This could potentially be split into different enum variants +/// for or-patterns and non-or patterns, but for now the flat structure makes +/// construction a bit easier, at the cost of more complicated invariants. +struct InterPat<'tcx> { + /// Place that this pattern node will test. + /// + /// If `None`, we're in a closure that didn't capture the relevant place, + /// because it won't actually be tested. + place: Option>, + /// Testable condition to compare the place to (e.g. "is 3" or "is Some"). + /// + /// If `None`, this pattern node is irrefutable or an or-pattern, + /// though it might have refutable descendants. + testable_case: Option>, + + /// Immediate subpatterns of a node that is *not* an or-pattern. + subpats: Vec>, + /// Immediate subpatterns of an or-pattern node. + /// + /// Invariant: If this is Some, then fields `subpats`, `testable_case`, + /// and `binding` must all be empty. + or_subpats: Option]>>, + + ascriptions: Vec>, + /// Binding to establish for a [`PatKind::Binding`] node. + binding: Option>, + + /// Span field of the THIR pattern this node was created from. + pattern_span: Span, + /// True if this pattern can never match, because all of its alternatives + /// contain a `!` pattern. + is_never: bool, +} + +impl<'tcx> InterPat<'tcx> { + fn lower_thir_pat( + cx: &mut Builder<'_, 'tcx>, + mut place_builder: PlaceBuilder<'tcx>, + pattern: &Pat<'tcx>, + ) -> Self { // Force the place type to the pattern's type. // FIXME(oli-obk): can we use this to simplify slice/array pattern hacks? if let Some(resolved) = place_builder.resolve_upvar(cx) { @@ -99,14 +250,19 @@ impl<'tcx> MatchPairTree<'tcx> { } } + // Variables that will become `InterPat` fields: let place = place_builder.try_to_place(cx); + let mut subpats = vec![]; + let mut or_subpats = None; + let mut ascriptions = vec![]; + let mut binding = None; // Apply any type ascriptions to the value at `match_pair.place`. if let Some(place) = place && let Some(extra) = &pattern.extra { for &Ascription { ref annotation, variance } in &extra.ascriptions { - extra_data.ascriptions.push(super::Ascription { + ascriptions.push(super::Ascription { source: place, annotation: annotation.clone(), variance, @@ -114,22 +270,16 @@ impl<'tcx> MatchPairTree<'tcx> { } } - let mut subpairs = Vec::new(); let testable_case = match pattern.kind { PatKind::Missing | PatKind::Wild | PatKind::Error(_) => None, PatKind::Or { ref pats } => { - let pats: Box<[FlatPat<'tcx>]> = - pats.iter().map(|pat| FlatPat::new(place_builder.clone(), pat, cx)).collect(); - if !pats[0].extra_data.bindings.is_empty() { - // Hold a place for any bindings established in (possibly-nested) or-patterns. - // By only holding a place when bindings are present, we skip over any - // or-patterns that will be simplified by `merge_trivial_subcandidates`. In - // other words, we can assume this expands into subcandidates. - // FIXME(@dianne): this needs updating/removing if we always merge or-patterns - extra_data.bindings.push(super::SubpatternBindings::FromOrPattern); - } - Some(TestableCase::Or { pats }) + or_subpats = Some( + pats.iter() + .map(|subpat| InterPat::lower_thir_pat(cx, place_builder.clone(), subpat)) + .collect::>(), + ); + None } PatKind::Range(ref range) => { @@ -165,48 +315,22 @@ impl<'tcx> MatchPairTree<'tcx> { } PatKind::Binding { mode, var, is_shorthand, ref subpattern, .. } => { - // In order to please the borrow checker, when lowering a pattern - // like `x @ subpat` we must establish any bindings in `subpat` - // before establishing the binding for `x`. - // - // For example (from #69971): - // - // ```ignore (illustrative) - // struct NonCopyStruct { - // copy_field: u32, - // } - // - // fn foo1(x: NonCopyStruct) { - // let y @ NonCopyStruct { copy_field: z } = x; - // // the above should turn into - // let z = x.copy_field; - // let y = x; - // } - // ``` - // First, recurse into the subpattern, if any. if let Some(subpattern) = subpattern.as_ref() { // this is the `x @ P` case; have to keep matching against `P` now - MatchPairTree::for_pattern( - place_builder, - subpattern, - cx, - &mut subpairs, - extra_data, - ); + subpats.push(InterPat::lower_thir_pat(cx, place_builder, subpattern)); } // Then push this binding, after any bindings in the subpattern. - if let Some(source) = place { - extra_data.bindings.push(super::SubpatternBindings::One(super::Binding { + if let Some(place) = place { + binding = Some(super::Binding { span: pattern.span, - source, + source: place, var_id: var, binding_mode: mode, is_shorthand, - })); + }); } - None } @@ -223,7 +347,7 @@ impl<'tcx> MatchPairTree<'tcx> { for (subplace, subpat) in prefix_slice_suffix(&place_builder, Some(array_len), prefix, slice, suffix) { - MatchPairTree::for_pattern(subplace, subpat, cx, &mut subpairs, extra_data); + subpats.push(InterPat::lower_thir_pat(cx, subplace, subpat)); } } else { // If the array length couldn't be determined, ignore the @@ -243,12 +367,12 @@ impl<'tcx> MatchPairTree<'tcx> { for (subplace, subpat) in prefix_slice_suffix(&place_builder, None, prefix, slice, suffix) { - MatchPairTree::for_pattern(subplace, subpat, cx, &mut subpairs, extra_data); + subpats.push(InterPat::lower_thir_pat(cx, subplace, subpat)); } if prefix.is_empty() && slice.is_some() && suffix.is_empty() { - // This pattern is shaped like `[..]`. It can match a slice - // of any length, so no length test is needed. + // A slice pattern shaped like `[..]` is irrefutable. + // It can match a slice of any length, so no length test is needed. None } else { // Any other shape of slice pattern requires a length test. @@ -269,7 +393,7 @@ impl<'tcx> MatchPairTree<'tcx> { let downcast_place = place_builder.downcast(adt_def, variant_index); // `(x as Variant)` for &FieldPat { field, pattern: ref subpat } in subpatterns { let subplace = downcast_place.clone_project(PlaceElem::Field(field, subpat.ty)); - MatchPairTree::for_pattern(subplace, subpat, cx, &mut subpairs, extra_data); + subpats.push(InterPat::lower_thir_pat(cx, subplace, subpat)); } // We treat non-exhaustive enums the same independent of the crate they are @@ -286,7 +410,7 @@ impl<'tcx> MatchPairTree<'tcx> { PatKind::Leaf { ref subpatterns } => { for &FieldPat { field, pattern: ref subpat } in subpatterns { let subplace = place_builder.clone_project(PlaceElem::Field(field, subpat.ty)); - MatchPairTree::for_pattern(subplace, subpat, cx, &mut subpairs, extra_data); + subpats.push(InterPat::lower_thir_pat(cx, subplace, subpat)); } None } @@ -296,27 +420,19 @@ impl<'tcx> MatchPairTree<'tcx> { Some(p_ty) if p_ty.is_ref() => p_ty, _ => span_bug!(pattern.span, "bad type for pinned deref: {:?}", pattern.ty), }; - MatchPairTree::for_pattern( + subpats.push(InterPat::lower_thir_pat( + cx, // Project into the `Pin(_)` struct, then deref the inner `&` or `&mut`. place_builder.field(FieldIdx::ZERO, pinned_ref_ty).deref(), subpattern, - cx, - &mut subpairs, - extra_data, - ); + )); None } PatKind::Deref { pin: Pinnedness::Not, ref subpattern } | PatKind::DerefPattern { ref subpattern, borrow: DerefPatBorrowMode::Box } => { - MatchPairTree::for_pattern( - place_builder.deref(), - subpattern, - cx, - &mut subpairs, - extra_data, - ); + subpats.push(InterPat::lower_thir_pat(cx, place_builder.deref(), subpattern)); None } @@ -330,13 +446,11 @@ impl<'tcx> MatchPairTree<'tcx> { Ty::new_ref(cx.tcx, cx.tcx.lifetimes.re_erased, subpattern.ty, mutability), pattern.span, ); - MatchPairTree::for_pattern( + subpats.push(InterPat::lower_thir_pat( + cx, PlaceBuilder::from(temp).deref(), subpattern, - cx, - &mut subpairs, - extra_data, - ); + )); Some(TestableCase::Deref { temp, mutability }) } @@ -348,24 +462,25 @@ impl<'tcx> MatchPairTree<'tcx> { PatKind::Never => Some(TestableCase::Never), }; - if let Some(testable_case) = testable_case { - // This pattern is refutable, so push a new match-pair node. - // - // Note: unless test_case is TestCase::Or, place must not be None. - // This means that the closure capture analysis in - // rustc_hir_typeck::upvar, and in particular the pattern handling - // code of ExprUseVisitor, must capture all of the places we'll use. - // Make sure to keep these two parts in sync! - match_pairs.push(MatchPairTree { - place, - testable_case, - subpairs, - pattern_span: pattern.span, - }) - } else { - // This pattern is irrefutable, so it doesn't need its own match-pair node. - // Just push its refutable subpatterns instead, if any. - match_pairs.extend(subpairs); + // A pattern node is guaranteed to never match if one of these is true: + // - The node itself is a never pattern (`!`). + // - It is not an or-pattern, and one of its subpatterns will never match. + // - It is an or-pattern, and _all_ of its or-subpatterns will never match. + let is_never = matches!(pattern.kind, PatKind::Never) + || subpats.iter().any(|subpat| subpat.is_never) + || or_subpats + .as_ref() + .is_some_and(|or_subpats| or_subpats.iter().all(|subpat| subpat.is_never)); + + InterPat { + place, + testable_case, + subpats, + or_subpats, + ascriptions, + binding, + pattern_span: pattern.span, + is_never, } } } diff --git a/compiler/rustc_mir_build/src/builder/matches/mod.rs b/compiler/rustc_mir_build/src/builder/matches/mod.rs index 2fbf772daf3d4..8352ec92e88b0 100644 --- a/compiler/rustc_mir_build/src/builder/matches/mod.rs +++ b/compiler/rustc_mir_build/src/builder/matches/mod.rs @@ -999,24 +999,6 @@ struct FlatPat<'tcx> { extra_data: PatternExtraData<'tcx>, } -impl<'tcx> FlatPat<'tcx> { - /// Creates a `FlatPat` containing a simplified [`MatchPairTree`] list/forest - /// for the given pattern. - fn new(place: PlaceBuilder<'tcx>, pattern: &Pat<'tcx>, cx: &mut Builder<'_, 'tcx>) -> Self { - // Recursively build a tree of match pairs for the given pattern. - let mut match_pairs = vec![]; - let mut extra_data = PatternExtraData { - span: pattern.span, - bindings: Vec::new(), - ascriptions: Vec::new(), - is_never: pattern.is_never_pattern(), - }; - MatchPairTree::for_pattern(place, pattern, cx, &mut match_pairs, &mut extra_data); - - Self { match_pairs, extra_data } - } -} - /// Candidates are a generalization of (a) top-level match arms, and /// (b) sub-branches of or-patterns, allowing the match-lowering process to handle /// them both in a mostly-uniform way. For example, the list of candidates passed @@ -1226,7 +1208,7 @@ struct Ascription<'tcx> { /// and helps [`TestKind::Switch`] and [`TestKind::SwitchInt`] know what target /// values to use. /// -/// Created by [`MatchPairTree::for_pattern`], and then inspected primarily by: +/// Created by [`MatchPairTree`], and then inspected primarily by: /// - [`Builder::pick_test_for_match_pair`] (to choose a test) /// - [`Builder::choose_bucket_for_candidate`] (to see how the test interacts with a match pair) /// diff --git a/compiler/rustc_public/src/abi.rs b/compiler/rustc_public/src/abi.rs index 1227fe23713cb..cde885def8a41 100644 --- a/compiler/rustc_public/src/abi.rs +++ b/compiler/rustc_public/src/abi.rs @@ -455,6 +455,7 @@ pub enum CallConvention { PreserveMost, PreserveAll, PreserveNone, + Tail, Custom, diff --git a/compiler/rustc_public/src/ty.rs b/compiler/rustc_public/src/ty.rs index f71ca7213e9ed..9b9a480ab5f82 100644 --- a/compiler/rustc_public/src/ty.rs +++ b/compiler/rustc_public/src/ty.rs @@ -1167,6 +1167,7 @@ pub enum Abi { RiscvInterruptM, RiscvInterruptS, RustPreserveNone, + RustTail, RustInvalid, Custom, Swift, diff --git a/compiler/rustc_public/src/unstable/convert/internal.rs b/compiler/rustc_public/src/unstable/convert/internal.rs index 37f00da9f7103..f18fe84053b32 100644 --- a/compiler/rustc_public/src/unstable/convert/internal.rs +++ b/compiler/rustc_public/src/unstable/convert/internal.rs @@ -618,6 +618,7 @@ impl RustcInternal for Abi { Abi::RiscvInterruptM => rustc_abi::ExternAbi::RiscvInterruptM, Abi::RiscvInterruptS => rustc_abi::ExternAbi::RiscvInterruptS, Abi::RustPreserveNone => rustc_abi::ExternAbi::RustPreserveNone, + Abi::RustTail => rustc_abi::ExternAbi::RustTail, Abi::Custom => rustc_abi::ExternAbi::Custom, Abi::Swift => rustc_abi::ExternAbi::Swift, } diff --git a/compiler/rustc_public/src/unstable/convert/stable/abi.rs b/compiler/rustc_public/src/unstable/convert/stable/abi.rs index f42399241cd28..7e0b04f8a7f61 100644 --- a/compiler/rustc_public/src/unstable/convert/stable/abi.rs +++ b/compiler/rustc_public/src/unstable/convert/stable/abi.rs @@ -125,6 +125,7 @@ impl<'tcx> Stable<'tcx> for CanonAbi { CanonAbi::Rust => CallConvention::Rust, CanonAbi::RustCold => CallConvention::Cold, CanonAbi::RustPreserveNone => CallConvention::PreserveNone, + CanonAbi::RustTail => CallConvention::Tail, CanonAbi::Custom => CallConvention::Custom, CanonAbi::Swift => CallConvention::Swift, CanonAbi::Arm(arm_call) => match arm_call { diff --git a/compiler/rustc_public/src/unstable/convert/stable/ty.rs b/compiler/rustc_public/src/unstable/convert/stable/ty.rs index 925d4a5b40b20..8469c500b24c8 100644 --- a/compiler/rustc_public/src/unstable/convert/stable/ty.rs +++ b/compiler/rustc_public/src/unstable/convert/stable/ty.rs @@ -1046,6 +1046,7 @@ impl<'tcx> Stable<'tcx> for rustc_abi::ExternAbi { ExternAbi::Unadjusted => Abi::Unadjusted, ExternAbi::RustCold => Abi::RustCold, ExternAbi::RustPreserveNone => Abi::RustPreserveNone, + ExternAbi::RustTail => Abi::RustTail, ExternAbi::RustInvalid => Abi::RustInvalid, ExternAbi::RiscvInterruptM => Abi::RiscvInterruptM, ExternAbi::RiscvInterruptS => Abi::RiscvInterruptS, diff --git a/compiler/rustc_resolve/src/rustdoc.rs b/compiler/rustc_resolve/src/rustdoc.rs index f26405cb223c0..92bc577f59201 100644 --- a/compiler/rustc_resolve/src/rustdoc.rs +++ b/compiler/rustc_resolve/src/rustdoc.rs @@ -412,17 +412,16 @@ pub fn may_be_doc_link(link_type: LinkType) -> bool { pub(crate) fn attrs_to_preprocessed_links(attrs: &[ast::Attribute]) -> Vec> { let (doc_fragments, other_attrs) = attrs_to_doc_fragments(attrs.iter().map(|attr| (attr, None)), false); - let mut doc = - prepare_to_doc_link_resolution(&doc_fragments).into_values().next().unwrap_or_default(); + let doc = prepare_to_doc_link_resolution(&doc_fragments).into_values().next(); + let mut links = doc.as_deref().map(parse_links).unwrap_or_default(); for attr in other_attrs { if let Some(note) = attr.deprecation_note() { - doc += note.as_str(); - doc += "\n"; + links.extend(parse_links(note.as_str())); } } - parse_links(&doc) + links } /// Similar version of `markdown_links` from rustdoc. diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index fb433aef68cf8..9313e869278db 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -1703,6 +1703,7 @@ symbols! { rust_logo, rust_out, rust_preserve_none_cc, + rust_tail_cc, rustc, rustc_abi, // FIXME(#82232, #143834): temporary name to mitigate `#[align]` nameres ambiguity diff --git a/compiler/rustc_target/src/spec/abi_map.rs b/compiler/rustc_target/src/spec/abi_map.rs index 8c56dcb899718..f7a7ae1eb7555 100644 --- a/compiler/rustc_target/src/spec/abi_map.rs +++ b/compiler/rustc_target/src/spec/abi_map.rs @@ -100,6 +100,7 @@ impl AbiMap { (ExternAbi::RustCold, _) if self.os == OsKind::Windows => CanonAbi::Rust, (ExternAbi::RustCold, _) => CanonAbi::RustCold, (ExternAbi::RustPreserveNone, _) => CanonAbi::RustPreserveNone, + (ExternAbi::RustTail, _) => CanonAbi::RustTail, (ExternAbi::Custom, _) => CanonAbi::Custom, diff --git a/compiler/rustc_trait_selection/src/solve/delegate.rs b/compiler/rustc_trait_selection/src/solve/delegate.rs index bd22ba6b6bf6d..7c2f5c7f170aa 100644 --- a/compiler/rustc_trait_selection/src/solve/delegate.rs +++ b/compiler/rustc_trait_selection/src/solve/delegate.rs @@ -7,6 +7,7 @@ use rustc_hir::def_id::{CRATE_DEF_ID, DefId}; use rustc_infer::infer::canonical::query_response::make_query_region_constraints; use rustc_infer::infer::canonical::{ Canonical, CanonicalExt as _, CanonicalQueryInput, CanonicalVarKind, CanonicalVarValues, + QueryRegionConstraint, }; use rustc_infer::infer::{InferCtxt, RegionVariableOrigin, SubregionOrigin, TyCtxtInferExt}; use rustc_infer::traits::solve::{FetchEligibleAssocItemResponse, Goal}; @@ -262,7 +263,9 @@ impl<'tcx> rustc_next_trait_solver::delegate::SolverDelegate for SolverDelegate< let mut seen = FxHashMap::default(); let mut constraints = vec![]; - for (outlives, _, vis) in region_constraints.constraints { + for QueryRegionConstraint { constraint: outlives, visible_for_leak_check: vis, .. } in + region_constraints.constraints + { match seen.entry(outlives) { Entry::Occupied(occupied) => { let idx = occupied.get(); diff --git a/compiler/rustc_trait_selection/src/traits/outlives_bounds.rs b/compiler/rustc_trait_selection/src/traits/outlives_bounds.rs index 8be26fed0ca42..a171a0de9dd79 100644 --- a/compiler/rustc_trait_selection/src/traits/outlives_bounds.rs +++ b/compiler/rustc_trait_selection/src/traits/outlives_bounds.rs @@ -1,4 +1,5 @@ use rustc_infer::infer::InferOk; +use rustc_infer::infer::canonical::QueryRegionConstraint; use rustc_infer::infer::resolve::OpportunisticRegionResolver; use rustc_infer::traits::query::type_op::ImpliedOutlivesBounds; use rustc_macros::extension; @@ -83,7 +84,7 @@ fn implied_outlives_bounds<'a, 'tcx>( // outlives bound required proving some higher-ranked coroutine obl. let QueryRegionConstraints { constraints, assumptions: _ } = constraints; let cause = ObligationCause::misc(span, body_id); - for &(constraint, _, vis) in &constraints { + for &QueryRegionConstraint { constraint, visible_for_leak_check: vis, .. } in &constraints { match constraint { ty::RegionConstraint::Outlives(predicate) => { infcx.register_outlives_constraint(predicate, vis, &cause) diff --git a/compiler/rustc_traits/src/coroutine_witnesses.rs b/compiler/rustc_traits/src/coroutine_witnesses.rs index 83a77f17b28ce..7fe8303b7459b 100644 --- a/compiler/rustc_traits/src/coroutine_witnesses.rs +++ b/compiler/rustc_traits/src/coroutine_witnesses.rs @@ -1,4 +1,5 @@ use rustc_infer::infer::TyCtxtInferExt; +use rustc_infer::infer::canonical::QueryRegionConstraint; use rustc_infer::infer::canonical::query_response::make_query_region_constraints; use rustc_infer::infer::resolve::OpportunisticRegionResolver; use rustc_infer::traits::{Obligation, ObligationCause}; @@ -80,7 +81,7 @@ fn compute_assumptions<'tcx>( tcx.mk_outlives_from_iter( constraints .into_iter() - .flat_map(|(constraint, _, _)| constraint.iter_outlives()) + .flat_map(|QueryRegionConstraint { constraint, .. }| constraint.iter_outlives()) // FIXME(higher_ranked_auto): We probably should deeply resolve these before // filtering out infers which only correspond to unconstrained infer regions // which we can sometimes get. diff --git a/library/alloc/src/str.rs b/library/alloc/src/str.rs index cf04402e3d984..230039713de8a 100644 --- a/library/alloc/src/str.rs +++ b/library/alloc/src/str.rs @@ -659,6 +659,108 @@ impl str { s } + /// Returns the case-folded equivalent of this string slice, as a new [`String`]. + /// + /// Case folding is a transformation, mostly matching lowercase, that is meant to be used + /// for case-insensitive string comparisons. Case-folded strings should not usually + /// be exposed directly to users. + /// + /// For the precise specification of case folding, see + /// [Chapter 3 (Conformance)](https://www.unicode.org/versions/latest/core-spec/chapter-3/#G63737) + /// of the Unicode standard. + /// + /// Since some characters can expand into multiple characters when case folding, + /// this function returns a [`String`] instead of modifying the parameter in-place. + /// + /// No [normalization] (e.g. NFC) is performed, so visually and semantically identical strings + /// might still casefold differently. For example, `"Å"` (U+00C5 LATIN CAPITAL LETTER A WITH RING ABOVE) + /// is considered distinct from `"Å"` (A followed by U+030A COMBINING RING ABOVE), + /// even though Unicode considers them canonically equivalent. + /// + /// Like [`char::to_casefold_unnormalized()`] this method does not handle language-specific + /// casing, like Turkish and Azeri I/ı/İ/i. See that method's documentation + /// for more information. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// #![feature(casefold)] + /// let s0 = "HELLO"; + /// let s1 = "Hello"; + /// + /// assert_eq!(s0.to_casefold_unnormalized(), s1.to_casefold_unnormalized()); + /// assert_eq!(s0.to_casefold_unnormalized(), "hello") + /// ``` + /// + /// Scripts without case are not changed: + /// + /// ``` + /// #![feature(casefold)] + /// let new_year = "农历新年"; + /// + /// assert_eq!(new_year, new_year.to_casefold_unnormalized()); + /// ``` + /// + /// One character can become multiple: + /// + /// ``` + /// #![feature(casefold)] + /// let s0 = "TSCHÜẞ"; + /// let s1 = "TSCHÜSS"; + /// let s2 = "tschüß"; + /// + /// assert_eq!(s0.to_casefold_unnormalized(), s1.to_casefold_unnormalized()); + /// assert_eq!(s0.to_casefold_unnormalized(), s2.to_casefold_unnormalized()); + /// assert_eq!(s0.to_casefold_unnormalized(), "tschüss"); + /// ``` + /// + /// No NFC [normalization] is performed: + /// + /// ```rust + /// #![feature(casefold)] + /// // These two strings are visually and semantically identical... + /// let comp = "Å"; + /// let decomp = "Å"; + /// + /// // ... but not codepoint-for-codepoint equal. + /// assert_eq!(comp, "\u{C5}"); + /// assert_eq!(decomp, "A\u{030A}"); + /// + /// // Their case-foldings are likewise unequal: + /// assert_eq!(comp.to_casefold_unnormalized(), "\u{E5}"); + /// assert_eq!(decomp.to_casefold_unnormalized(), "a\u{030A}"); + /// ``` + /// + /// [normalization]: https://www.unicode.org/faq/normalization + #[cfg(not(no_global_oom_handling))] + #[rustc_allow_incoherent_impl] + #[must_use = "this returns the case-folded string as a new String, \ + without modifying the original"] + #[unstable(feature = "casefold", issue = "154742")] + pub fn to_casefold_unnormalized(&self) -> String { + // SAFETY: `to_ascii_lowercase` preserves ASCII bytes, so the converted + // prefix remains valid UTF-8. + let (mut s, rest) = unsafe { convert_while_ascii(self, u8::to_ascii_lowercase) }; + + for c in rest.chars() { + match conversions::to_casefold(c) { + [a, '\0', _] => s.push(a), + [a, b, '\0'] => { + s.push(a); + s.push(b); + } + [a, b, c] => { + s.push(a); + s.push(b); + s.push(c); + } + } + } + s + } + /// Converts a [`Box`] into a [`String`] without copying or allocating. /// /// # Examples diff --git a/library/alloctests/tests/lib.rs b/library/alloctests/tests/lib.rs index b7c3e39c992b0..f7573c7d7fc3e 100644 --- a/library/alloctests/tests/lib.rs +++ b/library/alloctests/tests/lib.rs @@ -3,6 +3,7 @@ #![feature(const_heap)] #![feature(deque_extend_front)] #![feature(iter_array_chunks)] +#![feature(casefold)] #![feature(cow_is_borrowed)] #![feature(core_intrinsics)] #![feature(downcast_unchecked)] diff --git a/library/alloctests/tests/str.rs b/library/alloctests/tests/str.rs index dca2c49249aff..1875701b102a8 100644 --- a/library/alloctests/tests/str.rs +++ b/library/alloctests/tests/str.rs @@ -1886,7 +1886,13 @@ fn to_lowercase() { #[test] fn to_uppercase() { assert_eq!("".to_uppercase(), ""); - assert_eq!("aéDžßfiᾀ".to_uppercase(), "AÉDŽSSFIἈΙ"); + assert_eq!("aéDžßẞfiᾀ".to_uppercase(), "AÉDŽSSẞFIἈΙ"); +} + +#[test] +fn to_casefold_unnormalized() { + assert_eq!("".to_casefold_unnormalized(), ""); + assert_eq!("ꮿfiῲὼ\u{0345}ßẞΣς".to_casefold_unnormalized(), "Ꮿfiὼιὼιssssσσ"); } #[test] diff --git a/library/core/src/ascii/ascii_char.rs b/library/core/src/ascii/ascii_char.rs index a957005972a20..c8c05ee559f74 100644 --- a/library/core/src/ascii/ascii_char.rs +++ b/library/core/src/ascii/ascii_char.rs @@ -476,6 +476,11 @@ impl AsciiChar { #[unstable(feature = "ascii_char", issue = "110998")] #[inline] pub const unsafe fn from_u8_unchecked(b: u8) -> Self { + assert_unsafe_precondition!( + check_library_ub, + "`ascii::Char::from_u8_unchecked` input cannot exceed 127.", + (b: u8 = b) => b <= 127, + ); // SAFETY: Our safety precondition is that `b` is in-range. unsafe { transmute(b) } } diff --git a/library/core/src/char/methods.rs b/library/core/src/char/methods.rs index d8b7fe44e453a..a397dd8df5359 100644 --- a/library/core/src/char/methods.rs +++ b/library/core/src/char/methods.rs @@ -1076,16 +1076,17 @@ impl char { } /// Returns `true` if this `char` has the `Case_Ignorable` property. This narrow-use property - /// is used to implement context-dependent casing for the Greek letter sigma (uppercase Σ), + /// is used to implement context-dependent casing for the Greek letter sigma (uppercase 'Σ'), /// which has two lowercase forms. /// /// `Case_Ignorable` is [described][D136] in Chapter 3 (Conformance) of the Unicode Core Specification, - /// and specified in the [Unicode Character Database][ucd] [`DerivedCoreProperties.txt`]; - /// see those resources for more information. + /// and specified in the [Unicode Character Database][ucd] [`DerivedCoreProperties.txt`]. + /// See those resources, as well as [`to_lowercase()`]'s documentation, for more information. /// /// [D136]: https://www.unicode.org/versions/latest/core-spec/chapter-3/#G63116 /// [ucd]: https://www.unicode.org/reports/tr44/ /// [`DerivedCoreProperties.txt`]: https://www.unicode.org/Public/UCD/latest/ucd/DerivedCoreProperties.txt + /// [`to_lowercase()`]: Self::to_lowercase() #[must_use] #[inline] #[unstable(feature = "case_ignorable", issue = "154848")] @@ -1155,8 +1156,6 @@ impl char { /// If this `char` expands to multiple `char`s, the iterator yields the `char`s given by /// [`SpecialCasing.txt`]. The maximum number of `char`s in a case mapping is 3. /// - /// [`SpecialCasing.txt`]: https://www.unicode.org/Public/UCD/latest/ucd/SpecialCasing.txt - /// /// This operation performs an unconditional mapping without tailoring. That is, the conversion /// is independent of context and language. See [below](#notes-on-context-and-locale) /// for more information. @@ -1211,14 +1210,25 @@ impl char { /// /// ## Greek sigma /// - /// In Greek, the letter simga (uppercase Σ) has two lowercase forms: - /// ς which is used only at the end of a word, and σ which is used everywhere else. - /// `to_lowercase()` always uses the second form: + /// In Greek, the letter simga (uppercase 'Σ') has two lowercase forms: + /// 'σ' which is used in most situations, and 'ς' which appears only + /// at the end of a word. [`char::to_lowercase()`] always uses the first form: /// /// ``` /// assert_eq!('Σ'.to_lowercase().to_string(), "σ"); /// ``` /// + /// `str::to_lowercase()` (only available with the `alloc` crate) + /// *does* properly handle this contextual mapping, + /// so prefer using that method if you can. Alternatively, you can use + /// [`is_cased()`] and [`is_case_ignorable()`] to implement it yourself. + /// See `Final_Sigma` in [Table 3.17] of the Unicode Standard, + /// along with [`SpecialCasing.txt`], for more details. + /// + /// [`is_cased()`]: Self::is_cased() + /// [`is_case_ignorable()`]: Self::is_case_ignorable() + /// [Table 3.17]: https://www.unicode.org/versions/latest/core-spec/chapter-3/#G54277 + /// /// ## Turkish and Azeri I/ı/İ/i /// /// In Turkish and Azeri, the equivalent of 'i' in Latin has five forms instead of two: @@ -1226,13 +1236,13 @@ impl char { /// * 'Dotless': I / ı, sometimes written ï /// * 'Dotted': İ / i /// - /// Note that the uppercase undotted 'I' is the same as the Latin. Therefore: + /// Note that the uppercase undotted 'I' is the same codepoint as the Latin. Therefore: /// /// ``` /// let lower_i = 'I'.to_lowercase().to_string(); /// ``` /// - /// The value of `lower_i` here relies on the language of the text: if we're + /// `'I'`'s correct lowercase relies on the language of the text: if we're /// in `en-US`, it should be `"i"`, but if we're in `tr-TR` or `az-AZ`, it should /// be `"ı"`. `to_lowercase()` does not take this into account, and so: /// @@ -1243,6 +1253,8 @@ impl char { /// ``` /// /// holds across languages. + /// + /// [`SpecialCasing.txt`]: https://www.unicode.org/Public/UCD/latest/ucd/SpecialCasing.txt #[must_use = "this returns the lowercased character as a new iterator, \ without modifying the original"] #[stable(feature = "rust1", since = "1.0.0")] @@ -1393,22 +1405,22 @@ impl char { /// As stated above, this method is locale-insensitive. /// If you need locale support, consider using an external crate, /// like [`icu_casemap`](https://crates.io/crates/icu_casemap) - /// which is developed by Unicode. A description of a common - /// locale-dependent casing issue follows: + /// which is developed by Unicode. A description of one common + /// locale-dependent casing issue follows (there are others): /// /// In Turkish and Azeri, the equivalent of 'i' in Latin has five forms instead of two: /// /// * 'Dotless': I / ı, sometimes written ï /// * 'Dotted': İ / i /// - /// Note that the lowercase dotted 'i' is the same as the Latin. Therefore: + /// Note that the lowercase dotted 'i' is the same codepoint as the Latin. Therefore: /// /// ``` /// #![feature(titlecase)] /// let upper_i = 'i'.to_titlecase().to_string(); /// ``` /// - /// The value of `upper_i` here relies on the language of the text: if we're + /// `'i'`'s correct titlecase relies on the language of the text: if we're /// in `en-US`, it should be `"I"`, but if we're in `tr-TR` or `az-AZ`, it should /// be `"İ"`. `to_titlecase()` does not take this into account, and so: /// @@ -1505,21 +1517,21 @@ impl char { /// As stated above, this method is locale-insensitive. /// If you need locale support, consider using an external crate, /// like [`icu_casemap`](https://crates.io/crates/icu_casemap) - /// which is developed by Unicode. A description of a common - /// locale-dependent casing issue follows: + /// which is developed by Unicode. A description of one common + /// locale-dependent casing issue follows (there are others): /// /// In Turkish and Azeri, the equivalent of 'i' in Latin has five forms instead of two: /// /// * 'Dotless': I / ı, sometimes written ï /// * 'Dotted': İ / i /// - /// Note that the lowercase dotted 'i' is the same as the Latin. Therefore: + /// Note that the lowercase dotted 'i' is the same codepoint as the Latin. Therefore: /// /// ``` /// let upper_i = 'i'.to_uppercase().to_string(); /// ``` /// - /// The value of `upper_i` here relies on the language of the text: if we're + /// `'i'`'s correct uppercase relies on the language of the text: if we're /// in `en-US`, it should be `"I"`, but if we're in `tr-TR` or `az-AZ`, it should /// be `"İ"`. `to_uppercase()` does not take this into account, and so: /// @@ -1540,6 +1552,110 @@ impl char { ToUppercase(CaseMappingIter::new(conversions::to_upper(self))) } + /// Returns an iterator that yields the case folding of this `char` as one or more + /// `char`s. + /// + /// Case folding is meant to be used when performing case-insensitive string comparisons. + /// Case-folded strings should not usually be exposed directly to users. For most, + /// but not all, characters, the casefold mapping is identical to the lowercase one. + /// + /// This iterator yields the `char`(s) in the common or full case folding for this `char`, + /// as given by the [Unicode Character Database][ucd] [`CaseFolding.txt`]. + /// The maximum number of `char`s in a case folding is 3. + /// + /// [ucd]: https://www.unicode.org/reports/tr44/ + /// [`CaseFolding.txt`]: https://www.unicode.org/Public/UCD/latest/ucd/CaseFolding.txt + /// + /// + /// No [normalization] (e.g. NFC) is performed, so visually and semantically identical characters + /// might still casefold differently. For example, `'ά'` (U+03AC GREEK SMALL LETTER ALPHA WITH TONOS) + /// is considered distinct from `'ά'` (U+1F71 GREEK SMALL LETTER ALPHA WITH OXIA), + /// even though Unicode considers them canonically equivalent. + /// + /// In addition, this method is independent of language/locale, + /// so the special behavior of I/ı/İ/i in Turkish and Azeri is not handled. + /// + /// In the [Unicode Standard], Chapter 4 (Character Properties) discusses case folding in + /// general and Chapter 3 (Conformance) discusses the default algorithm for case folding. + /// + /// [Unicode Standard]: https://www.unicode.org/versions/latest/ + /// + /// # Examples + /// + /// The German sharp S `'ß'` (U+DF) is a single Unicode code point + /// that casefolds to `"ss"`. Its uppercase variant '`ẞ`' (U+1E9E) + /// has the same case-folding. + /// + /// As an iterator: + /// + /// ``` + /// #![feature(casefold)] + /// assert!('ß'.to_casefold_unnormalized().eq(['s', 's'])); + /// assert!('ẞ'.to_casefold_unnormalized().eq(['s', 's'])); + /// ``` + /// + /// Using [`to_string`](../std/string/trait.ToString.html#tymethod.to_string): + /// + /// ``` + /// #![feature(casefold)] + /// assert_eq!('ß'.to_casefold_unnormalized().to_string(), "ss"); + /// assert_eq!('ẞ'.to_casefold_unnormalized().to_string(), "ss"); + /// ``` + /// + /// No [normalization] is performed: + /// + /// ```rust + /// #![feature(casefold)] + /// // These two characters are visually and semantically identical; + /// // Unicode considers them to be canonically equivalent. + /// let alpha_tonos = 'ά'; + /// let alpha_oxia = 'ά'; + /// + /// // However, they are different codepoints: + /// assert_eq!(alpha_tonos, '\u{03AC}'); + /// assert_eq!(alpha_oxia, '\u{1F71}'); + /// + /// // Their case-foldings are likewise unequal: + /// assert!(alpha_tonos.to_casefold_unnormalized().eq(['\u{03AC}'])); + /// assert!(alpha_oxia.to_casefold_unnormalized().eq(['\u{1F71}'])); + /// ``` + /// + /// # Note on locale + /// + /// In Turkish and Azeri, the equivalent of 'i' in Latin has five forms instead of two: + /// + /// * 'Dotless': I / ı, sometimes written ï + /// * 'Dotted': İ / i + /// + /// Note that the uppercase undotted 'I' is the same codepoint as the Latin. Therefore: + /// + /// ``` + /// #![feature(casefold)] + /// let casefold_i = 'I'.to_casefold_unnormalized().to_string(); + /// ``` + /// + /// `'I'`'s correct case folding relies on the language of the text: if we're + /// in `en-US`, it should be `"i"`, but if we're in `tr-TR` or `az-AZ`, it should + /// be `"ı"`. `to_casefold_unnormalized()` does not take this into account, and so: + /// + /// ``` + /// #![feature(casefold)] + /// let casefold_i = 'I'.to_casefold_unnormalized().to_string(); + /// + /// assert_eq!(casefold_i, "i"); + /// ``` + /// + /// holds across languages. + /// + /// [normalization]: https://www.unicode.org/faq/normalization + #[must_use = "this returns the case-folded character as a new iterator, \ + without modifying the original"] + #[unstable(feature = "casefold", issue = "154742")] + #[inline] + pub fn to_casefold_unnormalized(self) -> ToCasefold { + ToCasefold(CaseMappingIter::new(conversions::to_casefold(self))) + } + /// Checks if the value is within the ASCII range. /// /// # Examples diff --git a/library/core/src/char/mod.rs b/library/core/src/char/mod.rs index 2416406576204..eab7076c8427d 100644 --- a/library/core/src/char/mod.rs +++ b/library/core/src/char/mod.rs @@ -519,6 +519,21 @@ casemappingiter_impls! { ToLowercase } +casemappingiter_impls! { + #[unstable(feature = "casefold", issue = "154742")] + #[unstable(feature = "casefold", issue = "154742")] + #[unstable(feature = "casefold", issue = "154742")] + #[unstable(feature = "casefold", issue = "154742")] + #[unstable(feature = "casefold", issue = "154742")] + /// Returns an iterator that yields the case-folded equivalent of a `char`. + /// + /// This `struct` is created by the [`to_casefold_unnormalized`] method on [`char`]. See + /// its documentation for more. + /// + /// [`to_casefold_unnormalized`]: char::to_casefold_unnormalized + ToCasefold +} + #[derive(Debug, Clone)] struct CaseMappingIter(core::array::IntoIter); diff --git a/library/core/src/str/mod.rs b/library/core/src/str/mod.rs index fe8ed6c8e637e..c96aaecf94229 100644 --- a/library/core/src/str/mod.rs +++ b/library/core/src/str/mod.rs @@ -2826,6 +2826,9 @@ impl str { /// Same as `to_ascii_lowercase(a) == to_ascii_lowercase(b)`, /// but without allocating and copying temporaries. /// + /// For Unicode-aware case-insensitive matching, consider + /// [`str::eq_ignore_case_unnormalized`]. + /// /// # Examples /// /// ``` @@ -2841,6 +2844,59 @@ impl str { self.as_bytes().eq_ignore_ascii_case(other.as_bytes()) } + /// Checks that two strings are a caseless match, according to + /// [Definition 144] in Chapter 3 of the Unicode Standard. + /// + /// [Definition 144]: https://www.unicode.org/versions/latest/core-spec/chapter-3/#G53513 + /// + /// Same as `a.to_casefold_unnormalized() == b.to_casefold_unnormalized()`, + /// but without allocating. See that method's documentation, + /// as well as [`char::to_casefold_unnormalized()`], + /// for more information about case folding. + /// + /// No [normalization] (e.g. NFC) is performed, so visually and semantically identical strings + /// might still compare unequal. For example, `"Å"` (U+00C5 LATIN CAPITAL LETTER A WITH RING ABOVE) + /// is considered distinct from `"Å"` (A followed by U+030A COMBINING RING ABOVE), + /// even though Unicode considers them canonically equivalent. + /// + /// In addition, this method is independent of language/locale, + /// so the special behavior of I/ı/İ/i in Turkish and Azeri is not handled. + /// + /// # Examples + /// + /// ``` + /// #![feature(casefold)] + /// assert!("Ferris".eq_ignore_case_unnormalized("FERRIS")); + /// assert!("Ferrös".eq_ignore_case_unnormalized("FERRÖS")); + /// assert!("ẞ".eq_ignore_case_unnormalized("ss")); + /// ``` + /// + /// No NFC [normalization] is performed: + /// + /// ```rust + /// #![feature(casefold)] + /// // These two strings are visually and semantically identical... + /// let comp = "Å"; + /// let decomp = "Å"; + /// + /// // ... but not codepoint-for-codepoint equal. + /// assert_eq!(comp, "\u{C5}"); + /// assert_eq!(decomp, "A\u{030A}"); + /// + /// // Their case-foldings are likewise unequal: + /// assert!(!comp.eq_ignore_case_unnormalized(decomp)); + /// ``` + /// + /// [normalization]: https://www.unicode.org/faq/normalization + #[unstable(feature = "casefold", issue = "154742")] + #[must_use] + #[inline] + pub fn eq_ignore_case_unnormalized(&self, other: &str) -> bool { + self.chars() + .flat_map(char::to_casefold_unnormalized) + .eq(other.chars().flat_map(char::to_casefold_unnormalized)) + } + /// Converts this string to its ASCII upper case equivalent in-place. /// /// ASCII letters 'a' to 'z' are mapped to 'A' to 'Z', diff --git a/library/core/src/sync/sync_view.rs b/library/core/src/sync/sync_view.rs index 3b02c4c727ca8..63e157bf90f23 100644 --- a/library/core/src/sync/sync_view.rs +++ b/library/core/src/sync/sync_view.rs @@ -188,7 +188,7 @@ impl SyncView { #[rustc_const_unstable(feature = "exclusive_wrapper", issue = "98407")] #[must_use] #[inline] - pub const fn as_pin(self: Pin<&Self>) -> Pin<&T> { + pub const fn as_pin_ref(self: Pin<&Self>) -> Pin<&T> { // SAFETY: `SyncView` can only produce `&T` if itself is unpinned // `Pin::map_unchecked` is not const, so we do this conversion manually unsafe { Pin::new_unchecked(&self.get_ref().inner) } diff --git a/library/core/src/unicode/unicode_data.rs b/library/core/src/unicode/unicode_data.rs index 83d3808051840..9df020ced674b 100644 --- a/library/core/src/unicode/unicode_data.rs +++ b/library/core/src/unicode/unicode_data.rs @@ -10,7 +10,8 @@ // to_lower : 1112 bytes, 1462 codepoints in 185 ranges (U+0000C0 - U+01E921) using 2-level LUT // to_upper : 1998 bytes, 1554 codepoints in 299 ranges (U+0000B5 - U+01E943) using 2-level LUT // to_title : 340 bytes, 135 codepoints in 49 ranges (U+0000DF - U+00FB17) using 2-level LUT -// Total : 9629 bytes +// to_casefold : 32 bytes, 174 codepoints in 5 ranges (U+000131 - U+00ABBF) using 2-level LUT +// Total : 9661 bytes #[inline(always)] const fn bitset_search< @@ -846,7 +847,7 @@ pub mod conversions { } pub fn to_lower(c: char) -> [char; 3] { - // https://util.unicode.org/UnicodeJsps/list-unicodeset.jsp?a=%5B%253AChanges_When_Lowercased%253A%5D-%5B%253AASCII%253A%5D&abb=on + // https://util.unicode.org/UnicodeJsps/list-unicodeset.jsp?a=[:Changes_When_Lowercased:]-[:ASCII:]&abb=on if c < '\u{C0}' { return [c.to_ascii_lowercase(), '\0', '\0']; } @@ -855,7 +856,7 @@ pub mod conversions { } pub fn to_upper(c: char) -> [char; 3] { - // https://util.unicode.org/UnicodeJsps/list-unicodeset.jsp?a=%5B%253AChanges_When_Uppercased%253A%5D-%5B%253AASCII%253A%5D&abb=on + // https://util.unicode.org/UnicodeJsps/list-unicodeset.jsp?a=[:Changes_When_Uppercased:]-[:ASCII:]&abb=on if c < '\u{B5}' { return [c.to_ascii_uppercase(), '\0', '\0']; } @@ -864,7 +865,7 @@ pub mod conversions { } pub fn to_title(c: char) -> [char; 3] { - // https://util.unicode.org/UnicodeJsps/list-unicodeset.jsp?a=%5B%253AChanges_When_Titlecased%253A%5D-%5B%253AASCII%253A%5D&abb=on + // https://util.unicode.org/UnicodeJsps/list-unicodeset.jsp?a=[:Changes_When_Titlecased:]-[:ASCII:]&abb=on if c < '\u{B5}' { return [c.to_ascii_uppercase(), '\0', '\0']; } @@ -872,6 +873,88 @@ pub mod conversions { lookup(c, &TITLECASE_LUT).or_else(|| lookup(c, &UPPERCASE_LUT)).unwrap_or([c, '\0', '\0']) } + pub fn to_casefold(c: char) -> [char; 3] { + // https://util.unicode.org/UnicodeJsps/list-unicodeset.jsp?a=[:Changes_When_Casefolded:]-[:ASCII:]&abb=on + if c < '\u{B5}' { + return [c.to_ascii_lowercase(), '\0', '\0']; + } + + + lookup(c, &CASEFOLD_LUT).unwrap_or_else(|| { + // Fall back to lowercase of uppercase + + let uppercase = lookup(c, &UPPERCASE_LUT).unwrap_or([c, '\0', '\0']); + + // We need to take the lowercase of each character in `uppercase`, + // and then concatenate them together. + + // Lowercase the first uppercased char + let mut final_result = to_lower(uppercase[0]); + + if uppercase[1] != '\0' { + // There's a 2nd uppercase char, lowercase it as well + let lowercase_1 = to_lower(uppercase[1]); + + // The lowercase of the second uppercase character + // can't be 3 chars long; + // that would bring the total case-folding length + // above 3 characters, which would violate + // a Unicode stability guarantee. + debug_assert_eq!(lowercase_1[2], '\0'); + + // Currently, in every case where there + // are multiple uppercased characters, + // the lowercase of the first uppercase + // has length 1. However, Unicode doesn't + // guarantee this. + // If, after updating the Unicode data + // to a new Unicode version, the below + // assertion starts to fail in + // `coretests/tests/unicode.rs` `to_casefold()`, + // delete it, and uncomment the + // `if` condition and corresponding + // `else` block below it. + debug_assert_eq!(final_result[1], '\0'); + //if final_result[1] == '\0' { + + final_result[1] = lowercase_1[0]; + + if uppercase[2] != '\0' { + // There's a 3rd uppercased char, lowercase it as well. + // Because of the Unicode stability guarantee that case-folding + // does not expand a string more than 3x in length, + // we know this lowercase must be 1 char long. + + debug_assert_eq!(lowercase_1[1], '\0'); + let lowercase_2 = to_lower(uppercase[2]); + debug_assert_eq!(lowercase_2[1], '\0'); + debug_assert_eq!(lowercase_2[2], '\0'); + final_result[2] = lowercase_2[0]; + } else { + // Currently, the lowercase of + // the second uppercase character + // can't be 2 chars long either, + // but Unicode doesn't guarantee this. + // If, after updating the Unicode data + // to a new Unicode version, the below + // assertion starts to fail in + // `coretests/tests/unicode.rs` `to_casefold()`, + // delete it and uncomment the line + // below it. + debug_assert_eq!(lowercase_1[1], '\0'); + //final_result[2] = lowercase_1[1]; + } + + /*} else { + final_result[2] = lowercase_1[0]; + debug_assert_eq!(lowercase_1[1], '\0'); + debug_assert_eq!(uppercase[2], '\0') + }*/ + } + final_result + }) + } + static LOWERCASE_LUT: L1Lut = L1Lut { l2_luts: [ L2Lut { @@ -1188,4 +1271,24 @@ pub mod conversions { }, ], }; + + static CASEFOLD_LUT: L1Lut = L1Lut { + l2_luts: [ + L2Lut { + singles: &[ // 4 entries, 24 bytes + (Range::singleton(0x0131), 0), (Range::step_by_1(0x13a0..=0x13f5), 0), + (Range::step_by_1(0x13f8..=0x13fd), -8), (Range::step_by_1(0xab70..=0xabbf), 26672), + ], + multis: &[ // 1 entries, 8 bytes + (0x1e9e, [0x0073, 0x0073, 0x0000]), + ], + }, + L2Lut { + singles: &[ // 0 entries, 0 bytes + ], + multis: &[ // 0 entries, 0 bytes + ], + }, + ], + }; } diff --git a/library/coretests/tests/char.rs b/library/coretests/tests/char.rs index 43372005ad5f3..e0921e2f39af5 100644 --- a/library/coretests/tests/char.rs +++ b/library/coretests/tests/char.rs @@ -212,6 +212,41 @@ fn test_to_uppercase() { assert_eq!(upper('ᾀ'), "ἈΙ"); } +#[test] +fn test_to_casefold_unnormalized() { + fn fold(c: char) -> String { + let to_casefold = c.to_casefold_unnormalized(); + assert_eq!(to_casefold.len(), to_casefold.count()); + let iter: String = c.to_casefold_unnormalized().collect(); + let disp: String = c.to_casefold_unnormalized().to_string(); + assert_eq!(iter, disp); + let iter_rev: String = c.to_casefold_unnormalized().rev().collect(); + let disp_rev: String = disp.chars().rev().collect(); + assert_eq!(iter_rev, disp_rev); + iter + } + assert_eq!(fold('A'), "a"); + assert_eq!(fold('Ö'), "ö"); + assert_eq!(fold('ß'), "ss"); + assert_eq!(fold('ẞ'), "ss"); + assert_eq!(fold('Ü'), "ü"); + assert_eq!(fold('💩'), "💩"); + assert_eq!(fold('Σ'), "σ"); + assert_eq!(fold('ς'), "σ"); + assert_eq!(fold('Τ'), "τ"); + assert_eq!(fold('Ι'), "ι"); + assert_eq!(fold('Γ'), "γ"); + assert_eq!(fold('Μ'), "μ"); + assert_eq!(fold('Α'), "α"); + assert_eq!(fold('Dž'), "dž"); + assert_eq!(fold('fi'), "fi"); + assert_eq!(fold('İ'), "i\u{307}"); + assert_eq!(fold('ꮿ'), "Ꮿ"); + assert_eq!(fold('Ꮿ'), "Ꮿ"); + assert_eq!(fold('ῲ'), "ὼι"); + assert_eq!(fold('\u{0345}'), "ι"); +} + #[test] fn test_is_control() { assert!('\u{0}'.is_control()); diff --git a/library/coretests/tests/lib.rs b/library/coretests/tests/lib.rs index aa6aa1478bd70..36cb121e8e981 100644 --- a/library/coretests/tests/lib.rs +++ b/library/coretests/tests/lib.rs @@ -10,6 +10,7 @@ #![feature(async_iterator)] #![feature(borrowed_buf_init)] #![feature(bstr)] +#![feature(casefold)] #![feature(cfg_target_has_reliable_f16_f128)] #![feature(char_internals)] #![feature(clone_to_uninit)] diff --git a/library/coretests/tests/unicode.rs b/library/coretests/tests/unicode.rs index 12eed25a1feae..05cea23fd4781 100644 --- a/library/coretests/tests/unicode.rs +++ b/library/coretests/tests/unicode.rs @@ -124,3 +124,22 @@ fn to_titlecase() { unicode_data::conversions::to_upper, ); } + +/// This test verifies some assumptions we currently make about Unicode casings +/// which might be falsified by future versions of the standard. +/// It's important that it gets run with debug assertions enabled, +/// so that the debug assertions in `core/src/unicode/unicode_data.rs` +/// `conversions::to_casefold` get run with every possible Unicode character as input. +#[test] +#[cfg_attr(miri, ignore)] // Miri is too slow +fn to_casefold() { + test_case_mapping(test_data::TO_CASEFOLD, unicode_data::conversions::to_casefold, |c| { + let upper = unicode_data::conversions::to_upper(c); + let lower = upper.map(unicode_data::conversions::to_lower); + let mut result = ['\0'; 3]; + for (i, c) in lower.into_iter().flatten().filter(|&c| c != '\0').enumerate() { + result[i] = c; + } + result + }); +} diff --git a/library/coretests/tests/unicode/test_data.rs b/library/coretests/tests/unicode/test_data.rs index 962770a0ff830..77b976c489c9b 100644 --- a/library/coretests/tests/unicode/test_data.rs +++ b/library/coretests/tests/unicode/test_data.rs @@ -2931,3 +2931,94 @@ pub(super) static TO_TITLE: &[(char, [char; 3]); 135] = &[ ('\u{fb16}', ['\u{54e}', '\u{576}', '\u{0}']), ('\u{fb17}', ['\u{544}', '\u{56d}', '\u{0}']), ]; + +#[rustfmt::skip] +pub(super) static TO_CASEFOLD: &[(char, [char; 3]); 174] = &[ + ('\u{131}', ['\u{131}', '\u{0}', '\u{0}']), ('\u{13a0}', ['\u{13a0}', '\u{0}', '\u{0}']), + ('\u{13a1}', ['\u{13a1}', '\u{0}', '\u{0}']), ('\u{13a2}', ['\u{13a2}', '\u{0}', '\u{0}']), + ('\u{13a3}', ['\u{13a3}', '\u{0}', '\u{0}']), ('\u{13a4}', ['\u{13a4}', '\u{0}', '\u{0}']), + ('\u{13a5}', ['\u{13a5}', '\u{0}', '\u{0}']), ('\u{13a6}', ['\u{13a6}', '\u{0}', '\u{0}']), + ('\u{13a7}', ['\u{13a7}', '\u{0}', '\u{0}']), ('\u{13a8}', ['\u{13a8}', '\u{0}', '\u{0}']), + ('\u{13a9}', ['\u{13a9}', '\u{0}', '\u{0}']), ('\u{13aa}', ['\u{13aa}', '\u{0}', '\u{0}']), + ('\u{13ab}', ['\u{13ab}', '\u{0}', '\u{0}']), ('\u{13ac}', ['\u{13ac}', '\u{0}', '\u{0}']), + ('\u{13ad}', ['\u{13ad}', '\u{0}', '\u{0}']), ('\u{13ae}', ['\u{13ae}', '\u{0}', '\u{0}']), + ('\u{13af}', ['\u{13af}', '\u{0}', '\u{0}']), ('\u{13b0}', ['\u{13b0}', '\u{0}', '\u{0}']), + ('\u{13b1}', ['\u{13b1}', '\u{0}', '\u{0}']), ('\u{13b2}', ['\u{13b2}', '\u{0}', '\u{0}']), + ('\u{13b3}', ['\u{13b3}', '\u{0}', '\u{0}']), ('\u{13b4}', ['\u{13b4}', '\u{0}', '\u{0}']), + ('\u{13b5}', ['\u{13b5}', '\u{0}', '\u{0}']), ('\u{13b6}', ['\u{13b6}', '\u{0}', '\u{0}']), + ('\u{13b7}', ['\u{13b7}', '\u{0}', '\u{0}']), ('\u{13b8}', ['\u{13b8}', '\u{0}', '\u{0}']), + ('\u{13b9}', ['\u{13b9}', '\u{0}', '\u{0}']), ('\u{13ba}', ['\u{13ba}', '\u{0}', '\u{0}']), + ('\u{13bb}', ['\u{13bb}', '\u{0}', '\u{0}']), ('\u{13bc}', ['\u{13bc}', '\u{0}', '\u{0}']), + ('\u{13bd}', ['\u{13bd}', '\u{0}', '\u{0}']), ('\u{13be}', ['\u{13be}', '\u{0}', '\u{0}']), + ('\u{13bf}', ['\u{13bf}', '\u{0}', '\u{0}']), ('\u{13c0}', ['\u{13c0}', '\u{0}', '\u{0}']), + ('\u{13c1}', ['\u{13c1}', '\u{0}', '\u{0}']), ('\u{13c2}', ['\u{13c2}', '\u{0}', '\u{0}']), + ('\u{13c3}', ['\u{13c3}', '\u{0}', '\u{0}']), ('\u{13c4}', ['\u{13c4}', '\u{0}', '\u{0}']), + ('\u{13c5}', ['\u{13c5}', '\u{0}', '\u{0}']), ('\u{13c6}', ['\u{13c6}', '\u{0}', '\u{0}']), + ('\u{13c7}', ['\u{13c7}', '\u{0}', '\u{0}']), ('\u{13c8}', ['\u{13c8}', '\u{0}', '\u{0}']), + ('\u{13c9}', ['\u{13c9}', '\u{0}', '\u{0}']), ('\u{13ca}', ['\u{13ca}', '\u{0}', '\u{0}']), + ('\u{13cb}', ['\u{13cb}', '\u{0}', '\u{0}']), ('\u{13cc}', ['\u{13cc}', '\u{0}', '\u{0}']), + ('\u{13cd}', ['\u{13cd}', '\u{0}', '\u{0}']), ('\u{13ce}', ['\u{13ce}', '\u{0}', '\u{0}']), + ('\u{13cf}', ['\u{13cf}', '\u{0}', '\u{0}']), ('\u{13d0}', ['\u{13d0}', '\u{0}', '\u{0}']), + ('\u{13d1}', ['\u{13d1}', '\u{0}', '\u{0}']), ('\u{13d2}', ['\u{13d2}', '\u{0}', '\u{0}']), + ('\u{13d3}', ['\u{13d3}', '\u{0}', '\u{0}']), ('\u{13d4}', ['\u{13d4}', '\u{0}', '\u{0}']), + ('\u{13d5}', ['\u{13d5}', '\u{0}', '\u{0}']), ('\u{13d6}', ['\u{13d6}', '\u{0}', '\u{0}']), + ('\u{13d7}', ['\u{13d7}', '\u{0}', '\u{0}']), ('\u{13d8}', ['\u{13d8}', '\u{0}', '\u{0}']), + ('\u{13d9}', ['\u{13d9}', '\u{0}', '\u{0}']), ('\u{13da}', ['\u{13da}', '\u{0}', '\u{0}']), + ('\u{13db}', ['\u{13db}', '\u{0}', '\u{0}']), ('\u{13dc}', ['\u{13dc}', '\u{0}', '\u{0}']), + ('\u{13dd}', ['\u{13dd}', '\u{0}', '\u{0}']), ('\u{13de}', ['\u{13de}', '\u{0}', '\u{0}']), + ('\u{13df}', ['\u{13df}', '\u{0}', '\u{0}']), ('\u{13e0}', ['\u{13e0}', '\u{0}', '\u{0}']), + ('\u{13e1}', ['\u{13e1}', '\u{0}', '\u{0}']), ('\u{13e2}', ['\u{13e2}', '\u{0}', '\u{0}']), + ('\u{13e3}', ['\u{13e3}', '\u{0}', '\u{0}']), ('\u{13e4}', ['\u{13e4}', '\u{0}', '\u{0}']), + ('\u{13e5}', ['\u{13e5}', '\u{0}', '\u{0}']), ('\u{13e6}', ['\u{13e6}', '\u{0}', '\u{0}']), + ('\u{13e7}', ['\u{13e7}', '\u{0}', '\u{0}']), ('\u{13e8}', ['\u{13e8}', '\u{0}', '\u{0}']), + ('\u{13e9}', ['\u{13e9}', '\u{0}', '\u{0}']), ('\u{13ea}', ['\u{13ea}', '\u{0}', '\u{0}']), + ('\u{13eb}', ['\u{13eb}', '\u{0}', '\u{0}']), ('\u{13ec}', ['\u{13ec}', '\u{0}', '\u{0}']), + ('\u{13ed}', ['\u{13ed}', '\u{0}', '\u{0}']), ('\u{13ee}', ['\u{13ee}', '\u{0}', '\u{0}']), + ('\u{13ef}', ['\u{13ef}', '\u{0}', '\u{0}']), ('\u{13f0}', ['\u{13f0}', '\u{0}', '\u{0}']), + ('\u{13f1}', ['\u{13f1}', '\u{0}', '\u{0}']), ('\u{13f2}', ['\u{13f2}', '\u{0}', '\u{0}']), + ('\u{13f3}', ['\u{13f3}', '\u{0}', '\u{0}']), ('\u{13f4}', ['\u{13f4}', '\u{0}', '\u{0}']), + ('\u{13f5}', ['\u{13f5}', '\u{0}', '\u{0}']), ('\u{13f8}', ['\u{13f0}', '\u{0}', '\u{0}']), + ('\u{13f9}', ['\u{13f1}', '\u{0}', '\u{0}']), ('\u{13fa}', ['\u{13f2}', '\u{0}', '\u{0}']), + ('\u{13fb}', ['\u{13f3}', '\u{0}', '\u{0}']), ('\u{13fc}', ['\u{13f4}', '\u{0}', '\u{0}']), + ('\u{13fd}', ['\u{13f5}', '\u{0}', '\u{0}']), ('\u{1e9e}', ['s', 's', '\u{0}']), + ('\u{ab70}', ['\u{13a0}', '\u{0}', '\u{0}']), ('\u{ab71}', ['\u{13a1}', '\u{0}', '\u{0}']), + ('\u{ab72}', ['\u{13a2}', '\u{0}', '\u{0}']), ('\u{ab73}', ['\u{13a3}', '\u{0}', '\u{0}']), + ('\u{ab74}', ['\u{13a4}', '\u{0}', '\u{0}']), ('\u{ab75}', ['\u{13a5}', '\u{0}', '\u{0}']), + ('\u{ab76}', ['\u{13a6}', '\u{0}', '\u{0}']), ('\u{ab77}', ['\u{13a7}', '\u{0}', '\u{0}']), + ('\u{ab78}', ['\u{13a8}', '\u{0}', '\u{0}']), ('\u{ab79}', ['\u{13a9}', '\u{0}', '\u{0}']), + ('\u{ab7a}', ['\u{13aa}', '\u{0}', '\u{0}']), ('\u{ab7b}', ['\u{13ab}', '\u{0}', '\u{0}']), + ('\u{ab7c}', ['\u{13ac}', '\u{0}', '\u{0}']), ('\u{ab7d}', ['\u{13ad}', '\u{0}', '\u{0}']), + ('\u{ab7e}', ['\u{13ae}', '\u{0}', '\u{0}']), ('\u{ab7f}', ['\u{13af}', '\u{0}', '\u{0}']), + ('\u{ab80}', ['\u{13b0}', '\u{0}', '\u{0}']), ('\u{ab81}', ['\u{13b1}', '\u{0}', '\u{0}']), + ('\u{ab82}', ['\u{13b2}', '\u{0}', '\u{0}']), ('\u{ab83}', ['\u{13b3}', '\u{0}', '\u{0}']), + ('\u{ab84}', ['\u{13b4}', '\u{0}', '\u{0}']), ('\u{ab85}', ['\u{13b5}', '\u{0}', '\u{0}']), + ('\u{ab86}', ['\u{13b6}', '\u{0}', '\u{0}']), ('\u{ab87}', ['\u{13b7}', '\u{0}', '\u{0}']), + ('\u{ab88}', ['\u{13b8}', '\u{0}', '\u{0}']), ('\u{ab89}', ['\u{13b9}', '\u{0}', '\u{0}']), + ('\u{ab8a}', ['\u{13ba}', '\u{0}', '\u{0}']), ('\u{ab8b}', ['\u{13bb}', '\u{0}', '\u{0}']), + ('\u{ab8c}', ['\u{13bc}', '\u{0}', '\u{0}']), ('\u{ab8d}', ['\u{13bd}', '\u{0}', '\u{0}']), + ('\u{ab8e}', ['\u{13be}', '\u{0}', '\u{0}']), ('\u{ab8f}', ['\u{13bf}', '\u{0}', '\u{0}']), + ('\u{ab90}', ['\u{13c0}', '\u{0}', '\u{0}']), ('\u{ab91}', ['\u{13c1}', '\u{0}', '\u{0}']), + ('\u{ab92}', ['\u{13c2}', '\u{0}', '\u{0}']), ('\u{ab93}', ['\u{13c3}', '\u{0}', '\u{0}']), + ('\u{ab94}', ['\u{13c4}', '\u{0}', '\u{0}']), ('\u{ab95}', ['\u{13c5}', '\u{0}', '\u{0}']), + ('\u{ab96}', ['\u{13c6}', '\u{0}', '\u{0}']), ('\u{ab97}', ['\u{13c7}', '\u{0}', '\u{0}']), + ('\u{ab98}', ['\u{13c8}', '\u{0}', '\u{0}']), ('\u{ab99}', ['\u{13c9}', '\u{0}', '\u{0}']), + ('\u{ab9a}', ['\u{13ca}', '\u{0}', '\u{0}']), ('\u{ab9b}', ['\u{13cb}', '\u{0}', '\u{0}']), + ('\u{ab9c}', ['\u{13cc}', '\u{0}', '\u{0}']), ('\u{ab9d}', ['\u{13cd}', '\u{0}', '\u{0}']), + ('\u{ab9e}', ['\u{13ce}', '\u{0}', '\u{0}']), ('\u{ab9f}', ['\u{13cf}', '\u{0}', '\u{0}']), + ('\u{aba0}', ['\u{13d0}', '\u{0}', '\u{0}']), ('\u{aba1}', ['\u{13d1}', '\u{0}', '\u{0}']), + ('\u{aba2}', ['\u{13d2}', '\u{0}', '\u{0}']), ('\u{aba3}', ['\u{13d3}', '\u{0}', '\u{0}']), + ('\u{aba4}', ['\u{13d4}', '\u{0}', '\u{0}']), ('\u{aba5}', ['\u{13d5}', '\u{0}', '\u{0}']), + ('\u{aba6}', ['\u{13d6}', '\u{0}', '\u{0}']), ('\u{aba7}', ['\u{13d7}', '\u{0}', '\u{0}']), + ('\u{aba8}', ['\u{13d8}', '\u{0}', '\u{0}']), ('\u{aba9}', ['\u{13d9}', '\u{0}', '\u{0}']), + ('\u{abaa}', ['\u{13da}', '\u{0}', '\u{0}']), ('\u{abab}', ['\u{13db}', '\u{0}', '\u{0}']), + ('\u{abac}', ['\u{13dc}', '\u{0}', '\u{0}']), ('\u{abad}', ['\u{13dd}', '\u{0}', '\u{0}']), + ('\u{abae}', ['\u{13de}', '\u{0}', '\u{0}']), ('\u{abaf}', ['\u{13df}', '\u{0}', '\u{0}']), + ('\u{abb0}', ['\u{13e0}', '\u{0}', '\u{0}']), ('\u{abb1}', ['\u{13e1}', '\u{0}', '\u{0}']), + ('\u{abb2}', ['\u{13e2}', '\u{0}', '\u{0}']), ('\u{abb3}', ['\u{13e3}', '\u{0}', '\u{0}']), + ('\u{abb4}', ['\u{13e4}', '\u{0}', '\u{0}']), ('\u{abb5}', ['\u{13e5}', '\u{0}', '\u{0}']), + ('\u{abb6}', ['\u{13e6}', '\u{0}', '\u{0}']), ('\u{abb7}', ['\u{13e7}', '\u{0}', '\u{0}']), + ('\u{abb8}', ['\u{13e8}', '\u{0}', '\u{0}']), ('\u{abb9}', ['\u{13e9}', '\u{0}', '\u{0}']), + ('\u{abba}', ['\u{13ea}', '\u{0}', '\u{0}']), ('\u{abbb}', ['\u{13eb}', '\u{0}', '\u{0}']), + ('\u{abbc}', ['\u{13ec}', '\u{0}', '\u{0}']), ('\u{abbd}', ['\u{13ed}', '\u{0}', '\u{0}']), + ('\u{abbe}', ['\u{13ee}', '\u{0}', '\u{0}']), ('\u{abbf}', ['\u{13ef}', '\u{0}', '\u{0}']), +]; diff --git a/library/proc_macro/src/lib.rs b/library/proc_macro/src/lib.rs index 7b21896cc4cae..4d6e7cb6671e8 100644 --- a/library/proc_macro/src/lib.rs +++ b/library/proc_macro/src/lib.rs @@ -28,6 +28,7 @@ #![feature(rustc_attrs)] #![feature(extend_one)] #![feature(mem_conjure_zst)] +#![feature(f16)] #![recursion_limit = "256"] #![allow(internal_features)] #![deny(ffi_unwind_calls)] @@ -46,6 +47,7 @@ mod to_tokens; use core::convert::From; use core::ops::BitOr; +use std::borrow::Cow; use std::ffi::CStr; use std::ops::{Range, RangeBounds}; use std::path::PathBuf; @@ -1311,6 +1313,63 @@ macro_rules! unsuffixed_int_literals { )*) } +macro_rules! integer_values { + ($($nb:ident => $fn_name:ident,)+) => { + $( + #[doc = concat!( + "Returns the unescaped `", + stringify!($nb), + "` value if the literal is a `", + stringify!($nb), + "` or if it's an \"unmarked\" integer which doesn't overflow.")] + #[unstable(feature = "proc_macro_value", issue = "136652")] + pub fn $fn_name(&self) -> Result<$nb, ConversionErrorKind> { + if self.0.kind != bridge::LitKind::Integer { + return Err(ConversionErrorKind::InvalidLiteralKind); + } + self.with_symbol_and_suffix(|symbol, suffix| { + match suffix { + stringify!($nb) | "" => { + let symbol = strip_underscores(symbol); + let (number, base) = parse_number(&symbol); + $nb::from_str_radix(&number, base as u32).map_err(|_| ConversionErrorKind::InvalidLiteralKind) + } + _ => Err(ConversionErrorKind::InvalidLiteralKind), + } + }) + } + )+ + } +} + +macro_rules! float_values { + ($($nb:ident => $fn_name:ident,)+) => { + $( + #[doc = concat!( + "Returns the unescaped `", + stringify!($nb), + "` value if the literal is a `", + stringify!($nb), + "` or if it's an \"unmarked\" float which doesn't overflow.")] + #[unstable(feature = "proc_macro_value", issue = "136652")] + pub fn $fn_name(&self) -> Result<$nb, ConversionErrorKind> { + if self.0.kind != bridge::LitKind::Float { + return Err(ConversionErrorKind::InvalidLiteralKind); + } + self.with_symbol_and_suffix(|symbol, suffix| { + match suffix { + stringify!($nb) | "" => { + let number = strip_underscores(symbol); + $nb::from_str(&number).map_err(|_| ConversionErrorKind::InvalidLiteralKind) + } + _ => Err(ConversionErrorKind::InvalidLiteralKind), + } + }) + } + )+ + } +} + impl Literal { fn new(kind: bridge::LitKind, value: &str, suffix: Option<&str>) -> Self { Literal(bridge::Literal { @@ -1704,6 +1763,82 @@ impl Literal { _ => Err(ConversionErrorKind::InvalidLiteralKind), }) } + + integer_values! { + u8 => u8_value, + u16 => u16_value, + u32 => u32_value, + u64 => u64_value, + u128 => u128_value, + i8 => i8_value, + i16 => i16_value, + i32 => i32_value, + i64 => i64_value, + i128 => i128_value, + } + + float_values! { + f16 => f16_value, + f32 => f32_value, + f64 => f64_value, + // FIXME: `f128` doesn't implement `FromStr` for the moment so we cannot obtain it from + // a `&str`. To be uncommented when it's added. + // f128 => f128_value, + } +} + +#[repr(u32)] +#[derive(PartialEq, Eq)] +enum Base { + Decimal = 10, + Binary = 2, + Octal = 8, + Hexadecimal = 16, +} + +fn parse_number(value: &str) -> (&str, Base) { + let mut iter = value.as_bytes().iter().copied(); + let Some(first_digit) = iter.next() else { + return ("0", Base::Decimal); + }; + let Some(second_digit) = iter.next() else { + return (value, Base::Decimal); + }; + + let mut base = Base::Decimal; + if first_digit == b'0' { + // Attempt to parse encoding base. + match second_digit { + b'b' => { + base = Base::Binary; + } + b'o' => { + base = Base::Octal; + } + b'x' => { + base = Base::Hexadecimal; + } + _ => {} + } + } + + let offset = if base == Base::Decimal { 0 } else { 2 }; + + (&value[offset..], base) +} + +fn strip_underscores(value_s: &str) -> Cow<'_, str> { + let value = value_s.as_bytes(); + if value.iter().copied().all(|c| c != b'_' && c != b'f') { + return Cow::Borrowed(value_s); + } + let mut output = String::with_capacity(value.len()); + for c in value.iter().copied() { + if c != b'_' { + output.push(c as char); + } + } + Cow::Owned(output) } /// Parse a single literal from its stringified representation. diff --git a/library/std/src/sys/fs/unix.rs b/library/std/src/sys/fs/unix.rs index eefec06f68f54..c9221269440d8 100644 --- a/library/std/src/sys/fs/unix.rs +++ b/library/std/src/sys/fs/unix.rs @@ -1441,267 +1441,146 @@ impl File { } } - #[cfg(any( - target_os = "freebsd", - target_os = "fuchsia", - target_os = "hurd", - target_os = "linux", - target_os = "netbsd", - target_os = "openbsd", - target_os = "cygwin", - target_os = "illumos", - target_os = "aix", - target_os = "android", - target_vendor = "apple", - ))] pub fn lock(&self) -> io::Result<()> { - cvt(unsafe { libc::flock(self.as_raw_fd(), libc::LOCK_EX) })?; - return Ok(()); - } - - #[cfg(target_os = "solaris")] - pub fn lock(&self) -> io::Result<()> { - let mut flock: libc::flock = unsafe { mem::zeroed() }; - flock.l_type = libc::F_WRLCK as libc::c_short; - flock.l_whence = libc::SEEK_SET as libc::c_short; - cvt(unsafe { libc::fcntl(self.as_raw_fd(), libc::F_SETLKW, &flock) })?; - Ok(()) - } - - #[cfg(not(any( - target_os = "freebsd", - target_os = "fuchsia", - target_os = "hurd", - target_os = "linux", - target_os = "netbsd", - target_os = "openbsd", - target_os = "cygwin", - target_os = "solaris", - target_os = "illumos", - target_os = "aix", - target_os = "android", - target_vendor = "apple", - )))] - pub fn lock(&self) -> io::Result<()> { - Err(io::const_error!(io::ErrorKind::Unsupported, "lock() not supported")) - } - - #[cfg(any( - target_os = "freebsd", - target_os = "fuchsia", - target_os = "hurd", - target_os = "linux", - target_os = "netbsd", - target_os = "openbsd", - target_os = "cygwin", - target_os = "illumos", - target_os = "aix", - target_os = "android", - target_vendor = "apple", - ))] - pub fn lock_shared(&self) -> io::Result<()> { - cvt(unsafe { libc::flock(self.as_raw_fd(), libc::LOCK_SH) })?; - return Ok(()); - } - - #[cfg(target_os = "solaris")] - pub fn lock_shared(&self) -> io::Result<()> { - let mut flock: libc::flock = unsafe { mem::zeroed() }; - flock.l_type = libc::F_RDLCK as libc::c_short; - flock.l_whence = libc::SEEK_SET as libc::c_short; - cvt(unsafe { libc::fcntl(self.as_raw_fd(), libc::F_SETLKW, &flock) })?; - Ok(()) - } - - #[cfg(not(any( - target_os = "freebsd", - target_os = "fuchsia", - target_os = "hurd", - target_os = "linux", - target_os = "netbsd", - target_os = "openbsd", - target_os = "cygwin", - target_os = "solaris", - target_os = "illumos", - target_os = "aix", - target_os = "android", - target_vendor = "apple", - )))] - pub fn lock_shared(&self) -> io::Result<()> { - Err(io::const_error!(io::ErrorKind::Unsupported, "lock_shared() not supported")) - } - - #[cfg(any( - target_os = "freebsd", - target_os = "fuchsia", - target_os = "hurd", - target_os = "linux", - target_os = "netbsd", - target_os = "openbsd", - target_os = "cygwin", - target_os = "illumos", - target_os = "aix", - target_os = "android", - target_vendor = "apple", - ))] - pub fn try_lock(&self) -> Result<(), TryLockError> { - let result = cvt(unsafe { libc::flock(self.as_raw_fd(), libc::LOCK_EX | libc::LOCK_NB) }); - if let Err(err) = result { - if err.kind() == io::ErrorKind::WouldBlock { - Err(TryLockError::WouldBlock) - } else { - Err(TryLockError::Error(err)) + cfg_select! { + any( + target_os = "freebsd", + target_os = "fuchsia", + target_os = "hurd", + target_os = "linux", + target_os = "netbsd", + target_os = "openbsd", + target_os = "cygwin", + target_os = "illumos", + target_os = "aix", + target_os = "android", + target_vendor = "apple", + ) => { + cvt(unsafe { libc::flock(self.as_raw_fd(), libc::LOCK_EX) })?; + return Ok(()); + } + _ => { + Err(io::const_error!(io::ErrorKind::Unsupported, "lock() not supported")) } - } else { - Ok(()) } } - #[cfg(target_os = "solaris")] - pub fn try_lock(&self) -> Result<(), TryLockError> { - let mut flock: libc::flock = unsafe { mem::zeroed() }; - flock.l_type = libc::F_WRLCK as libc::c_short; - flock.l_whence = libc::SEEK_SET as libc::c_short; - let result = cvt(unsafe { libc::fcntl(self.as_raw_fd(), libc::F_SETLK, &flock) }); - if let Err(err) = result { - if err.kind() == io::ErrorKind::WouldBlock { - Err(TryLockError::WouldBlock) - } else { - Err(TryLockError::Error(err)) + pub fn lock_shared(&self) -> io::Result<()> { + cfg_select! { + any( + target_os = "freebsd", + target_os = "fuchsia", + target_os = "hurd", + target_os = "linux", + target_os = "netbsd", + target_os = "openbsd", + target_os = "cygwin", + target_os = "illumos", + target_os = "aix", + target_os = "android", + target_vendor = "apple", + ) => { + cvt(unsafe { libc::flock(self.as_raw_fd(), libc::LOCK_SH) })?; + return Ok(()); + } + _ => { + Err(io::const_error!(io::ErrorKind::Unsupported, "lock_shared() not supported")) } - } else { - Ok(()) } } - #[cfg(not(any( - target_os = "freebsd", - target_os = "fuchsia", - target_os = "hurd", - target_os = "linux", - target_os = "netbsd", - target_os = "openbsd", - target_os = "cygwin", - target_os = "solaris", - target_os = "illumos", - target_os = "aix", - target_os = "android", - target_vendor = "apple", - )))] pub fn try_lock(&self) -> Result<(), TryLockError> { - Err(TryLockError::Error(io::const_error!( - io::ErrorKind::Unsupported, - "try_lock() not supported" - ))) - } - - #[cfg(any( - target_os = "freebsd", - target_os = "fuchsia", - target_os = "hurd", - target_os = "linux", - target_os = "netbsd", - target_os = "openbsd", - target_os = "cygwin", - target_os = "illumos", - target_os = "aix", - target_os = "android", - target_vendor = "apple", - ))] - pub fn try_lock_shared(&self) -> Result<(), TryLockError> { - let result = cvt(unsafe { libc::flock(self.as_raw_fd(), libc::LOCK_SH | libc::LOCK_NB) }); - if let Err(err) = result { - if err.kind() == io::ErrorKind::WouldBlock { - Err(TryLockError::WouldBlock) - } else { - Err(TryLockError::Error(err)) + cfg_select! { + any( + target_os = "freebsd", + target_os = "fuchsia", + target_os = "hurd", + target_os = "linux", + target_os = "netbsd", + target_os = "openbsd", + target_os = "cygwin", + target_os = "illumos", + target_os = "aix", + target_os = "android", + target_vendor = "apple", + ) => { + let result = cvt(unsafe { libc::flock(self.as_raw_fd(), libc::LOCK_EX | libc::LOCK_NB) }); + if let Err(err) = result { + if err.kind() == io::ErrorKind::WouldBlock { + Err(TryLockError::WouldBlock) + } else { + Err(TryLockError::Error(err)) + } + } else { + Ok(()) + } + } + _ => { + Err(TryLockError::Error(io::const_error!( + io::ErrorKind::Unsupported, + "try_lock() not supported" + ))) } - } else { - Ok(()) } } - #[cfg(target_os = "solaris")] pub fn try_lock_shared(&self) -> Result<(), TryLockError> { - let mut flock: libc::flock = unsafe { mem::zeroed() }; - flock.l_type = libc::F_RDLCK as libc::c_short; - flock.l_whence = libc::SEEK_SET as libc::c_short; - let result = cvt(unsafe { libc::fcntl(self.as_raw_fd(), libc::F_SETLK, &flock) }); - if let Err(err) = result { - if err.kind() == io::ErrorKind::WouldBlock { - Err(TryLockError::WouldBlock) - } else { - Err(TryLockError::Error(err)) + cfg_select! { + any( + target_os = "freebsd", + target_os = "fuchsia", + target_os = "hurd", + target_os = "linux", + target_os = "netbsd", + target_os = "openbsd", + target_os = "cygwin", + target_os = "illumos", + target_os = "aix", + target_os = "android", + target_vendor = "apple", + ) => { + let result = cvt(unsafe { libc::flock(self.as_raw_fd(), libc::LOCK_SH | libc::LOCK_NB) }); + if let Err(err) = result { + if err.kind() == io::ErrorKind::WouldBlock { + Err(TryLockError::WouldBlock) + } else { + Err(TryLockError::Error(err)) + } + } else { + Ok(()) + } + } + _ => { + Err(TryLockError::Error(io::const_error!( + io::ErrorKind::Unsupported, + "try_lock_shared() not supported" + ))) } - } else { - Ok(()) } } - #[cfg(not(any( - target_os = "freebsd", - target_os = "fuchsia", - target_os = "hurd", - target_os = "linux", - target_os = "netbsd", - target_os = "openbsd", - target_os = "cygwin", - target_os = "solaris", - target_os = "illumos", - target_os = "aix", - target_os = "android", - target_vendor = "apple", - )))] - pub fn try_lock_shared(&self) -> Result<(), TryLockError> { - Err(TryLockError::Error(io::const_error!( - io::ErrorKind::Unsupported, - "try_lock_shared() not supported" - ))) - } - - #[cfg(any( - target_os = "freebsd", - target_os = "fuchsia", - target_os = "hurd", - target_os = "linux", - target_os = "netbsd", - target_os = "openbsd", - target_os = "cygwin", - target_os = "illumos", - target_os = "aix", - target_os = "android", - target_vendor = "apple", - ))] pub fn unlock(&self) -> io::Result<()> { - cvt(unsafe { libc::flock(self.as_raw_fd(), libc::LOCK_UN) })?; - return Ok(()); - } - - #[cfg(target_os = "solaris")] - pub fn unlock(&self) -> io::Result<()> { - let mut flock: libc::flock = unsafe { mem::zeroed() }; - flock.l_type = libc::F_UNLCK as libc::c_short; - flock.l_whence = libc::SEEK_SET as libc::c_short; - cvt(unsafe { libc::fcntl(self.as_raw_fd(), libc::F_SETLKW, &flock) })?; - Ok(()) - } - - #[cfg(not(any( - target_os = "freebsd", - target_os = "fuchsia", - target_os = "hurd", - target_os = "linux", - target_os = "netbsd", - target_os = "openbsd", - target_os = "cygwin", - target_os = "solaris", - target_os = "illumos", - target_os = "aix", - target_os = "android", - target_vendor = "apple", - )))] - pub fn unlock(&self) -> io::Result<()> { - Err(io::const_error!(io::ErrorKind::Unsupported, "unlock() not supported")) + cfg_select! { + any( + target_os = "freebsd", + target_os = "fuchsia", + target_os = "hurd", + target_os = "linux", + target_os = "netbsd", + target_os = "openbsd", + target_os = "cygwin", + target_os = "illumos", + target_os = "aix", + target_os = "android", + target_vendor = "apple", + ) => { + cvt(unsafe { libc::flock(self.as_raw_fd(), libc::LOCK_UN) })?; + return Ok(()); + } + _ => { + Err(io::const_error!(io::ErrorKind::Unsupported, "unlock() not supported")) + } + } } pub fn truncate(&self, size: u64) -> io::Result<()> { diff --git a/library/std/src/sys/process/unix/unsupported/wait_status/tests.rs b/library/std/src/sys/process/unix/unsupported/wait_status/tests.rs index 0d9232fac5e4e..51af14f0aaace 100644 --- a/library/std/src/sys/process/unix/unsupported/wait_status/tests.rs +++ b/library/std/src/sys/process/unix/unsupported/wait_status/tests.rs @@ -8,6 +8,7 @@ // I.e. we're using Linux as a proxy for "trad unix". #[cfg(target_os = "linux")] #[test] +#[cfg_attr(miri, ignore)] // Miri is too slow fn compare_with_linux() { use super::ExitStatus as Emulated; use crate::os::unix::process::ExitStatusExt as _; diff --git a/library/std/src/sys/thread_local/guard/windows.rs b/library/std/src/sys/thread_local/guard/windows.rs index 01ac9526910c2..7a9c69ae43784 100644 --- a/library/std/src/sys/thread_local/guard/windows.rs +++ b/library/std/src/sys/thread_local/guard/windows.rs @@ -106,6 +106,7 @@ impl Drop for EnableGuard { } } +/// Set up the current thread to invoke `cleanup` when it finishes. pub fn enable() { let registered = if cfg!(target_thread_local) { #[thread_local] diff --git a/library/std/src/sys/thread_local/key/windows.rs b/library/std/src/sys/thread_local/key/windows.rs index 2ff0fd1196e12..420b628068a3a 100644 --- a/library/std/src/sys/thread_local/key/windows.rs +++ b/library/std/src/sys/thread_local/key/windows.rs @@ -60,6 +60,12 @@ impl LazyKey { #[inline] pub fn force(&'static self) -> Key { + if self.dtor.is_some() { + // Needs to be called on all threads where the key might have a non-null value! + // Otherwise, `run_dtors` might not be called on this thread. + guard::enable(); + } + match self.key.load(Acquire) { 0 => unsafe { self.init() }, key => key - 1, @@ -88,6 +94,8 @@ impl LazyKey { } unsafe { + // Add ourselves to the `DTORS` list, so that when `run_dtors` gets called, + // our dtor is invoked. register_dtor(self); } @@ -144,8 +152,6 @@ static DTORS: Atomic<*mut LazyKey> = AtomicPtr::new(ptr::null_mut()); /// Should only be called once per key, otherwise loops or breaks may occur in /// the linked list. unsafe fn register_dtor(key: &'static LazyKey) { - guard::enable(); - let this = <*const LazyKey>::cast_mut(key); // Use acquire ordering to pass along the changes done by the previously // registered keys when we store the new head with release ordering. diff --git a/library/std/src/sys/thread_local/mod.rs b/library/std/src/sys/thread_local/mod.rs index e88011aa22dad..d48bb1c8b721e 100644 --- a/library/std/src/sys/thread_local/mod.rs +++ b/library/std/src/sys/thread_local/mod.rs @@ -81,7 +81,7 @@ pub(crate) mod destructors { /// This module provides a way to schedule the execution of the destructor list /// and the [runtime cleanup](crate::rt::thread_cleanup) function. Calling `enable` -/// should ensure that these functions are called at the right times. +/// sets up the current thread to ensure that these functions are called at the right times. pub(crate) mod guard { cfg_select! { all(target_thread_local, target_vendor = "apple") => { diff --git a/library/std/src/thread/lifecycle.rs b/library/std/src/thread/lifecycle.rs index af239bee55189..d3a97bbf08fa2 100644 --- a/library/std/src/thread/lifecycle.rs +++ b/library/std/src/thread/lifecycle.rs @@ -66,7 +66,7 @@ where let rust_start = move || { let f = f.into_inner(); let try_result = panic::catch_unwind(panic::AssertUnwindSafe(|| { - crate::sys::backtrace::__rust_begin_short_backtrace(|| hooks.run()); + crate::sys::backtrace::__rust_begin_short_backtrace(|| hooks.inherit_and_run()); crate::sys::backtrace::__rust_begin_short_backtrace(f) })); // SAFETY: `their_packet` as been built just above and moved by the diff --git a/library/std/src/thread/spawnhook.rs b/library/std/src/thread/spawnhook.rs index 254793ac33d08..bb36fb687b4af 100644 --- a/library/std/src/thread/spawnhook.rs +++ b/library/std/src/thread/spawnhook.rs @@ -144,7 +144,7 @@ pub(super) struct ChildSpawnHooks { impl ChildSpawnHooks { // This is run on the newly spawned thread, directly at the start. - pub(super) fn run(self) { + pub(super) fn inherit_and_run(self) { SPAWN_HOOKS.set(self.hooks); for run in self.to_run { run(); diff --git a/library/std/tests/thread_local/tests.rs b/library/std/tests/thread_local/tests.rs index 7324b880af67d..633bab38eb4db 100644 --- a/library/std/tests/thread_local/tests.rs +++ b/library/std/tests/thread_local/tests.rs @@ -408,6 +408,7 @@ fn thread_current_in_dtor() { // https://github.com/rust-lang/rust/pull/148799#issuecomment-3731806901 #[cfg(target_os = "windows")] #[test] +#[cfg_attr(miri, ignore)] // Miri does not support fibers fn fiber_does_not_trigger_dtor() { use core::ffi::c_void; use std::ptr; diff --git a/src/tools/compiletest/src/runtest.rs b/src/tools/compiletest/src/runtest.rs index 72817ad64521a..79e04b12fbed3 100644 --- a/src/tools/compiletest/src/runtest.rs +++ b/src/tools/compiletest/src/runtest.rs @@ -1645,6 +1645,11 @@ impl<'test> TestCx<'test> { if self.config.mode == TestMode::CodegenUnits { compiler.args(&["-Z", "human_readable_cgu_names"]); } + + if self.config.mode == TestMode::DebugInfo && cfg!(target_os = "windows") { + // Prevent debugger processes from creating new console windows. + compiler.args(&["-Z", r#"crate-attr=windows_subsystem="windows""#]); + } } if self.config.optimize_tests && compiler_kind == CompilerKind::Rustc { diff --git a/src/tools/miri/tests/pass/shims/fs.rs b/src/tools/miri/tests/pass/shims/fs.rs index cb1088fb08515..f7298a9a2f235 100644 --- a/src/tools/miri/tests/pass/shims/fs.rs +++ b/src/tools/miri/tests/pass/shims/fs.rs @@ -410,8 +410,7 @@ fn test_pread_pwrite() { assert_eq!(&buf1, b" m"); } -// Miri does not support the way this is implemented on Solaris -// (https://github.com/rust-lang/miri/issues/5038). +// Solaris does not support per-handle file locking. #[cfg(not(target_os = "solaris"))] fn test_flock() { let bytes = b"Hello, World!\n"; diff --git a/src/tools/tidy/src/deps.rs b/src/tools/tidy/src/deps.rs index ef08286122916..89aae46ec8f23 100644 --- a/src/tools/tidy/src/deps.rs +++ b/src/tools/tidy/src/deps.rs @@ -597,6 +597,7 @@ const PERMITTED_CRANELIFT_DEPENDENCIES: &[&str] = &[ "log", "mach2", "memchr", + "memmap2", "object", "proc-macro2", "quote", diff --git a/src/tools/unicode-table-generator/Cargo.toml b/src/tools/unicode-table-generator/Cargo.toml index 3ca6e9e316f1d..3be916dc69bf5 100644 --- a/src/tools/unicode-table-generator/Cargo.toml +++ b/src/tools/unicode-table-generator/Cargo.toml @@ -7,3 +7,4 @@ edition = "2024" [dependencies] ucd-parse = "0.1.3" +rustc-hash = "2.0.0" diff --git a/src/tools/unicode-table-generator/src/cascading_map.rs b/src/tools/unicode-table-generator/src/cascading_map.rs index 56e6401908dcf..da06049beb575 100644 --- a/src/tools/unicode-table-generator/src/cascading_map.rs +++ b/src/tools/unicode-table-generator/src/cascading_map.rs @@ -1,7 +1,8 @@ -use std::collections::HashMap; use std::fmt::Write as _; use std::ops::Range; +use rustc_hash::FxHashMap; + use crate::fmt_list; use crate::raw_emitter::RawEmitter; @@ -27,7 +28,7 @@ impl RawEmitter { println!("there are {} points", points.len()); // how many distinct ranges need to be counted? - let mut codepoints_by_high_bytes = HashMap::>::new(); + let mut codepoints_by_high_bytes = FxHashMap::>::default(); for point in points { // assert that there is no whitespace over the 0x3000 range. assert!(point <= 0x3000, "the highest unicode whitespace value has changed"); diff --git a/src/tools/unicode-table-generator/src/case_mapping.rs b/src/tools/unicode-table-generator/src/case_mapping.rs index b7b385542ef53..9336eaf670e6a 100644 --- a/src/tools/unicode-table-generator/src/case_mapping.rs +++ b/src/tools/unicode-table-generator/src/case_mapping.rs @@ -48,21 +48,33 @@ use std::ops::RangeInclusive; use crate::fmt_helpers::Hex; use crate::{UnicodeData, fmt_list}; -pub(crate) fn generate_case_mapping(data: &UnicodeData) -> (String, [(String, usize); 3]) { +pub(crate) fn generate_case_mapping(data: &UnicodeData) -> (String, [(String, usize); 4]) { let mut file = String::new(); file.push_str("\n\n"); file.push_str(HEADER.trim_start()); file.push('\n'); - let (lower_tables, lower_desc, lower_size) = generate_tables("LOWER", &data.to_lower); + let (lower_tables, lower_desc, lower_size) = generate_tables("LOWERCASE", &data.to_lower); file.push_str(&lower_tables); file.push_str("\n\n"); - let (upper_tables, upper_desc, upper_size) = generate_tables("UPPER", &data.to_upper); + let (upper_tables, upper_desc, upper_size) = generate_tables("UPPERCASE", &data.to_upper); file.push_str(&upper_tables); file.push_str("\n\n"); - let (title_tables, title_desc, title_size) = generate_tables("TITLE", &data.to_title); + let (title_tables, title_desc, title_size) = generate_tables("TITLECASE", &data.to_title); file.push_str(&title_tables); - (file, [(lower_desc, lower_size), (upper_desc, upper_size), (title_desc, title_size)]) + file.push_str("\n\n"); + let (casefold_tables, casefold_desc, casefold_size) = + generate_tables("CASEFOLD", &data.to_casefold); + file.push_str(&casefold_tables); + ( + file, + [ + (lower_desc, lower_size), + (upper_desc, upper_size), + (title_desc, title_size), + (casefold_desc, casefold_size), + ], + ) } // So far, only planes 0 and 1 (Basic Multilingual Plane and Supplementary @@ -205,7 +217,7 @@ fn generate_tables(case: &str, data: &BTreeMap) -> (String, Strin output_high, input_high, "Case-mapping a character should not change its plane" ); - let delta = output_low as i16 - input_low as i16; + let delta = output_low.wrapping_sub(input_low).cast_signed(); let range = Range::singleton(input_low); l2_lut.singles.push((range, delta)); } @@ -264,7 +276,7 @@ fn generate_tables(case: &str, data: &BTreeMap) -> (String, Strin let size = l1_lut.size(); let num_ranges = l1_lut.l2_luts.iter().map(|l2| l2.singles.len() + l2.multis.len()).sum::(); - let table = format!("static {case}CASE_LUT: L1Lut = {l1_lut:#?};"); + let table = format!("static {case}_LUT: L1Lut = {l1_lut:#?};"); let desc = format!( "{:6} codepoints in {:3} ranges (U+{:06X} - U+{:06X}) using 2-level LUT", data.len(), @@ -381,7 +393,7 @@ fn lookup(input: char, l1_lut: &L1Lut) -> Option<[char; 3]> { } pub fn to_lower(c: char) -> [char; 3] { - // https://util.unicode.org/UnicodeJsps/list-unicodeset.jsp?a=%5B%253AChanges_When_Lowercased%253A%5D-%5B%253AASCII%253A%5D&abb=on + // https://util.unicode.org/UnicodeJsps/list-unicodeset.jsp?a=[:Changes_When_Lowercased:]-[:ASCII:]&abb=on if c < '\u{C0}' { return [c.to_ascii_lowercase(), '\0', '\0']; } @@ -390,7 +402,7 @@ pub fn to_lower(c: char) -> [char; 3] { } pub fn to_upper(c: char) -> [char; 3] { - // https://util.unicode.org/UnicodeJsps/list-unicodeset.jsp?a=%5B%253AChanges_When_Uppercased%253A%5D-%5B%253AASCII%253A%5D&abb=on + // https://util.unicode.org/UnicodeJsps/list-unicodeset.jsp?a=[:Changes_When_Uppercased:]-[:ASCII:]&abb=on if c < '\u{B5}' { return [c.to_ascii_uppercase(), '\0', '\0']; } @@ -399,11 +411,93 @@ pub fn to_upper(c: char) -> [char; 3] { } pub fn to_title(c: char) -> [char; 3] { - // https://util.unicode.org/UnicodeJsps/list-unicodeset.jsp?a=%5B%253AChanges_When_Titlecased%253A%5D-%5B%253AASCII%253A%5D&abb=on + // https://util.unicode.org/UnicodeJsps/list-unicodeset.jsp?a=[:Changes_When_Titlecased:]-[:ASCII:]&abb=on if c < '\u{B5}' { return [c.to_ascii_uppercase(), '\0', '\0']; } lookup(c, &TITLECASE_LUT).or_else(|| lookup(c, &UPPERCASE_LUT)).unwrap_or([c, '\0', '\0']) } + +pub fn to_casefold(c: char) -> [char; 3] { + // https://util.unicode.org/UnicodeJsps/list-unicodeset.jsp?a=[:Changes_When_Casefolded:]-[:ASCII:]&abb=on + if c < '\u{B5}' { + return [c.to_ascii_lowercase(), '\0', '\0']; + } + + + lookup(c, &CASEFOLD_LUT).unwrap_or_else(|| { + // Fall back to lowercase of uppercase + + let uppercase = lookup(c, &UPPERCASE_LUT).unwrap_or([c, '\0', '\0']); + + // We need to take the lowercase of each character in `uppercase`, + // and then concatenate them together. + + // Lowercase the first uppercased char + let mut final_result = to_lower(uppercase[0]); + + if uppercase[1] != '\0' { + // There's a 2nd uppercase char, lowercase it as well + let lowercase_1 = to_lower(uppercase[1]); + + // The lowercase of the second uppercase character + // can't be 3 chars long; + // that would bring the total case-folding length + // above 3 characters, which would violate + // a Unicode stability guarantee. + debug_assert_eq!(lowercase_1[2], '\0'); + + // Currently, in every case where there + // are multiple uppercased characters, + // the lowercase of the first uppercase + // has length 1. However, Unicode doesn't + // guarantee this. + // If, after updating the Unicode data + // to a new Unicode version, the below + // assertion starts to fail in + // `coretests/tests/unicode.rs` `to_casefold()`, + // delete it, and uncomment the + // `if` condition and corresponding + // `else` block below it. + debug_assert_eq!(final_result[1], '\0'); + //if final_result[1] == '\0' { + + final_result[1] = lowercase_1[0]; + + if uppercase[2] != '\0' { + // There's a 3rd uppercased char, lowercase it as well. + // Because of the Unicode stability guarantee that case-folding + // does not expand a string more than 3x in length, + // we know this lowercase must be 1 char long. + + debug_assert_eq!(lowercase_1[1], '\0'); + let lowercase_2 = to_lower(uppercase[2]); + debug_assert_eq!(lowercase_2[1], '\0'); + debug_assert_eq!(lowercase_2[2], '\0'); + final_result[2] = lowercase_2[0]; + } else { + // Currently, the lowercase of + // the second uppercase character + // can't be 2 chars long either, + // but Unicode doesn't guarantee this. + // If, after updating the Unicode data + // to a new Unicode version, the below + // assertion starts to fail in + // `coretests/tests/unicode.rs` `to_casefold()`, + // delete it and uncomment the line + // below it. + debug_assert_eq!(lowercase_1[1], '\0'); + //final_result[2] = lowercase_1[1]; + } + + /*} else { + final_result[2] = lowercase_1[0]; + debug_assert_eq!(lowercase_1[1], '\0'); + debug_assert_eq!(uppercase[2], '\0') + }*/ + } + final_result + }) +} "; diff --git a/src/tools/unicode-table-generator/src/main.rs b/src/tools/unicode-table-generator/src/main.rs index 398b4c7b7ec5a..a55cd2f657a6d 100644 --- a/src/tools/unicode-table-generator/src/main.rs +++ b/src/tools/unicode-table-generator/src/main.rs @@ -71,11 +71,12 @@ //! index of that offset is utilized as the answer to whether we're in the set //! or not. -use std::collections::{BTreeMap, HashMap}; +use std::collections::BTreeMap; use std::fmt::Write; use std::ops::Range; -use ucd_parse::Codepoints; +use rustc_hash::{FxHashMap, FxHashSet}; +use ucd_parse::{Codepoint, Codepoints}; mod cascading_map; mod case_mapping; @@ -106,6 +107,9 @@ struct UnicodeData { to_title: BTreeMap, /// Only stores mappings that are not to self to_lower: BTreeMap, + /// Only stores mappings that differ from + /// `to_upper` followed by `to_lower` + to_casefold: BTreeMap, } fn to_mapping( @@ -126,7 +130,7 @@ static UNICODE_DIRECTORY: &str = "unicode-downloads"; fn load_data() -> UnicodeData { unicode_download::fetch_latest(); - let mut properties = HashMap::new(); + let mut properties = FxHashMap::default(); for row in ucd_parse::parse::<_, ucd_parse::CoreProperty>(&UNICODE_DIRECTORY).unwrap() { if let Some(name) = PROPERTIES.iter().find(|prop| **prop == row.property.as_str()) { properties.entry(*name).or_insert_with(Vec::new).push(row.codepoints); @@ -138,7 +142,8 @@ fn load_data() -> UnicodeData { } } - let [mut to_lower, mut to_upper, mut to_title] = [const { BTreeMap::new() }; 3]; + let [mut to_lower, mut to_upper, mut to_title, mut to_casefold] = + [const { BTreeMap::new() }; 4]; for row in ucd_parse::UnicodeDataExpander::new( ucd_parse::parse::<_, ucd_parse::UnicodeData>(&UNICODE_DIRECTORY).unwrap(), ) { @@ -189,6 +194,78 @@ fn load_data() -> UnicodeData { } } + fn get_mapping_from_btreemap<'a>( + cp: Codepoint, + map: &'a BTreeMap, + ) -> Vec { + let mapping = + map.get(&cp.value()).copied().map(|cs| cs.map(|c| Codepoint::from_u32(c).unwrap())); + + mapping + .as_ref() + .map(|cs| { + let nul = Codepoint::from_u32(0).unwrap(); + if cs[1] == nul { + &cs[..1] + } else if cs[2] == nul { + &cs[..2] + } else { + &cs[..] + } + }) + .map_or_else(|| vec![cp], ToOwned::to_owned) + } + + let mut nontrivial_casefold = FxHashSet::default(); + + for row in ucd_parse::parse::<_, ucd_parse::CaseFold>(&UNICODE_DIRECTORY).unwrap() { + use ucd_parse::{CaseStatus, Codepoint}; + if matches!(row.status, CaseStatus::Common | CaseStatus::Full) { + let key = row.codepoint.value(); + nontrivial_casefold.insert(key); + + // We store case-fold data only for characters whose case-folding + // differs from the lowercase of their uppercase. + + let lower_upper_mapping: Vec = + get_mapping_from_btreemap(row.codepoint, &to_upper) + .into_iter() + .flat_map(|cp| get_mapping_from_btreemap(cp, &to_lower)) + .collect(); + + if let Some(casefold) = to_mapping(&lower_upper_mapping, &row.mapping) { + to_casefold.insert(key, casefold); + } + } + } + + // Now, account for characters that remain unchanged by case-folding + // (and are therefore omitted from `CaseFolding.txt`), + // but yet differ from the lowercase of their uppercase. + + for c in '\0'..=char::MAX { + let cnum: u32 = c.into(); + if !nontrivial_casefold.contains(&cnum) { + let cp = Codepoint::from_u32(cnum).unwrap(); + + use std::collections::btree_map::Entry; + match to_casefold.entry(cnum) { + Entry::Vacant(vacant_entry) => { + let lower_upper_mapping: Vec = + get_mapping_from_btreemap(cp, &to_upper) + .into_iter() + .flat_map(|cp| get_mapping_from_btreemap(cp, &to_lower)) + .collect(); + + if let Some(casefold) = to_mapping(&lower_upper_mapping, &[cp]) { + vacant_entry.insert(casefold); + } + } + Entry::Occupied(_) => {} + } + } + } + // Filter out ASCII codepoints. to_lower.retain(|&c, _| c > 0x7f); to_upper.retain(|&c, _| c > 0x7f); @@ -207,7 +284,7 @@ fn load_data() -> UnicodeData { .collect(); properties.sort_by_key(|p| p.0); - UnicodeData { ranges: properties, to_lower, to_title, to_upper } + UnicodeData { ranges: properties, to_lower, to_title, to_upper, to_casefold } } fn main() { @@ -259,7 +336,9 @@ fn main() { total_bytes += emitter.bytes_used; } let (conversions, sizes) = case_mapping::generate_case_mapping(&unicode_data); - for (name, (desc, size)) in ["to_lower", "to_upper", "to_title"].iter().zip(sizes) { + for (name, (desc, size)) in + ["to_lower", "to_upper", "to_title", "to_casefold"].iter().zip(sizes) + { table_file.push_str(&format!("// {:16}: {:5} bytes, {desc}\n", name, size,)); total_bytes += size; } @@ -369,10 +448,11 @@ pub(super) static {prop_upper}: &[RangeInclusive; {is_true_len}] = &[{is_t .unwrap(); } - for (name, lut) in ["TO_LOWER", "TO_UPPER", "TO_TITLE"].iter().zip([ + for (name, lut) in ["TO_LOWER", "TO_UPPER", "TO_TITLE", "TO_CASEFOLD"].iter().zip([ &data.to_lower, &data.to_upper, &data.to_title, + &data.to_casefold, ]) { let lut = lut .iter() diff --git a/src/tools/unicode-table-generator/src/raw_emitter.rs b/src/tools/unicode-table-generator/src/raw_emitter.rs index 297965615c1a5..de3395df3806e 100644 --- a/src/tools/unicode-table-generator/src/raw_emitter.rs +++ b/src/tools/unicode-table-generator/src/raw_emitter.rs @@ -1,7 +1,9 @@ -use std::collections::{BTreeMap, BTreeSet, HashMap}; +use std::collections::{BTreeMap, BTreeSet}; use std::fmt::{self, Write}; use std::ops::Range; +use rustc_hash::FxHashMap; + use crate::fmt_list; #[derive(Clone)] @@ -126,8 +128,11 @@ impl RawEmitter { for chunk in compressed_words.chunks(chunk_length) { chunks.insert(chunk); } - let chunk_map = - chunks.iter().enumerate().map(|(idx, &chunk)| (chunk, idx)).collect::>(); + let chunk_map = chunks + .iter() + .enumerate() + .map(|(idx, &chunk)| (chunk, idx)) + .collect::>(); let mut chunk_indices = Vec::new(); for chunk in compressed_words.chunks(chunk_length) { chunk_indices.push(chunk_map[chunk]); @@ -186,7 +191,7 @@ struct Canonicalized { /// Maps an input unique word to the associated index (u8) which is into /// canonical_words or canonicalized_words (in order). - unique_mapping: HashMap, + unique_mapping: FxHashMap, } impl Canonicalized { @@ -253,7 +258,7 @@ impl Canonicalized { // These are mapped words, which will be represented by an index into // the canonical_words and a Mapping; u16 when encoded. let mut canonicalized_words = Vec::new(); - let mut unique_mapping = HashMap::new(); + let mut unique_mapping = FxHashMap::default(); #[derive(Debug, PartialEq, Eq)] enum UniqueMapping { @@ -361,7 +366,7 @@ impl Canonicalized { }, ) }) - .collect::>(); + .collect::>(); let mut distinct_indices = BTreeSet::new(); for &w in unique_words { diff --git a/src/tools/unicode-table-generator/src/unicode_download.rs b/src/tools/unicode-table-generator/src/unicode_download.rs index c9826170905c2..b2fcf6444033d 100644 --- a/src/tools/unicode-table-generator/src/unicode_download.rs +++ b/src/tools/unicode-table-generator/src/unicode_download.rs @@ -7,8 +7,13 @@ static URL_PREFIX: &str = "https://www.unicode.org/Public/UCD/latest/ucd/"; static README: &str = "ReadMe.txt"; -static RESOURCES: &[&str] = - &["DerivedCoreProperties.txt", "PropList.txt", "UnicodeData.txt", "SpecialCasing.txt"]; +static RESOURCES: &[&str] = &[ + "CaseFolding.txt", + "DerivedCoreProperties.txt", + "PropList.txt", + "SpecialCasing.txt", + "UnicodeData.txt", +]; #[track_caller] fn fetch(url: &str) -> Output { diff --git a/tests/codegen-llvm/bpf-allows-unaligned.rs b/tests/codegen-llvm/bpf-allows-unaligned.rs index 7e95a56d984c9..c7a70d5b2e502 100644 --- a/tests/codegen-llvm/bpf-allows-unaligned.rs +++ b/tests/codegen-llvm/bpf-allows-unaligned.rs @@ -5,7 +5,7 @@ #[no_mangle] #[target_feature(enable = "allows-misaligned-mem-access")] -// CHECK: define noundef zeroext i8 @foo(i8 noundef returned %arg) unnamed_addr #0 +// CHECK: define noundef zeroext i8 @foo(i8 noundef returned %arg) unnamed_addr #0 { pub unsafe fn foo(arg: u8) -> u8 { arg } diff --git a/tests/codegen-llvm/branch-protection.rs b/tests/codegen-llvm/branch-protection.rs index 11847c256d6ba..ed1cb2cd137ea 100644 --- a/tests/codegen-llvm/branch-protection.rs +++ b/tests/codegen-llvm/branch-protection.rs @@ -22,7 +22,7 @@ extern crate minicore; use minicore::*; // A basic test function. -// CHECK: @test(){{.*}} [[ATTR:#[0-9]+]] +// CHECK: @test(){{.*}} [[ATTR:#[0-9]+]] { #[no_mangle] pub fn test() {} diff --git a/tests/codegen-llvm/frame-pointer-cli-control.rs b/tests/codegen-llvm/frame-pointer-cli-control.rs index 79cdfc70f1ad7..911a5f03cbcda 100644 --- a/tests/codegen-llvm/frame-pointer-cli-control.rs +++ b/tests/codegen-llvm/frame-pointer-cli-control.rs @@ -45,7 +45,7 @@ Specific cases where platforms or tools rely on frame pointers for sound or corr extern crate minicore; -// CHECK: i32 @peach{{.*}}[[PEACH_ATTRS:\#[0-9]+]] +// CHECK: i32 @peach{{.*}}[[PEACH_ATTRS:\#[0-9]+]] { #[no_mangle] pub fn peach(x: u32) -> u32 { x diff --git a/tests/codegen-llvm/frame-pointer.rs b/tests/codegen-llvm/frame-pointer.rs index a52d95a23862d..1d0dd762826b2 100644 --- a/tests/codegen-llvm/frame-pointer.rs +++ b/tests/codegen-llvm/frame-pointer.rs @@ -18,7 +18,7 @@ extern crate minicore; use minicore::*; -// CHECK: define i32 @peach{{.*}}[[PEACH_ATTRS:\#[0-9]+]] +// CHECK: define i32 @peach{{.*}}[[PEACH_ATTRS:\#[0-9]+]] { #[no_mangle] pub fn peach(x: u32) -> u32 { x diff --git a/tests/codegen-llvm/gpu-convergent.rs b/tests/codegen-llvm/gpu-convergent.rs index 376d65a3d4a25..bb9271ab69996 100644 --- a/tests/codegen-llvm/gpu-convergent.rs +++ b/tests/codegen-llvm/gpu-convergent.rs @@ -17,7 +17,7 @@ extern "C" { fn ext(); } -// CHECK: define {{.*}}_kernel void @fun(i32{{.*}}) unnamed_addr #[[ATTR:[0-9]+]] +// CHECK: define {{.*}}_kernel void @fun(i32{{.*}}) unnamed_addr #[[ATTR:[0-9]+]] { // CHECK: declare void @ext() unnamed_addr #[[ATTR]] // CHECK: attributes #[[ATTR]] = {{.*}} convergent #[no_mangle] diff --git a/tests/codegen-llvm/instrument-coverage/testprog.rs b/tests/codegen-llvm/instrument-coverage/testprog.rs index 67c49c438f9f7..ef61ede6de8ee 100644 --- a/tests/codegen-llvm/instrument-coverage/testprog.rs +++ b/tests/codegen-llvm/instrument-coverage/testprog.rs @@ -101,7 +101,7 @@ fn main() { // CHECK-SAME: @__llvm_prf_nm // CHECK-SAME: section "llvm.metadata" -// CHECK: define internal { {{.*}} } @_R{{[a-zA-Z0-9_]+}}testprog14will_be_called() unnamed_addr #{{[0-9]+}} +// CHECK: define internal { {{.*}} } @_R{{[a-zA-Z0-9_]+}}testprog14will_be_called() unnamed_addr #{{[0-9]+}} { // CHECK-NEXT: start: // CHECK-NOT: define internal // CHECK: atomicrmw add ptr @@ -109,7 +109,7 @@ fn main() { // CHECK: declare void @llvm.instrprof.increment(ptr, i64, i32, i32) #[[LLVM_INSTRPROF_INCREMENT_ATTR:[0-9]+]] -// WIN: define linkonce_odr hidden i32 @__llvm_profile_runtime_user() #[[LLVM_PROFILE_RUNTIME_USER_ATTR:[0-9]+]] comdat {{.*}} +// WIN: define linkonce_odr hidden i32 @__llvm_profile_runtime_user() #[[LLVM_PROFILE_RUNTIME_USER_ATTR:[0-9]+]] comdat {{.*}}{ // WIN-NEXT: %1 = load i32, ptr @__llvm_profile_runtime // WIN-NEXT: ret i32 %1 // WIN-NEXT: } diff --git a/tests/codegen-llvm/link_section.rs b/tests/codegen-llvm/link_section.rs index 61bde683c0a41..f196ea86c447d 100644 --- a/tests/codegen-llvm/link_section.rs +++ b/tests/codegen-llvm/link_section.rs @@ -29,7 +29,7 @@ pub static VAR2: E = E::A(666); #[link_section = "__TEST,three"] pub static VAR3: E = E::B(1.); -// CHECK: define {{(dso_local )?}}void @fn1() {{.*}} section "__TEST,four" +// CHECK: define {{(dso_local )?}}void @fn1() {{.*}} section "__TEST,four" { #[no_mangle] #[link_section = "__TEST,four"] pub fn fn1() {} diff --git a/tests/codegen-llvm/preserve-none.rs b/tests/codegen-llvm/preserve-none.rs index b45e49a466bf3..b8c8db25f272c 100644 --- a/tests/codegen-llvm/preserve-none.rs +++ b/tests/codegen-llvm/preserve-none.rs @@ -19,7 +19,7 @@ extern crate minicore; // UNSUPPORTED: define{{( dso_local)?}} void @peach(i16 #[no_mangle] #[inline(never)] -pub extern "rust-preserve-none" fn peach(x: u16) { +pub extern "rust-preserve-none" fn peach(_: u16) { loop {} } diff --git a/tests/codegen-llvm/sanitizer/cfi/emit-type-metadata-itanium-cxx-abi-normalized-generalized.rs b/tests/codegen-llvm/sanitizer/cfi/emit-type-metadata-itanium-cxx-abi-normalized-generalized.rs index 5b1aa97ab3338..7639ce7b10448 100644 --- a/tests/codegen-llvm/sanitizer/cfi/emit-type-metadata-itanium-cxx-abi-normalized-generalized.rs +++ b/tests/codegen-llvm/sanitizer/cfi/emit-type-metadata-itanium-cxx-abi-normalized-generalized.rs @@ -7,21 +7,21 @@ pub fn foo(f: fn(i32) -> i32, arg: i32) -> i32 { // CHECK-LABEL: define{{.*}}foo - // CHECK-SAME: {{.*}}!type ![[TYPE1:[0-9]+]] + // CHECK-SAME: {{.*}}![[TYPE1:[0-9]+]] // CHECK: call i1 @llvm.type.test(ptr {{%f|%0}}, metadata !"_ZTSFu3i32S_E.normalized.generalized") f(arg) } pub fn bar(f: fn(i32, i32) -> i32, arg1: i32, arg2: i32) -> i32 { // CHECK-LABEL: define{{.*}}bar - // CHECK-SAME: {{.*}}!type ![[TYPE2:[0-9]+]] + // CHECK-SAME: {{.*}}![[TYPE2:[0-9]+]] // CHECK: call i1 @llvm.type.test(ptr {{%f|%0}}, metadata !"_ZTSFu3i32S_S_E.normalized.generalized") f(arg1, arg2) } pub fn baz(f: fn(i32, i32, i32) -> i32, arg1: i32, arg2: i32, arg3: i32) -> i32 { // CHECK-LABEL: define{{.*}}baz - // CHECK-SAME: {{.*}}!type ![[TYPE3:[0-9]+]] + // CHECK-SAME: {{.*}}![[TYPE3:[0-9]+]] // CHECK: call i1 @llvm.type.test(ptr {{%f|%0}}, metadata !"_ZTSFu3i32S_S_S_E.normalized.generalized") f(arg1, arg2, arg3) } diff --git a/tests/codegen-llvm/some-non-zero-from-atomic-optimization.rs b/tests/codegen-llvm/some-non-zero-from-atomic-optimization.rs index 3df2d569f9a40..35317b0dd39cc 100644 --- a/tests/codegen-llvm/some-non-zero-from-atomic-optimization.rs +++ b/tests/codegen-llvm/some-non-zero-from-atomic-optimization.rs @@ -72,7 +72,7 @@ pub unsafe fn some_non_zero_from_atomic_get() -> Option { /// /// The way we check that the LLVM IR is correct is by making sure that neither /// `panic` nor `unreachable` is part of the LLVM IR: -// CHECK-LABEL: define {{.*}} i64 @some_non_zero_from_atomic_get2() {{.*}} +// CHECK-LABEL: define {{.*}} i64 @some_non_zero_from_atomic_get2() {{.*}} { // CHECK-NOT: panic // CHECK-NOT: unreachable #[no_mangle] diff --git a/tests/codegen-llvm/tailcc.rs b/tests/codegen-llvm/tailcc.rs new file mode 100644 index 0000000000000..15ae69cf0498c --- /dev/null +++ b/tests/codegen-llvm/tailcc.rs @@ -0,0 +1,28 @@ +//@ add-minicore +//@ revisions: I586 X86_64 AARCH64 +//@ [I586] compile-flags: -C no-prepopulate-passes --target=i586-unknown-linux-gnu +//@ [I586] needs-llvm-components: x86 +//@ [X86_64] compile-flags: -C no-prepopulate-passes --target=x86_64-unknown-linux-gnu +//@ [X86_64] needs-llvm-components: x86 +//@ [AARCH64] compile-flags: -C no-prepopulate-passes --target=aarch64-unknown-linux-gnu +//@ [AARCH64] needs-llvm-components: aarch64 + +#![crate_type = "lib"] +#![feature(no_core, rust_tail_cc, explicit_tail_calls)] +#![no_core] + +extern crate minicore; + +// CHECK: define{{( dso_local)?}} tailcc void @peach(i16 +#[no_mangle] +#[inline(never)] +pub extern "tail" fn peach(_: u16) { + loop {} +} + +// CHECK: call tailcc void @peach(i16 +pub fn quince(x: u16) { + if let 12345u16 = x { + peach(54321); + } +} diff --git a/tests/codegen-llvm/target-feature-negative-implication.rs b/tests/codegen-llvm/target-feature-negative-implication.rs index 376599738e526..a9cdca4283991 100644 --- a/tests/codegen-llvm/target-feature-negative-implication.rs +++ b/tests/codegen-llvm/target-feature-negative-implication.rs @@ -13,7 +13,7 @@ use minicore::*; #[no_mangle] pub unsafe fn banana() { // CHECK-LABEL: @banana() - // CHECK-SAME: [[BANANAATTRS:#[0-9]+]] + // CHECK-SAME: [[BANANAATTRS:#[0-9]+]] { } // CHECK: attributes [[BANANAATTRS]] diff --git a/tests/codegen-llvm/target-feature-overrides.rs b/tests/codegen-llvm/target-feature-overrides.rs index 3bf05c7977ebf..2adc8ee6f53bc 100644 --- a/tests/codegen-llvm/target-feature-overrides.rs +++ b/tests/codegen-llvm/target-feature-overrides.rs @@ -23,7 +23,7 @@ extern "C" { #[no_mangle] pub unsafe fn apple() -> u32 { // CHECK-LABEL: @apple() - // CHECK-SAME: [[APPLEATTRS:#[0-9]+]] + // CHECK-SAME: [[APPLEATTRS:#[0-9]+]] { // CHECK: {{.*}}call{{.*}}@peach peach() } @@ -32,7 +32,7 @@ pub unsafe fn apple() -> u32 { #[no_mangle] pub unsafe fn banana() -> u32 { // CHECK-LABEL: @banana() - // CHECK-SAME: [[BANANAATTRS:#[0-9]+]] + // CHECK-SAME: [[BANANAATTRS:#[0-9]+]] { // COMPAT: {{.*}}call{{.*}}@peach // INCOMPAT: {{.*}}call{{.*}}@apple apple() // Compatible for inline in COMPAT revision and can't be inlined in INCOMPAT diff --git a/tests/codegen-llvm/unwind-abis/aapcs-unwind-abi.rs b/tests/codegen-llvm/unwind-abis/aapcs-unwind-abi.rs index 279780e3a7aeb..ecace722e0dbe 100644 --- a/tests/codegen-llvm/unwind-abis/aapcs-unwind-abi.rs +++ b/tests/codegen-llvm/unwind-abis/aapcs-unwind-abi.rs @@ -16,11 +16,11 @@ pub trait Sized: MetaSized {} // `aapcs-unwind` extern functions. `aapcs-unwind` functions MUST NOT have this attribute. We // disable optimizations above to prevent LLVM from inferring the attribute. -// CHECK: @rust_item_that_cannot_unwind() unnamed_addr #0 +// CHECK: @rust_item_that_cannot_unwind() unnamed_addr #0 { #[no_mangle] pub extern "aapcs" fn rust_item_that_cannot_unwind() {} -// CHECK: @rust_item_that_can_unwind() unnamed_addr #1 +// CHECK: @rust_item_that_can_unwind() unnamed_addr #1 { #[no_mangle] pub extern "aapcs-unwind" fn rust_item_that_can_unwind() {} diff --git a/tests/codegen-llvm/unwind-abis/c-unwind-abi.rs b/tests/codegen-llvm/unwind-abis/c-unwind-abi.rs index 1b3312839e3e8..46c08b5fc4ff4 100644 --- a/tests/codegen-llvm/unwind-abis/c-unwind-abi.rs +++ b/tests/codegen-llvm/unwind-abis/c-unwind-abi.rs @@ -7,11 +7,11 @@ #![crate_type = "lib"] -// CHECK: @rust_item_that_cannot_unwind() unnamed_addr #0 +// CHECK: @rust_item_that_cannot_unwind() unnamed_addr #0 { #[no_mangle] pub extern "C" fn rust_item_that_cannot_unwind() {} -// CHECK: @rust_item_that_can_unwind() unnamed_addr #1 +// CHECK: @rust_item_that_can_unwind() unnamed_addr #1 { #[no_mangle] pub extern "C-unwind" fn rust_item_that_can_unwind() {} diff --git a/tests/codegen-llvm/unwind-abis/cdecl-unwind-abi.rs b/tests/codegen-llvm/unwind-abis/cdecl-unwind-abi.rs index 6f4eafb353ccb..8e643d6ce4947 100644 --- a/tests/codegen-llvm/unwind-abis/cdecl-unwind-abi.rs +++ b/tests/codegen-llvm/unwind-abis/cdecl-unwind-abi.rs @@ -7,11 +7,11 @@ #![crate_type = "lib"] -// CHECK: @rust_item_that_cannot_unwind() unnamed_addr #0 +// CHECK: @rust_item_that_cannot_unwind() unnamed_addr #0 { #[no_mangle] pub extern "cdecl" fn rust_item_that_cannot_unwind() {} -// CHECK: @rust_item_that_can_unwind() unnamed_addr #1 +// CHECK: @rust_item_that_can_unwind() unnamed_addr #1 { #[no_mangle] pub extern "cdecl-unwind" fn rust_item_that_can_unwind() {} diff --git a/tests/codegen-llvm/unwind-abis/fastcall-unwind-abi.rs b/tests/codegen-llvm/unwind-abis/fastcall-unwind-abi.rs index 51c6fd15b9c5c..7df46813ed1dd 100644 --- a/tests/codegen-llvm/unwind-abis/fastcall-unwind-abi.rs +++ b/tests/codegen-llvm/unwind-abis/fastcall-unwind-abi.rs @@ -16,11 +16,11 @@ pub trait Sized: MetaSized {} // `fastcall-unwind` extern functions. `fastcall-unwind` functions MUST NOT have this attribute. We // disable optimizations above to prevent LLVM from inferring the attribute. -// CHECK: @rust_item_that_cannot_unwind() unnamed_addr #0 +// CHECK: @rust_item_that_cannot_unwind() unnamed_addr #0 { #[no_mangle] pub extern "fastcall" fn rust_item_that_cannot_unwind() {} -// CHECK: @rust_item_that_can_unwind() unnamed_addr #1 +// CHECK: @rust_item_that_can_unwind() unnamed_addr #1 { #[no_mangle] pub extern "fastcall-unwind" fn rust_item_that_can_unwind() {} diff --git a/tests/codegen-llvm/unwind-abis/stdcall-unwind-abi.rs b/tests/codegen-llvm/unwind-abis/stdcall-unwind-abi.rs index b5fcea52b4d61..cc06ee125495a 100644 --- a/tests/codegen-llvm/unwind-abis/stdcall-unwind-abi.rs +++ b/tests/codegen-llvm/unwind-abis/stdcall-unwind-abi.rs @@ -16,11 +16,11 @@ pub trait Sized: MetaSized {} // extern functions. `stdcall-unwind` functions MUST NOT have this attribute. We disable // optimizations above to prevent LLVM from inferring the attribute. -// CHECK: @rust_item_that_cannot_unwind() unnamed_addr #0 +// CHECK: @rust_item_that_cannot_unwind() unnamed_addr #0 { #[no_mangle] pub extern "stdcall" fn rust_item_that_cannot_unwind() {} -// CHECK: @rust_item_that_can_unwind() unnamed_addr #1 +// CHECK: @rust_item_that_can_unwind() unnamed_addr #1 { #[no_mangle] pub extern "stdcall-unwind" fn rust_item_that_can_unwind() {} diff --git a/tests/codegen-llvm/unwind-abis/system-unwind-abi.rs b/tests/codegen-llvm/unwind-abis/system-unwind-abi.rs index 15fce95fe285b..5f9102483464b 100644 --- a/tests/codegen-llvm/unwind-abis/system-unwind-abi.rs +++ b/tests/codegen-llvm/unwind-abis/system-unwind-abi.rs @@ -7,11 +7,11 @@ #![crate_type = "lib"] -// CHECK: @rust_item_that_cannot_unwind() unnamed_addr #0 +// CHECK: @rust_item_that_cannot_unwind() unnamed_addr #0 { #[no_mangle] pub extern "system" fn rust_item_that_cannot_unwind() {} -// CHECK: @rust_item_that_can_unwind() unnamed_addr #1 +// CHECK: @rust_item_that_can_unwind() unnamed_addr #1 { #[no_mangle] pub extern "system-unwind" fn rust_item_that_can_unwind() {} diff --git a/tests/codegen-llvm/unwind-abis/sysv64-unwind-abi.rs b/tests/codegen-llvm/unwind-abis/sysv64-unwind-abi.rs index 1293e7c0a5f82..69bfaf80b4be6 100644 --- a/tests/codegen-llvm/unwind-abis/sysv64-unwind-abi.rs +++ b/tests/codegen-llvm/unwind-abis/sysv64-unwind-abi.rs @@ -16,11 +16,11 @@ pub trait Sized: MetaSized {} // `sysv64-unwind` extern functions. `sysv64-unwind` functions MUST NOT have this attribute. We // disable optimizations above to prevent LLVM from inferring the attribute. -// CHECK: @rust_item_that_cannot_unwind() unnamed_addr #0 +// CHECK: @rust_item_that_cannot_unwind() unnamed_addr #0 { #[no_mangle] pub extern "sysv64" fn rust_item_that_cannot_unwind() {} -// CHECK: @rust_item_that_can_unwind() unnamed_addr #1 +// CHECK: @rust_item_that_can_unwind() unnamed_addr #1 { #[no_mangle] pub extern "sysv64-unwind" fn rust_item_that_can_unwind() {} diff --git a/tests/codegen-llvm/unwind-abis/thiscall-unwind-abi.rs b/tests/codegen-llvm/unwind-abis/thiscall-unwind-abi.rs index a9b6c34ee58e2..05f6b8b70e171 100644 --- a/tests/codegen-llvm/unwind-abis/thiscall-unwind-abi.rs +++ b/tests/codegen-llvm/unwind-abis/thiscall-unwind-abi.rs @@ -16,11 +16,11 @@ pub trait Sized: MetaSized {} // `thiscall-unwind` extern functions. `thiscall-unwind` functions MUST NOT have this attribute. We // disable optimizations above to prevent LLVM from inferring the attribute. -// CHECK: @rust_item_that_cannot_unwind() unnamed_addr #0 +// CHECK: @rust_item_that_cannot_unwind() unnamed_addr #0 { #[no_mangle] pub extern "thiscall" fn rust_item_that_cannot_unwind() {} -// CHECK: @rust_item_that_can_unwind() unnamed_addr #1 +// CHECK: @rust_item_that_can_unwind() unnamed_addr #1 { #[no_mangle] pub extern "thiscall-unwind" fn rust_item_that_can_unwind() {} diff --git a/tests/codegen-llvm/unwind-abis/vectorcall-unwind-abi.rs b/tests/codegen-llvm/unwind-abis/vectorcall-unwind-abi.rs index 8cedb55ae1d28..d001a16b32a1c 100644 --- a/tests/codegen-llvm/unwind-abis/vectorcall-unwind-abi.rs +++ b/tests/codegen-llvm/unwind-abis/vectorcall-unwind-abi.rs @@ -16,11 +16,11 @@ pub trait Sized: MetaSized {} // `vectorcall-unwind` extern functions. `vectorcall-unwind` functions MUST NOT have this attribute. // We disable optimizations above to prevent LLVM from inferring the attribute. -// CHECK: @rust_item_that_cannot_unwind() unnamed_addr #0 +// CHECK: @rust_item_that_cannot_unwind() unnamed_addr #0 { #[no_mangle] pub extern "vectorcall" fn rust_item_that_cannot_unwind() {} -// CHECK: @rust_item_that_can_unwind() unnamed_addr #1 +// CHECK: @rust_item_that_can_unwind() unnamed_addr #1 { #[no_mangle] pub extern "vectorcall-unwind" fn rust_item_that_can_unwind() {} diff --git a/tests/codegen-llvm/unwind-abis/win64-unwind-abi.rs b/tests/codegen-llvm/unwind-abis/win64-unwind-abi.rs index 2a3ad330406e6..257f00b54e4d8 100644 --- a/tests/codegen-llvm/unwind-abis/win64-unwind-abi.rs +++ b/tests/codegen-llvm/unwind-abis/win64-unwind-abi.rs @@ -16,11 +16,11 @@ pub trait Sized: MetaSized {} // `win64-unwind` extern functions. `win64-unwind` functions MUST NOT have this attribute. We // disable optimizations above to prevent LLVM from inferring the attribute. -// CHECK: @rust_item_that_cannot_unwind() unnamed_addr #0 +// CHECK: @rust_item_that_cannot_unwind() unnamed_addr #0 { #[no_mangle] pub extern "win64" fn rust_item_that_cannot_unwind() {} -// CHECK: @rust_item_that_can_unwind() unnamed_addr #1 +// CHECK: @rust_item_that_can_unwind() unnamed_addr #1 { #[no_mangle] pub extern "win64-unwind" fn rust_item_that_can_unwind() {} diff --git a/tests/run-make/dynamic-loading-cdylib/foo.rs b/tests/run-make/dynamic-loading-cdylib/foo.rs index 15ce4825d1b33..5d29ca209edd8 100644 --- a/tests/run-make/dynamic-loading-cdylib/foo.rs +++ b/tests/run-make/dynamic-loading-cdylib/foo.rs @@ -6,18 +6,36 @@ pub extern "C" fn extern_fn_1(a: u32, b: u32) -> u32 { a + b } -struct NotifyOnDrop; +#[derive(Default)] +struct NotifyOnDrop { + last_result: std::cell::Cell, +} + +impl NotifyOnDrop { + fn save_and_print(&self, result: u32) { + self.last_result.set(result); + } +} impl Drop for NotifyOnDrop { fn drop(&mut self) { - println!("drop"); + println!("dropping, last result: {}", self.last_result.get()); } } +thread_local! { + static FOO: NotifyOnDrop = NotifyOnDrop::default(); +} + #[no_mangle] pub extern "C" fn extern_fn_2(a: u32, b: u32) -> u32 { - thread_local!(static FOO: NotifyOnDrop = NotifyOnDrop); - FOO.with(|_foo| {}); - println!("extern_fn_2"); - a * b + let result = a * b; + + FOO.with(|foo| { + foo.save_and_print(result); + }); + + println!("extern_fn_2({a}, {b})"); + + result } diff --git a/tests/run-make/dynamic-loading-cdylib/load_and_unload.rs b/tests/run-make/dynamic-loading-cdylib/load_and_unload.rs index 24409c16e8fea..ec3c558156c7b 100644 --- a/tests/run-make/dynamic-loading-cdylib/load_and_unload.rs +++ b/tests/run-make/dynamic-loading-cdylib/load_and_unload.rs @@ -101,6 +101,15 @@ fn main() { let result = unsafe { extern_fn_2(2, 3) }; println!("result of extern_fn_2(2, 3): {}", result); + println!("spawning thread"); + std::thread::spawn(move || { + let result = unsafe { extern_fn_2(4, 5) }; + println!("result of extern_fn_2(4, 5) in other thread: {}", result); + }) + .join() + .expect("Thread panicked"); + println!("thread joined"); + libloading::unload(foo); println!("unloaded library"); } diff --git a/tests/run-make/dynamic-loading-cdylib/output_unix.txt b/tests/run-make/dynamic-loading-cdylib/output_unix.txt index f79d5a2a63fa6..6e1736ca38d86 100644 --- a/tests/run-make/dynamic-loading-cdylib/output_unix.txt +++ b/tests/run-make/dynamic-loading-cdylib/output_unix.txt @@ -1,7 +1,12 @@ loaded library extern_fn_1 result of extern_fn_1(2, 3): 5 -extern_fn_2 +extern_fn_2(2, 3) result of extern_fn_2(2, 3): 6 +spawning thread +extern_fn_2(4, 5) +result of extern_fn_2(4, 5) in other thread: 20 +dropping, last result: 20 +thread joined unloaded library -drop +dropping, last result: 6 diff --git a/tests/run-make/dynamic-loading-cdylib/output_windows.txt b/tests/run-make/dynamic-loading-cdylib/output_windows.txt index 5ce77ad164359..e87baf4b52110 100644 --- a/tests/run-make/dynamic-loading-cdylib/output_windows.txt +++ b/tests/run-make/dynamic-loading-cdylib/output_windows.txt @@ -1,7 +1,12 @@ loaded library extern_fn_1 result of extern_fn_1(2, 3): 5 -extern_fn_2 +extern_fn_2(2, 3) result of extern_fn_2(2, 3): 6 -drop +spawning thread +extern_fn_2(4, 5) +result of extern_fn_2(4, 5) in other thread: 20 +dropping, last result: 20 +thread joined +dropping, last result: 6 unloaded library diff --git a/tests/rustdoc-ui/intra-doc/deprecated-note-link-after-unclosed-code-fence.rs b/tests/rustdoc-ui/intra-doc/deprecated-note-link-after-unclosed-code-fence.rs new file mode 100644 index 0000000000000..ac85c1474c1aa --- /dev/null +++ b/tests/rustdoc-ui/intra-doc/deprecated-note-link-after-unclosed-code-fence.rs @@ -0,0 +1,12 @@ +//@ check-pass + +// Regression test for https://github.com/rust-lang/rust/issues/157326. +#![allow(rustdoc::invalid_rust_codeblocks)] +#![deprecated(note = "use [Env::try_invoke] instead")] +//! ``` + +pub struct Env; + +impl Env { + pub fn try_invoke(&self) {} +} diff --git a/tests/ui/abi/rust-preserve-none-cc.rs b/tests/ui/abi/rust-preserve-none-cc.rs index deacb926971c8..20895e1583f4e 100644 --- a/tests/ui/abi/rust-preserve-none-cc.rs +++ b/tests/ui/abi/rust-preserve-none-cc.rs @@ -1,5 +1,6 @@ //@ run-pass //@ needs-unwind +//@ ignore-backends: gcc #![feature(rust_preserve_none_cc)] @@ -17,9 +18,7 @@ extern "rust-preserve-none" fn oven_explosion() { #[inline(never)] fn bite_into(yummy: u64) -> u64 { - let did_it_actually = std::panic::catch_unwind(move || { - oven_explosion() - }); + let did_it_actually = std::panic::catch_unwind(move || oven_explosion()); assert!(did_it_actually.is_err()); yummy - 25 } @@ -52,16 +51,26 @@ extern "rust-preserve-none" fn lotsa_apples( and_a.rome.iter().sum(), fuji + ambrosia, cosmic_crisp - honeycrisp, - bite_into(and_a.golden_delicious) + bite_into(and_a.golden_delicious), ) } fn main() { - let pie = lotsa_apples(220, 140, 210.54201234, &[180, 210], (), CrateOf { - mcintosh: 150.0, - golden_delicious: 185, - jonagold: None, - rome: [180, 182, 184, 186, 188, 190, 192, 194, 196, 198, 200, 202] - }, 270, 193.1, &[]); + let pie = lotsa_apples( + 220, + 140, + 210.54201234, + &[180, 210], + (), + CrateOf { + mcintosh: 150.0, + golden_delicious: 185, + jonagold: None, + rome: [180, 182, 184, 186, 188, 190, 192, 194, 196, 198, 200, 202], + }, + 270, + 193.1, + &[], + ); assert_eq!(pie, (2292, 403.64201234, 50, 160)); } diff --git a/tests/ui/abi/rust-tail-cc.rs b/tests/ui/abi/rust-tail-cc.rs new file mode 100644 index 0000000000000..aba5d0d695647 --- /dev/null +++ b/tests/ui/abi/rust-tail-cc.rs @@ -0,0 +1,80 @@ +//@ revisions: aarch64 x32 x64 +//@ run-pass +//@[aarch64] only-aarch64 +//@[x32] only-x86 +//@[x64] only-x86_64 +//@ needs-unwind +//@ ignore-backends: gcc + +#![feature(rust_tail_cc)] + +struct CrateOf<'a> { + mcintosh: f64, + golden_delicious: u64, + jonagold: Option<&'a u64>, + rome: [u64; 12], +} + +#[inline(never)] +extern "tail" fn oven_explosion() { + panic!("bad time"); +} + +#[inline(never)] +fn bite_into(yummy: u64) -> u64 { + let did_it_actually = std::panic::catch_unwind(move || oven_explosion()); + assert!(did_it_actually.is_err()); + yummy - 25 +} + +#[inline(never)] +extern "tail" fn lotsa_apples( + honeycrisp: u64, + gala: u32, + fuji: f64, + granny_smith: &[u64], + pink_lady: (), + and_a: CrateOf<'static>, + cosmic_crisp: u64, + ambrosia: f64, + winesap: &[u64], +) -> (u64, f64, u64, u64) { + assert_eq!(honeycrisp, 220); + assert_eq!(gala, 140); + assert_eq!(fuji, 210.54201234); + assert_eq!(granny_smith, &[180, 210]); + assert_eq!(pink_lady, ()); + assert_eq!(and_a.mcintosh, 150.0); + assert_eq!(and_a.golden_delicious, 185); + assert_eq!(and_a.jonagold, None); // my scales can't weight these gargantuans. + assert_eq!(and_a.rome, [180, 182, 184, 186, 188, 190, 192, 194, 196, 198, 200, 202]); + assert_eq!(cosmic_crisp, 270); + assert_eq!(ambrosia, 193.1); + assert_eq!(winesap, &[]); + ( + and_a.rome.iter().sum(), + fuji + ambrosia, + cosmic_crisp - honeycrisp, + bite_into(and_a.golden_delicious), + ) +} + +fn main() { + let pie = lotsa_apples( + 220, + 140, + 210.54201234, + &[180, 210], + (), + CrateOf { + mcintosh: 150.0, + golden_delicious: 185, + jonagold: None, + rome: [180, 182, 184, 186, 188, 190, 192, 194, 196, 198, 200, 202], + }, + 270, + 193.1, + &[], + ); + assert_eq!(pie, (2292, 403.64201234, 50, 160)); +} diff --git a/tests/ui/issues/issue-20055-box-trait.rs b/tests/ui/box/box-array-match-temporary-drop.rs similarity index 90% rename from tests/ui/issues/issue-20055-box-trait.rs rename to tests/ui/box/box-array-match-temporary-drop.rs index 43f1f43ba2785..d87c4307760f8 100644 --- a/tests/ui/issues/issue-20055-box-trait.rs +++ b/tests/ui/box/box-array-match-temporary-drop.rs @@ -1,5 +1,5 @@ //@ run-pass -// See Issues #20055 and #21695. +// See Issues https://github.com/rust-lang/rust/issues/20055 and https://github.com/rust-lang/rust/issues/21695. // We are checking here that the temporaries `Box<[i8, k]>`, for `k` // in 1, 2, 3, 4, that are induced by the match expression are diff --git a/tests/ui/issues/issue-20055-box-trait.stderr b/tests/ui/box/box-array-match-temporary-drop.stderr similarity index 83% rename from tests/ui/issues/issue-20055-box-trait.stderr rename to tests/ui/box/box-array-match-temporary-drop.stderr index b1cbb2a571733..09caa6741afa7 100644 --- a/tests/ui/issues/issue-20055-box-trait.stderr +++ b/tests/ui/box/box-array-match-temporary-drop.stderr @@ -1,5 +1,5 @@ warning: method `dummy` is never used - --> $DIR/issue-20055-box-trait.rs:11:8 + --> $DIR/box-array-match-temporary-drop.rs:11:8 | LL | trait Boo { | --- method in this trait diff --git a/tests/ui/box/box-deref-in-match-arm-no-invalid-ir.rs b/tests/ui/box/box-deref-in-match-arm-no-invalid-ir.rs new file mode 100644 index 0000000000000..8c005a392dca9 --- /dev/null +++ b/tests/ui/box/box-deref-in-match-arm-no-invalid-ir.rs @@ -0,0 +1,18 @@ +//! Regression test for https://github.com/rust-lang/rust/issues/18845 + +//@ run-pass +// This used to generate invalid IR in that even if we took the +// `false` branch we'd still try to free the Box from the other +// arm. This was due to treating `*Box::new(9)` as an rvalue datum +// instead of as a place. + +fn test(foo: bool) -> u8 { + match foo { + true => *Box::new(9), + false => 0 + } +} + +fn main() { + assert_eq!(9, test(true)); +} diff --git a/tests/ui/issues/issue-23491.rs b/tests/ui/box/box-dst-node-with-empty-slice.rs similarity index 68% rename from tests/ui/issues/issue-23491.rs rename to tests/ui/box/box-dst-node-with-empty-slice.rs index 0a2dfa4257a03..15ee8d4434b5d 100644 --- a/tests/ui/issues/issue-23491.rs +++ b/tests/ui/box/box-dst-node-with-empty-slice.rs @@ -1,3 +1,5 @@ +//! Regression test for https://github.com/rust-lang/rust/issues/23491 + //@ run-pass #![allow(unused_variables)] diff --git a/tests/ui/issues/issue-20055-box-unsized-array.rs b/tests/ui/box/box-fixed-array-coerce-unsized-match.rs similarity index 88% rename from tests/ui/issues/issue-20055-box-unsized-array.rs rename to tests/ui/box/box-fixed-array-coerce-unsized-match.rs index 2663bcfb4f727..4251495347183 100644 --- a/tests/ui/issues/issue-20055-box-unsized-array.rs +++ b/tests/ui/box/box-fixed-array-coerce-unsized-match.rs @@ -1,5 +1,5 @@ //@ run-pass -// Issue #2005: Check that boxed fixed-size arrays are properly +// Issue https://github.com/rust-lang/rust/issues/20055: Check that boxed fixed-size arrays are properly // accounted for (namely, only deallocated if they were actually // created) when they appear as temporaries in unused arms of a match // expression. diff --git a/tests/ui/feature-gates/feature-gate-rust-tail-cc.rs b/tests/ui/feature-gates/feature-gate-rust-tail-cc.rs new file mode 100644 index 0000000000000..b2bbf606cc7a8 --- /dev/null +++ b/tests/ui/feature-gates/feature-gate-rust-tail-cc.rs @@ -0,0 +1,21 @@ +#![crate_type = "lib"] + +extern "tail" fn apple() {} //~ ERROR "tail" ABI is experimental + +trait T { + extern "tail" fn banana(); //~ ERROR "tail" ABI is experimental + extern "tail" fn citrus() {} //~ ERROR "tail" ABI is experimental +} + +struct S; +impl T for S { + extern "tail" fn banana() {} //~ ERROR "tail" ABI is experimental +} + +impl S { + extern "tail" fn durian() {} //~ ERROR "tail" ABI is experimental +} + +type Fig = extern "tail" fn(); //~ ERROR "tail" ABI is experimental + +extern "tail" {} //~ ERROR "tail" ABI is experimental diff --git a/tests/ui/feature-gates/feature-gate-rust-tail-cc.stderr b/tests/ui/feature-gates/feature-gate-rust-tail-cc.stderr new file mode 100644 index 0000000000000..e588569e6bd79 --- /dev/null +++ b/tests/ui/feature-gates/feature-gate-rust-tail-cc.stderr @@ -0,0 +1,73 @@ +error[E0658]: the extern "tail" ABI is experimental and subject to change + --> $DIR/feature-gate-rust-tail-cc.rs:3:8 + | +LL | extern "tail" fn apple() {} + | ^^^^^^ + | + = note: see issue #157427 for more information + = help: add `#![feature(rust_tail_cc)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error[E0658]: the extern "tail" ABI is experimental and subject to change + --> $DIR/feature-gate-rust-tail-cc.rs:6:12 + | +LL | extern "tail" fn banana(); + | ^^^^^^ + | + = note: see issue #157427 for more information + = help: add `#![feature(rust_tail_cc)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error[E0658]: the extern "tail" ABI is experimental and subject to change + --> $DIR/feature-gate-rust-tail-cc.rs:7:12 + | +LL | extern "tail" fn citrus() {} + | ^^^^^^ + | + = note: see issue #157427 for more information + = help: add `#![feature(rust_tail_cc)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error[E0658]: the extern "tail" ABI is experimental and subject to change + --> $DIR/feature-gate-rust-tail-cc.rs:12:12 + | +LL | extern "tail" fn banana() {} + | ^^^^^^ + | + = note: see issue #157427 for more information + = help: add `#![feature(rust_tail_cc)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error[E0658]: the extern "tail" ABI is experimental and subject to change + --> $DIR/feature-gate-rust-tail-cc.rs:16:12 + | +LL | extern "tail" fn durian() {} + | ^^^^^^ + | + = note: see issue #157427 for more information + = help: add `#![feature(rust_tail_cc)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error[E0658]: the extern "tail" ABI is experimental and subject to change + --> $DIR/feature-gate-rust-tail-cc.rs:19:19 + | +LL | type Fig = extern "tail" fn(); + | ^^^^^^ + | + = note: see issue #157427 for more information + = help: add `#![feature(rust_tail_cc)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error[E0658]: the extern "tail" ABI is experimental and subject to change + --> $DIR/feature-gate-rust-tail-cc.rs:21:8 + | +LL | extern "tail" {} + | ^^^^^^ + | + = note: see issue #157427 for more information + = help: add `#![feature(rust_tail_cc)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error: aborting due to 7 previous errors + +For more information about this error, try `rustc --explain E0658`. diff --git a/tests/ui/methods/method-suggestion-trait-with-extra-generics-no-ice.rs b/tests/ui/methods/method-suggestion-trait-with-extra-generics-no-ice.rs new file mode 100644 index 0000000000000..0a98cdef5c923 --- /dev/null +++ b/tests/ui/methods/method-suggestion-trait-with-extra-generics-no-ice.rs @@ -0,0 +1,24 @@ +//! Regression test for #157189. +//! +//! When a method call fails to resolve, the "trait which provides `` is +//! implemented but not in scope" diagnostic probes all traits for a method of the +//! same name. Here `.borrow()` matches `std::borrow::Borrow::borrow`, and `Borrow` +//! has a generic parameter (`Borrowed`) besides `Self`. Building the trait +//! reference for the diagnostic used to pass only the receiver type as the single +//! argument, which mismatched the trait's generics and ICEd in +//! `debug_assert_args_compatible`. It should just report the error. + +trait Foo { + extern "C" fn borrow(&self); +} + +struct Bar; + +fn main() { + let foo: Box usize> = Box::new(Bar); + //~^ ERROR expected a `Fn(bool)` closure, found `Bar` + foo.borrow(); + //~^ ERROR no method named `borrow` found + foo.take() + //~^ ERROR `Box usize>` is not an iterator +} diff --git a/tests/ui/methods/method-suggestion-trait-with-extra-generics-no-ice.stderr b/tests/ui/methods/method-suggestion-trait-with-extra-generics-no-ice.stderr new file mode 100644 index 0000000000000..aa46a41fa3378 --- /dev/null +++ b/tests/ui/methods/method-suggestion-trait-with-extra-generics-no-ice.stderr @@ -0,0 +1,65 @@ +error[E0599]: no method named `borrow` found for struct `Box usize>` in the current scope + --> $DIR/method-suggestion-trait-with-extra-generics-no-ice.rs:20:9 + | +LL | foo.borrow(); + | ^^^^^^ + | + --> $SRC_DIR/core/src/borrow.rs:LL:COL + | + = note: the method is available for `Box usize>` here + | + = help: items from traits can only be used if the trait is in scope +help: use parentheses to call this trait object + | +LL | foo(/* bool */).borrow(); + | ++++++++++++ +help: trait `Borrow` which provides `borrow` is implemented but not in scope; perhaps you want to import it + | +LL + use std::borrow::Borrow; + | +help: there is a method `borrow_mut` with a similar name + | +LL | foo.borrow_mut(); + | ++++ + +error[E0277]: expected a `Fn(bool)` closure, found `Bar` + --> $DIR/method-suggestion-trait-with-extra-generics-no-ice.rs:18:43 + | +LL | let foo: Box usize> = Box::new(Bar); + | ^^^^^^^^^^^^^ expected an `Fn(bool)` closure, found `Bar` + | +help: the trait `Fn(bool)` is not implemented for `Bar` + --> $DIR/method-suggestion-trait-with-extra-generics-no-ice.rs:15:1 + | +LL | struct Bar; + | ^^^^^^^^^^ + = note: required for the cast from `Box` to `Box usize>` + +error[E0599]: `Box usize>` is not an iterator + --> $DIR/method-suggestion-trait-with-extra-generics-no-ice.rs:22:9 + | +LL | foo.take() + | ^^^^ + | | + | this is an associated function, not a method + | `Box usize>` is not an iterator + | + = note: found the following associated functions; to be used as methods, functions must have a `self` parameter + = note: the candidate is defined in an impl for the type `Box` + = note: the following trait bounds were not satisfied: + `dyn Fn(bool) -> usize: Iterator` + which is required by `Box usize>: Iterator` + `Box usize>: Iterator` + which is required by `&mut Box usize>: Iterator` + `dyn Fn(bool) -> usize: Iterator` + which is required by `&mut dyn Fn(bool) -> usize: Iterator` +help: use associated function syntax instead + | +LL - foo.take() +LL + Box:: usize>::take(foo) + | + +error: aborting due to 3 previous errors + +Some errors have detailed explanations: E0277, E0599. +For more information about an error, try `rustc --explain E0277`. diff --git a/tests/ui/print-request/print-calling-conventions.stdout b/tests/ui/print-request/print-calling-conventions.stdout index 506bbea23e171..af4f491fc069e 100644 --- a/tests/ui/print-request/print-calling-conventions.stdout +++ b/tests/ui/print-request/print-calling-conventions.stdout @@ -29,6 +29,7 @@ system system-unwind sysv64 sysv64-unwind +tail thiscall thiscall-unwind unadjusted diff --git a/tests/ui/proc-macro/auxiliary/api/literal.rs b/tests/ui/proc-macro/auxiliary/api/literal.rs index 7109340bb645b..097dfc479f992 100644 --- a/tests/ui/proc-macro/auxiliary/api/literal.rs +++ b/tests/ui/proc-macro/auxiliary/api/literal.rs @@ -1,10 +1,13 @@ // ignore-tidy-linelength +#![feature(f16)] + use proc_macro::Literal; pub fn test() { test_display_literal(); test_parse_literal(); + test_literal_value(); } fn test_display_literal() { @@ -81,3 +84,27 @@ fn test_parse_literal() { assert!("- 10".parse::().is_err()); assert!("-'x'".parse::().is_err()); } + +fn test_literal_value() { + assert!(Literal::u32_suffixed(10).u8_value().is_err()); + assert!(Literal::u32_suffixed(11).f32_value().is_err()); + assert!(Literal::u32_suffixed(12).u64_value().is_err()); + assert_eq!(Literal::u32_suffixed(13).u32_value(), Ok(13u32)); + assert_eq!(Literal::u32_unsuffixed(14).u64_value(), Ok(14u64)); + assert_eq!(Literal::u32_unsuffixed(15).u8_value(), Ok(15u8)); + assert!(Literal::u32_unsuffixed(400).u8_value().is_err()); + assert_eq!(Literal::u32_unsuffixed(401).u16_value(), Ok(401u16)); + assert!(Literal::i32_unsuffixed(-402).u16_value().is_err()); + assert_eq!(Literal::i32_unsuffixed(-403).i16_value(), Ok(-403i16)); + assert_eq!(Literal::u32_unsuffixed(0xff).u16_value(), Ok(0xffu16)); + assert_eq!(Literal::u32_unsuffixed(0b11).u16_value(), Ok(0b11u16)); + assert_eq!(Literal::u32_unsuffixed(0o11).u16_value(), Ok(0o11u16)); + + assert!(Literal::f32_suffixed(9.).u8_value().is_err()); + assert!(Literal::f32_suffixed(10.).f64_value().is_err()); + assert!(Literal::f32_suffixed(11.).f16_value().is_err()); + assert_eq!(Literal::f32_suffixed(12.).f32_value().map(|f| f.to_string()), Ok("12".to_string())); + assert_eq!(Literal::f32_unsuffixed(13.).f32_value().map(|f| f.to_string()), Ok("13".to_string())); + assert_eq!(Literal::f32_unsuffixed(14.).f64_value().map(|f| f.to_string()), Ok("14".to_string())); + assert_eq!(Literal::f32_unsuffixed(15.).f16_value().map(|f| f.to_string()), Ok("15".to_string())); +} diff --git a/tests/ui/proc-macro/auxiliary/api/proc_macro_api_tests.rs b/tests/ui/proc-macro/auxiliary/api/proc_macro_api_tests.rs index d778e46da6b99..493f03ecc8f83 100644 --- a/tests/ui/proc-macro/auxiliary/api/proc_macro_api_tests.rs +++ b/tests/ui/proc-macro/auxiliary/api/proc_macro_api_tests.rs @@ -1,6 +1,7 @@ //@ edition: 2021 #![feature(proc_macro_span)] +#![feature(proc_macro_value)] #![deny(dead_code)] // catch if a test function is never called extern crate proc_macro; diff --git a/tests/ui/proc-macro/test.rs b/tests/ui/proc-macro/test.rs index b36910a414b10..d935dbe8ad3fb 100644 --- a/tests/ui/proc-macro/test.rs +++ b/tests/ui/proc-macro/test.rs @@ -1,6 +1,9 @@ //@ check-pass //@ proc-macro: api/proc_macro_api_tests.rs //@ edition: 2021 +// Because of a (known) proc-macro ABI issue with GCC backend, this test +// fails because of it. +//@ ignore-backends: gcc //! This is for everything that *would* be a #[test] inside of libproc_macro, //! except for the fact that proc_macro objects are not capable of existing