Merge pull request #4859 from rust-lang/rustup-2026-02-15

Automatic Rustup
This commit is contained in:
Ralf Jung 2026-02-15 17:52:14 +00:00 committed by GitHub
commit 1f39d1f74f
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
537 changed files with 8823 additions and 5896 deletions

View file

@ -4093,7 +4093,6 @@ dependencies = [
"rustc_passes",
"rustc_privacy",
"rustc_query_impl",
"rustc_query_system",
"rustc_resolve",
"rustc_session",
"rustc_span",
@ -4226,6 +4225,7 @@ dependencies = [
"bitflags",
"either",
"gsgdt",
"parking_lot",
"polonius-engine",
"rustc_abi",
"rustc_apfloat",
@ -4512,22 +4512,17 @@ dependencies = [
name = "rustc_query_system"
version = "0.0.0"
dependencies = [
"parking_lot",
"rustc_abi",
"rustc_ast",
"rustc_data_structures",
"rustc_errors",
"rustc_feature",
"rustc_hashes",
"rustc_hir",
"rustc_index",
"rustc_macros",
"rustc_serialize",
"rustc_session",
"rustc_span",
"rustc_thread_pool",
"smallvec",
"tracing",
]
[[package]]

View file

@ -1,5 +1,5 @@
// tidy-alphabetical-start
#![cfg_attr(all(feature = "nightly", bootstrap), feature(assert_matches))]
#![cfg_attr(all(feature = "nightly", bootstrap, test), feature(assert_matches))]
#![cfg_attr(feature = "nightly", allow(internal_features))]
#![cfg_attr(feature = "nightly", feature(rustc_attrs))]
#![cfg_attr(feature = "nightly", feature(step_trait))]

View file

@ -3,7 +3,7 @@ use std::fmt::Write;
use rustc_ast::*;
use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap};
use rustc_errors::inline_fluent;
use rustc_errors::msg;
use rustc_hir as hir;
use rustc_hir::def::{DefKind, Res};
use rustc_session::parse::feature_err;
@ -67,7 +67,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
&self.tcx.sess,
sym::asm_experimental_arch,
sp,
inline_fluent!("inline assembly is not stable yet on this architecture"),
msg!("inline assembly is not stable yet on this architecture"),
)
.emit();
}
@ -84,7 +84,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
&self.tcx.sess,
sym::asm_unwind,
sp,
inline_fluent!("the `may_unwind` option is unstable"),
msg!("the `may_unwind` option is unstable"),
)
.emit();
}
@ -499,9 +499,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
sess,
sym::asm_goto_with_outputs,
*op_sp,
inline_fluent!(
"using both label and output operands for inline assembly is unstable"
),
msg!("using both label and output operands for inline assembly is unstable"),
)
.emit();
}

View file

@ -5,7 +5,7 @@ use std::sync::Arc;
use rustc_ast::*;
use rustc_ast_pretty::pprust::expr_to_string;
use rustc_data_structures::stack::ensure_sufficient_stack;
use rustc_errors::inline_fluent;
use rustc_errors::msg;
use rustc_hir as hir;
use rustc_hir::attrs::AttributeKind;
use rustc_hir::def::{DefKind, Res};
@ -1702,7 +1702,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
&self.tcx.sess,
sym::yield_expr,
span,
inline_fluent!("yield syntax is experimental"),
msg!("yield syntax is experimental"),
)
.emit();
}

View file

@ -878,7 +878,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
(hir::ParamName::Fresh, hir::LifetimeParamKind::Elided(kind))
}
LifetimeRes::Static { .. } | LifetimeRes::Error => return None,
LifetimeRes::Static { .. } | LifetimeRes::Error(..) => return None,
res => panic!(
"Unexpected lifetime resolution {:?} for {:?} at {:?}",
res, ident, ident.span
@ -1931,26 +1931,29 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
source: LifetimeSource,
syntax: LifetimeSyntax,
) -> &'hir hir::Lifetime {
let res = self.resolver.get_lifetime_res(id).unwrap_or(LifetimeRes::Error);
let res = match res {
LifetimeRes::Param { param, .. } => hir::LifetimeKind::Param(param),
LifetimeRes::Fresh { param, .. } => {
assert_eq!(ident.name, kw::UnderscoreLifetime);
let param = self.local_def_id(param);
hir::LifetimeKind::Param(param)
}
LifetimeRes::Infer => {
assert_eq!(ident.name, kw::UnderscoreLifetime);
hir::LifetimeKind::Infer
}
LifetimeRes::Static { .. } => {
assert!(matches!(ident.name, kw::StaticLifetime | kw::UnderscoreLifetime));
hir::LifetimeKind::Static
}
LifetimeRes::Error => hir::LifetimeKind::Error,
LifetimeRes::ElidedAnchor { .. } => {
panic!("Unexpected `ElidedAnchar` {:?} at {:?}", ident, ident.span);
let res = if let Some(res) = self.resolver.get_lifetime_res(id) {
match res {
LifetimeRes::Param { param, .. } => hir::LifetimeKind::Param(param),
LifetimeRes::Fresh { param, .. } => {
assert_eq!(ident.name, kw::UnderscoreLifetime);
let param = self.local_def_id(param);
hir::LifetimeKind::Param(param)
}
LifetimeRes::Infer => {
assert_eq!(ident.name, kw::UnderscoreLifetime);
hir::LifetimeKind::Infer
}
LifetimeRes::Static { .. } => {
assert!(matches!(ident.name, kw::StaticLifetime | kw::UnderscoreLifetime));
hir::LifetimeKind::Static
}
LifetimeRes::Error(guar) => hir::LifetimeKind::Error(guar),
LifetimeRes::ElidedAnchor { .. } => {
panic!("Unexpected `ElidedAnchar` {:?} at {:?}", ident, ident.span);
}
}
} else {
hir::LifetimeKind::Error(self.dcx().span_delayed_bug(ident.span, "unresolved lifetime"))
};
debug!(?res);
@ -2014,12 +2017,13 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
// AST resolution emitted an error on those parameters, so we lower them using
// `ParamName::Error`.
let ident = self.lower_ident(param.ident);
let param_name =
if let Some(LifetimeRes::Error) = self.resolver.get_lifetime_res(param.id) {
ParamName::Error(ident)
} else {
ParamName::Plain(ident)
};
let param_name = if let Some(LifetimeRes::Error(..)) =
self.resolver.get_lifetime_res(param.id)
{
ParamName::Error(ident)
} else {
ParamName::Plain(ident)
};
let kind =
hir::GenericParamKind::Lifetime { kind: hir::LifetimeParamKind::Explicit };

View file

@ -1,6 +1,6 @@
use rustc_ast::visit::{self, AssocCtxt, FnCtxt, FnKind, Visitor};
use rustc_ast::{self as ast, AttrVec, NodeId, PatKind, attr, token};
use rustc_errors::inline_fluent;
use rustc_errors::msg;
use rustc_feature::{AttributeGate, BUILTIN_ATTRIBUTE_MAP, BuiltinAttribute, Features};
use rustc_session::Session;
use rustc_session::parse::{feature_err, feature_warn};
@ -125,7 +125,7 @@ impl<'a> PostExpansionVisitor<'a> {
&self,
non_lifetime_binders,
non_lt_param_spans,
inline_fluent!("only lifetime parameters can be used in this context")
msg!("only lifetime parameters can be used in this context")
);
// FIXME(non_lifetime_binders): Const bound params are pretty broken.

View file

@ -3,7 +3,7 @@ use std::convert::identity;
use rustc_ast::token::Delimiter;
use rustc_ast::tokenstream::DelimSpan;
use rustc_ast::{AttrItem, Attribute, CRATE_NODE_ID, LitKind, ast, token};
use rustc_errors::{Applicability, PResult, inline_fluent};
use rustc_errors::{Applicability, PResult, msg};
use rustc_feature::{
AttrSuggestionStyle, AttributeTemplate, Features, GatedCfg, find_gated_cfg, template,
};
@ -141,7 +141,7 @@ fn parse_cfg_entry_target<S: Stage>(
cx.sess(),
sym::cfg_target_compact,
meta_span,
inline_fluent!("compact `cfg(target(..))` is experimental and subject to change"),
msg!("compact `cfg(target(..))` is experimental and subject to change"),
)
.emit();
}

View file

@ -1,4 +1,4 @@
use rustc_errors::inline_fluent;
use rustc_errors::msg;
use rustc_feature::Features;
use rustc_hir::attrs::AttributeKind::{LinkName, LinkOrdinal, LinkSection};
use rustc_hir::attrs::*;
@ -316,7 +316,7 @@ impl LinkParser {
sess,
sym::raw_dylib_elf,
nv.value_span,
inline_fluent!("link kind `raw-dylib` is unstable on ELF platforms"),
msg!("link kind `raw-dylib` is unstable on ELF platforms"),
)
.emit();
} else {
@ -331,7 +331,7 @@ impl LinkParser {
sess,
sym::link_arg_attribute,
nv.value_span,
inline_fluent!("link kind `link-arg` is unstable"),
msg!("link kind `link-arg` is unstable"),
)
.emit();
}
@ -396,8 +396,7 @@ impl LinkParser {
return true;
};
if !features.link_cfg() {
feature_err(sess, sym::link_cfg, item.span(), inline_fluent!("link cfg is unstable"))
.emit();
feature_err(sess, sym::link_cfg, item.span(), msg!("link cfg is unstable")).emit();
}
*cfg = parse_cfg_entry(cx, link_cfg).ok();
true

View file

@ -206,3 +206,12 @@ impl<S: Stage> SingleAttributeParser<S> for CollapseDebugInfoParser {
Some(AttributeKind::CollapseDebugInfo(info))
}
}
pub(crate) struct RustcProcMacroDeclsParser;
impl<S: Stage> NoArgsAttributeParser<S> for RustcProcMacroDeclsParser {
const PATH: &[Symbol] = &[sym::rustc_proc_macro_decls];
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Warn;
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Static)]);
const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcProcMacroDecls;
}

View file

@ -1,6 +1,7 @@
use std::path::PathBuf;
use rustc_ast::{LitIntType, LitKind, MetaItemLit};
use rustc_hir::LangItem;
use rustc_hir::attrs::{
BorrowckGraphvizFormatKind, CguFields, CguKind, DivergingBlockBehavior,
DivergingFallbackBehavior, RustcCleanAttribute, RustcCleanQueries, RustcLayoutType,
@ -12,7 +13,7 @@ use rustc_span::Symbol;
use super::prelude::*;
use super::util::parse_single_integer;
use crate::session_diagnostics::{
AttributeRequiresOpt, CguFieldsMissing, RustcScalableVectorCountOutOfRange,
AttributeRequiresOpt, CguFieldsMissing, RustcScalableVectorCountOutOfRange, UnknownLangItem,
};
pub(crate) struct RustcMainParser;
@ -626,6 +627,32 @@ impl<S: Stage> SingleAttributeParser<S> for RustcScalableVectorParser {
}
}
pub(crate) struct LangParser;
impl<S: Stage> SingleAttributeParser<S> for LangParser {
const PATH: &[Symbol] = &[sym::lang];
const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepInnermost;
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(ALL_TARGETS); // Targets are checked per lang item in `rustc_passes`
const TEMPLATE: AttributeTemplate = template!(NameValueStr: "name");
fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option<AttributeKind> {
let Some(nv) = args.name_value() else {
cx.expected_name_value(cx.attr_span, None);
return None;
};
let Some(name) = nv.value_as_str() else {
cx.expected_string_literal(nv.value_span, Some(nv.value_as_lit()));
return None;
};
let Some(lang_item) = LangItem::from_name(name) else {
cx.emit_err(UnknownLangItem { span: cx.attr_span, name });
return None;
};
Some(AttributeKind::Lang(lang_item, cx.attr_span))
}
}
pub(crate) struct RustcHasIncoherentInherentImplsParser;
impl<S: Stage> NoArgsAttributeParser<S> for RustcHasIncoherentInherentImplsParser {
@ -641,6 +668,15 @@ impl<S: Stage> NoArgsAttributeParser<S> for RustcHasIncoherentInherentImplsParse
const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcHasIncoherentInherentImpls;
}
pub(crate) struct PanicHandlerParser;
impl<S: Stage> NoArgsAttributeParser<S> for PanicHandlerParser {
const PATH: &[Symbol] = &[sym::panic_handler];
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(ALL_TARGETS); // Targets are checked per lang item in `rustc_passes`
const CREATE: fn(Span) -> AttributeKind = |span| AttributeKind::Lang(LangItem::PanicImpl, span);
}
pub(crate) struct RustcHiddenTypeOfOpaquesParser;
impl<S: Stage> NoArgsAttributeParser<S> for RustcHiddenTypeOfOpaquesParser {
@ -1103,6 +1139,45 @@ impl<S: Stage> NoArgsAttributeParser<S> for RustcEffectiveVisibilityParser {
const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcEffectiveVisibility;
}
pub(crate) struct RustcDiagnosticItemParser;
impl<S: Stage> SingleAttributeParser<S> for RustcDiagnosticItemParser {
const PATH: &[Symbol] = &[sym::rustc_diagnostic_item];
const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepOutermost;
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[
Allow(Target::Trait),
Allow(Target::Struct),
Allow(Target::Enum),
Allow(Target::MacroDef),
Allow(Target::TyAlias),
Allow(Target::AssocTy),
Allow(Target::AssocConst),
Allow(Target::Fn),
Allow(Target::Const),
Allow(Target::Mod),
Allow(Target::Impl { of_trait: false }),
Allow(Target::Method(MethodKind::Inherent)),
Allow(Target::Method(MethodKind::Trait { body: false })),
Allow(Target::Method(MethodKind::Trait { body: true })),
Allow(Target::Method(MethodKind::TraitImpl)),
Allow(Target::Crate),
]);
const TEMPLATE: AttributeTemplate = template!(NameValueStr: "name");
fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option<AttributeKind> {
let Some(nv) = args.name_value() else {
cx.expected_name_value(cx.attr_span, None);
return None;
};
let Some(value) = nv.value_as_str() else {
cx.expected_string_literal(nv.value_span, Some(nv.value_as_lit()));
return None;
};
Some(AttributeKind::RustcDiagnosticItem(value))
}
}
pub(crate) struct RustcSymbolName;
impl<S: Stage> SingleAttributeParser<S> for RustcSymbolName {

View file

@ -257,3 +257,36 @@ impl<S: Stage> SingleAttributeParser<S> for TestRunnerParser {
Some(AttributeKind::TestRunner(meta.path().0.clone()))
}
}
pub(crate) struct RustcTestMarkerParser;
impl<S: Stage> SingleAttributeParser<S> for RustcTestMarkerParser {
const PATH: &[Symbol] = &[sym::rustc_test_marker];
const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepOutermost;
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Warn;
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[
Allow(Target::Const),
Allow(Target::Fn),
Allow(Target::Static),
]);
const TEMPLATE: AttributeTemplate = template!(NameValueStr: "test_path");
fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option<AttributeKind> {
let Some(name_value) = args.name_value() else {
cx.expected_name_value(cx.attr_span, Some(sym::rustc_test_marker));
return None;
};
let Some(value_str) = name_value.value_as_str() else {
cx.expected_string_literal(name_value.value_span, None);
return None;
};
if value_str.as_str().trim().is_empty() {
cx.expected_non_empty_string_literal(name_value.value_span);
return None;
}
Some(AttributeKind::RustcTestMarker(value_str))
}
}

View file

@ -181,6 +181,7 @@ attribute_parsers!(
Single<IgnoreParser>,
Single<InlineParser>,
Single<InstructionSetParser>,
Single<LangParser>,
Single<LinkNameParser>,
Single<LinkOrdinalParser>,
Single<LinkSectionParser>,
@ -203,6 +204,7 @@ attribute_parsers!(
Single<RustcBuiltinMacroParser>,
Single<RustcDefPath>,
Single<RustcDeprecatedSafe2024Parser>,
Single<RustcDiagnosticItemParser>,
Single<RustcForceInlineParser>,
Single<RustcIfThisChangedParser>,
Single<RustcLayoutScalarValidRangeEndParser>,
@ -215,6 +217,7 @@ attribute_parsers!(
Single<RustcScalableVectorParser>,
Single<RustcSimdMonomorphizeLaneLimitParser>,
Single<RustcSymbolName>,
Single<RustcTestMarkerParser>,
Single<SanitizeParser>,
Single<ShouldPanicParser>,
Single<SkipDuringMethodDispatchParser>,
@ -253,6 +256,7 @@ attribute_parsers!(
Single<WithoutArgs<NoMangleParser>>,
Single<WithoutArgs<NoStdParser>>,
Single<WithoutArgs<NonExhaustiveParser>>,
Single<WithoutArgs<PanicHandlerParser>>,
Single<WithoutArgs<PanicRuntimeParser>>,
Single<WithoutArgs<ParenSugarParser>>,
Single<WithoutArgs<PassByValueParser>>,
@ -297,6 +301,7 @@ attribute_parsers!(
Single<WithoutArgs<RustcOutlivesParser>>,
Single<WithoutArgs<RustcPassIndirectlyInNonRusticAbisParser>>,
Single<WithoutArgs<RustcPreserveUbChecksParser>>,
Single<WithoutArgs<RustcProcMacroDeclsParser>>,
Single<WithoutArgs<RustcReallocatorParser>>,
Single<WithoutArgs<RustcRegionsParser>>,
Single<WithoutArgs<RustcShouldNotBeCalledOnConstItems>>,

View file

@ -1013,6 +1013,15 @@ pub(crate) struct DocAliasMalformed {
pub span: Span,
}
#[derive(Diagnostic)]
#[diag("definition of an unknown lang item: `{$name}`", code = E0522)]
pub(crate) struct UnknownLangItem {
#[primary_span]
#[label("definition of unknown lang item `{$name}`")]
pub span: Span,
pub name: Symbol,
}
#[derive(Diagnostic)]
#[diag("target `{$current_target}` does not support `#[instruction_set({$instruction_set}::*)]`")]
pub(crate) struct UnsupportedInstructionSet<'a> {

View file

@ -4,9 +4,7 @@ use std::collections::BTreeMap;
use rustc_abi::{FieldIdx, VariantIdx};
use rustc_data_structures::fx::FxIndexMap;
use rustc_errors::{
Applicability, Diag, DiagMessage, EmissionGuarantee, MultiSpan, inline_fluent, listify,
};
use rustc_errors::{Applicability, Diag, DiagMessage, EmissionGuarantee, MultiSpan, listify, msg};
use rustc_hir::def::{CtorKind, Namespace};
use rustc_hir::{
self as hir, CoroutineKind, GenericBound, LangItem, WhereBoundPredicate, WherePredicateKind,
@ -1313,7 +1311,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
let mut span: MultiSpan = spans.clone().into();
err.arg("ty", param_ty.to_string());
let msg = err.dcx.eagerly_translate_to_string(
inline_fluent!("`{$ty}` is made to be an `FnOnce` closure here"),
msg!("`{$ty}` is made to be an `FnOnce` closure here"),
err.args.iter(),
);
err.remove_arg("ty");
@ -1322,12 +1320,9 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
}
span.push_span_label(
fn_call_span,
inline_fluent!("this value implements `FnOnce`, which causes it to be moved when called"),
);
err.span_note(
span,
inline_fluent!("`FnOnce` closures can only be called once"),
msg!("this value implements `FnOnce`, which causes it to be moved when called"),
);
err.span_note(span, msg!("`FnOnce` closures can only be called once"));
} else {
err.subdiagnostic(CaptureReasonNote::FnOnceMoveInCall { var_span });
}
@ -1573,6 +1568,5 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
}
}
const LIMITATION_NOTE: DiagMessage = inline_fluent!(
"due to a current limitation of the type system, this implies a `'static` lifetime"
);
const LIMITATION_NOTE: DiagMessage =
msg!("due to a current limitation of the type system, this implies a `'static` lifetime");

View file

@ -1,7 +1,7 @@
//! Error reporting machinery for lifetime errors.
use rustc_data_structures::fx::FxIndexSet;
use rustc_errors::{Applicability, Diag, ErrorGuaranteed, MultiSpan, inline_fluent};
use rustc_errors::{Applicability, Diag, ErrorGuaranteed, MultiSpan, msg};
use rustc_hir as hir;
use rustc_hir::GenericBound::Trait;
use rustc_hir::QPath::Resolved;
@ -291,7 +291,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
if suggestions.len() > 0 {
suggestions.dedup();
diag.multipart_suggestion_verbose(
inline_fluent!("consider restricting the type parameter to the `'static` lifetime"),
msg!("consider restricting the type parameter to the `'static` lifetime"),
suggestions,
Applicability::MaybeIncorrect,
);
@ -982,18 +982,16 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
let mut multi_span: MultiSpan = vec![*span].into();
multi_span.push_span_label(
*span,
inline_fluent!("this has an implicit `'static` lifetime requirement"),
msg!("this has an implicit `'static` lifetime requirement"),
);
multi_span.push_span_label(
ident.span,
inline_fluent!(
"calling this method introduces the `impl`'s `'static` requirement"
),
msg!("calling this method introduces the `impl`'s `'static` requirement"),
);
err.subdiagnostic(RequireStaticErr::UsedImpl { multi_span });
err.span_suggestion_verbose(
span.shrink_to_hi(),
inline_fluent!("consider relaxing the implicit `'static` requirement"),
msg!("consider relaxing the implicit `'static` requirement"),
" + '_",
Applicability::MaybeIncorrect,
);
@ -1156,7 +1154,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
if ocx.evaluate_obligations_error_on_ambiguity().is_empty() && count > 0 {
diag.span_suggestion_verbose(
tcx.hir_body(*body).value.peel_blocks().span.shrink_to_lo(),
inline_fluent!("dereference the return value"),
msg!("dereference the return value"),
"*".repeat(count),
Applicability::MachineApplicable,
);
@ -1200,7 +1198,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
if let Some(closure_span) = closure_span {
diag.span_suggestion_verbose(
closure_span,
inline_fluent!("consider adding 'move' keyword before the nested closure"),
msg!("consider adding 'move' keyword before the nested closure"),
"move ",
Applicability::MaybeIncorrect,
);

View file

@ -182,8 +182,7 @@ impl LocalizedConstraintGraphVisitor for LoanLivenessVisitor<'_> {
//
// FIXME: analyze potential unsoundness, possibly in concert with a borrowck
// implementation in a-mir-formality, fuzzing, or manually crafting counter-examples.
let location = self.liveness.location_from_point(node.point);
if self.liveness.is_live_at(node.region, location) {
if self.liveness.is_live_at_point(node.region, node.point) {
self.live_loans.insert(node.point, loan);
}
}

View file

@ -24,13 +24,13 @@ use rustc_trait_selection::traits::query::type_op::custom::CustomTypeOp;
use tracing::{debug, instrument};
use super::reverse_sccs::ReverseSccGraph;
use crate::BorrowckInferCtxt;
use crate::consumers::RegionInferenceContext;
use crate::session_diagnostics::LifetimeMismatchOpaqueParam;
use crate::type_check::canonical::fully_perform_op_raw;
use crate::type_check::free_region_relations::UniversalRegionRelations;
use crate::type_check::{Locations, MirTypeckRegionConstraints};
use crate::universal_regions::{RegionClassification, UniversalRegions};
use crate::{BorrowckInferCtxt, CollectRegionConstraintsResult};
mod member_constraints;
mod region_ctxt;
@ -126,6 +126,31 @@ fn nll_var_to_universal_region<'tcx>(
}
}
/// Record info needed to report the same name error later.
#[derive(Copy, Clone, Debug)]
pub(crate) struct UnexpectedHiddenRegion<'tcx> {
// The def_id of the body where this error occurs.
// Needed to handle region vars with their corresponding `infcx`.
def_id: LocalDefId,
opaque_type_key: OpaqueTypeKey<'tcx>,
hidden_type: ProvisionalHiddenType<'tcx>,
member_region: Region<'tcx>,
}
impl<'tcx> UnexpectedHiddenRegion<'tcx> {
pub(crate) fn to_error(self) -> (LocalDefId, DeferredOpaqueTypeError<'tcx>) {
let UnexpectedHiddenRegion { def_id, opaque_type_key, hidden_type, member_region } = self;
(
def_id,
DeferredOpaqueTypeError::UnexpectedHiddenRegion {
opaque_type_key,
hidden_type,
member_region,
},
)
}
}
/// Collect all defining uses of opaque types inside of this typeck root. This
/// expects the hidden type to be mapped to the definition parameters of the opaque
/// and errors if we end up with distinct hidden types.
@ -176,11 +201,13 @@ struct DefiningUse<'tcx> {
/// It also means that this whole function is not really soundness critical as we
/// recheck all uses of the opaques regardless.
pub(crate) fn compute_definition_site_hidden_types<'tcx>(
def_id: LocalDefId,
infcx: &BorrowckInferCtxt<'tcx>,
universal_region_relations: &Frozen<UniversalRegionRelations<'tcx>>,
constraints: &MirTypeckRegionConstraints<'tcx>,
location_map: Rc<DenseLocationMap>,
hidden_types: &mut FxIndexMap<LocalDefId, ty::DefinitionSiteHiddenType<'tcx>>,
unconstrained_hidden_type_errors: &mut Vec<UnexpectedHiddenRegion<'tcx>>,
opaque_types: &[(OpaqueTypeKey<'tcx>, ProvisionalHiddenType<'tcx>)],
) -> Vec<DeferredOpaqueTypeError<'tcx>> {
let mut errors = Vec::new();
@ -204,8 +231,10 @@ pub(crate) fn compute_definition_site_hidden_types<'tcx>(
// up equal to one of their choice regions and compute the actual hidden type of
// the opaque type definition. This is stored in the `root_cx`.
compute_definition_site_hidden_types_from_defining_uses(
def_id,
&rcx,
hidden_types,
unconstrained_hidden_type_errors,
&defining_uses,
&mut errors,
);
@ -274,8 +303,10 @@ fn collect_defining_uses<'tcx>(
#[instrument(level = "debug", skip(rcx, hidden_types, defining_uses, errors))]
fn compute_definition_site_hidden_types_from_defining_uses<'tcx>(
def_id: LocalDefId,
rcx: &RegionCtxt<'_, 'tcx>,
hidden_types: &mut FxIndexMap<LocalDefId, ty::DefinitionSiteHiddenType<'tcx>>,
unconstrained_hidden_type_errors: &mut Vec<UnexpectedHiddenRegion<'tcx>>,
defining_uses: &[DefiningUse<'tcx>],
errors: &mut Vec<DeferredOpaqueTypeError<'tcx>>,
) {
@ -293,16 +324,29 @@ fn compute_definition_site_hidden_types_from_defining_uses<'tcx>(
Ok(hidden_type) => hidden_type,
Err(r) => {
debug!("UnexpectedHiddenRegion: {:?}", r);
errors.push(DeferredOpaqueTypeError::UnexpectedHiddenRegion {
hidden_type,
opaque_type_key,
member_region: ty::Region::new_var(tcx, r),
});
let guar = tcx.dcx().span_delayed_bug(
hidden_type.span,
"opaque type with non-universal region args",
);
ty::ProvisionalHiddenType::new_error(tcx, guar)
// If we're using the next solver, the unconstrained region may be resolved by a
// fully defining use from another body.
// So we don't generate error eagerly here.
if rcx.infcx.tcx.use_typing_mode_borrowck() {
unconstrained_hidden_type_errors.push(UnexpectedHiddenRegion {
def_id,
hidden_type,
opaque_type_key,
member_region: ty::Region::new_var(tcx, r),
});
continue;
} else {
errors.push(DeferredOpaqueTypeError::UnexpectedHiddenRegion {
hidden_type,
opaque_type_key,
member_region: ty::Region::new_var(tcx, r),
});
let guar = tcx.dcx().span_delayed_bug(
hidden_type.span,
"opaque type with non-universal region args",
);
ty::ProvisionalHiddenType::new_error(tcx, guar)
}
}
};
@ -570,6 +614,40 @@ pub(crate) fn apply_definition_site_hidden_types<'tcx>(
errors
}
/// We handle `UnexpectedHiddenRegion` error lazily in the next solver as
/// there may be a fully defining use in another body.
///
/// In case such a defining use does not exist, we register an error here.
pub(crate) fn handle_unconstrained_hidden_type_errors<'tcx>(
tcx: TyCtxt<'tcx>,
hidden_types: &mut FxIndexMap<LocalDefId, ty::DefinitionSiteHiddenType<'tcx>>,
unconstrained_hidden_type_errors: &mut Vec<UnexpectedHiddenRegion<'tcx>>,
collect_region_constraints_results: &mut FxIndexMap<
LocalDefId,
CollectRegionConstraintsResult<'tcx>,
>,
) {
let mut unconstrained_hidden_type_errors = std::mem::take(unconstrained_hidden_type_errors);
unconstrained_hidden_type_errors
.retain(|unconstrained| !hidden_types.contains_key(&unconstrained.opaque_type_key.def_id));
unconstrained_hidden_type_errors.iter().for_each(|t| {
tcx.dcx()
.span_delayed_bug(t.hidden_type.span, "opaque type with non-universal region args");
});
// `UnexpectedHiddenRegion` error contains region var which only makes sense in the
// corresponding `infcx`.
// So we need to insert the error to the body where it originates from.
for error in unconstrained_hidden_type_errors {
let (def_id, error) = error.to_error();
let Some(result) = collect_region_constraints_results.get_mut(&def_id) else {
unreachable!("the body should depend on opaques type if it has opaque use");
};
result.deferred_opaque_type_errors.push(error);
}
}
/// In theory `apply_definition_site_hidden_types` could introduce new uses of opaque types.
/// We do not check these new uses so this could be unsound.
///

