Merge pull request #4859 from rust-lang/rustup-2026-02-15
Automatic Rustup
This commit is contained in:
commit
1f39d1f74f
537 changed files with 8823 additions and 5896 deletions
|
|
@ -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]]
|
||||
|
|
|
|||
|
|
@ -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))]
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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 };
|
||||
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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))
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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>>,
|
||||
|
|
|
|||
|
|
@ -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> {
|
||||
|
|
|
|||
|
|
@ -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");
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
);
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
///
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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)]
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@
|
|||
],
|
||||
"ignorePaths": [
|
||||
"src/intrinsic/archs.rs",
|
||||
"src/intrinsic/old_archs.rs",
|
||||
"src/intrinsic/llvm.rs"
|
||||
],
|
||||
"ignoreRegExpList": [
|
||||
|
|
|
|||
|
|
@ -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 }}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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",
|
||||
]
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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"]
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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-*-* } } */
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -1 +1 @@
|
|||
0081ca6631abdfa02bf42bc85aaf507b8a0e6beb
|
||||
efdd0a7290c22f5438d7c5380105d353ee3e8518
|
||||
|
|
|
|||
|
|
@ -1,3 +1,3 @@
|
|||
[toolchain]
|
||||
channel = "nightly-2025-12-20"
|
||||
channel = "nightly-2026-02-14"
|
||||
components = ["rust-src", "rustc-dev", "llvm-tools-preview"]
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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))
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -151,7 +151,6 @@ impl<'gcc, 'tcx> CodegenCx<'gcc, 'tcx> {
|
|||
///
|
||||
/// If there’s 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,
|
||||
|
|
|
|||
|
|
@ -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
|
|
@ -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");
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
1390
compiler/rustc_codegen_gcc/src/intrinsic/old_archs.rs
Normal file
1390
compiler/rustc_codegen_gcc/src/intrinsic/old_archs.rs
Normal file
File diff suppressed because it is too large
Load diff
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -0,0 +1 @@
|
|||
tests/ui/simd/intrinsic/splat.rs
|
||||
|
|
@ -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
|
||||
|
|
|
|||
38
compiler/rustc_codegen_gcc/tests/run/call-llvm-intrinsics.rs
Normal file
38
compiler/rustc_codegen_gcc/tests/run/call-llvm-intrinsics.rs
Normal 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();
|
||||
}
|
||||
102
compiler/rustc_codegen_gcc/tests/run/simd-ffi.rs
Normal file
102
compiler/rustc_codegen_gcc/tests/run/simd-ffi.rs
Normal 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() {}
|
||||
27
compiler/rustc_codegen_gcc/tests/run/unreachable-function.rs
Normal file
27
compiler/rustc_codegen_gcc/tests/run/unreachable-function.rs
Normal 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);
|
||||
}
|
||||
|
|
@ -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())
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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(|| ...)`"
|
||||
));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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(),
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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(),
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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());
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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)]
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
}
|
||||
```
|
||||
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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))
|
||||
};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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: `// !`")
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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(...))]`.
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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>),
|
||||
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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 },
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
}
|
||||
_ =>
|
||||
|
|
|
|||
|
|
@ -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>(
|
||||
|
|
|
|||
|
|
@ -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 => {}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
};
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
);
|
||||
|
|
|
|||
|
|
@ -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
Loading…
Add table
Add a link
Reference in a new issue