View file

@ -131,9 +131,17 @@ impl LivenessValues {
}
}
/// Returns whether `region` is marked live at the given `location`.
/// Returns whether `region` is marked live at the given
/// [`location`][rustc_middle::mir::Location].
pub(crate) fn is_live_at(&self, region: RegionVid, location: Location) -> bool {
let point = self.location_map.point_from_location(location);
self.is_live_at_point(region, point)
}
/// Returns whether `region` is marked live at the given
/// [`point`][rustc_mir_dataflow::points::PointIndex].
#[inline]
pub(crate) fn is_live_at_point(&self, region: RegionVid, point: PointIndex) -> bool {
if let Some(points) = &self.points {
points.row(region).is_some_and(|r| r.contains(point))
} else {

View file

@ -12,8 +12,9 @@ use smallvec::SmallVec;
use crate::consumers::BorrowckConsumer;
use crate::nll::compute_closure_requirements_modulo_opaques;
use crate::region_infer::opaque_types::{
apply_definition_site_hidden_types, clone_and_resolve_opaque_types,
UnexpectedHiddenRegion, apply_definition_site_hidden_types, clone_and_resolve_opaque_types,
compute_definition_site_hidden_types, detect_opaque_types_added_while_handling_opaque_types,
handle_unconstrained_hidden_type_errors,
};
use crate::type_check::{Locations, constraint_conversion};
use crate::{
@ -26,7 +27,12 @@ use crate::{
pub(super) struct BorrowCheckRootCtxt<'tcx> {
pub tcx: TyCtxt<'tcx>,
root_def_id: LocalDefId,
/// This contains fully resolved hidden types or `ty::Error`.
hidden_types: FxIndexMap<LocalDefId, ty::DefinitionSiteHiddenType<'tcx>>,
/// This contains unconstrained regions in hidden types.
/// Only used for deferred error reporting. See
/// [`crate::region_infer::opaque_types::handle_unconstrained_hidden_type_errors`]
unconstrained_hidden_type_errors: Vec<UnexpectedHiddenRegion<'tcx>>,
/// The region constraints computed by [borrowck_collect_region_constraints]. This uses
/// an [FxIndexMap] to guarantee that iterating over it visits nested bodies before
/// their parents.
@ -49,6 +55,7 @@ impl<'tcx> BorrowCheckRootCtxt<'tcx> {
tcx,
root_def_id,
hidden_types: Default::default(),
unconstrained_hidden_type_errors: Default::default(),
collect_region_constraints_results: Default::default(),
propagated_borrowck_results: Default::default(),
tainted_by_errors: None,
@ -84,23 +91,32 @@ impl<'tcx> BorrowCheckRootCtxt<'tcx> {
fn handle_opaque_type_uses(&mut self) {
let mut per_body_info = Vec::new();
for input in self.collect_region_constraints_results.values_mut() {
for (def_id, input) in &mut self.collect_region_constraints_results {
let (num_entries, opaque_types) = clone_and_resolve_opaque_types(
&input.infcx,
&input.universal_region_relations,
&mut input.constraints,
);
input.deferred_opaque_type_errors = compute_definition_site_hidden_types(
*def_id,
&input.infcx,
&input.universal_region_relations,
&input.constraints,
Rc::clone(&input.location_map),
&mut self.hidden_types,
&mut self.unconstrained_hidden_type_errors,
&opaque_types,
);
per_body_info.push((num_entries, opaque_types));
}
handle_unconstrained_hidden_type_errors(
self.tcx,
&mut self.hidden_types,
&mut self.unconstrained_hidden_type_errors,
&mut self.collect_region_constraints_results,
);
for (input, (opaque_types_storage_num_entries, opaque_types)) in
self.collect_region_constraints_results.values_mut().zip(per_body_info)
{

View file

@ -1,7 +1,7 @@
use rustc_errors::codes::*;
use rustc_errors::{
Diag, DiagCtxtHandle, Diagnostic, EmissionGuarantee, Level, MultiSpan, SingleLabelManySpans,
Subdiagnostic, inline_fluent,
Subdiagnostic, msg,
};
use rustc_macros::{Diagnostic, LintDiagnostic, Subdiagnostic};
use rustc_span::{Ident, Span, Symbol};
@ -764,7 +764,7 @@ pub(crate) struct FormatUnusedArg {
impl Subdiagnostic for FormatUnusedArg {
fn add_to_diag<G: EmissionGuarantee>(self, diag: &mut Diag<'_, G>) {
diag.arg("named", self.named);
let msg = diag.eagerly_translate(inline_fluent!(
let msg = diag.eagerly_translate(msg!(
"{$named ->
[true] named argument
*[false] argument
@ -947,13 +947,12 @@ pub(crate) struct AsmClobberNoReg {
impl<'a, G: EmissionGuarantee> Diagnostic<'a, G> for AsmClobberNoReg {
fn into_diag(self, dcx: DiagCtxtHandle<'a>, level: Level) -> Diag<'a, G> {
// eager translation as `span_labels` takes `AsRef<str>`
let lbl1 = dcx.eagerly_translate_to_string(inline_fluent!("clobber_abi"), [].into_iter());
let lbl2 =
dcx.eagerly_translate_to_string(inline_fluent!("generic outputs"), [].into_iter());
let lbl1 = dcx.eagerly_translate_to_string(msg!("clobber_abi"), [].into_iter());
let lbl2 = dcx.eagerly_translate_to_string(msg!("generic outputs"), [].into_iter());
Diag::new(
dcx,
level,
inline_fluent!("asm with `clobber_abi` must specify explicit registers for outputs"),
msg!("asm with `clobber_abi` must specify explicit registers for outputs"),
)
.with_span(self.spans.clone())
.with_span_labels(self.clobbers, &lbl1)

View file

@ -106,6 +106,7 @@ fn codegen_global_asm_inner<'tcx>(
match *piece {
InlineAsmTemplatePiece::String(ref s) => global_asm.push_str(s),
InlineAsmTemplatePiece::Placeholder { operand_idx, modifier: _, span } => {
use rustc_codegen_ssa::back::symbol_export::escape_symbol_name;
match operands[operand_idx] {
GlobalAsmOperandRef::Const { ref string } => {
global_asm.push_str(string);
@ -121,7 +122,7 @@ fn codegen_global_asm_inner<'tcx>(
let symbol = tcx.symbol_name(instance);
// FIXME handle the case where the function was made private to the
// current codegen unit
global_asm.push_str(symbol.name);
global_asm.push_str(&escape_symbol_name(tcx, symbol.name, span));
}
GlobalAsmOperandRef::SymStatic { def_id } => {
if cfg!(not(feature = "inline_asm_sym")) {
@ -133,7 +134,7 @@ fn codegen_global_asm_inner<'tcx>(
let instance = Instance::mono(tcx, def_id);
let symbol = tcx.symbol_name(instance);
global_asm.push_str(symbol.name);
global_asm.push_str(&escape_symbol_name(tcx, symbol.name, span));
}
}
}

View file

@ -2,8 +2,8 @@
// Note: please avoid adding other feature gates where possible
#![feature(rustc_private)]
// Only used to define intrinsics in `compiler_builtins.rs`.
#![feature(f16)]
#![feature(f128)]
#![cfg_attr(feature = "jit", feature(f16))]
#![cfg_attr(feature = "jit", feature(f128))]
// Note: please avoid adding other feature gates where possible
#![warn(rust_2018_idioms)]
#![warn(unreachable_pub)]

View file

@ -18,6 +18,7 @@
],
"ignorePaths": [
"src/intrinsic/archs.rs",
"src/intrinsic/old_archs.rs",
"src/intrinsic/llvm.rs"
],
"ignoreRegExpList": [

View file

@ -113,6 +113,10 @@ jobs:
git config --global user.name "User"
./y.sh prepare
- name: Add more failing tests for GCC without 128-bit integers support
if: ${{ matrix.libgccjit_version.gcc == 'gcc-15-without-int128.deb' }}
run: cat tests/failing-ui-tests-without-128bit-integers.txt >> tests/failing-ui-tests.txt
- name: Run tests
run: |
./y.sh test --release --clean --build-sysroot ${{ matrix.commands }}

View file

@ -83,7 +83,7 @@ jobs:
run: |
./y.sh prepare --only-libcore --cross
./y.sh build --sysroot --target-triple m68k-unknown-linux-gnu --target ${{ github.workspace }}/target_specs/m68k-unknown-linux-gnu.json
CG_RUSTFLAGS="-Clinker=m68k-unknown-linux-gnu-gcc" ./y.sh cargo build --manifest-path=./tests/hello-world/Cargo.toml --target ${{ github.workspace }}/target_specs/m68k-unknown-linux-gnu.json
CG_RUSTFLAGS="-Clinker=m68k-unknown-linux-gnu-gcc" ./y.sh cargo build -Zjson-target-spec --manifest-path=./tests/hello-world/Cargo.toml --target ${{ github.workspace }}/target_specs/m68k-unknown-linux-gnu.json
./y.sh clean all
- name: Build

View file

@ -56,18 +56,18 @@ dependencies = [
[[package]]
name = "gccjit"
version = "3.1.1"
version = "3.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ff80f4d6d0749eab3a69122210b3a1fdd52edb6162781aadd7c4842e26983683"
checksum = "26b73d18b642ce16378af78f89664841d7eeafa113682ff5d14573424eb0232a"
dependencies = [
"gccjit_sys",
]
[[package]]
name = "gccjit_sys"
version = "1.1.2"
version = "1.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4f81d901767ddba371a619fa9bba657066a4d3c5607ee69bbb557c1c5ba9bf85"
checksum = "ee689456c013616942d5aef9a84d613cefcc3b335340d036f3650fc1a7459e15"
dependencies = [
"libc",
]

View file

@ -24,7 +24,7 @@ default = ["master"]
[dependencies]
object = { version = "0.37.0", default-features = false, features = ["std", "read"] }
tempfile = "3.20"
gccjit = { version = "3.1.1", features = ["dlopen"] }
gccjit = { version = "3.3.0", features = ["dlopen"] }
#gccjit = { git = "https://github.com/rust-lang/gccjit.rs", branch = "error-dlopen", features = ["dlopen"] }
# Local copy.

View file

@ -45,12 +45,12 @@ The default configuration (see below in the [Quick start](#quick-start) section)
./y.sh test --release
```
If don't need to test GCC patches you wrote in our GCC fork, then the default configuration should
If you don't need to test GCC patches you wrote in our GCC fork, then the default configuration should
be all you need. You can update the `rustc_codegen_gcc` without worrying about GCC.
### Building with your own GCC version
If you wrote a patch for GCC and want to test it without this backend, you will need
If you wrote a patch for GCC and want to test it with this backend, you will need
to do a few more things.
To build it (most of these instructions come from [here](https://gcc.gnu.org/onlinedocs/jit/internals/index.html), so don't hesitate to take a look there if you encounter an issue):
@ -127,7 +127,7 @@ You have to run these commands, in the corresponding order:
$ ./y.sh prepare
$ ./y.sh build --sysroot
```
To check if all is working correctly, run:
To check if all is working correctly, run:
```bash
$ ./y.sh cargo build --manifest-path tests/hello-world/Cargo.toml

View file

@ -6,4 +6,4 @@ seh = "seh"
typ = "typ"
[files]
extend-exclude = ["src/intrinsic/archs.rs"]
extend-exclude = ["src/intrinsic/archs.rs", "src/intrinsic/old_archs.rs"]

View file

@ -141,6 +141,10 @@ pub fn build_sysroot(env: &HashMap<String, String>, config: &ConfigInfo) -> Resu
}
let mut args: Vec<&dyn AsRef<OsStr>> = vec![&"cargo", &"build", &"--target", &config.target];
if config.target.ends_with(".json") {
args.push(&"-Zjson-target-spec");
}
for feature in &config.features {
args.push(&"--features");
args.push(feature);

View file

@ -679,10 +679,10 @@ fn test_projects(env: &Env, args: &TestArg) -> Result<(), String> {
create_dir(projects_path)?;
let nb_parts = args.nb_parts.unwrap_or(0);
if nb_parts > 0 {
if let Some(count) = projects.len().checked_div(nb_parts) {
// We increment the number of tests by one because if this is an odd number, we would skip
// one test.
let count = projects.len() / nb_parts + 1;
let count = count + 1;
let current_part = args.current_part.unwrap();
let start = current_part * count;
// We remove the projects we don't want to test.

View file

@ -2,9 +2,9 @@
## How to debug GCC LTO
Run do the command with `-v -save-temps` and then extract the `lto1` line from the output and run that under the debugger.
Run the command with `-v -save-temps` and then extract the `lto1` line from the output and run that under the debugger.
## How to debug stdarch tests that cannot be ran locally
## How to debug stdarch tests that cannot be run locally
First, run the tests normally:

View file

@ -15,7 +15,7 @@ That can be caused by the fact that you try to compile with `lto = "fat"`, but y
### ld: cannot find crtbegin.o
When compiling an executable with libgccijt, if setting the `*LIBRARY_PATH` variables to the install directory, you will get the following errors:
When compiling an executable with libgccjit, if setting the `*LIBRARY_PATH` variables to the install directory, you will get the following errors:
```
ld: cannot find crtbegin.o: No such file or directory

View file

@ -3,7 +3,7 @@
You can see the full documentation about what GIMPLE is [here](https://gcc.gnu.org/onlinedocs/gccint/GIMPLE.html). In this document we will explain how to generate it.
First, we'll copy the content from `gcc/gcc/testsuite/jit.dg/test-const-attribute.c` into a
file named `local.c` and remove the content we're not interested into:
file named `local.c` and remove the content we're not interested in:
```diff
- /* { dg-do compile { target x86_64-*-* } } */

View file

@ -53,7 +53,7 @@ If you wish to build a custom sysroot, pass the path of your sysroot source to `
### How to use [mem-trace](https://github.com/antoyo/mem-trace)
`rustc` needs to be built without `jemalloc` so that `mem-trace` can overload `malloc` since `jemalloc` is linked statically, so a `LD_PRELOAD`-ed library won't a chance to intercept the calls to `malloc`.
`rustc` needs to be built without `jemalloc` so that `mem-trace` can overload `malloc` since `jemalloc` is linked statically, so a `LD_PRELOAD`-ed library won't have a chance to intercept the calls to `malloc`.
### How to generate GIMPLE

View file

@ -1 +1 @@
0081ca6631abdfa02bf42bc85aaf507b8a0e6beb
efdd0a7290c22f5438d7c5380105d353ee3e8518

View file

@ -1,3 +1,3 @@
[toolchain]
channel = "nightly-2025-12-20"
channel = "nightly-2026-02-14"
components = ["rust-src", "rustc-dev", "llvm-tools-preview"]

View file

@ -575,9 +575,7 @@ impl<'a, 'gcc, 'tcx> AsmBuilderMethods<'tcx> for Builder<'a, 'gcc, 'tcx> {
}
if dest.is_none() && options.contains(InlineAsmOptions::NORETURN) {
let builtin_unreachable = self.context.get_builtin_function("__builtin_unreachable");
let builtin_unreachable: RValue<'gcc> =
unsafe { std::mem::transmute(builtin_unreachable) };
self.call(self.type_void(), None, None, builtin_unreachable, &[], None, None);
self.llbb().add_eval(None, self.context.new_call(None, builtin_unreachable, &[]));
}
// Write results to outputs.

View file

@ -1495,6 +1495,8 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> {
#[cfg(not(feature = "master"))]
fn extract_element(&mut self, vec: RValue<'gcc>, idx: RValue<'gcc>) -> RValue<'gcc> {
use crate::context::new_array_type;
let vector_type = vec
.get_type()
.unqualified()
@ -1503,7 +1505,7 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> {
let element_type = vector_type.get_element_type();
let vec_num_units = vector_type.get_num_units();
let array_type =
self.context.new_array_type(self.location, element_type, vec_num_units as u64);
new_array_type(self.context, self.location, element_type, vec_num_units as u64);
let array = self.context.new_bitcast(self.location, vec, array_type).to_rvalue();
self.context.new_array_access(self.location, array, idx).to_rvalue()
}
@ -1871,32 +1873,31 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> {
// On the other hand, f_max works even if int_ty::MAX is greater than float_ty::MAX. Because
// we're rounding towards zero, we just get float_ty::MAX (which is always an integer).
// This already happens today with u128::MAX = 2^128 - 1 > f32::MAX.
let int_max = |signed: bool, int_width: u64| -> u128 {
fn int_max(signed: bool, int_width: u64) -> u128 {
let shift_amount = 128 - int_width;
if signed { i128::MAX as u128 >> shift_amount } else { u128::MAX >> shift_amount }
};
let int_min = |signed: bool, int_width: u64| -> i128 {
}
fn int_min(signed: bool, int_width: u64) -> i128 {
if signed { i128::MIN >> (128 - int_width) } else { 0 }
};
}
let compute_clamp_bounds_single = |signed: bool, int_width: u64| -> (u128, u128) {
// TODO: rewrite using a generic function with <F: Float>.
let compute_clamp_bounds_half = |signed: bool, int_width: u64| -> (u128, u128) {
let rounded_min =
ieee::Single::from_i128_r(int_min(signed, int_width), Round::TowardZero);
assert_eq!(rounded_min.status, Status::OK);
ieee::Half::from_i128_r(int_min(signed, int_width), Round::TowardZero);
//assert_eq!(rounded_min.status, Status::OK);
let rounded_max =
ieee::Single::from_u128_r(int_max(signed, int_width), Round::TowardZero);
ieee::Half::from_u128_r(int_max(signed, int_width), Round::TowardZero);
assert!(rounded_max.value.is_finite());
(rounded_min.value.to_bits(), rounded_max.value.to_bits())
};
let compute_clamp_bounds_double = |signed: bool, int_width: u64| -> (u128, u128) {
let rounded_min =
ieee::Double::from_i128_r(int_min(signed, int_width), Round::TowardZero);
fn compute_clamp_bounds<F: Float>(signed: bool, int_width: u64) -> (u128, u128) {
let rounded_min = F::from_i128_r(int_min(signed, int_width), Round::TowardZero);
assert_eq!(rounded_min.status, Status::OK);
let rounded_max =
ieee::Double::from_u128_r(int_max(signed, int_width), Round::TowardZero);
let rounded_max = F::from_u128_r(int_max(signed, int_width), Round::TowardZero);
assert!(rounded_max.value.is_finite());
(rounded_min.value.to_bits(), rounded_max.value.to_bits())
};
}
// To implement saturation, we perform the following steps:
//
// 1. Cast val to an integer with fpto[su]i. This may result in undef.
@ -1926,15 +1927,19 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> {
let float_bits_to_llval = |bx: &mut Self, bits| {
let bits_llval = match float_width {
16 => bx.cx().const_u16(bits as u16),
32 => bx.cx().const_u32(bits as u32),
64 => bx.cx().const_u64(bits as u64),
128 => bx.cx().const_u128(bits),
n => bug!("unsupported float width {}", n),
};
bx.bitcast(bits_llval, float_ty)
};
let (f_min, f_max) = match float_width {
32 => compute_clamp_bounds_single(signed, int_width),
64 => compute_clamp_bounds_double(signed, int_width),
16 => compute_clamp_bounds_half(signed, int_width),
32 => compute_clamp_bounds::<ieee::Single>(signed, int_width),
64 => compute_clamp_bounds::<ieee::Double>(signed, int_width),
128 => compute_clamp_bounds::<ieee::Quad>(signed, int_width),
n => bug!("unsupported float width {}", n),
};
let f_min = float_bits_to_llval(self, f_min);

View file

@ -8,7 +8,7 @@ use rustc_middle::mir::Mutability;
use rustc_middle::mir::interpret::{ConstAllocation, GlobalAlloc, PointerArithmetic, Scalar};
use rustc_middle::ty::layout::LayoutOf;
use crate::context::CodegenCx;
use crate::context::{CodegenCx, new_array_type};
use crate::type_of::LayoutGccExt;
impl<'gcc, 'tcx> CodegenCx<'gcc, 'tcx> {
@ -20,6 +20,10 @@ impl<'gcc, 'tcx> CodegenCx<'gcc, 'tcx> {
bytes_in_context(self, bytes)
}
pub fn const_u16(&self, i: u16) -> RValue<'gcc> {
self.const_uint(self.type_u16(), i as u64)
}
fn global_string(&self, string: &str) -> LValue<'gcc> {
// TODO(antoyo): handle non-null-terminated strings.
let string = self.context.new_string_literal(string);
@ -55,7 +59,7 @@ pub fn bytes_in_context<'gcc, 'tcx>(cx: &CodegenCx<'gcc, 'tcx>, bytes: &[u8]) ->
0 => {
let context = &cx.context;
let byte_type = context.new_type::<u64>();
let typ = context.new_array_type(None, byte_type, bytes.len() as u64 / 8);
let typ = new_array_type(context, None, byte_type, bytes.len() as u64 / 8);
let elements: Vec<_> = bytes
.chunks_exact(8)
.map(|arr| {
@ -76,7 +80,7 @@ pub fn bytes_in_context<'gcc, 'tcx>(cx: &CodegenCx<'gcc, 'tcx>, bytes: &[u8]) ->
4 => {
let context = &cx.context;
let byte_type = context.new_type::<u32>();
let typ = context.new_array_type(None, byte_type, bytes.len() as u64 / 4);
let typ = new_array_type(context, None, byte_type, bytes.len() as u64 / 4);
let elements: Vec<_> = bytes
.chunks_exact(4)
.map(|arr| {
@ -95,7 +99,7 @@ pub fn bytes_in_context<'gcc, 'tcx>(cx: &CodegenCx<'gcc, 'tcx>, bytes: &[u8]) ->
_ => {
let context = cx.context;
let byte_type = context.new_type::<u8>();
let typ = context.new_array_type(None, byte_type, bytes.len() as u64);
let typ = new_array_type(context, None, byte_type, bytes.len() as u64);
let elements: Vec<_> = bytes
.iter()
.map(|&byte| context.new_rvalue_from_int(byte_type, byte as i32))

View file

@ -19,6 +19,8 @@ use rustc_middle::ty::layout::{
};
use rustc_middle::ty::{self, ExistentialTraitRef, Instance, Ty, TyCtxt};
use rustc_session::Session;
#[cfg(feature = "master")]
use rustc_session::config::DebugInfo;
use rustc_span::source_map::respan;
use rustc_span::{DUMMY_SP, Span};
use rustc_target::spec::{HasTargetSpec, HasX86AbiOpt, Target, TlsModel, X86Abi};
@ -145,6 +147,11 @@ impl<'gcc, 'tcx> CodegenCx<'gcc, 'tcx> {
supports_f64_type: bool,
supports_f128_type: bool,
) -> Self {
#[cfg(feature = "master")]
if tcx.sess.opts.debuginfo != DebugInfo::None {
context.set_filename(codegen_unit.name().as_str());
}
let create_type = |ctype, rust_type| {
let layout = tcx
.layout_of(ty::TypingEnv::fully_monomorphized().as_query_input(rust_type))
@ -194,8 +201,8 @@ impl<'gcc, 'tcx> CodegenCx<'gcc, 'tcx> {
// TODO(antoyo): re-enable the alignment when libgccjit fixed the issue in
// gcc_jit_context_new_array_constructor (it should not use reinterpret_cast).
let i128_type = context.new_array_type(None, i64_type, 2)/*.get_aligned(i128_align)*/;
let u128_type = context.new_array_type(None, u64_type, 2)/*.get_aligned(u128_align)*/;
let i128_type = new_array_type(context, None, i64_type, 2)/*.get_aligned(i128_align)*/;
let u128_type = new_array_type(context, None, u64_type, 2)/*.get_aligned(u128_align)*/;
(i128_type, u128_type)
};
@ -601,3 +608,17 @@ fn to_gcc_tls_mode(tls_model: TlsModel) -> gccjit::TlsModel {
TlsModel::Emulated => gccjit::TlsModel::GlobalDynamic,
}
}
pub fn new_array_type<'gcc>(
context: &'gcc Context<'gcc>,
location: Option<Location<'gcc>>,
typ: Type<'gcc>,
size: u64,
) -> Type<'gcc> {
#[cfg(feature = "master")]
{
context.new_array_type_u64(location, typ, size)
}
#[cfg(not(feature = "master"))]
context.new_array_type(location, typ, size)
}

View file

@ -151,7 +151,6 @@ impl<'gcc, 'tcx> CodegenCx<'gcc, 'tcx> {
///
/// If theres a value with the same name already declared, the function will
/// update the declaration and return existing Value instead.
#[expect(clippy::let_and_return)]
fn declare_raw_fn<'gcc>(
cx: &CodegenCx<'gcc, '_>,
name: &str,

View file

@ -942,7 +942,7 @@ impl<'gcc, 'tcx> CodegenCx<'gcc, 'tcx> {
fn float_to_int_cast(
&self,
signed: bool,
value: RValue<'gcc>,
mut value: RValue<'gcc>,
dest_typ: Type<'gcc>,
) -> RValue<'gcc> {
let value_type = value.get_type();
@ -951,16 +951,22 @@ impl<'gcc, 'tcx> CodegenCx<'gcc, 'tcx> {
}
debug_assert!(dest_typ.dyncast_array().is_some());
let (dest_type, param_type) = match self.type_kind(value_type) {
TypeKind::Half => (Some(self.float_type), self.float_type),
_ => (None, value_type),
};
let name_suffix = match self.type_kind(value_type) {
// cSpell:disable
TypeKind::Float => "sfti",
// Since we will cast Half to a float, we use sfti for both.
TypeKind::Half | TypeKind::Float => "sfti",
TypeKind::Double => "dfti",
TypeKind::FP128 => "tfti",
// cSpell:enable
kind => panic!("cannot cast a {:?} to non-native integer", kind),
};
let sign = if signed { "" } else { "uns" };
let func_name = format!("__fix{}{}", sign, name_suffix);
let param = self.context.new_parameter(None, value_type, "n");
let param = self.context.new_parameter(None, param_type, "n");
let func = self.context.new_function(
None,
FunctionType::Extern,
@ -969,6 +975,9 @@ impl<'gcc, 'tcx> CodegenCx<'gcc, 'tcx> {
func_name,
false,
);
if let Some(dest_type) = dest_type {
value = self.context.new_cast(None, value, dest_type);
}
self.context.new_call(None, func, &[value])
}

File diff suppressed because it is too large Load diff

View file

@ -4,7 +4,7 @@ use gccjit::{CType, Context, Field, Function, FunctionPtrType, RValue, ToRValue,
use rustc_codegen_ssa::traits::BuilderMethods;
use crate::builder::Builder;
use crate::context::CodegenCx;
use crate::context::{CodegenCx, new_array_type};
fn encode_key_128_type<'a, 'gcc, 'tcx>(
builder: &Builder<'a, 'gcc, 'tcx>,
@ -585,7 +585,7 @@ pub fn adjust_intrinsic_arguments<'a, 'b, 'gcc, 'tcx>(
"__builtin_ia32_encodekey128_u32" => {
let mut new_args = args.to_vec();
let m128i = builder.context.new_vector_type(builder.i64_type, 2);
let array_type = builder.context.new_array_type(None, m128i, 6);
let array_type = new_array_type(builder.context, None, m128i, 6);
let result = builder.current_func().new_local(None, array_type, "result");
new_args.push(result.get_address(None));
args = new_args.into();
@ -593,7 +593,7 @@ pub fn adjust_intrinsic_arguments<'a, 'b, 'gcc, 'tcx>(
"__builtin_ia32_encodekey256_u32" => {
let mut new_args = args.to_vec();
let m128i = builder.context.new_vector_type(builder.i64_type, 2);
let array_type = builder.context.new_array_type(None, m128i, 7);
let array_type = new_array_type(builder.context, None, m128i, 7);
let result = builder.current_func().new_local(None, array_type, "result");
new_args.push(result.get_address(None));
args = new_args.into();
@ -620,7 +620,7 @@ pub fn adjust_intrinsic_arguments<'a, 'b, 'gcc, 'tcx>(
let first_value = old_args.swap_remove(0);
let element_type = first_value.get_type();
let array_type = builder.context.new_array_type(None, element_type, 8);
let array_type = new_array_type(builder.context, None, element_type, 8);
let result = builder.current_func().new_local(None, array_type, "result");
new_args.push(result.get_address(None));
@ -869,7 +869,7 @@ pub fn adjust_intrinsic_return_value<'a, 'gcc, 'tcx>(
builder.llbb().add_assignment(None, field1, return_value);
let field2 = result.access_field(None, field2);
let field2_type = field2.to_rvalue().get_type();
let array_type = builder.context.new_array_type(None, field2_type, 6);
let array_type = new_array_type(builder.context, None, field2_type, 6);
let ptr = builder.context.new_cast(None, args[2], array_type.make_pointer());
let field2_ptr =
builder.context.new_cast(None, field2.get_address(None), array_type.make_pointer());
@ -891,7 +891,7 @@ pub fn adjust_intrinsic_return_value<'a, 'gcc, 'tcx>(
builder.llbb().add_assignment(None, field1, return_value);
let field2 = result.access_field(None, field2);
let field2_type = field2.to_rvalue().get_type();
let array_type = builder.context.new_array_type(None, field2_type, 7);
let array_type = new_array_type(builder.context, None, field2_type, 7);
let ptr = builder.context.new_cast(None, args[3], array_type.make_pointer());
let field2_ptr =
builder.context.new_cast(None, field2.get_address(None), array_type.make_pointer());
@ -937,7 +937,7 @@ pub fn adjust_intrinsic_return_value<'a, 'gcc, 'tcx>(
builder.llbb().add_assignment(None, field1, return_value);
let field2 = result.access_field(None, field2);
let field2_type = field2.to_rvalue().get_type();
let array_type = builder.context.new_array_type(None, field2_type, 8);
let array_type = new_array_type(builder.context, None, field2_type, 8);
let ptr = builder.context.new_cast(None, args[0], array_type.make_pointer());
let field2_ptr =
builder.context.new_cast(None, field2.get_address(None), array_type.make_pointer());
@ -1061,7 +1061,18 @@ pub fn intrinsic<'gcc, 'tcx>(name: &str, cx: &CodegenCx<'gcc, 'tcx>) -> Function
"llvm.x86.xgetbv" => "__builtin_ia32_xgetbv",
// NOTE: this doc specifies the equivalent GCC builtins: http://huonw.github.io/llvmint/llvmint/x86/index.html
// FIXME: Should handle other targets than `ia32`.
"llvm.sqrt.v2f64" => "__builtin_ia32_sqrtpd",
// FIXME: Should handle other targets than `ia32`.
"llvm.sqrt.v4f32" => "__builtin_ia32_sqrtps",
"llvm.sqrt.f32" => {
let gcc_name = "__builtin_sqrtf";
let func = cx.context.get_builtin_function(gcc_name);
cx.functions.borrow_mut().insert(gcc_name.to_string(), func);
return func;
}
// FIXME: Should handle other targets than `ia32`.
"llvm.smax.v4i32" => "__builtin_ia32_pmaxsd128",
"llvm.x86.avx512.pmul.dq.512" => "__builtin_ia32_pmuldq512_mask",
"llvm.x86.avx512.pmulu.dq.512" => "__builtin_ia32_pmuludq512_mask",
"llvm.x86.avx512.max.ps.512" => "__builtin_ia32_maxps512_mask",
@ -1604,5 +1615,7 @@ pub fn intrinsic<'gcc, 'tcx>(name: &str, cx: &CodegenCx<'gcc, 'tcx>) -> Function
func
}
#[cfg(feature = "master")]
include!("old_archs.rs");
#[cfg(feature = "master")]
include!("archs.rs");

View file

@ -208,6 +208,7 @@ fn get_simple_function_f128<'gcc, 'tcx>(
let f128_type = cx.type_f128();
let func_name = match name {
sym::ceilf128 => "ceilf128",
sym::fabsf128 => "fabsf128",
sym::floorf128 => "floorf128",
sym::truncf128 => "truncf128",
sym::roundf128 => "roundf128",
@ -262,6 +263,7 @@ fn f16_builtin<'gcc, 'tcx>(
let builtin_name = match name {
sym::ceilf16 => "__builtin_ceilf",
sym::copysignf16 => "__builtin_copysignf",
sym::fabsf16 => "fabsf",
sym::floorf16 => "__builtin_floorf",
sym::fmaf16 => "fmaf",
sym::maxnumf16 => "__builtin_fmaxf",
@ -328,6 +330,7 @@ impl<'a, 'gcc, 'tcx> IntrinsicCallBuilderMethods<'tcx> for Builder<'a, 'gcc, 'tc
}
sym::ceilf16
| sym::copysignf16
| sym::fabsf16
| sym::floorf16
| sym::fmaf16
| sym::maxnumf16
@ -648,15 +651,15 @@ impl<'a, 'gcc, 'tcx> IntrinsicCallBuilderMethods<'tcx> for Builder<'a, 'gcc, 'tc
let fn_ptr = func.get_address(None);
let fn_ty = fn_ptr.get_type();
let mut llargs = vec![];
let mut call_args = vec![];
for arg in args {
match arg.val {
OperandValue::ZeroSized => {}
OperandValue::Immediate(_) => llargs.push(arg.immediate()),
OperandValue::Immediate(_) => call_args.push(arg.immediate()),
OperandValue::Pair(a, b) => {
llargs.push(a);
llargs.push(b);
call_args.push(a);
call_args.push(b);
}
OperandValue::Ref(op_place_val) => {
let mut llval = op_place_val.llval;
@ -673,13 +676,13 @@ impl<'a, 'gcc, 'tcx> IntrinsicCallBuilderMethods<'tcx> for Builder<'a, 'gcc, 'tc
// We store bools as `i8` so we need to truncate to `i1`.
llval = self.to_immediate_scalar(llval, scalar);
}
llargs.push(llval);
call_args.push(llval);
}
}
}
// FIXME directly use the llvm intrinsic adjustment functions here
let llret = self.call(fn_ty, None, None, fn_ptr, &llargs, None, None);
let llret = self.call(fn_ty, None, None, fn_ptr, &call_args, None, None);
if is_cleanup {
self.apply_attrs_to_cleanup_callsite(llret);
}
@ -720,7 +723,8 @@ impl<'a, 'gcc, 'tcx> IntrinsicCallBuilderMethods<'tcx> for Builder<'a, 'gcc, 'tc
}
fn va_end(&mut self, _va_list: RValue<'gcc>) -> RValue<'gcc> {
unimplemented!();
// TODO(antoyo): implement.
self.context.new_rvalue_from_int(self.int_type, 0)
}
}

File diff suppressed because it is too large Load diff

View file

@ -234,6 +234,8 @@ impl CodegenBackend for GccCodegenBackend {
#[cfg(feature = "master")]
{
gccjit::set_lang_name(c"GNU Rust");
let target_cpu = target_cpu(sess);
// Get the second TargetInfo with the correct CPU features by setting the arch.

View file

@ -13,7 +13,7 @@ use rustc_middle::ty::layout::TyAndLayout;
use rustc_middle::{bug, ty};
use crate::common::TypeReflection;
use crate::context::CodegenCx;
use crate::context::{CodegenCx, new_array_type};
use crate::type_of::LayoutGccExt;
impl<'gcc, 'tcx> CodegenCx<'gcc, 'tcx> {
@ -311,7 +311,7 @@ impl<'gcc, 'tcx> BaseTypeCodegenMethods for CodegenCx<'gcc, 'tcx> {
len = 0;
}
self.context.new_array_type(None, ty, len)
new_array_type(self.context, None, ty, len)
}
}

View file

@ -11,4 +11,4 @@ tests/run-make/foreign-exceptions/
tests/run-make/glibc-staticlib-args/
tests/run-make/lto-smoke-c/
tests/run-make/return-non-c-like-enum/
tests/run-make/short-ice

View file

@ -0,0 +1 @@
tests/ui/simd/intrinsic/splat.rs

View file

@ -89,11 +89,13 @@ tests/ui/thir-print/offset_of.rs
tests/ui/iterators/rangefrom-overflow-debug.rs
tests/ui/iterators/rangefrom-overflow-overflow-checks.rs
tests/ui/iterators/iter-filter-count-debug-check.rs
tests/ui/eii/codegen_single_crate.rs
tests/ui/eii/codegen_cross_crate.rs
tests/ui/eii/linking/codegen_single_crate.rs
tests/ui/eii/linking/codegen_cross_crate.rs
tests/ui/eii/default/local_crate.rs
tests/ui/eii/multiple_impls.rs
tests/ui/eii/duplicate/multiple_impls.rs
tests/ui/eii/default/call_default.rs
tests/ui/eii/same-symbol.rs
tests/ui/eii/linking/same-symbol.rs
tests/ui/eii/privacy1.rs
tests/ui/eii/default/call_impl.rs
tests/ui/c-variadic/copy.rs
tests/ui/asm/x86_64/global_asm_escape.rs

View file

@ -0,0 +1,38 @@
// Compiler:
//
// Run-time:
// status: 0
// FIXME: Remove this test once rustc's `./tests/codegen/riscv-abi/call-llvm-intrinsics.rs`
// stops ignoring GCC backend.
#![feature(link_llvm_intrinsics)]
#![allow(internal_features)]
struct A;
impl Drop for A {
fn drop(&mut self) {
println!("A");
}
}
extern "C" {
#[link_name = "llvm.sqrt.f32"]
fn sqrt(x: f32) -> f32;
}
pub fn do_call() {
let _a = A;
unsafe {
// Ensure that we `call` LLVM intrinsics instead of trying to `invoke` them
// CHECK: store float 4.000000e+00, float* %{{.}}, align 4
// CHECK: call float @llvm.sqrt.f32(float %{{.}}
sqrt(4.0);
}
}
fn main() {
do_call();
}

View file

@ -0,0 +1,102 @@
// Compiler:
//
// Run-time:
// status: 0
// FIXME: Remove this test once <tests/run-make/simd-ffi/simd.rs> stops
// ignoring GCC backend.
#![allow(internal_features, non_camel_case_types)]
// we can compile to a variety of platforms, because we don't need
// cross-compiled standard libraries.
#![feature(no_core, auto_traits)]
#![no_core]
#![feature(repr_simd, simd_ffi, link_llvm_intrinsics, lang_items, rustc_attrs)]
#[derive(Copy)]
#[repr(simd)]
pub struct f32x4([f32; 4]);
extern "C" {
#[link_name = "llvm.sqrt.v4f32"]
fn vsqrt(x: f32x4) -> f32x4;
}
pub fn foo(x: f32x4) -> f32x4 {
unsafe { vsqrt(x) }
}
#[derive(Copy)]
#[repr(simd)]
pub struct i32x4([i32; 4]);
extern "C" {
// _mm_sll_epi32
#[cfg(all(any(target_arch = "x86", target_arch = "x86-64"), target_feature = "sse2"))]
#[link_name = "llvm.x86.sse2.psll.d"]
fn integer(a: i32x4, b: i32x4) -> i32x4;
// vmaxq_s32
#[cfg(target_arch = "arm")]
#[link_name = "llvm.arm.neon.vmaxs.v4i32"]
fn integer(a: i32x4, b: i32x4) -> i32x4;
// vmaxq_s32
#[cfg(target_arch = "aarch64")]
#[link_name = "llvm.aarch64.neon.maxs.v4i32"]
fn integer(a: i32x4, b: i32x4) -> i32x4;
// Use a generic LLVM intrinsic to do type checking on other platforms
#[cfg(not(any(
all(any(target_arch = "x86", target_arch = "x86-64"), target_feature = "sse2"),
target_arch = "arm",
target_arch = "aarch64"
)))]
#[link_name = "llvm.smax.v4i32"]
fn integer(a: i32x4, b: i32x4) -> i32x4;
}
pub fn bar(a: i32x4, b: i32x4) -> i32x4 {
unsafe { integer(a, b) }
}
#[lang = "pointee_sized"]
pub trait PointeeSized {}
#[lang = "meta_sized"]
pub trait MetaSized: PointeeSized {}
#[lang = "sized"]
pub trait Sized: MetaSized {}
#[lang = "copy"]
pub trait Copy {}
impl Copy for f32 {}
impl Copy for i32 {}
impl Copy for [f32; 4] {}
impl Copy for [i32; 4] {}
pub mod marker {
pub use Copy;
}
#[lang = "freeze"]
auto trait Freeze {}
#[macro_export]
#[rustc_builtin_macro]
macro_rules! Copy {
() => {};
}
#[macro_export]
#[rustc_builtin_macro]
macro_rules! derive {
() => {};
}
#[lang = "start"]
fn start<T>(_main: fn() -> T, _argc: isize, _argv: *const *const u8, _sigpipe: u8) -> isize {
0
}
fn main() {}

View file

@ -0,0 +1,27 @@
// Compiler:
//
// Run-time:
// status: 0
use std::arch::asm;
fn exit_syscall(status: i32) -> ! {
#[cfg(target_arch = "x86_64")]
unsafe {
asm!(
"syscall",
in("rax") 60,
in("rdi") status,
options(noreturn)
);
}
#[cfg(not(target_arch = "x86_64"))]
std::process::exit(status);
}
fn main() {
// Used to crash with rustc_codegen_gcc.
exit_syscall(0);
std::process::exit(1);
}

View file

@ -12,7 +12,7 @@ def run_command(command, cwd=None):
sys.exit(1)
def clone_repository(repo_name, path, repo_url, branch="master", sub_paths=None):
def clone_repository(repo_name, path, repo_url, sub_paths):
if os.path.exists(path):
while True:
choice = input("There is already a `{}` folder, do you want to update it? [y/N]".format(path))
@ -21,18 +21,15 @@ def clone_repository(repo_name, path, repo_url, branch="master", sub_paths=None)
return
elif choice.lower() == "y":
print("Updating repository...")
run_command(["git", "pull", "origin", branch], cwd=path)
run_command(["git", "pull", "origin", "main"], cwd=path)
return
else:
print("Didn't understand answer...")
print("Cloning {} repository...".format(repo_name))
if sub_paths is None:
run_command(["git", "clone", repo_url, "--depth", "1", path])
else:
run_command(["git", "clone", repo_url, "--filter=tree:0", "--no-checkout", path])
run_command(["git", "sparse-checkout", "init"], cwd=path)
run_command(["git", "sparse-checkout", "set", *sub_paths], cwd=path)
run_command(["git", "checkout"], cwd=path)
run_command(["git", "clone", repo_url, "--filter=tree:0", "--no-checkout", path])
run_command(["git", "sparse-checkout", "init"], cwd=path)
run_command(["git", "sparse-checkout", "set", *sub_paths], cwd=path)
run_command(["git", "checkout"], cwd=path)
def append_intrinsic(array, intrinsic_name, translation):
@ -45,121 +42,36 @@ def convert_to_string(content):
return content
def extract_intrinsics_from_llvm(llvm_path, intrinsics):
command = ["llvm-tblgen", "llvm/IR/Intrinsics.td"]
def extract_intrinsics_from_llvm(llvm_path):
intrinsics = {}
command = ["llvm-tblgen", "llvm/IR/Intrinsics.td", "--dump-json"]
cwd = os.path.join(llvm_path, "llvm/include")
print("=> Running command `{}` from `{}`".format(command, cwd))
p = subprocess.Popen(command, cwd=cwd, stdout=subprocess.PIPE)
output, err = p.communicate()
lines = convert_to_string(output).splitlines()
pos = 0
while pos < len(lines):
line = lines[pos]
if not line.startswith("def "):
pos += 1
content = json.loads(convert_to_string(output))
for intrinsic in content:
data = content[intrinsic]
if not isinstance(data, dict):
continue
intrinsic = line.split(" ")[1].strip()
content = line
while pos < len(lines):
line = lines[pos].split(" // ")[0].strip()
content += line
pos += 1
if line == "}":
break
entries = re.findall('string ClangBuiltinName = "(\\w+)";', content)
current_arch = re.findall('string TargetPrefix = "(\\w+)";', content)
if len(entries) == 1 and len(current_arch) == 1:
current_arch = current_arch[0]
intrinsic = intrinsic.split("_")
if len(intrinsic) < 2 or intrinsic[0] != "int":
continue
intrinsic[0] = "llvm"
intrinsic = ".".join(intrinsic)
if current_arch not in intrinsics:
intrinsics[current_arch] = []
append_intrinsic(intrinsics[current_arch], intrinsic, entries[0])
def append_translation(json_data, p, array):
it = json_data["index"][p]
content = it["docs"].split('`')
if len(content) != 5:
return
append_intrinsic(array, content[1], content[3])
def extract_intrinsics_from_llvmint(llvmint, intrinsics):
archs = [
"AMDGPU",
"aarch64",
"arm",
"cuda",
"hexagon",
"mips",
"nvvm",
"ppc",
"ptx",
"x86",
"xcore",
]
json_file = os.path.join(llvmint, "target/doc/llvmint.json")
# We need to regenerate the documentation!
run_command(
["cargo", "rustdoc", "--", "-Zunstable-options", "--output-format", "json"],
cwd=llvmint,
)
with open(json_file, "r", encoding="utf8") as f:
json_data = json.loads(f.read())
for p in json_data["paths"]:
it = json_data["paths"][p]
if it["crate_id"] != 0:
# This is from an external crate.
current_arch = data.get("TargetPrefix")
builtin_name = data.get("ClangBuiltinName")
if current_arch is None or current_arch == "" or builtin_name is None:
continue
if it["kind"] != "function":
# We're only looking for functions.
intrinsic = intrinsic.split("_")
if len(intrinsic) < 2 or intrinsic[0] != "int":
continue
# if len(it["path"]) == 2:
# # This is a "general" intrinsic, not bound to a specific arch.
# append_translation(json_data, p, general)
# continue
if len(it["path"]) != 3 or it["path"][1] not in archs:
continue
arch = it["path"][1]
if arch not in intrinsics:
intrinsics[arch] = []
append_translation(json_data, p, intrinsics[arch])
intrinsic[0] = "llvm"
intrinsic = ".".join(intrinsic)
if current_arch not in intrinsics:
intrinsics[current_arch] = []
append_intrinsic(intrinsics[current_arch], intrinsic, builtin_name)
return intrinsics
def fill_intrinsics(intrinsics, from_intrinsics, all_intrinsics):
for arch in from_intrinsics:
if arch not in intrinsics:
intrinsics[arch] = []
for entry in from_intrinsics[arch]:
if entry[0] in all_intrinsics:
if all_intrinsics[entry[0]] == entry[1]:
# This is a "full" duplicate, both the LLVM instruction and the GCC
# translation are the same.
continue
intrinsics[arch].append((entry[0], entry[1], True))
else:
intrinsics[arch].append((entry[0], entry[1], False))
all_intrinsics[entry[0]] = entry[1]
def update_intrinsics(llvm_path, llvmint, llvmint2):
intrinsics_llvm = {}
intrinsics_llvmint = {}
all_intrinsics = {}
extract_intrinsics_from_llvm(llvm_path, intrinsics_llvm)
extract_intrinsics_from_llvmint(llvmint, intrinsics_llvmint)
extract_intrinsics_from_llvmint(llvmint2, intrinsics_llvmint)
intrinsics = {}
# We give priority to translations from LLVM over the ones from llvmint.
fill_intrinsics(intrinsics, intrinsics_llvm, all_intrinsics)
fill_intrinsics(intrinsics, intrinsics_llvmint, all_intrinsics)
def update_intrinsics(llvm_path):
intrinsics = extract_intrinsics_from_llvm(llvm_path)
archs = [arch for arch in intrinsics]
archs.sort()
@ -173,33 +85,41 @@ def update_intrinsics(llvm_path, llvmint, llvmint2):
# Since all intrinsic names start with "llvm.", we skip that prefix.
print("Updating content of `{}`...".format(output_file))
with open(output_file, "w", encoding="utf8") as out:
out.write("// File generated by `rustc_codegen_gcc/tools/generate_intrinsics.py`\n")
out.write("// DO NOT EDIT IT!\n")
out.write("/// Translate a given LLVM intrinsic name to an equivalent GCC one.\n")
out.write("fn map_arch_intrinsic(full_name:&str)->&'static str{\n")
out.write('let Some(name) = full_name.strip_prefix("llvm.") else { unimplemented!("***** unsupported LLVM intrinsic {}", full_name) };\n')
out.write('let Some((arch, name)) = name.split_once(\'.\') else { unimplemented!("***** unsupported LLVM intrinsic {}", name) };\n')
out.write("match arch {\n")
out.write("""// File generated by `rustc_codegen_gcc/tools/generate_intrinsics.py`
// DO NOT EDIT IT!
/// Translate a given LLVM intrinsic name to an equivalent GCC one.
fn map_arch_intrinsic(full_name:&str)-> &'static str {
let Some(name) = full_name.strip_prefix("llvm.") else { unimplemented!("***** unsupported LLVM intrinsic {}", full_name) };
let Some((arch, name)) = name.split_once('.') else { unimplemented!("***** unsupported LLVM intrinsic llvm.{}", name) };
let old_arch_res = old_archs(arch, name);
if let ArchCheckResult::Ok(res) = old_arch_res {
return res;
}
match arch {""")
for arch in archs:
if len(intrinsics[arch]) == 0:
continue
attribute = "#[expect(non_snake_case)]" if arch[0].isupper() else ""
out.write("\"{}\" => {{ {} fn {}(name: &str,full_name:&str) -> &'static str {{ match name {{".format(arch, attribute, arch))
intrinsics[arch].sort(key=lambda x: (x[0], x[2]))
intrinsics[arch].sort(key=lambda x: (x[0], x[1]))
out.write(' // {}\n'.format(arch))
for entry in intrinsics[arch]:
llvm_name = entry[0].removeprefix("llvm.");
llvm_name = llvm_name.removeprefix(arch);
llvm_name = llvm_name.removeprefix(".");
if entry[2] is True: # if it is a duplicate
out.write(' // [DUPLICATE]: "{}" => "{}",\n'.format(llvm_name, entry[1]))
elif "_round_mask" in entry[1]:
if "_round_mask" in entry[1]:
out.write(' // [INVALID CONVERSION]: "{}" => "{}",\n'.format(llvm_name, entry[1]))
else:
out.write(' "{}" => "{}",\n'.format(llvm_name, entry[1]))
out.write(' _ => unimplemented!("***** unsupported LLVM intrinsic {full_name}"),\n')
out.write("}} }} {}(name,full_name) }}\n,".format(arch))
out.write(' _ => unimplemented!("***** unsupported LLVM architecture {arch}, intrinsic:{full_name}"),\n')
out.write(""" _ => {
match old_arch_res {
ArchCheckResult::UnknownIntrinsic => unimplemented!("***** unsupported LLVM intrinsic {full_name}"),
ArchCheckResult::UnknownArch => unimplemented!("***** unsupported LLVM architecture {arch}, intrinsic: {full_name}"),
ArchCheckResult::Ok(_) => unreachable!(),
}
}""")
out.write("}\n}")
subprocess.call(["rustfmt", output_file])
print("Done!")
@ -210,35 +130,21 @@ def main():
os.path.dirname(os.path.abspath(__file__)),
"llvm-project",
)
llvmint_path = os.path.join(
os.path.dirname(os.path.abspath(__file__)),
"llvmint",
)
llvmint2_path = os.path.join(
os.path.dirname(os.path.abspath(__file__)),
"llvmint-2",
)
# First, we clone the LLVM repository if it's not already here.
clone_repository(
"llvm-project",
llvm_path,
"https://github.com/llvm/llvm-project",
branch="main",
sub_paths=["llvm/include/llvm/IR", "llvm/include/llvm/CodeGen/"],
["llvm/include/llvm/IR", "llvm/include/llvm/CodeGen/"],
)
clone_repository(
"llvmint",
llvmint_path,
"https://github.com/GuillaumeGomez/llvmint",
)
clone_repository(
"llvmint2",
llvmint2_path,
"https://github.com/antoyo/llvmint",
)
update_intrinsics(llvm_path, llvmint_path, llvmint2_path)
update_intrinsics(llvm_path)
# llvm-tblgen can be built with:
#
# mkdir llvm-tblgen-build && cd llvm-tblgen-build
# cmake -G Ninja -DLLVM_ENABLE_PROJECTS="llvm" -DCMAKE_BUILD_TYPE=Release ../llvm
# ninja llvm-tblgen
if __name__ == "__main__":
sys.exit(main())

View file

@ -400,6 +400,7 @@ impl<'tcx> AsmCodegenMethods<'tcx> for CodegenCx<'_, 'tcx> {
match *piece {
InlineAsmTemplatePiece::String(ref s) => template_str.push_str(s),
InlineAsmTemplatePiece::Placeholder { operand_idx, modifier: _, span } => {
use rustc_codegen_ssa::back::symbol_export::escape_symbol_name;
match operands[operand_idx] {
GlobalAsmOperandRef::Const { ref string } => {
// Const operands get injected directly into the
@ -414,7 +415,7 @@ impl<'tcx> AsmCodegenMethods<'tcx> for CodegenCx<'_, 'tcx> {
llvm::LLVMRustGetMangledName(llval, s);
})
.expect("symbol is not valid UTF-8");
template_str.push_str(&escape_symbol_name(self, symbol, span));
template_str.push_str(&escape_symbol_name(self.tcx, &symbol, span));
}
GlobalAsmOperandRef::SymStatic { def_id } => {
let llval = self
@ -428,7 +429,7 @@ impl<'tcx> AsmCodegenMethods<'tcx> for CodegenCx<'_, 'tcx> {
llvm::LLVMRustGetMangledName(llval, s);
})
.expect("symbol is not valid UTF-8");
template_str.push_str(&escape_symbol_name(self, symbol, span));
template_str.push_str(&escape_symbol_name(self.tcx, &symbol, span));
}
}
}
@ -1390,42 +1391,3 @@ fn llvm_fixup_output_type<'ll, 'tcx>(
_ => layout.llvm_type(cx),
}
}
fn escape_symbol_name<'ll, 'tcx>(cx: &CodegenCx<'ll, 'tcx>, symbol: String, span: Span) -> String {
use rustc_target::spec::{Arch, BinaryFormat};
if !symbol.is_empty()
&& symbol.chars().all(|c| matches!(c, '0'..='9' | 'A'..='Z' | 'a'..='z' | '_' | '$' | '.'))
{
return symbol;
}
if cx.tcx.sess.target.binary_format == BinaryFormat::Xcoff {
cx.tcx.sess.dcx().span_fatal(
span,
format!(
"symbol escaping is not supported for the binary format {}",
cx.tcx.sess.target.binary_format
),
);
}
if cx.tcx.sess.target.arch == Arch::Nvptx64 {
cx.tcx.sess.dcx().span_fatal(
span,
format!(
"symbol escaping is not supported for the architecture {}",
cx.tcx.sess.target.arch
),
);
}
let mut escaped_symbol = String::new();
escaped_symbol.push('\"');
for c in symbol.chars() {
match c {
'\n' => escaped_symbol.push_str("\\\n"),
'"' => escaped_symbol.push_str("\\\""),
'\\' => escaped_symbol.push_str("\\\\"),
c => escaped_symbol.push(c),
}
}
escaped_symbol.push('\"');
escaped_symbol
}

View file

@ -16,7 +16,7 @@ module to generate correct metadata and insert it into the LLVM IR.
As the exact format of metadata trees may change between different LLVM
versions, we now use LLVM
[DIBuilder](https://llvm.org/docs/doxygen/html/classllvm_1_1DIBuilder.html)
to create metadata where possible. This will hopefully ease the adaption of
to create metadata where possible. This will hopefully ease the adaptation of
this module to future LLVM versions.
The public API of the module is a set of functions that will insert the
@ -87,19 +87,19 @@ describe the type anew. This behavior is encapsulated in the
## Source Locations and Line Information
In addition to data type descriptions the debugging information must also
allow to map machine code locations back to source code locations in order
allow mapping machine code locations back to source code locations in order
to be useful. This functionality is also handled in this module. The
following functions allow to control source mappings:
following functions allow controlling source mappings:
+ `set_source_location()`
+ `clear_source_location()`
+ `start_emitting_source_locations()`
`set_source_location()` allows to set the current source location. All IR
`set_source_location()` allows setting the current source location. All IR
instructions created after a call to this function will be linked to the
given source location, until another location is specified with
`set_source_location()` or the source location is cleared with
`clear_source_location()`. In the later case, subsequent IR instruction
`clear_source_location()`. In the latter case, subsequent IR instructions
will not be linked to any source location. As you can see, this is a
stateful API (mimicking the one in LLVM), so be careful with source
locations set by previous calls. It's probably best to not rely on any

View file

@ -2,7 +2,7 @@ use std::ffi::CString;
use std::path::Path;
use rustc_data_structures::small_c_str::SmallCStr;
use rustc_errors::{Diag, DiagCtxtHandle, Diagnostic, EmissionGuarantee, Level, inline_fluent};
use rustc_errors::{Diag, DiagCtxtHandle, Diagnostic, EmissionGuarantee, Level, msg};
use rustc_macros::Diagnostic;
use rustc_span::Span;
@ -28,7 +28,7 @@ impl<G: EmissionGuarantee> Diagnostic<'_, G> for ParseTargetMachineConfig<'_> {
Diag::new(
dcx,
level,
inline_fluent!("failed to parse target machine config to target machine: {$error}"),
msg!("failed to parse target machine config to target machine: {$error}"),
)
.with_arg("error", message)
}
@ -121,25 +121,25 @@ impl<G: EmissionGuarantee> Diagnostic<'_, G> for WithLlvmError<'_> {
fn into_diag(self, dcx: DiagCtxtHandle<'_>, level: Level) -> Diag<'_, G> {
use LlvmError::*;
let msg_with_llvm_err = match &self.0 {
WriteOutput { .. } => inline_fluent!("could not write output to {$path}: {$llvm_err}"),
CreateTargetMachine { .. } => inline_fluent!(
"could not create LLVM TargetMachine for triple: {$triple}: {$llvm_err}"
),
RunLlvmPasses => inline_fluent!("failed to run LLVM passes: {$llvm_err}"),
WriteIr { .. } => inline_fluent!("failed to write LLVM IR to {$path}: {$llvm_err}"),
WriteOutput { .. } => msg!("could not write output to {$path}: {$llvm_err}"),
CreateTargetMachine { .. } => {
msg!("could not create LLVM TargetMachine for triple: {$triple}: {$llvm_err}")
}
RunLlvmPasses => msg!("failed to run LLVM passes: {$llvm_err}"),
WriteIr { .. } => msg!("failed to write LLVM IR to {$path}: {$llvm_err}"),
PrepareThinLtoContext => {
inline_fluent!("failed to prepare thin LTO context: {$llvm_err}")
msg!("failed to prepare thin LTO context: {$llvm_err}")
}
LoadBitcode { .. } => {
inline_fluent!("failed to load bitcode of module \"{$name}\": {$llvm_err}")
msg!("failed to load bitcode of module \"{$name}\": {$llvm_err}")
}
WriteThinLtoKey { .. } => {
inline_fluent!("error while writing ThinLTO key data: {$err}: {$llvm_err}")
msg!("error while writing ThinLTO key data: {$err}: {$llvm_err}")
}
PrepareThinLtoModule => {
inline_fluent!("failed to prepare thin LTO module: {$llvm_err}")
msg!("failed to prepare thin LTO module: {$llvm_err}")
}
ParseBitcode => inline_fluent!("failed to parse bitcode for LTO module: {$llvm_err}"),
ParseBitcode => msg!("failed to parse bitcode for LTO module: {$llvm_err}"),
};
self.0
.into_diag(dcx, level)

View file

@ -41,7 +41,8 @@ impl<'tcx> PreDefineCodegenMethods<'tcx> for CodegenCx<'_, 'tcx> {
});
llvm::set_linkage(g, base::linkage_to_llvm(linkage));
llvm::set_visibility(g, base::visibility_to_llvm(visibility));
self.set_visibility(g, linkage, visibility);
self.assume_dso_local(g, false);
let attrs = self.tcx.codegen_instance_attrs(instance.def);
@ -69,16 +70,7 @@ impl<'tcx> PreDefineCodegenMethods<'tcx> for CodegenCx<'_, 'tcx> {
{
llvm::SetUniqueComdat(self.llmod, lldecl);
}
// If we're compiling the compiler-builtins crate, e.g., the equivalent of
// compiler-rt, then we want to implicitly compile everything with hidden
// visibility as we're going to link this object all over the place but
// don't want the symbols to get exported.
if linkage != Linkage::Internal && self.tcx.is_compiler_builtins(LOCAL_CRATE) {
llvm::set_visibility(lldecl, llvm::Visibility::Hidden);
} else {
llvm::set_visibility(lldecl, base::visibility_to_llvm(visibility));
}
self.set_visibility(lldecl, linkage, visibility);
debug!("predefine_fn: instance = {:?}", instance);
@ -122,6 +114,18 @@ impl CodegenCx<'_, '_> {
assume
}
fn set_visibility(&self, lldecl: &llvm::Value, linkage: Linkage, visibility: Visibility) {
// If we're compiling the compiler-builtins crate, i.e., the equivalent of
// compiler-rt, then we want to implicitly compile everything with hidden
// visibility as we're going to link this object all over the place but
// don't want the symbols to get exported.
if linkage != Linkage::Internal && self.tcx.is_compiler_builtins(LOCAL_CRATE) {
llvm::set_visibility(lldecl, llvm::Visibility::Hidden);
} else {
llvm::set_visibility(lldecl, base::visibility_to_llvm(visibility));
}
}
fn should_assume_dso_local(&self, llval: &llvm::Value, is_declaration: bool) -> bool {
let linkage = llvm::get_linkage(llval);
let visibility = llvm::get_visibility(llval);

View file

@ -1122,7 +1122,7 @@ pub(super) fn emit_va_arg<'ll, 'tcx>(
AllowHigherAlign::Yes,
ForceRightAdjust::No,
),
Arch::Wasm32 => emit_ptr_va_arg(
Arch::Wasm32 | Arch::Wasm64 => emit_ptr_va_arg(
bx,
addr,
target_ty,
@ -1135,7 +1135,6 @@ pub(super) fn emit_va_arg<'ll, 'tcx>(
AllowHigherAlign::Yes,
ForceRightAdjust::No,
),
Arch::Wasm64 => bug!("c-variadic functions are not fully implemented for wasm64"),
Arch::CSky => emit_ptr_va_arg(
bx,
addr,

View file

@ -3,7 +3,7 @@ use std::path::PathBuf;
use std::process::Command;
use itertools::Itertools;
use rustc_errors::inline_fluent;
use rustc_errors::msg;
use rustc_middle::middle::exported_symbols::SymbolExportKind;
use rustc_session::Session;
pub(super) use rustc_target::spec::apple::OSVersion;
@ -185,21 +185,19 @@ pub(super) fn get_sdk_root(sess: &Session) -> Option<PathBuf> {
// FIXME(madsmtm): Make this a lint, to allow deny warnings to work.
// (Or fix <https://github.com/rust-lang/rust/issues/21204>).
let mut diag = sess.dcx().create_warn(err);
diag.note(inline_fluent!("the SDK is needed by the linker to know where to find symbols in system libraries and for embedding the SDK version in the final object file"));
diag.note(msg!("the SDK is needed by the linker to know where to find symbols in system libraries and for embedding the SDK version in the final object file"));
// Recognize common error cases, and give more Rust-specific error messages for those.
if let Some(developer_dir) = xcode_select_developer_dir() {
diag.arg("developer_dir", &developer_dir);
diag.note(inline_fluent!(
"found active developer directory at \"{$developer_dir}\""
));
diag.note(msg!("found active developer directory at \"{$developer_dir}\""));
if developer_dir.as_os_str().to_string_lossy().contains("CommandLineTools") {
if sdk_name != "MacOSX" {
diag.help(inline_fluent!("when compiling for iOS, tvOS, visionOS or watchOS, you need a full installation of Xcode"));
diag.help(msg!("when compiling for iOS, tvOS, visionOS or watchOS, you need a full installation of Xcode"));
}
}
} else {
diag.help(inline_fluent!("pass the path of an Xcode installation via the DEVELOPER_DIR environment variable, or an SDK with the SDKROOT environment variable"));
diag.help(msg!("pass the path of an Xcode installation via the DEVELOPER_DIR environment variable, or an SDK with the SDKROOT environment variable"));
}
diag.emit();

View file

@ -14,6 +14,7 @@ use rustc_middle::query::LocalCrate;
use rustc_middle::ty::{self, GenericArgKind, GenericArgsRef, Instance, SymbolName, Ty, TyCtxt};
use rustc_middle::util::Providers;
use rustc_session::config::CrateType;
use rustc_span::Span;
use rustc_symbol_mangling::mangle_internal_symbol;
use rustc_target::spec::{Arch, Os, TlsModel};
use tracing::debug;
@ -764,3 +765,43 @@ fn wasm_import_module_map(tcx: TyCtxt<'_>, cnum: CrateNum) -> DefIdMap<String> {
ret
}
pub fn escape_symbol_name(tcx: TyCtxt<'_>, symbol: &str, span: Span) -> String {
// https://github.com/llvm/llvm-project/blob/a55fbab0cffc9b4af497b9e4f187b61143743e06/llvm/lib/MC/MCSymbol.cpp
use rustc_target::spec::{Arch, BinaryFormat};
if !symbol.is_empty()
&& symbol.chars().all(|c| matches!(c, '0'..='9' | 'A'..='Z' | 'a'..='z' | '_' | '$' | '.'))
{
return symbol.to_string();
}
if tcx.sess.target.binary_format == BinaryFormat::Xcoff {
tcx.sess.dcx().span_fatal(
span,
format!(
"symbol escaping is not supported for the binary format {}",
tcx.sess.target.binary_format
),
);
}
if tcx.sess.target.arch == Arch::Nvptx64 {
tcx.sess.dcx().span_fatal(
span,
format!(
"symbol escaping is not supported for the architecture {}",
tcx.sess.target.arch
),
);
}
let mut escaped_symbol = String::new();
escaped_symbol.push('\"');
for c in symbol.chars() {
match c {
'\n' => escaped_symbol.push_str("\\\n"),
'"' => escaped_symbol.push_str("\\\""),
'\\' => escaped_symbol.push_str("\\\\"),
c => escaped_symbol.push(c),
}
}
escaped_symbol.push('\"');
escaped_symbol
}

View file

@ -8,7 +8,7 @@ use rustc_hir::attrs::{
};
use rustc_hir::def::DefKind;
use rustc_hir::def_id::{DefId, LOCAL_CRATE, LocalDefId};
use rustc_hir::{self as hir, Attribute, LangItem, find_attr, lang_items};
use rustc_hir::{self as hir, Attribute, find_attr};
use rustc_middle::middle::codegen_fn_attrs::{
CodegenFnAttrFlags, CodegenFnAttrs, PatchableFunctionEntry, SanitizerFnAttrs,
};
@ -504,7 +504,7 @@ fn handle_lang_items(
attrs: &[Attribute],
codegen_fn_attrs: &mut CodegenFnAttrs,
) {
let lang_item = lang_items::extract(attrs).and_then(|(name, _)| LangItem::from_name(name));
let lang_item = find_attr!(attrs, AttributeKind::Lang(lang, _) => lang);
// Weak lang items have the same semantics as "std internal" symbols in the
// sense that they're preserved through all our LTO passes and only

View file

@ -8,8 +8,7 @@ use std::process::ExitStatus;
use rustc_errors::codes::*;
use rustc_errors::{
Diag, DiagArgValue, DiagCtxtHandle, Diagnostic, EmissionGuarantee, IntoDiagArg, Level,
inline_fluent,
Diag, DiagArgValue, DiagCtxtHandle, Diagnostic, EmissionGuarantee, IntoDiagArg, Level, msg,
};
use rustc_macros::{Diagnostic, LintDiagnostic, Subdiagnostic};
use rustc_middle::ty::layout::LayoutError;
@ -217,122 +216,122 @@ impl<G: EmissionGuarantee> Diagnostic<'_, G> for ThorinErrorWrapper {
fn into_diag(self, dcx: DiagCtxtHandle<'_>, level: Level) -> Diag<'_, G> {
let build = |msg| Diag::new(dcx, level, msg);
match self.0 {
thorin::Error::ReadInput(_) => build(inline_fluent!("failed to read input file")),
thorin::Error::ReadInput(_) => build(msg!("failed to read input file")),
thorin::Error::ParseFileKind(_) => {
build(inline_fluent!("failed to parse input file kind"))
build(msg!("failed to parse input file kind"))
}
thorin::Error::ParseObjectFile(_) => {
build(inline_fluent!("failed to parse input object file"))
build(msg!("failed to parse input object file"))
}
thorin::Error::ParseArchiveFile(_) => {
build(inline_fluent!("failed to parse input archive file"))
build(msg!("failed to parse input archive file"))
}
thorin::Error::ParseArchiveMember(_) => {
build(inline_fluent!("failed to parse archive member"))
build(msg!("failed to parse archive member"))
}
thorin::Error::InvalidInputKind => build(inline_fluent!("input is not an archive or elf object")),
thorin::Error::DecompressData(_) => build(inline_fluent!("failed to decompress compressed section")),
thorin::Error::InvalidInputKind => build(msg!("input is not an archive or elf object")),
thorin::Error::DecompressData(_) => build(msg!("failed to decompress compressed section")),
thorin::Error::NamelessSection(_, offset) => {
build(inline_fluent!("section without name at offset {$offset}"))
build(msg!("section without name at offset {$offset}"))
.with_arg("offset", format!("0x{offset:08x}"))
}
thorin::Error::RelocationWithInvalidSymbol(section, offset) => {
build(inline_fluent!("relocation with invalid symbol for section `{$section}` at offset {$offset}"))
build(msg!("relocation with invalid symbol for section `{$section}` at offset {$offset}"))
.with_arg("section", section)
.with_arg("offset", format!("0x{offset:08x}"))
}
thorin::Error::MultipleRelocations(section, offset) => {
build(inline_fluent!("multiple relocations for section `{$section}` at offset {$offset}"))
build(msg!("multiple relocations for section `{$section}` at offset {$offset}"))
.with_arg("section", section)
.with_arg("offset", format!("0x{offset:08x}"))
}
thorin::Error::UnsupportedRelocation(section, offset) => {
build(inline_fluent!("unsupported relocation for section {$section} at offset {$offset}"))
build(msg!("unsupported relocation for section {$section} at offset {$offset}"))
.with_arg("section", section)
.with_arg("offset", format!("0x{offset:08x}"))
}
thorin::Error::MissingDwoName(id) => build(inline_fluent!("missing path attribute to DWARF object ({$id})"))
thorin::Error::MissingDwoName(id) => build(msg!("missing path attribute to DWARF object ({$id})"))
.with_arg("id", format!("0x{id:08x}")),
thorin::Error::NoCompilationUnits => {
build(inline_fluent!("input object has no compilation units"))
build(msg!("input object has no compilation units"))
}
thorin::Error::NoDie => build(inline_fluent!("no top-level debugging information entry in compilation/type unit")),
thorin::Error::NoDie => build(msg!("no top-level debugging information entry in compilation/type unit")),
thorin::Error::TopLevelDieNotUnit => {
build(inline_fluent!("top-level debugging information entry is not a compilation/type unit"))
build(msg!("top-level debugging information entry is not a compilation/type unit"))
}
thorin::Error::MissingRequiredSection(section) => {
build(inline_fluent!("input object missing required section `{$section}`"))
build(msg!("input object missing required section `{$section}`"))
.with_arg("section", section)
}
thorin::Error::ParseUnitAbbreviations(_) => {
build(inline_fluent!("failed to parse unit abbreviations"))
build(msg!("failed to parse unit abbreviations"))
}
thorin::Error::ParseUnitAttribute(_) => {
build(inline_fluent!("failed to parse unit attribute"))
build(msg!("failed to parse unit attribute"))
}
thorin::Error::ParseUnitHeader(_) => {
build(inline_fluent!("failed to parse unit header"))
build(msg!("failed to parse unit header"))
}
thorin::Error::ParseUnit(_) => build(inline_fluent!("failed to parse unit")),
thorin::Error::ParseUnit(_) => build(msg!("failed to parse unit")),
thorin::Error::IncompatibleIndexVersion(section, format, actual) => {
build(inline_fluent!("incompatible `{$section}` index version: found version {$actual}, expected version {$format}"))
build(msg!("incompatible `{$section}` index version: found version {$actual}, expected version {$format}"))
.with_arg("section", section)
.with_arg("actual", actual)
.with_arg("format", format)
}
thorin::Error::OffsetAtIndex(_, index) => {
build(inline_fluent!("read offset at index {$index} of `.debug_str_offsets.dwo` section")).with_arg("index", index)
build(msg!("read offset at index {$index} of `.debug_str_offsets.dwo` section")).with_arg("index", index)
}
thorin::Error::StrAtOffset(_, offset) => {
build(inline_fluent!("read string at offset {$offset} of `.debug_str.dwo` section"))
build(msg!("read string at offset {$offset} of `.debug_str.dwo` section"))
.with_arg("offset", format!("0x{offset:08x}"))
}
thorin::Error::ParseIndex(_, section) => {
build(inline_fluent!("failed to parse `{$section}` index section")).with_arg("section", section)
build(msg!("failed to parse `{$section}` index section")).with_arg("section", section)
}
thorin::Error::UnitNotInIndex(unit) => {
build(inline_fluent!("unit {$unit} from input package is not in its index"))
build(msg!("unit {$unit} from input package is not in its index"))
.with_arg("unit", format!("0x{unit:08x}"))
}
thorin::Error::RowNotInIndex(_, row) => {
build(inline_fluent!("row {$row} found in index's hash table not present in index")).with_arg("row", row)
build(msg!("row {$row} found in index's hash table not present in index")).with_arg("row", row)
}
thorin::Error::SectionNotInRow => build(inline_fluent!("section not found in unit's row in index")),
thorin::Error::EmptyUnit(unit) => build(inline_fluent!("unit {$unit} in input DWARF object with no data"))
thorin::Error::SectionNotInRow => build(msg!("section not found in unit's row in index")),
thorin::Error::EmptyUnit(unit) => build(msg!("unit {$unit} in input DWARF object with no data"))
.with_arg("unit", format!("0x{unit:08x}")),
thorin::Error::MultipleDebugInfoSection => {
build(inline_fluent!("multiple `.debug_info.dwo` sections"))
build(msg!("multiple `.debug_info.dwo` sections"))
}
thorin::Error::MultipleDebugTypesSection => {
build(inline_fluent!("multiple `.debug_types.dwo` sections in a package"))
build(msg!("multiple `.debug_types.dwo` sections in a package"))
}
thorin::Error::NotSplitUnit => build(inline_fluent!("regular compilation unit in object (missing dwo identifier)")),
thorin::Error::DuplicateUnit(unit) => build(inline_fluent!("duplicate split compilation unit ({$unit})"))
thorin::Error::NotSplitUnit => build(msg!("regular compilation unit in object (missing dwo identifier)")),
thorin::Error::DuplicateUnit(unit) => build(msg!("duplicate split compilation unit ({$unit})"))
.with_arg("unit", format!("0x{unit:08x}")),
thorin::Error::MissingReferencedUnit(unit) => {
build(inline_fluent!("unit {$unit} referenced by executable was not found"))
build(msg!("unit {$unit} referenced by executable was not found"))
.with_arg("unit", format!("0x{unit:08x}"))
}
thorin::Error::NoOutputObjectCreated => {
build(inline_fluent!("no output object was created from inputs"))
build(msg!("no output object was created from inputs"))
}
thorin::Error::MixedInputEncodings => {
build(inline_fluent!("input objects have mixed encodings"))
build(msg!("input objects have mixed encodings"))
}
thorin::Error::Io(e) => {
build(inline_fluent!("{$error}")).with_arg("error", format!("{e}"))
build(msg!("{$error}")).with_arg("error", format!("{e}"))
}
thorin::Error::ObjectRead(e) => {
build(inline_fluent!("{$error}")).with_arg("error", format!("{e}"))
build(msg!("{$error}")).with_arg("error", format!("{e}"))
}
thorin::Error::ObjectWrite(e) => {
build(inline_fluent!("{$error}")).with_arg("error", format!("{e}"))
build(msg!("{$error}")).with_arg("error", format!("{e}"))
}
thorin::Error::GimliRead(e) => {
build(inline_fluent!("{$error}")).with_arg("error", format!("{e}"))
build(msg!("{$error}")).with_arg("error", format!("{e}"))
}
thorin::Error::GimliWrite(e) => {
build(inline_fluent!("{$error}")).with_arg("error", format!("{e}"))
build(msg!("{$error}")).with_arg("error", format!("{e}"))
}
_ => unimplemented!("Untranslated thorin error"),
}
@ -350,11 +349,8 @@ pub(crate) struct LinkingFailed<'a> {
impl<G: EmissionGuarantee> Diagnostic<'_, G> for LinkingFailed<'_> {
fn into_diag(mut self, dcx: DiagCtxtHandle<'_>, level: Level) -> Diag<'_, G> {
let mut diag = Diag::new(
dcx,
level,
inline_fluent!("linking with `{$linker_path}` failed: {$exit_status}"),
);
let mut diag =
Diag::new(dcx, level, msg!("linking with `{$linker_path}` failed: {$exit_status}"));
diag.arg("linker_path", format!("{}", self.linker_path.display()));
diag.arg("exit_status", format!("{}", self.exit_status));
@ -463,11 +459,11 @@ impl<G: EmissionGuarantee> Diagnostic<'_, G> for LinkingFailed<'_> {
// Trying to match an error from OS linkers
// which by now we have no way to translate.
if contains_undefined_ref {
diag.note(inline_fluent!("some `extern` functions couldn't be found; some native libraries may need to be installed or have their path specified"))
.note(inline_fluent!("use the `-l` flag to specify native libraries to link"));
diag.note(msg!("some `extern` functions couldn't be found; some native libraries may need to be installed or have their path specified"))
.note(msg!("use the `-l` flag to specify native libraries to link"));
if rustc_session::utils::was_invoked_from_cargo() {
diag.note(inline_fluent!("use the `cargo:rustc-link-lib` directive to specify the native libraries to link with Cargo (see https://doc.rust-lang.org/cargo/reference/build-scripts.html#rustc-link-lib)"));
diag.note(msg!("use the `cargo:rustc-link-lib` directive to specify the native libraries to link with Cargo (see https://doc.rust-lang.org/cargo/reference/build-scripts.html#rustc-link-lib)"));
}
}
diag
@ -482,12 +478,11 @@ pub(crate) struct LinkExeStatusStackBufferOverrun;
impl<'a, G: EmissionGuarantee> Diagnostic<'a, G> for LinkExeStatusStackBufferOverrun {
fn into_diag(self, dcx: rustc_errors::DiagCtxtHandle<'a>, level: Level) -> Diag<'a, G> {
let mut diag =
Diag::new(dcx, level, inline_fluent!("0xc0000409 is `STATUS_STACK_BUFFER_OVERRUN`"));
diag.note(inline_fluent!(
let mut diag = Diag::new(dcx, level, msg!("0xc0000409 is `STATUS_STACK_BUFFER_OVERRUN`"));
diag.note(msg!(
"this may have been caused by a program abort and not a stack buffer overrun"
));
diag.note(inline_fluent!("consider checking the Application Event Log for Windows Error Reporting events to see the fail fast error code"));
diag.note(msg!("consider checking the Application Event Log for Windows Error Reporting events to see the fail fast error code"));
diag
}
}
@ -1233,9 +1228,7 @@ impl<G: EmissionGuarantee> Diagnostic<'_, G> for TargetFeatureDisableOrEnable<'_
let mut diag = Diag::new(
dcx,
level,
inline_fluent!(
"the target features {$features} must all be either enabled or disabled together"
),
msg!("the target features {$features} must all be either enabled or disabled together"),
);
if let Some(span) = self.span {
diag.span(span);

View file

@ -1,5 +1,6 @@
use rustc_abi::{BackendRepr, Float, Integer, Primitive, RegKind};
use rustc_hir::attrs::{InstructionSetAttr, Linkage};
use rustc_hir::def_id::LOCAL_CRATE;
use rustc_middle::mir::mono::{MonoItemData, Visibility};
use rustc_middle::mir::{InlineAsmOperand, START_BLOCK};
use rustc_middle::ty::layout::{FnAbiOf, LayoutOf, TyAndLayout};
@ -128,6 +129,15 @@ fn prefix_and_suffix<'tcx>(
let is_arm = tcx.sess.target.arch == Arch::Arm;
let is_thumb = tcx.sess.unstable_target_features.contains(&sym::thumb_mode);
// If we're compiling the compiler-builtins crate, e.g., the equivalent of
// compiler-rt, then we want to implicitly compile everything with hidden
// visibility as we're going to link this object all over the place but
// don't want the symbols to get exported. For naked asm we set the visibility here.
let mut visibility = item_data.visibility;
if item_data.linkage != Linkage::Internal && tcx.is_compiler_builtins(LOCAL_CRATE) {
visibility = Visibility::Hidden;
}
let attrs = tcx.codegen_instance_attrs(instance.def);
let link_section = attrs.link_section.map(|symbol| symbol.as_str().to_string());
@ -217,7 +227,7 @@ fn prefix_and_suffix<'tcx>(
writeln!(begin, ".pushsection {section},\"ax\", {progbits}").unwrap();
writeln!(begin, ".balign {align_bytes}").unwrap();
write_linkage(&mut begin).unwrap();
match item_data.visibility {
match visibility {
Visibility::Default => {}
Visibility::Protected => writeln!(begin, ".protected {asm_name}").unwrap(),
Visibility::Hidden => writeln!(begin, ".hidden {asm_name}").unwrap(),
@ -243,7 +253,7 @@ fn prefix_and_suffix<'tcx>(
writeln!(begin, ".pushsection {},regular,pure_instructions", section).unwrap();
writeln!(begin, ".balign {align_bytes}").unwrap();
write_linkage(&mut begin).unwrap();
match item_data.visibility {
match visibility {
Visibility::Default | Visibility::Protected => {}
Visibility::Hidden => writeln!(begin, ".private_extern {asm_name}").unwrap(),
}
@ -280,7 +290,7 @@ fn prefix_and_suffix<'tcx>(
writeln!(begin, ".section {section},\"\",@").unwrap();
// wasm functions cannot be aligned, so skip
write_linkage(&mut begin).unwrap();
if let Visibility::Hidden = item_data.visibility {
if let Visibility::Hidden = visibility {
writeln!(begin, ".hidden {asm_name}").unwrap();
}
writeln!(begin, ".type {asm_name}, @function").unwrap();
@ -313,7 +323,7 @@ fn prefix_and_suffix<'tcx>(
writeln!(begin, ".align {}", align_bytes).unwrap();
write_linkage(&mut begin).unwrap();
if let Visibility::Hidden = item_data.visibility {
if let Visibility::Hidden = visibility {
// FIXME apparently `.globl {asm_name}, hidden` is valid
// but due to limitations with `.weak` (see above) we can't really use that in general yet
}

View file

@ -2,7 +2,7 @@
use hir::{ConstContext, LangItem};
use rustc_errors::codes::*;
use rustc_errors::{Applicability, Diag, MultiSpan, inline_fluent};
use rustc_errors::{Applicability, Diag, MultiSpan, msg};
use rustc_hir as hir;
use rustc_hir::def_id::DefId;
use rustc_infer::infer::TyCtxtInferExt;
@ -181,7 +181,7 @@ impl<'tcx> NonConstOp<'tcx> for FnCallNonConst<'tcx> {
);
if let ConstContext::Static(_) = ccx.const_kind() {
err.note(inline_fluent!(
err.note(msg!(
"consider wrapping this expression in `std::sync::LazyLock::new(|| ...)`"
));
}

View file

@ -43,40 +43,36 @@ pub enum ConstEvalErrKind {
impl MachineStopType for ConstEvalErrKind {
fn diagnostic_message(&self) -> DiagMessage {
use ConstEvalErrKind::*;
use rustc_errors::inline_fluent;
use rustc_errors::msg;
match self {
ConstAccessesMutGlobal => "constant accesses mutable global memory".into(),
ModifiedGlobal => {
"modifying a static's initial value from another static's initializer".into()
}
Panic { .. } => inline_fluent!("evaluation panicked: {$msg}"),
Panic { .. } => msg!("evaluation panicked: {$msg}"),
RecursiveStatic => {
"encountered static that tried to access itself during initialization".into()
}
AssertFailure(x) => x.diagnostic_message(),
WriteThroughImmutablePointer => {
inline_fluent!(
msg!(
"writing through a pointer that was derived from a shared (immutable) reference"
)
}
ConstMakeGlobalPtrAlreadyMadeGlobal { .. } => {
inline_fluent!(
"attempting to call `const_make_global` twice on the same allocation {$alloc}"
)
msg!("attempting to call `const_make_global` twice on the same allocation {$alloc}")
}
ConstMakeGlobalPtrIsNonHeap(_) => {
inline_fluent!(
msg!(
"pointer passed to `const_make_global` does not point to a heap allocation: {$ptr}"
)
}
ConstMakeGlobalWithDanglingPtr(_) => {
inline_fluent!("pointer passed to `const_make_global` is dangling: {$ptr}")
msg!("pointer passed to `const_make_global` is dangling: {$ptr}")
}
ConstMakeGlobalWithOffset(_) => {
inline_fluent!(
"making {$ptr} global which does not point to the beginning of an object"
)
msg!("making {$ptr} global which does not point to the beginning of an object")
}
}
}

View file

@ -2,7 +2,7 @@ use std::sync::atomic::Ordering::Relaxed;
use either::{Left, Right};
use rustc_abi::{self as abi, BackendRepr};
use rustc_errors::{E0080, inline_fluent};
use rustc_errors::{E0080, msg};
use rustc_hir::def::DefKind;
use rustc_middle::mir::interpret::{AllocId, ErrorHandled, InterpErrorInfo, ReportedErrorInfo};
use rustc_middle::mir::{self, ConstAlloc, ConstValue};
@ -469,11 +469,11 @@ fn report_eval_error<'tcx>(
diag.code(E0080);
diag.span_label(
span,
inline_fluent!(
msg!(
"evaluation of `{$instance}` failed {$num_frames ->
[0] here
*[other] inside this call
}"
[0] here
*[other] inside this call
}"
),
);
for frame in frames {

View file

@ -5,7 +5,7 @@ use std::hash::Hash;
use rustc_abi::{Align, Size};
use rustc_ast::Mutability;
use rustc_data_structures::fx::{FxHashMap, FxIndexMap, IndexEntry};
use rustc_errors::inline_fluent;
use rustc_errors::msg;
use rustc_hir::def_id::{DefId, LocalDefId};
use rustc_hir::{self as hir, CRATE_HIR_ID, LangItem};
use rustc_middle::mir::AssertMessage;
@ -489,12 +489,12 @@ impl<'tcx> interpret::Machine<'tcx> for CompileTimeMachine<'tcx> {
let align = match Align::from_bytes(align) {
Ok(a) => a,
Err(err) => throw_ub_custom!(
inline_fluent!(
msg!(
"invalid align passed to `{$name}`: {$align} is {$err_kind ->
[not_power_of_two] not a power of 2
[too_large] too large
*[other] {\"\"}
}"
[not_power_of_two] not a power of 2
[too_large] too large
*[other] {\"\"}
}"
),
name = "const_allocate",
err_kind = err.diag_ident(),
@ -519,12 +519,12 @@ impl<'tcx> interpret::Machine<'tcx> for CompileTimeMachine<'tcx> {
let align = match Align::from_bytes(align) {
Ok(a) => a,
Err(err) => throw_ub_custom!(
inline_fluent!(
msg!(
"invalid align passed to `{$name}`: {$align} is {$err_kind ->
[not_power_of_two] not a power of 2
[too_large] too large
*[other] {\"\"}
}"
[not_power_of_two] not a power of 2
[too_large] too large
*[other] {\"\"}
}"
),
name = "const_deallocate",
err_kind = err.diag_ident(),

View file

@ -6,7 +6,7 @@ use rustc_abi::WrappingRange;
use rustc_errors::codes::*;
use rustc_errors::{
Diag, DiagArgValue, DiagMessage, Diagnostic, EmissionGuarantee, Level, MultiSpan,
Subdiagnostic, inline_fluent,
Subdiagnostic, msg,
};
use rustc_hir::ConstContext;
use rustc_macros::{Diagnostic, LintDiagnostic, Subdiagnostic};
@ -389,20 +389,21 @@ impl Subdiagnostic for FrameNote {
diag.arg("instance", self.instance);
let mut span: MultiSpan = self.span.into();
if self.has_label && !self.span.is_dummy() {
span.push_span_label(self.span, inline_fluent!("the failure occurred here"));
span.push_span_label(self.span, msg!("the failure occurred here"));
}
let msg = diag.eagerly_translate(inline_fluent!(
let msg = diag.eagerly_translate(msg!(
r#"{$times ->
[0] {const_eval_frame_note_inner}
*[other] [... {$times} additional calls {const_eval_frame_note_inner} ...]
}
const_eval_frame_note_inner = inside {$where_ ->
[closure] closure
[instance] `{$instance}`
*[other] {""}
}
"#
[0] inside {$where_ ->
[closure] closure
[instance] `{$instance}`
*[other] {""}
}
*[other] [... {$times} additional calls inside {$where_ ->
[closure] closure
[instance] `{$instance}`
*[other] {""}
} ...]
}"#
));
diag.remove_arg("times");
diag.remove_arg("where_");
@ -652,122 +653,129 @@ impl<'a> ReportErrorExt for UndefinedBehaviorInfo<'a> {
ValidationError(e) => e.diagnostic_message(),
Unreachable => "entering unreachable code".into(),
BoundsCheckFailed { .. } => inline_fluent!("indexing out of bounds: the len is {$len} but the index is {$index}"),
BoundsCheckFailed { .. } => msg!("indexing out of bounds: the len is {$len} but the index is {$index}"),
DivisionByZero => "dividing by zero".into(),
RemainderByZero => "calculating the remainder with a divisor of zero".into(),
DivisionOverflow => "overflow in signed division (dividing MIN by -1)".into(),
RemainderOverflow => "overflow in signed remainder (dividing MIN by -1)".into(),
PointerArithOverflow => "overflowing pointer arithmetic: the total offset in bytes does not fit in an `isize`".into(),
ArithOverflow { .. } => inline_fluent!("arithmetic overflow in `{$intrinsic}`"),
ShiftOverflow { .. } => inline_fluent!("overflowing shift by {$shift_amount} in `{$intrinsic}`"),
ArithOverflow { .. } => msg!("arithmetic overflow in `{$intrinsic}`"),
ShiftOverflow { .. } => msg!("overflowing shift by {$shift_amount} in `{$intrinsic}`"),
InvalidMeta(InvalidMetaKind::SliceTooBig) => "invalid metadata in wide pointer: slice is bigger than largest supported object".into(),
InvalidMeta(InvalidMetaKind::TooBig) => "invalid metadata in wide pointer: total size is bigger than largest supported object".into(),
UnterminatedCString(_) => "reading a null-terminated string starting at {$pointer} with no null found before end of allocation".into(),
PointerUseAfterFree(_, _) => inline_fluent!("{$operation ->
[MemoryAccess] memory access failed
[InboundsPointerArithmetic] in-bounds pointer arithmetic failed
*[Dereferenceable] pointer not dereferenceable
}: {$alloc_id} has been freed, so this pointer is dangling"),
PointerOutOfBounds { .. } => inline_fluent!("{$operation ->
[MemoryAccess] memory access failed
[InboundsPointerArithmetic] in-bounds pointer arithmetic failed
*[Dereferenceable] pointer not dereferenceable
}: {$operation ->
[MemoryAccess] attempting to access {$inbounds_size ->
[1] 1 byte
*[x] {$inbounds_size} bytes
}
[InboundsPointerArithmetic] attempting to offset pointer by {$inbounds_size ->
[1] 1 byte
*[x] {$inbounds_size} bytes
}
*[Dereferenceable] pointer must {$inbounds_size ->
[0] point to some allocation
[1] be dereferenceable for 1 byte
*[x] be dereferenceable for {$inbounds_size} bytes
}
}, but got {$pointer} which {$ptr_offset_is_neg ->
[true] points to before the beginning of the allocation
*[false] {$inbounds_size_is_neg ->
[false] {$alloc_size_minus_ptr_offset ->
[0] is at or beyond the end of the allocation of size {$alloc_size ->
[1] 1 byte
*[x] {$alloc_size} bytes
}
[1] is only 1 byte from the end of the allocation
*[x] is only {$alloc_size_minus_ptr_offset} bytes from the end of the allocation
}
*[true] {$ptr_offset_abs ->
[0] is at the beginning of the allocation
*[other] is only {$ptr_offset_abs} bytes from the beginning of the allocation
}
}
}
"),
DanglingIntPointer { addr: 0, .. } => inline_fluent!("{$operation ->
[MemoryAccess] memory access failed
[InboundsPointerArithmetic] in-bounds pointer arithmetic failed
*[Dereferenceable] pointer not dereferenceable
}: {$operation ->
[MemoryAccess] attempting to access {$inbounds_size ->
[1] 1 byte
*[x] {$inbounds_size} bytes
}
[InboundsPointerArithmetic] attempting to offset pointer by {$inbounds_size ->
[1] 1 byte
*[x] {$inbounds_size} bytes
}
*[Dereferenceable] pointer must {$inbounds_size ->
[0] point to some allocation
[1] be dereferenceable for 1 byte
*[x] be dereferenceable for {$inbounds_size} bytes
}
}, but got null pointer"),
DanglingIntPointer { .. } => inline_fluent!("{$operation ->
[MemoryAccess] memory access failed
[InboundsPointerArithmetic] in-bounds pointer arithmetic failed
*[Dereferenceable] pointer not dereferenceable
}: {$operation ->
[MemoryAccess] attempting to access {$inbounds_size ->
[1] 1 byte
*[x] {$inbounds_size} bytes
}
[InboundsPointerArithmetic] attempting to offset pointer by {$inbounds_size ->
[1] 1 byte
*[x] {$inbounds_size} bytes
}
*[Dereferenceable] pointer must {$inbounds_size ->
[0] point to some allocation
[1] be dereferenceable for 1 byte
*[x] be dereferenceable for {$inbounds_size} bytes
}
}, but got {$pointer} which is a dangling pointer (it has no provenance)"),
AlignmentCheckFailed { .. } => inline_fluent!("{$msg ->
[AccessedPtr] accessing memory
*[other] accessing memory based on pointer
} with alignment {$has}, but alignment {$required} is required"),
WriteToReadOnly(_) => inline_fluent!("writing to {$allocation} which is read-only"),
DerefFunctionPointer(_) => inline_fluent!("accessing {$allocation} which contains a function"),
DerefVTablePointer(_) => inline_fluent!("accessing {$allocation} which contains a vtable"),
DerefTypeIdPointer(_) => inline_fluent!("accessing {$allocation} which contains a `TypeId`"),
InvalidBool(_) => inline_fluent!("interpreting an invalid 8-bit value as a bool: 0x{$value}"),
InvalidChar(_) => inline_fluent!("interpreting an invalid 32-bit value as a char: 0x{$value}"),
InvalidTag(_) => inline_fluent!("enum value has invalid tag: {$tag}"),
InvalidFunctionPointer(_) => inline_fluent!("using {$pointer} as function pointer but it does not point to a function"),
InvalidVTablePointer(_) => inline_fluent!("using {$pointer} as vtable pointer but it does not point to a vtable"),
InvalidVTableTrait { .. } => inline_fluent!("using vtable for `{$vtable_dyn_type}` but `{$expected_dyn_type}` was expected"),
InvalidStr(_) => inline_fluent!("this string is not valid UTF-8: {$err}"),
PointerUseAfterFree(_, _) => msg!(
"{$operation ->
[MemoryAccess] memory access failed
[InboundsPointerArithmetic] in-bounds pointer arithmetic failed
*[Dereferenceable] pointer not dereferenceable
}: {$alloc_id} has been freed, so this pointer is dangling"
),
PointerOutOfBounds { .. } => msg!(
"{$operation ->
[MemoryAccess] memory access failed
[InboundsPointerArithmetic] in-bounds pointer arithmetic failed
*[Dereferenceable] pointer not dereferenceable
}: {$operation ->
[MemoryAccess] attempting to access {$inbounds_size ->
[1] 1 byte
*[x] {$inbounds_size} bytes
}
[InboundsPointerArithmetic] attempting to offset pointer by {$inbounds_size ->
[1] 1 byte
*[x] {$inbounds_size} bytes
}
*[Dereferenceable] pointer must {$inbounds_size ->
[0] point to some allocation
[1] be dereferenceable for 1 byte
*[x] be dereferenceable for {$inbounds_size} bytes
}
}, but got {$pointer} which {$ptr_offset_is_neg ->
[true] points to before the beginning of the allocation
*[false] {$inbounds_size_is_neg ->
[false] {$alloc_size_minus_ptr_offset ->
[0] is at or beyond the end of the allocation of size {$alloc_size ->
[1] 1 byte
*[x] {$alloc_size} bytes
}
[1] is only 1 byte from the end of the allocation
*[x] is only {$alloc_size_minus_ptr_offset} bytes from the end of the allocation
}
*[true] {$ptr_offset_abs ->
[0] is at the beginning of the allocation
*[other] is only {$ptr_offset_abs} bytes from the beginning of the allocation
}
}
}"
),
DanglingIntPointer { addr: 0, .. } => msg!(
"{$operation ->
[MemoryAccess] memory access failed
[InboundsPointerArithmetic] in-bounds pointer arithmetic failed
*[Dereferenceable] pointer not dereferenceable
}: {$operation ->
[MemoryAccess] attempting to access {$inbounds_size ->
[1] 1 byte
*[x] {$inbounds_size} bytes
}
[InboundsPointerArithmetic] attempting to offset pointer by {$inbounds_size ->
[1] 1 byte
*[x] {$inbounds_size} bytes
}
*[Dereferenceable] pointer must {$inbounds_size ->
[0] point to some allocation
[1] be dereferenceable for 1 byte
*[x] be dereferenceable for {$inbounds_size} bytes
}
}, but got null pointer"),
DanglingIntPointer { .. } => msg!(
"{$operation ->
[MemoryAccess] memory access failed
[InboundsPointerArithmetic] in-bounds pointer arithmetic failed
*[Dereferenceable] pointer not dereferenceable
}: {$operation ->
[MemoryAccess] attempting to access {$inbounds_size ->
[1] 1 byte
*[x] {$inbounds_size} bytes
}
[InboundsPointerArithmetic] attempting to offset pointer by {$inbounds_size ->
[1] 1 byte
*[x] {$inbounds_size} bytes
}
*[Dereferenceable] pointer must {$inbounds_size ->
[0] point to some allocation
[1] be dereferenceable for 1 byte
*[x] be dereferenceable for {$inbounds_size} bytes
}
}, but got {$pointer} which is a dangling pointer (it has no provenance)"),
AlignmentCheckFailed { .. } => msg!(
"{$msg ->
[AccessedPtr] accessing memory
*[other] accessing memory based on pointer
} with alignment {$has}, but alignment {$required} is required"
),
WriteToReadOnly(_) => msg!("writing to {$allocation} which is read-only"),
DerefFunctionPointer(_) => msg!("accessing {$allocation} which contains a function"),
DerefVTablePointer(_) => msg!("accessing {$allocation} which contains a vtable"),
DerefTypeIdPointer(_) => msg!("accessing {$allocation} which contains a `TypeId`"),
InvalidBool(_) => msg!("interpreting an invalid 8-bit value as a bool: 0x{$value}"),
InvalidChar(_) => msg!("interpreting an invalid 32-bit value as a char: 0x{$value}"),
InvalidTag(_) => msg!("enum value has invalid tag: {$tag}"),
InvalidFunctionPointer(_) => msg!("using {$pointer} as function pointer but it does not point to a function"),
InvalidVTablePointer(_) => msg!("using {$pointer} as vtable pointer but it does not point to a vtable"),
InvalidVTableTrait { .. } => msg!("using vtable for `{$vtable_dyn_type}` but `{$expected_dyn_type}` was expected"),
InvalidStr(_) => msg!("this string is not valid UTF-8: {$err}"),
InvalidUninitBytes(None) => "using uninitialized data, but this operation requires initialized memory".into(),
InvalidUninitBytes(Some(_)) => inline_fluent!("reading memory at {$alloc}{$access}, but memory is uninitialized at {$uninit}, and this operation requires initialized memory"),
InvalidUninitBytes(Some(_)) => msg!("reading memory at {$alloc}{$access}, but memory is uninitialized at {$uninit}, and this operation requires initialized memory"),
DeadLocal => "accessing a dead local variable".into(),
ScalarSizeMismatch(_) => inline_fluent!("scalar size mismatch: expected {$target_size} bytes but got {$data_size} bytes instead"),
ScalarSizeMismatch(_) => msg!("scalar size mismatch: expected {$target_size} bytes but got {$data_size} bytes instead"),
UninhabitedEnumVariantWritten(_) => "writing discriminant of an uninhabited enum variant".into(),
UninhabitedEnumVariantRead(_) => "read discriminant of an uninhabited enum variant".into(),
InvalidNichedEnumVariantWritten { .. } => {
inline_fluent!("trying to set discriminant of a {$ty} to the niched variant, but the value does not match")
msg!("trying to set discriminant of a {$ty} to the niched variant, but the value does not match")
}
AbiMismatchArgument { .. } => inline_fluent!("calling a function whose parameter #{$arg_idx} has type {$callee_ty} passing argument of type {$caller_ty}"),
AbiMismatchReturn { .. } => inline_fluent!("calling a function with return type {$callee_ty} passing return place of type {$caller_ty}"),
AbiMismatchArgument { .. } => msg!("calling a function whose parameter #{$arg_idx} has type {$callee_ty} passing argument of type {$caller_ty}"),
AbiMismatchReturn { .. } => msg!("calling a function with return type {$callee_ty} passing return place of type {$caller_ty}"),
}
}
@ -912,189 +920,172 @@ impl<'tcx> ReportErrorExt for ValidationErrorInfo<'tcx> {
match self.kind {
PtrToUninhabited { ptr_kind: PointerKind::Box, .. } => {
inline_fluent!(
"{$front_matter}: encountered a box pointing to uninhabited type {$ty}"
)
msg!("{$front_matter}: encountered a box pointing to uninhabited type {$ty}")
}
PtrToUninhabited { ptr_kind: PointerKind::Ref(_), .. } => {
inline_fluent!(
"{$front_matter}: encountered a reference pointing to uninhabited type {$ty}"
)
msg!("{$front_matter}: encountered a reference pointing to uninhabited type {$ty}")
}
PointerAsInt { .. } => {
inline_fluent!("{$front_matter}: encountered a pointer, but {$expected}")
msg!("{$front_matter}: encountered a pointer, but {$expected}")
}
PartialPointer => {
msg!("{$front_matter}: encountered a partial pointer or a mix of pointers")
}
PartialPointer => inline_fluent!(
"{$front_matter}: encountered a partial pointer or a mix of pointers"
),
MutableRefToImmutable => {
inline_fluent!(
msg!(
"{$front_matter}: encountered mutable reference or box pointing to read-only memory"
)
}
NullFnPtr { .. } => {
inline_fluent!(
msg!(
"{$front_matter}: encountered a {$maybe ->
[true] maybe-null
*[false] null
} function pointer"
[true] maybe-null
*[false] null
} function pointer"
)
}
NeverVal => {
inline_fluent!("{$front_matter}: encountered a value of the never type `!`")
msg!("{$front_matter}: encountered a value of the never type `!`")
}
NonnullPtrMaybeNull { .. } => {
inline_fluent!(
msg!(
"{$front_matter}: encountered a maybe-null pointer, but expected something that is definitely non-zero"
)
}
PtrOutOfRange { .. } => {
inline_fluent!(
msg!(
"{$front_matter}: encountered a pointer with unknown absolute address, but expected something that is definitely {$in_range}"
)
}
OutOfRange { .. } => {
inline_fluent!(
"{$front_matter}: encountered {$value}, but expected something {$in_range}"
)
msg!("{$front_matter}: encountered {$value}, but expected something {$in_range}")
}
UnsafeCellInImmutable => {
inline_fluent!("{$front_matter}: encountered `UnsafeCell` in read-only memory")
msg!("{$front_matter}: encountered `UnsafeCell` in read-only memory")
}
UninhabitedVal { .. } => {
inline_fluent!("{$front_matter}: encountered a value of uninhabited type `{$ty}`")
msg!("{$front_matter}: encountered a value of uninhabited type `{$ty}`")
}
InvalidEnumTag { .. } => {
inline_fluent!(
"{$front_matter}: encountered {$value}, but expected a valid enum tag"
)
msg!("{$front_matter}: encountered {$value}, but expected a valid enum tag")
}
UninhabitedEnumVariant => {
inline_fluent!("{$front_matter}: encountered an uninhabited enum variant")
msg!("{$front_matter}: encountered an uninhabited enum variant")
}
Uninit { .. } => {
inline_fluent!("{$front_matter}: encountered uninitialized memory, but {$expected}")
msg!("{$front_matter}: encountered uninitialized memory, but {$expected}")
}
InvalidVTablePtr { .. } => {
inline_fluent!(
"{$front_matter}: encountered {$value}, but expected a vtable pointer"
)
msg!("{$front_matter}: encountered {$value}, but expected a vtable pointer")
}
InvalidMetaWrongTrait { .. } => {
inline_fluent!(
msg!(
"{$front_matter}: wrong trait in wide pointer vtable: expected `{$expected_dyn_type}`, but encountered `{$vtable_dyn_type}`"
)
}
InvalidMetaSliceTooLarge { ptr_kind: PointerKind::Box } => {
inline_fluent!(
msg!(
"{$front_matter}: encountered invalid box metadata: slice is bigger than largest supported object"
)
}
InvalidMetaSliceTooLarge { ptr_kind: PointerKind::Ref(_) } => {
inline_fluent!(
msg!(
"{$front_matter}: encountered invalid reference metadata: slice is bigger than largest supported object"
)
}
InvalidMetaTooLarge { ptr_kind: PointerKind::Box } => {
inline_fluent!(
msg!(
"{$front_matter}: encountered invalid box metadata: total size is bigger than largest supported object"
)
}
InvalidMetaTooLarge { ptr_kind: PointerKind::Ref(_) } => {
inline_fluent!(
msg!(
"{$front_matter}: encountered invalid reference metadata: total size is bigger than largest supported object"
)
}
UnalignedPtr { ptr_kind: PointerKind::Ref(_), .. } => {
inline_fluent!(
msg!(
"{$front_matter}: encountered an unaligned reference (required {$required_bytes} byte alignment but found {$found_bytes})"
)
}
UnalignedPtr { ptr_kind: PointerKind::Box, .. } => {
inline_fluent!(
msg!(
"{$front_matter}: encountered an unaligned box (required {$required_bytes} byte alignment but found {$found_bytes})"
)
}
NullPtr { ptr_kind: PointerKind::Box, .. } => {
inline_fluent!(
msg!(
"{$front_matter}: encountered a {$maybe ->
[true] maybe-null
*[false] null
} box"
[true] maybe-null
*[false] null
} box"
)
}
NullPtr { ptr_kind: PointerKind::Ref(_), .. } => {
inline_fluent!(
msg!(
"{$front_matter}: encountered a {$maybe ->
[true] maybe-null
*[false] null
} reference"
[true] maybe-null
*[false] null
} reference"
)
}
DanglingPtrNoProvenance { ptr_kind: PointerKind::Box, .. } => {
inline_fluent!(
"{$front_matter}: encountered a dangling box ({$pointer} has no provenance)"
)
msg!("{$front_matter}: encountered a dangling box ({$pointer} has no provenance)")
}
DanglingPtrNoProvenance { ptr_kind: PointerKind::Ref(_), .. } => {
inline_fluent!(
msg!(
"{$front_matter}: encountered a dangling reference ({$pointer} has no provenance)"
)
}
DanglingPtrOutOfBounds { ptr_kind: PointerKind::Box } => {
inline_fluent!(
msg!(
"{$front_matter}: encountered a dangling box (going beyond the bounds of its allocation)"
)
}
DanglingPtrOutOfBounds { ptr_kind: PointerKind::Ref(_) } => {
inline_fluent!(
msg!(
"{$front_matter}: encountered a dangling reference (going beyond the bounds of its allocation)"
)
}
DanglingPtrUseAfterFree { ptr_kind: PointerKind::Box } => {
inline_fluent!("{$front_matter}: encountered a dangling box (use-after-free)")
msg!("{$front_matter}: encountered a dangling box (use-after-free)")
}
DanglingPtrUseAfterFree { ptr_kind: PointerKind::Ref(_) } => {
inline_fluent!("{$front_matter}: encountered a dangling reference (use-after-free)")
msg!("{$front_matter}: encountered a dangling reference (use-after-free)")
}
InvalidBool { .. } => {
inline_fluent!("{$front_matter}: encountered {$value}, but expected a boolean")
msg!("{$front_matter}: encountered {$value}, but expected a boolean")
}
InvalidChar { .. } => {
inline_fluent!(
msg!(
"{$front_matter}: encountered {$value}, but expected a valid unicode scalar value (in `0..=0x10FFFF` but not in `0xD800..=0xDFFF`)"
)
}
InvalidFnPtr { .. } => {
inline_fluent!(
"{$front_matter}: encountered {$value}, but expected a function pointer"
)
msg!("{$front_matter}: encountered {$value}, but expected a function pointer")
}
}
}
fn add_args<G: EmissionGuarantee>(self, err: &mut Diag<'_, G>) {
use rustc_errors::inline_fluent;
use rustc_errors::msg;
use rustc_middle::mir::interpret::ValidationErrorKind::*;
if let PointerAsInt { .. } | PartialPointer = self.kind {
err.help(inline_fluent!("this code performed an operation that depends on the underlying bytes representing a pointer"));
err.help(inline_fluent!("the absolute address of a pointer is not known at compile-time, so such operations are not supported"));
err.help(msg!("this code performed an operation that depends on the underlying bytes representing a pointer"));
err.help(msg!("the absolute address of a pointer is not known at compile-time, so such operations are not supported"));
}
let message = if let Some(path) = self.path {
err.dcx.eagerly_translate_to_string(
inline_fluent!("constructing invalid value at {$path}"),
msg!("constructing invalid value at {$path}"),
[("path".into(), DiagArgValue::Str(path.into()))].iter().map(|(a, b)| (a, b)),
)
} else {
err.dcx.eagerly_translate_to_string(
inline_fluent!("constructing invalid value"),
[].into_iter(),
)
err.dcx.eagerly_translate_to_string(msg!("constructing invalid value"), [].into_iter())
};
err.arg("front_matter", message);
@ -1107,17 +1098,17 @@ impl<'tcx> ReportErrorExt for ValidationErrorInfo<'tcx> {
let WrappingRange { start: lo, end: hi } = r;
assert!(hi <= max_hi);
let msg = if lo > hi {
inline_fluent!("less or equal to {$hi}, or greater or equal to {$lo}")
msg!("less or equal to {$hi}, or greater or equal to {$lo}")
} else if lo == hi {
inline_fluent!("equal to {$lo}")
msg!("equal to {$lo}")
} else if lo == 0 {
assert!(hi < max_hi, "should not be printing if the range covers everything");
inline_fluent!("less or equal to {$hi}")
msg!("less or equal to {$hi}")
} else if hi == max_hi {
assert!(lo > 0, "should not be printing if the range covers everything");
inline_fluent!("greater or equal to {$lo}")
msg!("greater or equal to {$lo}")
} else {
inline_fluent!("in the range {$lo}..={$hi}")
msg!("in the range {$lo}..={$hi}")
};
let args = [
@ -1135,17 +1126,17 @@ impl<'tcx> ReportErrorExt for ValidationErrorInfo<'tcx> {
}
PointerAsInt { expected } | Uninit { expected } => {
let msg = match expected {
ExpectedKind::Reference => inline_fluent!("expected a reference"),
ExpectedKind::Box => inline_fluent!("expected a box"),
ExpectedKind::RawPtr => inline_fluent!("expected a raw pointer"),
ExpectedKind::InitScalar => inline_fluent!("expected initialized scalar value"),
ExpectedKind::Bool => inline_fluent!("expected a boolean"),
ExpectedKind::Char => inline_fluent!("expected a unicode scalar value"),
ExpectedKind::Float => inline_fluent!("expected a floating point number"),
ExpectedKind::Int => inline_fluent!("expected an integer"),
ExpectedKind::FnPtr => inline_fluent!("expected a function pointer"),
ExpectedKind::EnumTag => inline_fluent!("expected a valid enum tag"),
ExpectedKind::Str => inline_fluent!("expected a string"),
ExpectedKind::Reference => msg!("expected a reference"),
ExpectedKind::Box => msg!("expected a box"),
ExpectedKind::RawPtr => msg!("expected a raw pointer"),
ExpectedKind::InitScalar => msg!("expected initialized scalar value"),
ExpectedKind::Bool => msg!("expected a boolean"),
ExpectedKind::Char => msg!("expected a unicode scalar value"),
ExpectedKind::Float => msg!("expected a floating point number"),
ExpectedKind::Int => msg!("expected an integer"),
ExpectedKind::FnPtr => msg!("expected a function pointer"),
ExpectedKind::EnumTag => msg!("expected a valid enum tag"),
ExpectedKind::Str => msg!("expected a string"),
};
let msg = err.dcx.eagerly_translate_to_string(msg, [].into_iter());
err.arg("expected", msg);
@ -1199,14 +1190,14 @@ impl ReportErrorExt for UnsupportedOpInfo {
}
UnsupportedOpInfo::UnsizedLocal => "unsized locals are not supported".into(),
UnsupportedOpInfo::ReadPartialPointer(_) => {
inline_fluent!("unable to read parts of a pointer from memory at {$ptr}")
msg!("unable to read parts of a pointer from memory at {$ptr}")
}
UnsupportedOpInfo::ReadPointerAsInt(_) => "unable to turn pointer into integer".into(),
UnsupportedOpInfo::ThreadLocalStatic(_) => {
inline_fluent!("cannot access thread local static `{$did}`")
msg!("cannot access thread local static `{$did}`")
}
UnsupportedOpInfo::ExternStatic(_) => {
inline_fluent!("cannot access extern static `{$did}`")
msg!("cannot access extern static `{$did}`")
}
}
.into()

View file

@ -6,7 +6,7 @@ use std::borrow::Cow;
use either::{Left, Right};
use rustc_abi::{self as abi, ExternAbi, FieldIdx, Integer, VariantIdx};
use rustc_data_structures::assert_matches;
use rustc_errors::inline_fluent;
use rustc_errors::msg;
use rustc_hir::def_id::DefId;
use rustc_middle::ty::layout::{IntegerExt, TyAndLayout};
use rustc_middle::ty::{self, AdtDef, Instance, Ty, VariantDef};
@ -297,9 +297,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
}
// Find next caller arg.
let Some((caller_arg, caller_abi)) = caller_args.next() else {
throw_ub_custom!(inline_fluent!(
"calling a function with fewer arguments than it requires"
));
throw_ub_custom!(msg!("calling a function with fewer arguments than it requires"));
};
assert_eq!(caller_arg.layout().layout, caller_abi.layout.layout);
// Sadly we cannot assert that `caller_arg.layout().ty` and `caller_abi.layout.ty` are
@ -366,7 +364,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
if caller_fn_abi.conv != callee_fn_abi.conv {
throw_ub_custom!(
rustc_errors::inline_fluent!(
rustc_errors::msg!(
"calling a function with calling convention \"{$callee_conv}\" using calling convention \"{$caller_conv}\""
),
callee_conv = format!("{}", callee_fn_abi.conv),
@ -499,9 +497,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
"mismatch between callee ABI and callee body arguments"
);
if caller_args.next().is_some() {
throw_ub_custom!(inline_fluent!(
"calling a function with more arguments than it expected"
));
throw_ub_custom!(msg!("calling a function with more arguments than it expected"));
}
// Don't forget to check the return type!
if !self.check_argument_compat(&caller_fn_abi.ret, &callee_fn_abi.ret)? {
@ -701,7 +697,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
let vtable_entries = self.vtable_entries(receiver_trait.principal(), dyn_ty);
let Some(ty::VtblEntry::Method(fn_inst)) = vtable_entries.get(idx).copied() else {
// FIXME(fee1-dead) these could be variants of the UB info enum instead of this
throw_ub_custom!(inline_fluent!(
throw_ub_custom!(msg!(
"`dyn` call trying to call something that is not a method"
));
};
@ -900,7 +896,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
}
);
if unwinding && self.frame_idx() == 0 {
throw_ub_custom!(inline_fluent!("unwinding past the topmost frame of the stack"));
throw_ub_custom!(msg!("unwinding past the topmost frame of the stack"));
}
// Get out the return value. Must happen *before* the frame is popped as we have to get the

View file

@ -2,7 +2,7 @@ use rustc_abi::{FieldIdx, Integer};
use rustc_apfloat::ieee::{Double, Half, Quad, Single};
use rustc_apfloat::{Float, FloatConvert};
use rustc_data_structures::assert_matches;
use rustc_errors::inline_fluent;
use rustc_errors::msg;
use rustc_middle::mir::CastKind;
use rustc_middle::mir::interpret::{InterpResult, PointerArithmetic, Scalar};
use rustc_middle::ty::adjustment::PointerCoercion;
@ -139,7 +139,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
assert_eq!(cast_ty, dest.layout.ty); // we otherwise ignore `cast_ty` enirely...
if src.layout.size != dest.layout.size {
throw_ub_custom!(
inline_fluent!(
msg!(
"transmuting from {$src_bytes}-byte type to {$dest_bytes}-byte type: `{$src}` -> `{$dest}`"
),
src_bytes = src.layout.size.bytes(),

View file

@ -1,7 +1,7 @@
use either::{Left, Right};
use rustc_abi::{Align, HasDataLayout, Size, TargetDataLayout};
use rustc_data_structures::debug_assert_matches;
use rustc_errors::{DiagCtxtHandle, inline_fluent};
use rustc_errors::{DiagCtxtHandle, msg};
use rustc_hir::def_id::DefId;
use rustc_hir::limit::Limit;
use rustc_middle::mir::interpret::{ErrorHandled, InvalidMetaKind, ReportedErrorInfo};
@ -555,7 +555,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
mir::UnwindAction::Cleanup(block) => Left(mir::Location { block, statement_index: 0 }),
mir::UnwindAction::Continue => Right(self.frame_mut().body.span),
mir::UnwindAction::Unreachable => {
throw_ub_custom!(inline_fluent!(
throw_ub_custom!(msg!(
"unwinding past a stack frame that does not allow unwinding"
));
}

View file

@ -7,7 +7,7 @@ mod simd;
use rustc_abi::{FIRST_VARIANT, FieldIdx, HasDataLayout, Size, VariantIdx};
use rustc_apfloat::ieee::{Double, Half, Quad, Single};
use rustc_data_structures::assert_matches;
use rustc_errors::inline_fluent;
use rustc_errors::msg;
use rustc_hir::def_id::CRATE_DEF_ID;
use rustc_infer::infer::TyCtxtInferExt;
use rustc_middle::mir::interpret::{CTFE_ALLOC_SALT, read_target_uint, write_target_uint};
@ -443,7 +443,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
_ => {
// Not into the same allocation -- this is UB.
throw_ub_custom!(
inline_fluent!(
msg!(
"`{$name}` called on two different pointers that are not both derived from the same allocation"
),
name = intrinsic_name,
@ -466,10 +466,12 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
// a < b
if intrinsic_name == sym::ptr_offset_from_unsigned {
throw_ub_custom!(
inline_fluent!("`ptr_offset_from_unsigned` called when first pointer has smaller {$is_addr ->
[true] address
*[false] offset
} than second: {$a_offset} < {$b_offset}"),
msg!(
"`ptr_offset_from_unsigned` called when first pointer has smaller {$is_addr ->
[true] address
*[false] offset
} than second: {$a_offset} < {$b_offset}"
),
a_offset = a_offset,
b_offset = b_offset,
is_addr = is_addr,
@ -481,7 +483,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
let dist = val.to_target_isize(self)?;
if dist >= 0 || i128::from(dist) == self.pointer_size().signed_int_min() {
throw_ub_custom!(
inline_fluent!(
msg!(
"`{$name}` called when first pointer is too far before second"
),
name = intrinsic_name,
@ -495,7 +497,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
// because they were more than isize::MAX apart.
if dist < 0 {
throw_ub_custom!(
inline_fluent!(
msg!(
"`{$name}` called when first pointer is too far ahead of second"
),
name = intrinsic_name,
@ -516,12 +518,12 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
&& a_alloc_id == b_alloc_id
{
err_ub_custom!(
inline_fluent!("`{$name}` called on two different pointers where the memory range between them is not in-bounds of an allocation"),
msg!("`{$name}` called on two different pointers where the memory range between them is not in-bounds of an allocation"),
name = intrinsic_name,
)
} else {
err_ub_custom!(
inline_fluent!("`{$name}` called on two different pointers that are not both derived from the same allocation"),
msg!("`{$name}` called on two different pointers that are not both derived from the same allocation"),
name = intrinsic_name,
)
}
@ -536,7 +538,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
.map_err_kind(|_| {
// Make the error more specific.
err_ub_custom!(
inline_fluent!("`{$name}` called on two different pointers that are not both derived from the same allocation"),
msg!("`{$name}` called on two different pointers that are not both derived from the same allocation"),
name = intrinsic_name,
)
})?;
@ -766,7 +768,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
let op = self.eval_operand(op, None)?;
let cond = self.read_scalar(&op)?.to_bool()?;
if !cond {
throw_ub_custom!(inline_fluent!("`assume` called with `false`"));
throw_ub_custom!(msg!("`assume` called with `false`"));
}
interp_ok(())
}
@ -796,7 +798,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
let bits_out = match name {
sym::ctpop => u128::from(bits.count_ones()),
sym::ctlz_nonzero | sym::cttz_nonzero if bits == 0 => {
throw_ub_custom!(inline_fluent!("`{$name}` called on 0"), name = name,);
throw_ub_custom!(msg!("`{$name}` called on 0"), name = name,);
}
sym::ctlz | sym::ctlz_nonzero => u128::from(bits.leading_zeros()) - extra,
sym::cttz | sym::cttz_nonzero => u128::from((bits << extra).trailing_zeros()) - extra,
@ -829,7 +831,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
// sign does not matter for 0 test, so `to_bits` is fine
if rem.to_scalar().to_bits(a.layout.size)? != 0 {
throw_ub_custom!(
inline_fluent!("exact_div: {$a} cannot be divided by {$b} without remainder"),
msg!("exact_div: {$a} cannot be divided by {$b} without remainder"),
a = format!("{a}"),
b = format!("{b}")
)
@ -914,7 +916,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
let size = self.compute_size_in_bytes(size, count).ok_or_else(|| {
err_ub_custom!(
inline_fluent!("overflow computing total size of `{$name}`"),
msg!("overflow computing total size of `{$name}`"),
name = if nonoverlapping { "copy_nonoverlapping" } else { "copy" }
)
})?;
@ -978,10 +980,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
// `checked_mul` enforces a too small bound (the correct one would probably be target_isize_max),
// but no actual allocation can be big enough for the difference to be noticeable.
let len = self.compute_size_in_bytes(layout.size, count).ok_or_else(|| {
err_ub_custom!(
inline_fluent!("overflow computing total size of `{$name}`"),
name = name
)
err_ub_custom!(msg!("overflow computing total size of `{$name}`"), name = name)
})?;
let bytes = std::iter::repeat_n(byte, len.bytes_usize());

View file

@ -15,7 +15,7 @@ use rustc_abi::{Align, HasDataLayout, Size};
use rustc_ast::Mutability;
use rustc_data_structures::assert_matches;
use rustc_data_structures::fx::{FxHashSet, FxIndexMap};
use rustc_errors::inline_fluent;
use rustc_errors::msg;
use rustc_middle::mir::display_allocation;
use rustc_middle::ty::{self, Instance, Ty, TyCtxt};
use rustc_middle::{bug, throw_ub_format};
@ -291,12 +291,12 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
let (alloc_id, offset, _prov) = self.ptr_get_alloc_id(ptr, 0)?;
if offset.bytes() != 0 {
throw_ub_custom!(
inline_fluent!(
msg!(
"{$kind ->
[dealloc] deallocating
[realloc] reallocating
*[other] {\"\"}
} {$ptr} which does not point to the beginning of an object"
[dealloc] deallocating
[realloc] reallocating
*[other] {\"\"}
} {$ptr} which does not point to the beginning of an object"
),
ptr = format!("{ptr:?}"),
kind = "realloc"
@ -377,12 +377,12 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
if offset.bytes() != 0 {
throw_ub_custom!(
inline_fluent!(
msg!(
"{$kind ->
[dealloc] deallocating
[realloc] reallocating
*[other] {\"\"}
} {$ptr} which does not point to the beginning of an object"
[dealloc] deallocating
[realloc] reallocating
*[other] {\"\"}
} {$ptr} which does not point to the beginning of an object"
),
ptr = format!("{ptr:?}"),
kind = "dealloc",
@ -394,13 +394,13 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
return Err(match self.tcx.try_get_global_alloc(alloc_id) {
Some(GlobalAlloc::Function { .. }) => {
err_ub_custom!(
inline_fluent!(
msg!(
"deallocating {$alloc_id}, which is {$kind ->
[fn] a function
[vtable] a vtable
[static_mem] static memory
*[other] {\"\"}
}"
[fn] a function
[vtable] a vtable
[static_mem] static memory
*[other] {\"\"}
}"
),
alloc_id = alloc_id,
kind = "fn",
@ -408,13 +408,13 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
}
Some(GlobalAlloc::VTable(..)) => {
err_ub_custom!(
inline_fluent!(
msg!(
"deallocating {$alloc_id}, which is {$kind ->
[fn] a function
[vtable] a vtable
[static_mem] static memory
*[other] {\"\"}
}"
[fn] a function
[vtable] a vtable
[static_mem] static memory
*[other] {\"\"}
}"
),
alloc_id = alloc_id,
kind = "vtable",
@ -422,13 +422,13 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
}
Some(GlobalAlloc::TypeId { .. }) => {
err_ub_custom!(
inline_fluent!(
msg!(
"deallocating {$alloc_id}, which is {$kind ->
[fn] a function
[vtable] a vtable
[static_mem] static memory
*[other] {\"\"}
}"
[fn] a function
[vtable] a vtable
[static_mem] static memory
*[other] {\"\"}
}"
),
alloc_id = alloc_id,
kind = "typeid",
@ -436,13 +436,13 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
}
Some(GlobalAlloc::Static(..) | GlobalAlloc::Memory(..)) => {
err_ub_custom!(
inline_fluent!(
msg!(
"deallocating {$alloc_id}, which is {$kind ->
[fn] a function
[vtable] a vtable
[static_mem] static memory
*[other] {\"\"}
}"
[fn] a function
[vtable] a vtable
[static_mem] static memory
*[other] {\"\"}
}"
),
alloc_id = alloc_id,
kind = "static_mem"
@ -454,14 +454,11 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
};
if alloc.mutability.is_not() {
throw_ub_custom!(
inline_fluent!("deallocating immutable allocation {$alloc}"),
alloc = alloc_id,
);
throw_ub_custom!(msg!("deallocating immutable allocation {$alloc}"), alloc = alloc_id,);
}
if alloc_kind != kind {
throw_ub_custom!(
inline_fluent!(
msg!(
"deallocating {$alloc}, which is {$alloc_kind} memory, using {$kind} deallocation operation"
),
alloc = alloc_id,
@ -472,7 +469,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
if let Some((size, align)) = old_size_and_align {
if size != alloc.size() || align != alloc.align {
throw_ub_custom!(
inline_fluent!(
msg!(
"incorrect layout on deallocation: {$alloc} has size {$size} and alignment {$align}, but gave size {$size_found} and alignment {$align_found}"
),
alloc = alloc_id,
@ -1593,7 +1590,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
if (src_offset <= dest_offset && src_offset + size > dest_offset)
|| (dest_offset <= src_offset && dest_offset + size > src_offset)
{
throw_ub_custom!(inline_fluent!(
throw_ub_custom!(msg!(
"`copy_nonoverlapping` called on overlapping ranges"
));
}

View file

@ -12,6 +12,7 @@
#![allow(rustc::potential_query_instability)]
#![cfg_attr(bootstrap, feature(assert_matches))]
#![cfg_attr(bootstrap, feature(cold_path))]
#![cfg_attr(test, feature(test))]
#![deny(unsafe_op_in_unsafe_fn)]
#![feature(allocator_api)]
#![feature(ascii_char)]
@ -30,7 +31,6 @@
#![feature(ptr_alignment_type)]
#![feature(rustc_attrs)]
#![feature(sized_hierarchy)]
#![feature(test)]
#![feature(thread_id_value)]
#![feature(trusted_len)]
#![feature(type_alias_impl_trait)]

View file

@ -7,8 +7,8 @@ Erroneous code example:
#![allow(internal_features)]
extern "C" {
#[lang = "cake"] // error: unknown external lang item: `cake`
fn cake();
#[lang = "copy"] // error: unknown external lang item: `copy`
fn copy();
}
```

View file

@ -6,9 +6,7 @@ use rustc_macros::Subdiagnostic;
use rustc_span::{Span, Symbol};
use crate::diagnostic::DiagLocation;
use crate::{
Diag, DiagCtxtHandle, Diagnostic, EmissionGuarantee, Level, Subdiagnostic, inline_fluent,
};
use crate::{Diag, DiagCtxtHandle, Diagnostic, EmissionGuarantee, Level, Subdiagnostic, msg};
impl IntoDiagArg for DiagLocation {
fn into_diag_arg(self, _: &mut Option<std::path::PathBuf>) -> DiagArgValue {
@ -43,48 +41,50 @@ impl<G: EmissionGuarantee> Diagnostic<'_, G> for TargetDataLayoutErrors<'_> {
fn into_diag(self, dcx: DiagCtxtHandle<'_>, level: Level) -> Diag<'_, G> {
match self {
TargetDataLayoutErrors::InvalidAddressSpace { addr_space, err, cause } => {
Diag::new(dcx, level, inline_fluent!("invalid address space `{$addr_space}` for `{$cause}` in \"data-layout\": {$err}"))
Diag::new(dcx, level, msg!("invalid address space `{$addr_space}` for `{$cause}` in \"data-layout\": {$err}"))
.with_arg("addr_space", addr_space)
.with_arg("cause", cause)
.with_arg("err", err)
}
TargetDataLayoutErrors::InvalidBits { kind, bit, cause, err } => {
Diag::new(dcx, level, inline_fluent!("invalid {$kind} `{$bit}` for `{$cause}` in \"data-layout\": {$err}"))
Diag::new(dcx, level, msg!("invalid {$kind} `{$bit}` for `{$cause}` in \"data-layout\": {$err}"))
.with_arg("kind", kind)
.with_arg("bit", bit)
.with_arg("cause", cause)
.with_arg("err", err)
}
TargetDataLayoutErrors::MissingAlignment { cause } => {
Diag::new(dcx, level, inline_fluent!("missing alignment for `{$cause}` in \"data-layout\""))
Diag::new(dcx, level, msg!("missing alignment for `{$cause}` in \"data-layout\""))
.with_arg("cause", cause)
}
TargetDataLayoutErrors::InvalidAlignment { cause, err } => {
Diag::new(dcx, level, inline_fluent!("invalid alignment for `{$cause}` in \"data-layout\": `{$align}` is {$err_kind ->
[not_power_of_two] not a power of 2
[too_large] too large
*[other] {\"\"}
}"))
Diag::new(dcx, level, msg!(
"invalid alignment for `{$cause}` in \"data-layout\": `{$align}` is {$err_kind ->
[not_power_of_two] not a power of 2
[too_large] too large
*[other] {\"\"}
}"
))
.with_arg("cause", cause)
.with_arg("err_kind", err.diag_ident())
.with_arg("align", err.align())
}
TargetDataLayoutErrors::InconsistentTargetArchitecture { dl, target } => {
Diag::new(dcx, level, inline_fluent!(
Diag::new(dcx, level, msg!(
"inconsistent target specification: \"data-layout\" claims architecture is {$dl}-endian, while \"target-endian\" is `{$target}`"
))
.with_arg("dl", dl).with_arg("target", target)
}
TargetDataLayoutErrors::InconsistentTargetPointerWidth { pointer_size, target } => {
Diag::new(dcx, level, inline_fluent!(
Diag::new(dcx, level, msg!(
"inconsistent target specification: \"data-layout\" claims pointers are {$pointer_size}-bit, while \"target-pointer-width\" is `{$target}`"
)).with_arg("pointer_size", pointer_size).with_arg("target", target)
}
TargetDataLayoutErrors::InvalidBitsSize { err } => {
Diag::new(dcx, level, inline_fluent!("{$err}")).with_arg("err", err)
Diag::new(dcx, level, msg!("{$err}")).with_arg("err", err)
}
TargetDataLayoutErrors::UnknownPointerSpecification { err } => {
Diag::new(dcx, level, inline_fluent!("unknown pointer specification `{$err}` in datalayout string"))
Diag::new(dcx, level, msg!("unknown pointer specification `{$err}` in datalayout string"))
.with_arg("err", err)
}
}

View file

@ -14,8 +14,6 @@
#![feature(negative_impls)]
#![feature(never_type)]
#![feature(rustc_attrs)]
#![feature(try_blocks)]
#![feature(yeet_expr)]
// tidy-alphabetical-end
extern crate self as rustc_errors;
@ -63,6 +61,7 @@ pub use rustc_error_messages::{
use rustc_hashes::Hash128;
use rustc_lint_defs::LintExpectationId;
pub use rustc_lint_defs::{Applicability, listify, pluralize};
pub use rustc_macros::msg;
use rustc_macros::{Decodable, Encodable};
pub use rustc_span::ErrorGuaranteed;
pub use rustc_span::fatal_error::{FatalError, FatalErrorMarker, catch_fatal_errors};
@ -1515,7 +1514,7 @@ impl DiagCtxtInner {
// the usual `Diag`/`DiagCtxt` level, so we must augment `bug`
// in a lower-level fashion.
bug.arg("level", bug.level);
let msg = inline_fluent!(
let msg = msg!(
"`flushed_delayed` got diagnostic with level {$level}, instead of the expected `DelayedBug`"
);
let msg = self.eagerly_translate_for_subdiag(&bug, msg); // after the `arg` call
@ -1559,13 +1558,13 @@ impl DelayedDiagInner {
// lower-level fashion.
let mut diag = self.inner;
let msg = match self.note.status() {
BacktraceStatus::Captured => inline_fluent!(
BacktraceStatus::Captured => msg!(
"delayed at {$emitted_at}
{$note}"
{$note}"
),
// Avoid the needless newline when no backtrace has been captured,
// the display impl should just be a single line.
_ => inline_fluent!("delayed at {$emitted_at} - {$note}"),
_ => msg!("delayed at {$emitted_at} - {$note}"),
};
diag.arg("emitted_at", diag.emitted_at.clone());
diag.arg("note", self.note);

View file

@ -90,14 +90,3 @@ impl Translator {
}
}
}
/// This macro creates a translatable `DiagMessage` from a literal string.
/// It should be used in places where a translatable message is needed, but struct diagnostics are undesired.
///
/// This is a macro because in the future we may want to globally register these messages.
#[macro_export]
macro_rules! inline_fluent {
($inline: literal) => {
rustc_errors::DiagMessage::Inline(std::borrow::Cow::Borrowed($inline))
};
}

View file

@ -919,7 +919,7 @@ impl SyntaxExtension {
fn get_hide_backtrace(attrs: &[hir::Attribute]) -> bool {
// FIXME(estebank): instead of reusing `#[rustc_diagnostic_item]` as a proxy, introduce a
// new attribute purely for this under the `#[diagnostic]` namespace.
ast::attr::find_by_name(attrs, sym::rustc_diagnostic_item).is_some()
find_attr!(attrs, AttributeKind::RustcDiagnosticItem(..))
}
/// Constructs a syntax extension with the given properties

View file

@ -15,7 +15,7 @@ use rustc_attr_parsing::{
AttributeParser, CFG_TEMPLATE, EvalConfigResult, ShouldEmit, eval_config_entry, parse_cfg,
};
use rustc_data_structures::flat_map_in_place::FlatMapInPlace;
use rustc_errors::inline_fluent;
use rustc_errors::msg;
use rustc_feature::{
ACCEPTED_LANG_FEATURES, EnabledLangFeature, EnabledLibFeature, Features, REMOVED_LANG_FEATURES,
UNSTABLE_LANG_FEATURES,
@ -433,14 +433,14 @@ impl<'a> StripUnconfigured<'a> {
&self.sess,
sym::stmt_expr_attributes,
attr.span,
inline_fluent!("attributes on expressions are experimental"),
msg!("attributes on expressions are experimental"),
);
if attr.is_doc_comment() {
err.help(if attr.style == AttrStyle::Outer {
inline_fluent!("`///` is used for outer documentation comments; for a plain comment, use `//`")
msg!("`///` is used for outer documentation comments; for a plain comment, use `//`")
} else {
inline_fluent!("`//!` is used for inner documentation comments; for a plain comment, use `//` by removing the `!` or inserting a space in between them: `// !`")
msg!("`//!` is used for inner documentation comments; for a plain comment, use `//` by removing the `!` or inserting a space in between them: `// !`")
});
}

View file

@ -19,7 +19,7 @@ use rustc_attr_parsing::{
};
use rustc_data_structures::flat_map_in_place::FlatMapInPlace;
use rustc_data_structures::stack::ensure_sufficient_stack;
use rustc_errors::{PResult, inline_fluent};
use rustc_errors::{PResult, msg};
use rustc_feature::Features;
use rustc_hir::Target;
use rustc_hir::def::MacroKinds;
@ -1051,7 +1051,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
self.sess,
sym::proc_macro_hygiene,
item.span,
inline_fluent!("file modules in proc macro input are unstable"),
msg!("file modules in proc macro input are unstable"),
)
.emit();
}

View file

@ -11,32 +11,11 @@ use {rustc_ast as ast, rustc_proc_macro as pm};
use crate::base::{self, *};
use crate::{errors, proc_macro_server};
struct MessagePipe<T> {
tx: std::sync::mpsc::SyncSender<T>,
rx: std::sync::mpsc::Receiver<T>,
}
impl<T> pm::bridge::server::MessagePipe<T> for MessagePipe<T> {
fn new() -> (Self, Self) {
let (tx1, rx1) = std::sync::mpsc::sync_channel(1);
let (tx2, rx2) = std::sync::mpsc::sync_channel(1);
(MessagePipe { tx: tx1, rx: rx2 }, MessagePipe { tx: tx2, rx: rx1 })
}
fn send(&mut self, value: T) {
self.tx.send(value).unwrap();
}
fn recv(&mut self) -> Option<T> {
self.rx.recv().ok()
}
}
fn exec_strategy(sess: &Session) -> impl pm::bridge::server::ExecutionStrategy + 'static {
pm::bridge::server::MaybeCrossThread::<MessagePipe<_>>::new(
sess.opts.unstable_opts.proc_macro_execution_strategy
pm::bridge::server::MaybeCrossThread {
cross_thread: sess.opts.unstable_opts.proc_macro_execution_strategy
== ProcMacroExecutionStrategy::CrossThread,
)
}
}
pub struct BangProcMacro {

View file

@ -862,13 +862,6 @@ pub static BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
register_tool, CrateLevel, template!(List: &["tool1, tool2, ..."]), DuplicatesOk,
EncodeCrossCrate::No, experimental!(register_tool),
),
// lang-team MCP 147
gated!(
deprecated_safe, Normal, template!(List: &[r#"since = "version", note = "...""#]), ErrorFollowing,
EncodeCrossCrate::Yes, experimental!(deprecated_safe),
),
// `#[cfi_encoding = ""]`
gated!(
cfi_encoding, Normal, template!(NameValueStr: "encoding"), ErrorPreceding,

View file

@ -102,6 +102,8 @@ declare_features! (
/// Allows default type parameters to influence type inference.
(removed, default_type_parameter_fallback, "1.82.0", Some(27336),
Some("never properly implemented; requires significant design work"), 127655),
/// Allows using `#[deprecated_safe]` to deprecate the safeness of a function or trait
(removed, deprecated_safe, "CURRENT_RUSTC_VERSION", Some(94978), Some("never properly implemented, in the way of attribute refactor"), 152554),
/// Allows deriving traits as per `SmartPointer` specification
(removed, derive_smart_pointer, "1.84.0", Some(123430), Some("replaced by `CoercePointee`"), 131284),
/// Tells rustdoc to automatically generate `#[doc(cfg(...))]`.

View file

@ -454,8 +454,6 @@ declare_features! (
/// Allows the use of default values on struct definitions and the construction of struct
/// literals with the functional update syntax without a base.
(unstable, default_field_values, "1.85.0", Some(132162)),
/// Allows using `#[deprecated_safe]` to deprecate the safeness of a function or trait
(unstable, deprecated_safe, "1.61.0", Some(94978)),
/// Allows having using `suggestion` in the `#[deprecated]` attribute.
(unstable, deprecated_suggestion, "1.61.0", Some(94785)),
/// Allows deref patterns.

View file

@ -8,6 +8,7 @@ use rustc_ast::token::DocFragmentKind;
use rustc_ast::{AttrStyle, Path, ast};
use rustc_data_structures::fx::FxIndexMap;
use rustc_error_messages::{DiagArgValue, IntoDiagArg};
use rustc_hir::LangItem;
use rustc_macros::{Decodable, Encodable, HashStable_Generic, PrintAttribute};
use rustc_span::def_id::DefId;
use rustc_span::hygiene::Transparency;
@ -953,6 +954,9 @@ pub enum AttributeKind {
/// Represents `#[instruction_set]`
InstructionSet(InstructionSetAttr),
/// Represents `#[lang]`
Lang(LangItem, Span),
/// Represents `#[link]`.
Link(ThinVec<LinkEntry>, Span),
@ -1156,6 +1160,9 @@ pub enum AttributeKind {
/// Represents `#[rustc_deprecated_safe_2024]`
RustcDeprecatedSafe2024 { suggestion: Symbol },
/// Represents `#[rustc_diagnostic_item]`
RustcDiagnosticItem(Symbol),
/// Represents `#[rustc_dummy]`.
RustcDummy,
@ -1288,6 +1295,9 @@ pub enum AttributeKind {
/// Represents `#[rustc_preserve_ub_checks]`
RustcPreserveUbChecks,
/// Represents `#[rustc_proc_macro_decls]`
RustcProcMacroDecls,
/// Represents `#[rustc_pub_transparent]` (used by the `repr_transparent_external_private_fields` lint).
RustcPubTransparent(Span),
@ -1329,6 +1339,9 @@ pub enum AttributeKind {
/// Represents `#[rustc_symbol_name]`
RustcSymbolName(Span),
/// Represents `#[rustc_test_marker]`
RustcTestMarker(Symbol),
/// Represents `#[rustc_then_this_would_need]`
RustcThenThisWouldNeed(Span, ThinVec<Ident>),

View file

@ -50,6 +50,7 @@ impl AttributeKind {
Ignore { .. } => No,
Inline(..) => No,
InstructionSet(..) => No,
Lang(..) => Yes,
Link(..) => No,
LinkName { .. } => Yes, // Needed for rustdoc
LinkOrdinal { .. } => No,
@ -113,6 +114,7 @@ impl AttributeKind {
RustcDelayedBugFromInsideQuery => No,
RustcDenyExplicitImpl(..) => No,
RustcDeprecatedSafe2024 { .. } => Yes,
RustcDiagnosticItem(..) => Yes,
RustcDummy => No,
RustcDumpDefParents => No,
RustcDumpItemBounds => No,
@ -156,6 +158,7 @@ impl AttributeKind {
RustcPassByValue(..) => Yes,
RustcPassIndirectlyInNonRusticAbis(..) => No,
RustcPreserveUbChecks => No,
RustcProcMacroDecls => No,
RustcPubTransparent(..) => Yes,
RustcReallocator => No,
RustcRegions => No,
@ -168,6 +171,7 @@ impl AttributeKind {
RustcStdInternalSymbol(..) => No,
RustcStrictCoherence(..) => Yes,
RustcSymbolName(..) => Yes,
RustcTestMarker(..) => No,
RustcThenThisWouldNeed(..) => No,
RustcTrivialFieldReads => Yes,
RustcUnsafeSpecializationMarker(..) => No,

View file

@ -990,7 +990,7 @@ pub enum LifetimeRes {
/// `'static` lifetime.
Static,
/// Resolution failure.
Error,
Error(rustc_span::ErrorGuaranteed),
/// HACK: This is used to recover the NodeId of an elided lifetime.
ElidedAnchor { start: NodeId, end: NodeId },
}

View file

@ -238,7 +238,7 @@ pub enum LifetimeKind {
/// Indicates an error during lowering (usually `'_` in wrong place)
/// that was already reported.
Error,
Error(ErrorGuaranteed),
/// User wrote an anonymous lifetime, either `'_` or nothing (which gets
/// converted to `'_`). The semantics of this lifetime should be inferred
@ -258,7 +258,7 @@ impl LifetimeKind {
// -- but this is because, as far as the code in the compiler is
// concerned -- `Fresh` variants act equivalently to "some fresh name".
// They correspond to early-bound regions on an impl, in other words.
LifetimeKind::Error | LifetimeKind::Param(..) | LifetimeKind::Static => false,
LifetimeKind::Error(..) | LifetimeKind::Param(..) | LifetimeKind::Static => false,
}
}
}

View file

@ -7,12 +7,12 @@
//! * Traits that represent operators; e.g., `Add`, `Sub`, `Index`.
//! * Functions called by the compiler itself.
use rustc_ast::attr::AttributeExt;
use rustc_data_structures::fx::FxIndexMap;
use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
use rustc_macros::{BlobDecodable, Encodable, HashStable_Generic};
use rustc_span::{Span, Symbol, kw, sym};
use rustc_macros::{BlobDecodable, Encodable, HashStable_Generic, PrintAttribute};
use rustc_span::{Symbol, kw, sym};
use crate::attrs::PrintAttribute;
use crate::def_id::DefId;
use crate::{MethodKind, Target};
@ -75,7 +75,7 @@ macro_rules! language_item_table {
$( $(#[$attr:meta])* $variant:ident, $module:ident :: $name:ident, $method:ident, $target:expr, $generics:expr; )*
) => {
/// A representation of all the valid lang items in Rust.
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, Encodable, BlobDecodable)]
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, Encodable, BlobDecodable, PrintAttribute)]
pub enum LangItem {
$(
#[doc = concat!("The `", stringify!($name), "` lang item.")]
@ -150,18 +150,6 @@ impl<CTX> HashStable<CTX> for LangItem {
}
}
/// Extracts the first `lang = "$name"` out of a list of attributes.
/// The `#[panic_handler]` attribute is also extracted out when found.
pub fn extract(attrs: &[impl AttributeExt]) -> Option<(Symbol, Span)> {
attrs.iter().find_map(|attr| {
Some(match attr {
_ if attr.has_name(sym::lang) => (attr.value_str()?, attr.span()),
_ if attr.has_name(sym::panic_handler) => (sym::panic_impl, attr.span()),
_ => return None,
})
})
}
language_item_table! {
// Variant name, Name, Getter method name, Target Generic requirements;
Sized, sym::sized, sized_trait, Target::Trait, GenericRequirement::Exact(0);

View file

@ -5,9 +5,7 @@ use hir::intravisit::{self, Visitor};
use rustc_abi::{ExternAbi, ScalableElt};
use rustc_data_structures::fx::{FxHashSet, FxIndexMap, FxIndexSet};
use rustc_errors::codes::*;
use rustc_errors::{
Applicability, ErrorGuaranteed, inline_fluent, pluralize, struct_span_code_err,
};
use rustc_errors::{Applicability, ErrorGuaranteed, msg, pluralize, struct_span_code_err};
use rustc_hir::attrs::{AttributeKind, EiiDecl, EiiImpl, EiiImplResolution};
use rustc_hir::def::{DefKind, Res};
use rustc_hir::def_id::{DefId, LocalDefId};
@ -1771,7 +1769,7 @@ fn check_method_receiver<'tcx>(
the `arbitrary_self_types` feature",
),
)
.with_help(inline_fluent!("consider changing to `self`, `&self`, `&mut self`, or a type implementing `Receiver` such as `self: Box<Self>`, `self: Rc<Self>`, or `self: Arc<Self>`"))
.with_help(msg!("consider changing to `self`, `&self`, `&mut self`, or a type implementing `Receiver` such as `self: Box<Self>`, `self: Rc<Self>`, or `self: Arc<Self>`"))
.emit()
}
None | Some(ArbitrarySelfTypesLevel::Basic)
@ -1795,7 +1793,7 @@ fn check_method_receiver<'tcx>(
the `arbitrary_self_types_pointers` feature",
),
)
.with_help(inline_fluent!("consider changing to `self`, `&self`, `&mut self`, or a type implementing `Receiver` such as `self: Box<Self>`, `self: Rc<Self>`, or `self: Arc<Self>`"))
.with_help(msg!("consider changing to `self`, `&self`, `&mut self`, or a type implementing `Receiver` such as `self: Box<Self>`, `self: Rc<Self>`, or `self: Arc<Self>`"))
.emit()
}
_ =>

View file

@ -1063,6 +1063,70 @@ fn lower_fn_sig_recovering_infer_ret_ty<'tcx>(
)
}
/// Convert `ReLateParam`s in `value` back into `ReBound`s and bind it with `bound_vars`.
fn late_param_regions_to_bound<'tcx, T>(
tcx: TyCtxt<'tcx>,
scope: DefId,
bound_vars: &'tcx ty::List<ty::BoundVariableKind<'tcx>>,
value: T,
) -> ty::Binder<'tcx, T>
where
T: ty::TypeFoldable<TyCtxt<'tcx>>,
{
let value = fold_regions(tcx, value, |r, debruijn| match r.kind() {
ty::ReLateParam(lp) => {
// Should be in scope, otherwise inconsistency happens somewhere.
assert_eq!(lp.scope, scope);
let br = match lp.kind {
// These variants preserve the bound var index.
kind @ (ty::LateParamRegionKind::Anon(idx)
| ty::LateParamRegionKind::NamedAnon(idx, _)) => {
let idx = idx as usize;
let var = ty::BoundVar::from_usize(idx);
let Some(ty::BoundVariableKind::Region(kind)) = bound_vars.get(idx).copied()
else {
bug!("unexpected late-bound region {kind:?} for bound vars {bound_vars:?}");
};
ty::BoundRegion { var, kind }
}
// For named regions, look up the corresponding bound var.
ty::LateParamRegionKind::Named(def_id) => bound_vars
.iter()
.enumerate()
.find_map(|(idx, bv)| match bv {
ty::BoundVariableKind::Region(kind @ ty::BoundRegionKind::Named(did))
if did == def_id =>
{
Some(ty::BoundRegion { var: ty::BoundVar::from_usize(idx), kind })
}
_ => None,
})
.unwrap(),
ty::LateParamRegionKind::ClosureEnv => bound_vars
.iter()
.enumerate()
.find_map(|(idx, bv)| match bv {
ty::BoundVariableKind::Region(kind @ ty::BoundRegionKind::ClosureEnv) => {
Some(ty::BoundRegion { var: ty::BoundVar::from_usize(idx), kind })
}
_ => None,
})
.unwrap(),
};
ty::Region::new_bound(tcx, debruijn, br)
}
_ => r,
});
ty::Binder::bind_with_vars(value, bound_vars)
}
fn recover_infer_ret_ty<'tcx>(
icx: &ItemCtxt<'tcx>,
infer_ret_ty: &'tcx hir::Ty<'tcx>,
@ -1138,13 +1202,22 @@ fn recover_infer_ret_ty<'tcx>(
);
}
let guar = diag.emit();
ty::Binder::dummy(tcx.mk_fn_sig(
// If we return a dummy binder here, we can ICE later in borrowck when it encounters
// `ReLateParam` regions (e.g. in a local type annotation) which weren't registered via the
// signature binder. See #135845.
let bound_vars = tcx.late_bound_vars(hir_id);
let scope = def_id.to_def_id();
let fn_sig = tcx.mk_fn_sig(
fn_sig.inputs().iter().copied(),
recovered_ret_ty.unwrap_or_else(|| Ty::new_error(tcx, guar)),
fn_sig.c_variadic,
fn_sig.safety,
fn_sig.abi,
))
);
late_param_regions_to_bound(tcx, scope, bound_vars, fn_sig)
}
pub fn suggest_impl_trait<'tcx>(

View file

@ -663,7 +663,7 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> {
LifetimeKind::Param(def_id) => {
self.resolve_lifetime_ref(def_id, lt);
}
LifetimeKind::Error => {}
LifetimeKind::Error(..) => {}
LifetimeKind::ImplicitObjectLifetimeDefault
| LifetimeKind::Infer
| LifetimeKind::Static => {
@ -804,7 +804,7 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> {
// If the user wrote an explicit name, use that.
self.visit_lifetime(&*lifetime);
}
LifetimeKind::Error => {}
LifetimeKind::Error(..) => {}
}
}
hir::TyKind::Ref(lifetime_ref, ref mt) => {
@ -891,8 +891,10 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> {
hir::LifetimeKind::Param(param_def_id) => {
self.resolve_lifetime_ref(param_def_id, lifetime_ref)
}
// If we've already reported an error, just ignore `lifetime_ref`.
hir::LifetimeKind::Error => {}
// Keep track of lifetimes about which errors have already been reported
hir::LifetimeKind::Error(guar) => {
self.insert_lifetime(lifetime_ref, ResolvedArg::Error(guar))
}
// Those will be resolved by typechecking.
hir::LifetimeKind::ImplicitObjectLifetimeDefault | hir::LifetimeKind::Infer => {}
}

View file

@ -4,7 +4,7 @@ use rustc_abi::ExternAbi;
use rustc_errors::codes::*;
use rustc_errors::{
Applicability, Diag, DiagCtxtHandle, DiagSymbolList, Diagnostic, EmissionGuarantee, Level,
MultiSpan, inline_fluent, listify,
MultiSpan, listify, msg,
};
use rustc_hir::limit::Limit;
use rustc_macros::{Diagnostic, LintDiagnostic, Subdiagnostic};
@ -444,7 +444,7 @@ impl<'a, G: EmissionGuarantee> Diagnostic<'a, G> for MissingGenericParams {
let mut err = Diag::new(
dcx,
level,
inline_fluent!(
msg!(
"the {$descr} {$parameterCount ->
[one] parameter
*[other] parameters
@ -455,7 +455,7 @@ impl<'a, G: EmissionGuarantee> Diagnostic<'a, G> for MissingGenericParams {
err.code(E0393);
err.span_label(
self.def_span,
inline_fluent!(
msg!(
"{$descr} {$parameterCount ->
[one] parameter
*[other] parameters
@ -511,7 +511,7 @@ impl<'a, G: EmissionGuarantee> Diagnostic<'a, G> for MissingGenericParams {
// least we can clue them to the correct syntax `Trait</* Term */>`.
err.span_suggestion_verbose(
self.span.shrink_to_hi(),
inline_fluent!(
msg!(
"explicitly specify the {$descr} {$parameterCount ->
[one] parameter
*[other] parameters
@ -533,7 +533,7 @@ impl<'a, G: EmissionGuarantee> Diagnostic<'a, G> for MissingGenericParams {
if !suggested {
err.span_label(
self.span,
inline_fluent!(
msg!(
"missing {$parameterCount ->
[one] reference
*[other] references
@ -542,7 +542,7 @@ impl<'a, G: EmissionGuarantee> Diagnostic<'a, G> for MissingGenericParams {
);
}
err.note(inline_fluent!(
err.note(msg!(
"because the parameter {$parameterCount ->
[one] default references
*[other] defaults reference

View file

@ -451,17 +451,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
} else {
let reason =
if let hir::LifetimeKind::ImplicitObjectLifetimeDefault = lifetime.kind {
if let hir::Node::Ty(hir::Ty {
kind: hir::TyKind::Ref(parent_lifetime, _),
..
}) = tcx.parent_hir_node(hir_id)
&& tcx.named_bound_var(parent_lifetime.hir_id).is_none()
{
// Parent lifetime must have failed to resolve. Don't emit a redundant error.
RegionInferReason::ExplicitObjectLifetime
} else {
RegionInferReason::ObjectLifetimeDefault(span.shrink_to_hi())
}
RegionInferReason::ObjectLifetimeDefault(span.shrink_to_hi())
} else {
RegionInferReason::ExplicitObjectLifetime
};

View file

@ -3,8 +3,8 @@ use rustc_data_structures::sorted_map::SortedMap;
use rustc_data_structures::unord::UnordMap;
use rustc_errors::codes::*;
use rustc_errors::{
Applicability, Diag, ErrorGuaranteed, MultiSpan, SuggestionStyle, inline_fluent, listify,
pluralize, struct_span_code_err,
Applicability, Diag, ErrorGuaranteed, MultiSpan, SuggestionStyle, listify, msg, pluralize,
struct_span_code_err,
};
use rustc_hir::def::{CtorOf, DefKind, Res};
use rustc_hir::def_id::DefId;
@ -304,7 +304,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
// was also not an exact match, so we also suggest changing it.
err.span_suggestion_verbose(
assoc_ident.span,
inline_fluent!("...and changing the associated {$assoc_kind} name"),
msg!("...and changing the associated {$assoc_kind} name"),
suggested_name,
Applicability::MaybeIncorrect,
);

View file

@ -35,11 +35,10 @@ use rustc_infer::infer::{InferCtxt, TyCtxtInferExt};
use rustc_infer::traits::DynCompatibilityViolation;
use rustc_macros::{TypeFoldable, TypeVisitable};
use rustc_middle::middle::stability::AllowUnstable;
use rustc_middle::mir::interpret::LitToConstInput;
use rustc_middle::ty::print::PrintPolyTraitRefExt as _;
use rustc_middle::ty::{
self, Const, GenericArgKind, GenericArgsRef, GenericParamDefKind, Ty, TyCtxt,
TypeSuperFoldable, TypeVisitableExt, TypingMode, Upcast, fold_regions,
self, Const, GenericArgKind, GenericArgsRef, GenericParamDefKind, LitToConstInput, Ty, TyCtxt,
TypeSuperFoldable, TypeVisitableExt, TypingMode, Upcast, const_lit_matches_ty, fold_regions,
};
use rustc_middle::{bug, span_bug};
use rustc_session::lint::builtin::AMBIGUOUS_ASSOCIATED_ITEMS;
@ -2465,7 +2464,13 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
let parent_did = tcx.parent(*def_id);
(tcx.adt_def(parent_did), fn_args, parent_did)
}
_ => return non_adt_or_variant_res(),
_ => {
let e = self.dcx().span_err(
span,
"complex const arguments must be placed inside of a `const` block",
);
return Const::new_error(tcx, e);
}
};
let variant_def = adt_def.variant_with_id(variant_did);
@ -2803,8 +2808,17 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
span: Span,
) -> Const<'tcx> {
let tcx = self.tcx();
if let LitKind::Err(guar) = *kind {
return ty::Const::new_error(tcx, guar);
}
let input = LitToConstInput { lit: *kind, ty, neg };
tcx.at(span).lit_to_const(input)
match tcx.at(span).lit_to_const(input) {
Some(value) => ty::Const::new_value(tcx, value.valtree, value.ty),
None => {
let e = tcx.dcx().span_err(span, "type annotations needed for the literal");
ty::Const::new_error(tcx, e)
}
}
}
#[instrument(skip(self), level = "debug")]
@ -2833,11 +2847,15 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
_ => None,
};
lit_input
// Allow the `ty` to be an alias type, though we cannot handle it here, we just go through
// the more expensive anon const code path.
.filter(|l| !l.ty.has_aliases())
.map(|l| tcx.at(expr.span).lit_to_const(l))
lit_input.and_then(|l| {
if const_lit_matches_ty(tcx, &l.lit, l.ty, l.neg) {
tcx.at(expr.span)
.lit_to_const(l)
.map(|value| ty::Const::new_value(tcx, value.valtree, value.ty))
} else {
None
}
})
}
fn require_type_const_attribute(

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