commit
248ffb67dc
834 changed files with 15927 additions and 10890 deletions
15
Cargo.lock
15
Cargo.lock
|
|
@ -630,7 +630,7 @@ checksum = "a1d728cc89cf3aee9ff92b05e62b19ee65a02b5702cff7d5a377e32c6ae29d8d"
|
|||
|
||||
[[package]]
|
||||
name = "clippy"
|
||||
version = "0.1.94"
|
||||
version = "0.1.95"
|
||||
dependencies = [
|
||||
"anstream",
|
||||
"askama",
|
||||
|
|
@ -657,7 +657,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "clippy_config"
|
||||
version = "0.1.94"
|
||||
version = "0.1.95"
|
||||
dependencies = [
|
||||
"clippy_utils",
|
||||
"itertools",
|
||||
|
|
@ -681,7 +681,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "clippy_lints"
|
||||
version = "0.1.94"
|
||||
version = "0.1.95"
|
||||
dependencies = [
|
||||
"arrayvec",
|
||||
"cargo_metadata 0.18.1",
|
||||
|
|
@ -713,7 +713,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "clippy_utils"
|
||||
version = "0.1.94"
|
||||
version = "0.1.95"
|
||||
dependencies = [
|
||||
"arrayvec",
|
||||
"itertools",
|
||||
|
|
@ -1117,7 +1117,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "declare_clippy_lint"
|
||||
version = "0.1.94"
|
||||
version = "0.1.95"
|
||||
|
||||
[[package]]
|
||||
name = "derive-where"
|
||||
|
|
@ -3356,9 +3356,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "rustc-demangle"
|
||||
version = "0.1.26"
|
||||
version = "0.1.27"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "56f7d92ca342cea22a06f2121d944b4fd82af56988c270852495420f961d4ace"
|
||||
checksum = "b50b8869d9fc858ce7266cce0194bd74df58b9d0e3f6df3a9fc8eb470d95c09d"
|
||||
|
||||
[[package]]
|
||||
name = "rustc-hash"
|
||||
|
|
@ -3865,7 +3865,6 @@ dependencies = [
|
|||
"rustc_fluent_macro",
|
||||
"rustc_hashes",
|
||||
"rustc_index",
|
||||
"rustc_lexer",
|
||||
"rustc_lint_defs",
|
||||
"rustc_macros",
|
||||
"rustc_serialize",
|
||||
|
|
|
|||
|
|
@ -62,9 +62,9 @@ Stabilized APIs
|
|||
- [`<uN>::unchecked_shl`](https://doc.rust-lang.org/stable/std/primitive.usize.html#method.unchecked_shl)
|
||||
- [`<uN>::unchecked_shr`](https://doc.rust-lang.org/stable/std/primitive.usize.html#method.unchecked_shr)
|
||||
- [`<[T]>::as_array`](https://doc.rust-lang.org/stable/std/primitive.slice.html#method.as_array)
|
||||
- [`<[T]>::as_array_mut`](https://doc.rust-lang.org/stable/std/primitive.slice.html#method.as_mut_array)
|
||||
- [`<[T]>::as_mut_array`](https://doc.rust-lang.org/stable/std/primitive.slice.html#method.as_mut_array)
|
||||
- [`<*const [T]>::as_array`](https://doc.rust-lang.org/stable/std/primitive.pointer.html#method.as_array)
|
||||
- [`<*mut [T]>::as_array_mut`](https://doc.rust-lang.org/stable/std/primitive.pointer.html#method.as_mut_array)
|
||||
- [`<*mut [T]>::as_mut_array`](https://doc.rust-lang.org/stable/std/primitive.pointer.html#method.as_mut_array)
|
||||
- [`VecDeque::pop_front_if`](https://doc.rust-lang.org/stable/std/collections/struct.VecDeque.html#method.pop_front_if)
|
||||
- [`VecDeque::pop_back_if`](https://doc.rust-lang.org/stable/std/collections/struct.VecDeque.html#method.pop_back_if)
|
||||
- [`Duration::from_nanos_u128`](https://doc.rust-lang.org/stable/std/time/struct.Duration.html#method.from_nanos_u128)
|
||||
|
|
|
|||
|
|
@ -27,6 +27,7 @@ pub enum CanonAbi {
|
|||
C,
|
||||
Rust,
|
||||
RustCold,
|
||||
RustPreserveNone,
|
||||
|
||||
/// An ABI that rustc does not know how to call or define.
|
||||
Custom,
|
||||
|
|
@ -54,7 +55,7 @@ pub enum CanonAbi {
|
|||
impl CanonAbi {
|
||||
pub fn is_rustic_abi(self) -> bool {
|
||||
match self {
|
||||
CanonAbi::Rust | CanonAbi::RustCold => true,
|
||||
CanonAbi::Rust | CanonAbi::RustCold | CanonAbi::RustPreserveNone => true,
|
||||
CanonAbi::C
|
||||
| CanonAbi::Custom
|
||||
| CanonAbi::Arm(_)
|
||||
|
|
@ -74,6 +75,7 @@ impl fmt::Display for CanonAbi {
|
|||
CanonAbi::C => ExternAbi::C { unwind: false },
|
||||
CanonAbi::Rust => ExternAbi::Rust,
|
||||
CanonAbi::RustCold => ExternAbi::RustCold,
|
||||
CanonAbi::RustPreserveNone => ExternAbi::RustPreserveNone,
|
||||
CanonAbi::Custom => ExternAbi::Custom,
|
||||
CanonAbi::Arm(arm_call) => match arm_call {
|
||||
ArmCall::Aapcs => ExternAbi::Aapcs { unwind: false },
|
||||
|
|
|
|||
|
|
@ -42,6 +42,13 @@ pub enum ExternAbi {
|
|||
/// in a platform-agnostic way.
|
||||
RustInvalid,
|
||||
|
||||
/// Preserves no registers.
|
||||
///
|
||||
/// Note, that this ABI is not stable in the registers it uses, is intended as an optimization
|
||||
/// and may fall-back to a more conservative calling convention if the backend does not support
|
||||
/// forcing callers to save all registers.
|
||||
RustPreserveNone,
|
||||
|
||||
/// Unstable impl detail that directly uses Rust types to describe the ABI to LLVM.
|
||||
/// Even normally-compatible Rust types can become ABI-incompatible with this ABI!
|
||||
Unadjusted,
|
||||
|
|
@ -163,6 +170,7 @@ abi_impls! {
|
|||
RustCall =><= "rust-call",
|
||||
RustCold =><= "rust-cold",
|
||||
RustInvalid =><= "rust-invalid",
|
||||
RustPreserveNone =><= "rust-preserve-none",
|
||||
Stdcall { unwind: false } =><= "stdcall",
|
||||
Stdcall { unwind: true } =><= "stdcall-unwind",
|
||||
System { unwind: false } =><= "system",
|
||||
|
|
@ -243,7 +251,7 @@ impl ExternAbi {
|
|||
/// - are subject to change between compiler versions
|
||||
pub fn is_rustic_abi(self) -> bool {
|
||||
use ExternAbi::*;
|
||||
matches!(self, Rust | RustCall | RustCold)
|
||||
matches!(self, Rust | RustCall | RustCold | RustPreserveNone)
|
||||
}
|
||||
|
||||
/// Returns whether the ABI supports C variadics. This only controls whether we allow *imports*
|
||||
|
|
@ -315,7 +323,8 @@ impl ExternAbi {
|
|||
| Self::Thiscall { .. }
|
||||
| Self::Vectorcall { .. }
|
||||
| Self::SysV64 { .. }
|
||||
| Self::Win64 { .. } => true,
|
||||
| Self::Win64 { .. }
|
||||
| Self::RustPreserveNone => true,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3626,6 +3626,7 @@ impl Item {
|
|||
pub fn opt_generics(&self) -> Option<&Generics> {
|
||||
match &self.kind {
|
||||
ItemKind::ExternCrate(..)
|
||||
| ItemKind::ConstBlock(_)
|
||||
| ItemKind::Use(_)
|
||||
| ItemKind::Mod(..)
|
||||
| ItemKind::ForeignMod(_)
|
||||
|
|
@ -3895,6 +3896,17 @@ impl ConstItemRhs {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Encodable, Decodable, Debug, Walkable)]
|
||||
pub struct ConstBlockItem {
|
||||
pub id: NodeId,
|
||||
pub span: Span,
|
||||
pub block: Box<Block>,
|
||||
}
|
||||
|
||||
impl ConstBlockItem {
|
||||
pub const IDENT: Ident = Ident { name: kw::Underscore, span: DUMMY_SP };
|
||||
}
|
||||
|
||||
// Adding a new variant? Please update `test_item` in `tests/ui/macros/stringify.rs`.
|
||||
#[derive(Clone, Encodable, Decodable, Debug)]
|
||||
pub enum ItemKind {
|
||||
|
|
@ -3914,6 +3926,11 @@ pub enum ItemKind {
|
|||
///
|
||||
/// E.g., `const FOO: i32 = 42;`.
|
||||
Const(Box<ConstItem>),
|
||||
/// A module-level const block.
|
||||
/// Equivalent to `const _: () = const { ... };`.
|
||||
///
|
||||
/// E.g., `const { assert!(true) }`.
|
||||
ConstBlock(ConstBlockItem),
|
||||
/// A function declaration (`fn`).
|
||||
///
|
||||
/// E.g., `fn foo(bar: usize) -> usize { .. }`.
|
||||
|
|
@ -3990,6 +4007,8 @@ impl ItemKind {
|
|||
| ItemKind::MacroDef(ident, _)
|
||||
| ItemKind::Delegation(box Delegation { ident, .. }) => Some(ident),
|
||||
|
||||
ItemKind::ConstBlock(_) => Some(ConstBlockItem::IDENT),
|
||||
|
||||
ItemKind::Use(_)
|
||||
| ItemKind::ForeignMod(_)
|
||||
| ItemKind::GlobalAsm(_)
|
||||
|
|
@ -4003,9 +4022,9 @@ impl ItemKind {
|
|||
pub fn article(&self) -> &'static str {
|
||||
use ItemKind::*;
|
||||
match self {
|
||||
Use(..) | Static(..) | Const(..) | Fn(..) | Mod(..) | GlobalAsm(..) | TyAlias(..)
|
||||
| Struct(..) | Union(..) | Trait(..) | TraitAlias(..) | MacroDef(..)
|
||||
| Delegation(..) | DelegationMac(..) => "a",
|
||||
Use(..) | Static(..) | Const(..) | ConstBlock(..) | Fn(..) | Mod(..)
|
||||
| GlobalAsm(..) | TyAlias(..) | Struct(..) | Union(..) | Trait(..) | TraitAlias(..)
|
||||
| MacroDef(..) | Delegation(..) | DelegationMac(..) => "a",
|
||||
ExternCrate(..) | ForeignMod(..) | MacCall(..) | Enum(..) | Impl { .. } => "an",
|
||||
}
|
||||
}
|
||||
|
|
@ -4016,6 +4035,7 @@ impl ItemKind {
|
|||
ItemKind::Use(..) => "`use` import",
|
||||
ItemKind::Static(..) => "static item",
|
||||
ItemKind::Const(..) => "constant item",
|
||||
ItemKind::ConstBlock(..) => "const block",
|
||||
ItemKind::Fn(..) => "function",
|
||||
ItemKind::Mod(..) => "module",
|
||||
ItemKind::ForeignMod(..) => "extern block",
|
||||
|
|
@ -4045,7 +4065,18 @@ impl ItemKind {
|
|||
| Self::Trait(box Trait { generics, .. })
|
||||
| Self::TraitAlias(box TraitAlias { generics, .. })
|
||||
| Self::Impl(Impl { generics, .. }) => Some(generics),
|
||||
_ => None,
|
||||
|
||||
Self::ExternCrate(..)
|
||||
| Self::Use(..)
|
||||
| Self::Static(..)
|
||||
| Self::ConstBlock(..)
|
||||
| Self::Mod(..)
|
||||
| Self::ForeignMod(..)
|
||||
| Self::GlobalAsm(..)
|
||||
| Self::MacCall(..)
|
||||
| Self::MacroDef(..)
|
||||
| Self::Delegation(..)
|
||||
| Self::DelegationMac(..) => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,7 +5,6 @@
|
|||
//! This API is completely unstable and subject to change.
|
||||
|
||||
// tidy-alphabetical-start
|
||||
#![cfg_attr(bootstrap, feature(array_windows))]
|
||||
#![doc(test(attr(deny(warnings), allow(internal_features))))]
|
||||
#![feature(associated_type_defaults)]
|
||||
#![feature(box_patterns)]
|
||||
|
|
|
|||
|
|
@ -425,6 +425,7 @@ macro_rules! common_visitor_and_walkers {
|
|||
ByRef,
|
||||
Closure,
|
||||
Const,
|
||||
ConstBlockItem,
|
||||
ConstItem,
|
||||
ConstItemRhs,
|
||||
Defaultness,
|
||||
|
|
@ -825,6 +826,8 @@ macro_rules! common_visitor_and_walkers {
|
|||
visit_visitable!($($mut)? vis, use_tree),
|
||||
ItemKind::Static(item) =>
|
||||
visit_visitable!($($mut)? vis, item),
|
||||
ItemKind::ConstBlock(item) =>
|
||||
visit_visitable!($($mut)? vis, item),
|
||||
ItemKind::Const(item) =>
|
||||
visit_visitable!($($mut)? vis, item),
|
||||
ItemKind::Mod(safety, ident, mod_kind) =>
|
||||
|
|
|
|||
|
|
@ -205,6 +205,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
| ItemKind::Use(..)
|
||||
| ItemKind::Static(..)
|
||||
| ItemKind::Const(..)
|
||||
| ItemKind::ConstBlock(..)
|
||||
| ItemKind::Mod(..)
|
||||
| ItemKind::ForeignMod(..)
|
||||
| ItemKind::GlobalAsm(..)
|
||||
|
|
@ -282,8 +283,13 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
self.lower_define_opaque(hir_id, define_opaque);
|
||||
hir::ItemKind::Static(*m, ident, ty, body_id)
|
||||
}
|
||||
ItemKind::Const(box ast::ConstItem {
|
||||
ident, generics, ty, rhs, define_opaque, ..
|
||||
ItemKind::Const(box ConstItem {
|
||||
defaultness: _,
|
||||
ident,
|
||||
generics,
|
||||
ty,
|
||||
rhs,
|
||||
define_opaque,
|
||||
}) => {
|
||||
let ident = self.lower_ident(*ident);
|
||||
let (generics, (ty, rhs)) = self.lower_generics(
|
||||
|
|
@ -302,6 +308,19 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
self.lower_define_opaque(hir_id, &define_opaque);
|
||||
hir::ItemKind::Const(ident, generics, ty, rhs)
|
||||
}
|
||||
ItemKind::ConstBlock(ConstBlockItem { span, id, block }) => hir::ItemKind::Const(
|
||||
self.lower_ident(ConstBlockItem::IDENT),
|
||||
hir::Generics::empty(),
|
||||
self.arena.alloc(self.ty_tup(DUMMY_SP, &[])),
|
||||
hir::ConstItemRhs::Body({
|
||||
let body = hir::Expr {
|
||||
hir_id: self.lower_node_id(*id),
|
||||
kind: hir::ExprKind::Block(self.lower_block(block, false), None),
|
||||
span: self.lower_span(*span),
|
||||
};
|
||||
self.record_body(&[], body)
|
||||
}),
|
||||
),
|
||||
ItemKind::Fn(box Fn {
|
||||
sig: FnSig { decl, header, span: fn_sig_span },
|
||||
ident,
|
||||
|
|
|
|||
|
|
@ -95,6 +95,11 @@ pub fn extern_abi_stability(abi: ExternAbi) -> Result<(), UnstableAbi> {
|
|||
ExternAbi::RustCold => {
|
||||
Err(UnstableAbi { abi, feature: sym::rust_cold_cc, explain: GateReason::Experimental })
|
||||
}
|
||||
ExternAbi::RustPreserveNone => Err(UnstableAbi {
|
||||
abi,
|
||||
feature: sym::rust_preserve_none_cc,
|
||||
explain: GateReason::Experimental,
|
||||
}),
|
||||
ExternAbi::RustInvalid => {
|
||||
Err(UnstableAbi { abi, feature: sym::rustc_attrs, explain: GateReason::ImplDetail })
|
||||
}
|
||||
|
|
|
|||
|
|
@ -400,6 +400,7 @@ impl<'a> AstValidator<'a> {
|
|||
CanonAbi::C
|
||||
| CanonAbi::Rust
|
||||
| CanonAbi::RustCold
|
||||
| CanonAbi::RustPreserveNone
|
||||
| CanonAbi::Arm(_)
|
||||
| CanonAbi::X86(_) => { /* nothing to check */ }
|
||||
|
||||
|
|
|
|||
|
|
@ -537,6 +537,7 @@ pub fn check_crate(krate: &ast::Crate, sess: &Session, features: &Features) {
|
|||
gate_all!(super_let, "`super let` is experimental");
|
||||
gate_all!(frontmatter, "frontmatters are experimental");
|
||||
gate_all!(coroutines, "coroutine syntax is experimental");
|
||||
gate_all!(const_block_items, "const block items are experimental");
|
||||
|
||||
if !visitor.features.never_patterns() {
|
||||
if let Some(spans) = spans.get(&sym::never_patterns) {
|
||||
|
|
|
|||
|
|
@ -205,6 +205,17 @@ impl<'a> State<'a> {
|
|||
define_opaque.as_deref(),
|
||||
);
|
||||
}
|
||||
ast::ItemKind::ConstBlock(ast::ConstBlockItem { id: _, span: _, block }) => {
|
||||
let ib = self.ibox(INDENT_UNIT);
|
||||
self.word("const");
|
||||
self.nbsp();
|
||||
{
|
||||
let cb = self.cbox(0);
|
||||
let ib = self.ibox(0);
|
||||
self.print_block_with_attrs(block, &[], cb, ib);
|
||||
}
|
||||
self.end(ib);
|
||||
}
|
||||
ast::ItemKind::Const(box ast::ConstItem {
|
||||
defaultness,
|
||||
ident,
|
||||
|
|
|
|||
|
|
@ -360,7 +360,8 @@ fn parse_cfg_attr_internal<'a>(
|
|||
) -> PResult<'a, (CfgEntry, Vec<(ast::AttrItem, Span)>)> {
|
||||
// Parse cfg predicate
|
||||
let pred_start = parser.token.span;
|
||||
let meta = MetaItemOrLitParser::parse_single(parser, ShouldEmit::ErrorsAndLints)?;
|
||||
let meta =
|
||||
MetaItemOrLitParser::parse_single(parser, ShouldEmit::ErrorsAndLints { recover: true })?;
|
||||
let pred_span = pred_start.with_hi(parser.token.span.hi());
|
||||
|
||||
let cfg_predicate = AttributeParser::parse_single_args(
|
||||
|
|
@ -375,7 +376,7 @@ fn parse_cfg_attr_internal<'a>(
|
|||
CRATE_NODE_ID,
|
||||
Target::Crate,
|
||||
features,
|
||||
ShouldEmit::ErrorsAndLints,
|
||||
ShouldEmit::ErrorsAndLints { recover: true },
|
||||
&meta,
|
||||
parse_cfg_entry,
|
||||
&CFG_ATTR_TEMPLATE,
|
||||
|
|
|
|||
|
|
@ -78,8 +78,9 @@ pub fn parse_cfg_select(
|
|||
}
|
||||
}
|
||||
} else {
|
||||
let meta = MetaItemOrLitParser::parse_single(p, ShouldEmit::ErrorsAndLints)
|
||||
.map_err(|diag| diag.emit())?;
|
||||
let meta =
|
||||
MetaItemOrLitParser::parse_single(p, ShouldEmit::ErrorsAndLints { recover: true })
|
||||
.map_err(|diag| diag.emit())?;
|
||||
let cfg_span = meta.span();
|
||||
let cfg = AttributeParser::parse_single_args(
|
||||
sess,
|
||||
|
|
@ -94,7 +95,7 @@ pub fn parse_cfg_select(
|
|||
// Doesn't matter what the target actually is here.
|
||||
Target::Crate,
|
||||
features,
|
||||
ShouldEmit::ErrorsAndLints,
|
||||
ShouldEmit::ErrorsAndLints { recover: true },
|
||||
&meta,
|
||||
parse_cfg_entry,
|
||||
&AttributeTemplate::default(),
|
||||
|
|
|
|||
|
|
@ -717,3 +717,100 @@ impl<S: Stage> NoArgsAttributeParser<S> for EiiForeignItemParser {
|
|||
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::ForeignFn)]);
|
||||
const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::EiiForeignItem;
|
||||
}
|
||||
|
||||
pub(crate) struct PatchableFunctionEntryParser;
|
||||
|
||||
impl<S: Stage> SingleAttributeParser<S> for PatchableFunctionEntryParser {
|
||||
const PATH: &[Symbol] = &[sym::patchable_function_entry];
|
||||
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
|
||||
const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepInnermost;
|
||||
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Fn)]);
|
||||
const TEMPLATE: AttributeTemplate = template!(List: &["prefix_nops = m, entry_nops = n"]);
|
||||
|
||||
fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option<AttributeKind> {
|
||||
let Some(meta_item_list) = args.list() else {
|
||||
cx.expected_list(cx.attr_span, args);
|
||||
return None;
|
||||
};
|
||||
|
||||
let mut prefix = None;
|
||||
let mut entry = None;
|
||||
|
||||
if meta_item_list.len() == 0 {
|
||||
cx.expected_list(meta_item_list.span, args);
|
||||
return None;
|
||||
}
|
||||
|
||||
let mut errored = false;
|
||||
|
||||
for item in meta_item_list.mixed() {
|
||||
let Some(meta_item) = item.meta_item() else {
|
||||
errored = true;
|
||||
cx.expected_name_value(item.span(), None);
|
||||
continue;
|
||||
};
|
||||
|
||||
let Some(name_value_lit) = meta_item.args().name_value() else {
|
||||
errored = true;
|
||||
cx.expected_name_value(item.span(), None);
|
||||
continue;
|
||||
};
|
||||
|
||||
let attrib_to_write = match meta_item.ident().map(|ident| ident.name) {
|
||||
Some(sym::prefix_nops) => {
|
||||
// Duplicate prefixes are not allowed
|
||||
if prefix.is_some() {
|
||||
errored = true;
|
||||
cx.duplicate_key(meta_item.path().span(), sym::prefix_nops);
|
||||
continue;
|
||||
}
|
||||
&mut prefix
|
||||
}
|
||||
Some(sym::entry_nops) => {
|
||||
// Duplicate entries are not allowed
|
||||
if entry.is_some() {
|
||||
errored = true;
|
||||
cx.duplicate_key(meta_item.path().span(), sym::entry_nops);
|
||||
continue;
|
||||
}
|
||||
&mut entry
|
||||
}
|
||||
_ => {
|
||||
errored = true;
|
||||
cx.expected_specific_argument(
|
||||
meta_item.path().span(),
|
||||
&[sym::prefix_nops, sym::entry_nops],
|
||||
);
|
||||
continue;
|
||||
}
|
||||
};
|
||||
|
||||
let rustc_ast::LitKind::Int(val, _) = name_value_lit.value_as_lit().kind else {
|
||||
errored = true;
|
||||
cx.expected_integer_literal(name_value_lit.value_span);
|
||||
continue;
|
||||
};
|
||||
|
||||
let Ok(val) = val.get().try_into() else {
|
||||
errored = true;
|
||||
cx.expected_integer_literal_in_range(
|
||||
name_value_lit.value_span,
|
||||
u8::MIN as isize,
|
||||
u8::MAX as isize,
|
||||
);
|
||||
continue;
|
||||
};
|
||||
|
||||
*attrib_to_write = Some(val);
|
||||
}
|
||||
|
||||
if errored {
|
||||
None
|
||||
} else {
|
||||
Some(AttributeKind::PatchableFunctionEntry {
|
||||
prefix: prefix.unwrap_or(0),
|
||||
entry: entry.unwrap_or(0),
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,8 @@
|
|||
use rustc_hir::attrs::WindowsSubsystemKind;
|
||||
use rustc_hir::attrs::{CrateType, WindowsSubsystemKind};
|
||||
use rustc_hir::lints::AttributeLintKind;
|
||||
use rustc_session::lint::builtin::UNKNOWN_CRATE_TYPES;
|
||||
use rustc_span::Symbol;
|
||||
use rustc_span::edit_distance::find_best_match_for_name;
|
||||
|
||||
use super::prelude::*;
|
||||
|
||||
|
|
@ -26,6 +30,56 @@ impl<S: Stage> SingleAttributeParser<S> for CrateNameParser {
|
|||
}
|
||||
}
|
||||
|
||||
pub(crate) struct CrateTypeParser;
|
||||
|
||||
impl<S: Stage> CombineAttributeParser<S> for CrateTypeParser {
|
||||
const PATH: &[Symbol] = &[sym::crate_type];
|
||||
type Item = CrateType;
|
||||
const CONVERT: ConvertFn<Self::Item> = |items, _| AttributeKind::CrateType(items);
|
||||
|
||||
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Crate)]);
|
||||
|
||||
const TEMPLATE: AttributeTemplate =
|
||||
template!(NameValueStr: "crate type", "https://doc.rust-lang.org/reference/linkage.html");
|
||||
|
||||
fn extend(
|
||||
cx: &mut AcceptContext<'_, '_, S>,
|
||||
args: &ArgParser,
|
||||
) -> impl IntoIterator<Item = Self::Item> {
|
||||
let ArgParser::NameValue(n) = args else {
|
||||
cx.expected_name_value(cx.attr_span, None);
|
||||
return None;
|
||||
};
|
||||
|
||||
let Some(crate_type) = n.value_as_str() else {
|
||||
cx.expected_string_literal(n.value_span, Some(n.value_as_lit()));
|
||||
return None;
|
||||
};
|
||||
|
||||
let Ok(crate_type) = crate_type.try_into() else {
|
||||
// We don't error on invalid `#![crate_type]` when not applied to a crate
|
||||
if cx.shared.target == Target::Crate {
|
||||
let candidate = find_best_match_for_name(
|
||||
&CrateType::all_stable().iter().map(|(name, _)| *name).collect::<Vec<_>>(),
|
||||
crate_type,
|
||||
None,
|
||||
);
|
||||
cx.emit_lint(
|
||||
UNKNOWN_CRATE_TYPES,
|
||||
AttributeLintKind::CrateTypeUnknown {
|
||||
span: n.value_span,
|
||||
suggested: candidate,
|
||||
},
|
||||
n.value_span,
|
||||
);
|
||||
}
|
||||
return None;
|
||||
};
|
||||
|
||||
Some(crate_type)
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) struct RecursionLimitParser;
|
||||
|
||||
impl<S: Stage> SingleAttributeParser<S> for RecursionLimitParser {
|
||||
|
|
@ -184,3 +238,39 @@ impl<S: Stage> SingleAttributeParser<S> for WindowsSubsystemParser {
|
|||
Some(AttributeKind::WindowsSubsystem(kind, cx.attr_span))
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) struct PanicRuntimeParser;
|
||||
|
||||
impl<S: Stage> NoArgsAttributeParser<S> for PanicRuntimeParser {
|
||||
const PATH: &[Symbol] = &[sym::panic_runtime];
|
||||
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Warn;
|
||||
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Crate)]);
|
||||
const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::PanicRuntime;
|
||||
}
|
||||
|
||||
pub(crate) struct NeedsPanicRuntimeParser;
|
||||
|
||||
impl<S: Stage> NoArgsAttributeParser<S> for NeedsPanicRuntimeParser {
|
||||
const PATH: &[Symbol] = &[sym::needs_panic_runtime];
|
||||
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Warn;
|
||||
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Crate)]);
|
||||
const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::NeedsPanicRuntime;
|
||||
}
|
||||
|
||||
pub(crate) struct ProfilerRuntimeParser;
|
||||
|
||||
impl<S: Stage> NoArgsAttributeParser<S> for ProfilerRuntimeParser {
|
||||
const PATH: &[Symbol] = &[sym::profiler_runtime];
|
||||
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Warn;
|
||||
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Crate)]);
|
||||
const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::ProfilerRuntime;
|
||||
}
|
||||
|
||||
pub(crate) struct NoBuiltinsParser;
|
||||
|
||||
impl<S: Stage> NoArgsAttributeParser<S> for NoBuiltinsParser {
|
||||
const PATH: &[Symbol] = &[sym::no_builtins];
|
||||
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Warn;
|
||||
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Crate)]);
|
||||
const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::NoBuiltins;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -665,3 +665,12 @@ impl<S: Stage> NoArgsAttributeParser<S> for NeedsAllocatorParser {
|
|||
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Crate)]);
|
||||
const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::NeedsAllocator;
|
||||
}
|
||||
|
||||
pub(crate) struct CompilerBuiltinsParser;
|
||||
|
||||
impl<S: Stage> NoArgsAttributeParser<S> for CompilerBuiltinsParser {
|
||||
const PATH: &[Symbol] = &[sym::compiler_builtins];
|
||||
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Warn;
|
||||
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Crate)]);
|
||||
const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::CompilerBuiltins;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -91,3 +91,25 @@ impl<S: Stage> SingleAttributeParser<S> for ShouldPanicParser {
|
|||
})
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) struct RustcVarianceParser;
|
||||
|
||||
impl<S: Stage> NoArgsAttributeParser<S> for RustcVarianceParser {
|
||||
const PATH: &[Symbol] = &[sym::rustc_variance];
|
||||
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Warn;
|
||||
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[
|
||||
Allow(Target::Struct),
|
||||
Allow(Target::Enum),
|
||||
Allow(Target::Union),
|
||||
]);
|
||||
const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcVariance;
|
||||
}
|
||||
|
||||
pub(crate) struct RustcVarianceOfOpaquesParser;
|
||||
|
||||
impl<S: Stage> NoArgsAttributeParser<S> for RustcVarianceOfOpaquesParser {
|
||||
const PATH: &[Symbol] = &[sym::rustc_variance_of_opaques];
|
||||
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Warn;
|
||||
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Crate)]);
|
||||
const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcVarianceOfOpaques;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -94,12 +94,12 @@ impl<S: Stage> NoArgsAttributeParser<S> for DenyExplicitImplParser {
|
|||
const CREATE: fn(Span) -> AttributeKind = AttributeKind::DenyExplicitImpl;
|
||||
}
|
||||
|
||||
pub(crate) struct DoNotImplementViaObjectParser;
|
||||
impl<S: Stage> NoArgsAttributeParser<S> for DoNotImplementViaObjectParser {
|
||||
const PATH: &[Symbol] = &[sym::rustc_do_not_implement_via_object];
|
||||
pub(crate) struct DynIncompatibleTraitParser;
|
||||
impl<S: Stage> NoArgsAttributeParser<S> for DynIncompatibleTraitParser {
|
||||
const PATH: &[Symbol] = &[sym::rustc_dyn_incompatible_trait];
|
||||
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
|
||||
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Trait)]);
|
||||
const CREATE: fn(Span) -> AttributeKind = AttributeKind::DoNotImplementViaObject;
|
||||
const CREATE: fn(Span) -> AttributeKind = AttributeKind::DynIncompatibleTrait;
|
||||
}
|
||||
|
||||
// Specialization
|
||||
|
|
|
|||
|
|
@ -23,14 +23,15 @@ use crate::attributes::cfi_encoding::CfiEncodingParser;
|
|||
use crate::attributes::codegen_attrs::{
|
||||
ColdParser, CoverageParser, EiiForeignItemParser, ExportNameParser, ForceTargetFeatureParser,
|
||||
NakedParser, NoMangleParser, ObjcClassParser, ObjcSelectorParser, OptimizeParser,
|
||||
RustcPassIndirectlyInNonRusticAbisParser, SanitizeParser, TargetFeatureParser,
|
||||
ThreadLocalParser, TrackCallerParser, UsedParser,
|
||||
PatchableFunctionEntryParser, RustcPassIndirectlyInNonRusticAbisParser, SanitizeParser,
|
||||
TargetFeatureParser, ThreadLocalParser, TrackCallerParser, UsedParser,
|
||||
};
|
||||
use crate::attributes::confusables::ConfusablesParser;
|
||||
use crate::attributes::crate_level::{
|
||||
CrateNameParser, MoveSizeLimitParser, NoCoreParser, NoMainParser, NoStdParser,
|
||||
PatternComplexityLimitParser, RecursionLimitParser, RustcCoherenceIsCoreParser,
|
||||
TypeLengthLimitParser, WindowsSubsystemParser,
|
||||
CrateNameParser, CrateTypeParser, MoveSizeLimitParser, NeedsPanicRuntimeParser,
|
||||
NoBuiltinsParser, NoCoreParser, NoMainParser, NoStdParser, PanicRuntimeParser,
|
||||
PatternComplexityLimitParser, ProfilerRuntimeParser, RecursionLimitParser,
|
||||
RustcCoherenceIsCoreParser, TypeLengthLimitParser, WindowsSubsystemParser,
|
||||
};
|
||||
use crate::attributes::debugger::DebuggerViualizerParser;
|
||||
use crate::attributes::deprecation::DeprecationParser;
|
||||
|
|
@ -40,8 +41,9 @@ use crate::attributes::dummy::DummyParser;
|
|||
use crate::attributes::inline::{InlineParser, RustcForceInlineParser};
|
||||
use crate::attributes::instruction_set::InstructionSetParser;
|
||||
use crate::attributes::link_attrs::{
|
||||
ExportStableParser, FfiConstParser, FfiPureParser, LinkNameParser, LinkOrdinalParser,
|
||||
LinkParser, LinkSectionParser, LinkageParser, NeedsAllocatorParser, StdInternalSymbolParser,
|
||||
CompilerBuiltinsParser, ExportStableParser, FfiConstParser, FfiPureParser, LinkNameParser,
|
||||
LinkOrdinalParser, LinkParser, LinkSectionParser, LinkageParser, NeedsAllocatorParser,
|
||||
StdInternalSymbolParser,
|
||||
};
|
||||
use crate::attributes::lint_helpers::{
|
||||
AsPtrParser, AutomaticallyDerivedParser, PassByValueParser, PubTransparentParser,
|
||||
|
|
@ -85,11 +87,13 @@ use crate::attributes::semantics::MayDangleParser;
|
|||
use crate::attributes::stability::{
|
||||
BodyStabilityParser, ConstStabilityIndirectParser, ConstStabilityParser, StabilityParser,
|
||||
};
|
||||
use crate::attributes::test_attrs::{IgnoreParser, ShouldPanicParser};
|
||||
use crate::attributes::test_attrs::{
|
||||
IgnoreParser, RustcVarianceOfOpaquesParser, RustcVarianceParser, ShouldPanicParser,
|
||||
};
|
||||
use crate::attributes::traits::{
|
||||
AllowIncoherentImplParser, CoinductiveParser, DenyExplicitImplParser,
|
||||
DoNotImplementViaObjectParser, FundamentalParser, MarkerParser, ParenSugarParser,
|
||||
PointeeParser, SkipDuringMethodDispatchParser, SpecializationTraitParser, TypeConstParser,
|
||||
DynIncompatibleTraitParser, FundamentalParser, MarkerParser, ParenSugarParser, PointeeParser,
|
||||
SkipDuringMethodDispatchParser, SpecializationTraitParser, TypeConstParser,
|
||||
UnsafeSpecializationMarkerParser,
|
||||
};
|
||||
use crate::attributes::transparency::TransparencyParser;
|
||||
|
|
@ -103,18 +107,18 @@ type GroupType<S> = LazyLock<GroupTypeInner<S>>;
|
|||
|
||||
pub(super) struct GroupTypeInner<S: Stage> {
|
||||
pub(super) accepters: BTreeMap<&'static [Symbol], Vec<GroupTypeInnerAccept<S>>>,
|
||||
pub(super) finalizers: Vec<FinalizeFn<S>>,
|
||||
}
|
||||
|
||||
pub(super) struct GroupTypeInnerAccept<S: Stage> {
|
||||
pub(super) template: AttributeTemplate,
|
||||
pub(super) accept_fn: AcceptFn<S>,
|
||||
pub(super) allowed_targets: AllowedTargets,
|
||||
pub(super) finalizer: FinalizeFn<S>,
|
||||
}
|
||||
|
||||
type AcceptFn<S> =
|
||||
pub(crate) type AcceptFn<S> =
|
||||
Box<dyn for<'sess, 'a> Fn(&mut AcceptContext<'_, 'sess, S>, &ArgParser) + Send + Sync>;
|
||||
type FinalizeFn<S> =
|
||||
pub(crate) type FinalizeFn<S> =
|
||||
Box<dyn Send + Sync + Fn(&mut FinalizeContext<'_, '_, S>) -> Option<AttributeKind>>;
|
||||
|
||||
macro_rules! attribute_parsers {
|
||||
|
|
@ -142,8 +146,7 @@ macro_rules! attribute_parsers {
|
|||
@[$stage: ty] pub(crate) static $name: ident = [$($names: ty),* $(,)?];
|
||||
) => {
|
||||
pub(crate) static $name: GroupType<$stage> = LazyLock::new(|| {
|
||||
let mut accepts = BTreeMap::<_, Vec<GroupTypeInnerAccept<$stage>>>::new();
|
||||
let mut finalizes = Vec::<FinalizeFn<$stage>>::new();
|
||||
let mut accepters = BTreeMap::<_, Vec<GroupTypeInnerAccept<$stage>>>::new();
|
||||
$(
|
||||
{
|
||||
thread_local! {
|
||||
|
|
@ -151,7 +154,7 @@ macro_rules! attribute_parsers {
|
|||
};
|
||||
|
||||
for (path, template, accept_fn) in <$names>::ATTRIBUTES {
|
||||
accepts.entry(*path).or_default().push(GroupTypeInnerAccept {
|
||||
accepters.entry(*path).or_default().push(GroupTypeInnerAccept {
|
||||
template: *template,
|
||||
accept_fn: Box::new(|cx, args| {
|
||||
STATE_OBJECT.with_borrow_mut(|s| {
|
||||
|
|
@ -159,17 +162,16 @@ macro_rules! attribute_parsers {
|
|||
})
|
||||
}),
|
||||
allowed_targets: <$names as crate::attributes::AttributeParser<$stage>>::ALLOWED_TARGETS,
|
||||
finalizer: Box::new(|cx| {
|
||||
let state = STATE_OBJECT.take();
|
||||
state.finalize(cx)
|
||||
}),
|
||||
});
|
||||
}
|
||||
|
||||
finalizes.push(Box::new(|cx| {
|
||||
let state = STATE_OBJECT.take();
|
||||
state.finalize(cx)
|
||||
}));
|
||||
}
|
||||
)*
|
||||
|
||||
GroupTypeInner { accepters:accepts, finalizers:finalizes }
|
||||
GroupTypeInner { accepters }
|
||||
});
|
||||
};
|
||||
}
|
||||
|
|
@ -191,6 +193,7 @@ attribute_parsers!(
|
|||
// tidy-alphabetical-start
|
||||
Combine<AllowConstFnUnstableParser>,
|
||||
Combine<AllowInternalUnstableParser>,
|
||||
Combine<CrateTypeParser>,
|
||||
Combine<DebuggerViualizerParser>,
|
||||
Combine<ForceTargetFeatureParser>,
|
||||
Combine<LinkParser>,
|
||||
|
|
@ -223,6 +226,7 @@ attribute_parsers!(
|
|||
Single<ObjcClassParser>,
|
||||
Single<ObjcSelectorParser>,
|
||||
Single<OptimizeParser>,
|
||||
Single<PatchableFunctionEntryParser>,
|
||||
Single<PathAttributeParser>,
|
||||
Single<PatternComplexityLimitParser>,
|
||||
Single<ProcMacroDeriveParser>,
|
||||
|
|
@ -250,11 +254,12 @@ attribute_parsers!(
|
|||
Single<WithoutArgs<AutomaticallyDerivedParser>>,
|
||||
Single<WithoutArgs<CoinductiveParser>>,
|
||||
Single<WithoutArgs<ColdParser>>,
|
||||
Single<WithoutArgs<CompilerBuiltinsParser>>,
|
||||
Single<WithoutArgs<ConstContinueParser>>,
|
||||
Single<WithoutArgs<ConstStabilityIndirectParser>>,
|
||||
Single<WithoutArgs<CoroutineParser>>,
|
||||
Single<WithoutArgs<DenyExplicitImplParser>>,
|
||||
Single<WithoutArgs<DoNotImplementViaObjectParser>>,
|
||||
Single<WithoutArgs<DynIncompatibleTraitParser>>,
|
||||
Single<WithoutArgs<EiiForeignItemParser>>,
|
||||
Single<WithoutArgs<ExportStableParser>>,
|
||||
Single<WithoutArgs<FfiConstParser>>,
|
||||
|
|
@ -265,6 +270,8 @@ attribute_parsers!(
|
|||
Single<WithoutArgs<MarkerParser>>,
|
||||
Single<WithoutArgs<MayDangleParser>>,
|
||||
Single<WithoutArgs<NeedsAllocatorParser>>,
|
||||
Single<WithoutArgs<NeedsPanicRuntimeParser>>,
|
||||
Single<WithoutArgs<NoBuiltinsParser>>,
|
||||
Single<WithoutArgs<NoCoreParser>>,
|
||||
Single<WithoutArgs<NoImplicitPreludeParser>>,
|
||||
Single<WithoutArgs<NoLinkParser>>,
|
||||
|
|
@ -272,12 +279,14 @@ attribute_parsers!(
|
|||
Single<WithoutArgs<NoMangleParser>>,
|
||||
Single<WithoutArgs<NoStdParser>>,
|
||||
Single<WithoutArgs<NonExhaustiveParser>>,
|
||||
Single<WithoutArgs<PanicRuntimeParser>>,
|
||||
Single<WithoutArgs<ParenSugarParser>>,
|
||||
Single<WithoutArgs<PassByValueParser>>,
|
||||
Single<WithoutArgs<PinV2Parser>>,
|
||||
Single<WithoutArgs<PointeeParser>>,
|
||||
Single<WithoutArgs<ProcMacroAttributeParser>>,
|
||||
Single<WithoutArgs<ProcMacroParser>>,
|
||||
Single<WithoutArgs<ProfilerRuntimeParser>>,
|
||||
Single<WithoutArgs<PubTransparentParser>>,
|
||||
Single<WithoutArgs<RustcAllocatorParser>>,
|
||||
Single<WithoutArgs<RustcAllocatorZeroedParser>>,
|
||||
|
|
@ -300,6 +309,8 @@ attribute_parsers!(
|
|||
Single<WithoutArgs<RustcPassIndirectlyInNonRusticAbisParser>>,
|
||||
Single<WithoutArgs<RustcReallocatorParser>>,
|
||||
Single<WithoutArgs<RustcShouldNotBeCalledOnConstItems>>,
|
||||
Single<WithoutArgs<RustcVarianceOfOpaquesParser>>,
|
||||
Single<WithoutArgs<RustcVarianceParser>>,
|
||||
Single<WithoutArgs<SpecializationTraitParser>>,
|
||||
Single<WithoutArgs<StdInternalSymbolParser>>,
|
||||
Single<WithoutArgs<ThreadLocalParser>>,
|
||||
|
|
@ -370,7 +381,7 @@ impl Stage for Late {
|
|||
}
|
||||
|
||||
fn should_emit(&self) -> ShouldEmit {
|
||||
ShouldEmit::ErrorsAndLints
|
||||
ShouldEmit::ErrorsAndLints { recover: true }
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -427,7 +438,7 @@ impl<'f, 'sess: 'f, S: Stage> SharedContext<'f, 'sess, S> {
|
|||
pub(crate) fn emit_lint(&mut self, lint: &'static Lint, kind: AttributeLintKind, span: Span) {
|
||||
if !matches!(
|
||||
self.stage.should_emit(),
|
||||
ShouldEmit::ErrorsAndLints | ShouldEmit::EarlyFatal { also_emit_lints: true }
|
||||
ShouldEmit::ErrorsAndLints { .. } | ShouldEmit::EarlyFatal { also_emit_lints: true }
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
|
@ -503,6 +514,18 @@ impl<'f, 'sess: 'f, S: Stage> AcceptContext<'f, 'sess, S> {
|
|||
self.emit_parse_error(span, AttributeParseErrorReason::ExpectedIntegerLiteral)
|
||||
}
|
||||
|
||||
pub(crate) fn expected_integer_literal_in_range(
|
||||
&self,
|
||||
span: Span,
|
||||
lower_bound: isize,
|
||||
upper_bound: isize,
|
||||
) -> ErrorGuaranteed {
|
||||
self.emit_parse_error(
|
||||
span,
|
||||
AttributeParseErrorReason::ExpectedIntegerLiteralInRange { lower_bound, upper_bound },
|
||||
)
|
||||
}
|
||||
|
||||
pub(crate) fn expected_list(&self, span: Span, args: &ArgParser) -> ErrorGuaranteed {
|
||||
let span = match args {
|
||||
ArgParser::NoArgs => span,
|
||||
|
|
@ -742,9 +765,18 @@ pub enum ShouldEmit {
|
|||
EarlyFatal { also_emit_lints: bool },
|
||||
/// The operation will emit errors and lints.
|
||||
/// This is usually what you need.
|
||||
ErrorsAndLints,
|
||||
/// The operation will emit *not* errors and lints.
|
||||
/// Use this if you are *sure* that this operation will be called at a different time with `ShouldEmit::ErrorsAndLints`.
|
||||
ErrorsAndLints {
|
||||
/// Whether [`ArgParser`] will attempt to recover from errors.
|
||||
///
|
||||
/// If true, it will attempt to recover from bad input (like an invalid literal). Setting
|
||||
/// this to false will instead return early, and not raise errors except at the top level
|
||||
/// (in [`ArgParser::from_attr_args`]).
|
||||
recover: bool,
|
||||
},
|
||||
/// The operation will *not* emit errors and lints.
|
||||
///
|
||||
/// The parser can still call `delay_bug`, so you *must* ensure that this operation will also be
|
||||
/// called with `ShouldEmit::ErrorsAndLints`.
|
||||
Nothing,
|
||||
}
|
||||
|
||||
|
|
@ -753,7 +785,7 @@ impl ShouldEmit {
|
|||
match self {
|
||||
ShouldEmit::EarlyFatal { .. } if diag.level() == Level::DelayedBug => diag.emit(),
|
||||
ShouldEmit::EarlyFatal { .. } => diag.upgrade_to_fatal().emit(),
|
||||
ShouldEmit::ErrorsAndLints => diag.emit(),
|
||||
ShouldEmit::ErrorsAndLints { .. } => diag.emit(),
|
||||
ShouldEmit::Nothing => diag.delay_as_bug(),
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ use rustc_session::Session;
|
|||
use rustc_session::lint::{BuiltinLintDiag, LintId};
|
||||
use rustc_span::{DUMMY_SP, Span, Symbol, sym};
|
||||
|
||||
use crate::context::{AcceptContext, FinalizeContext, SharedContext, Stage};
|
||||
use crate::context::{AcceptContext, FinalizeContext, FinalizeFn, SharedContext, Stage};
|
||||
use crate::early_parsed::{EARLY_PARSED_ATTRIBUTES, EarlyParsedState};
|
||||
use crate::parser::{ArgParser, PathParser, RefPathParser};
|
||||
use crate::session_diagnostics::ParsedDescription;
|
||||
|
|
@ -270,6 +270,8 @@ impl<'sess, S: Stage> AttributeParser<'sess, S> {
|
|||
let mut attr_paths: Vec<RefPathParser<'_>> = Vec::new();
|
||||
let mut early_parsed_state = EarlyParsedState::default();
|
||||
|
||||
let mut finalizers: Vec<&FinalizeFn<S>> = Vec::with_capacity(attrs.len());
|
||||
|
||||
for attr in attrs {
|
||||
// If we're only looking for a single attribute, skip all the ones we don't care about.
|
||||
if let Some(expected) = self.parse_only {
|
||||
|
|
@ -383,6 +385,8 @@ impl<'sess, S: Stage> AttributeParser<'sess, S> {
|
|||
};
|
||||
|
||||
(accept.accept_fn)(&mut cx, &args);
|
||||
finalizers.push(&accept.finalizer);
|
||||
|
||||
if !matches!(cx.stage.should_emit(), ShouldEmit::Nothing) {
|
||||
Self::check_target(&accept.allowed_targets, target, &mut cx);
|
||||
}
|
||||
|
|
@ -417,7 +421,7 @@ impl<'sess, S: Stage> AttributeParser<'sess, S> {
|
|||
}
|
||||
|
||||
early_parsed_state.finalize_early_parsed_attributes(&mut attributes);
|
||||
for f in &S::parsers().finalizers {
|
||||
for f in &finalizers {
|
||||
if let Some(attr) = f(&mut FinalizeContext {
|
||||
shared: SharedContext { cx: self, target_span, target, emit_lint: &mut emit_lint },
|
||||
all_attrs: &attr_paths,
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@ use rustc_errors::{Diag, PResult};
|
|||
use rustc_hir::{self as hir, AttrPath};
|
||||
use rustc_parse::exp;
|
||||
use rustc_parse::parser::{ForceCollect, Parser, PathStyle, token_descr};
|
||||
use rustc_session::errors::{create_lit_error, report_lit_error};
|
||||
use rustc_session::errors::create_lit_error;
|
||||
use rustc_session::parse::ParseSess;
|
||||
use rustc_span::{Ident, Span, Symbol, sym};
|
||||
use thin_vec::ThinVec;
|
||||
|
|
@ -113,16 +113,29 @@ impl ArgParser {
|
|||
Some(match value {
|
||||
AttrArgs::Empty => Self::NoArgs,
|
||||
AttrArgs::Delimited(args) => {
|
||||
// The arguments of rustc_dummy and diagnostic::do_not_recommend are not validated
|
||||
// if the arguments are delimited.
|
||||
// See https://doc.rust-lang.org/reference/attributes/diagnostics.html#r-attributes.diagnostic.namespace.unknown-invalid-syntax
|
||||
if parts == &[sym::rustc_dummy]
|
||||
|| parts == &[sym::diagnostic, sym::do_not_recommend]
|
||||
{
|
||||
return Some(ArgParser::List(MetaItemListParser {
|
||||
sub_parsers: ThinVec::new(),
|
||||
span: args.dspan.entire(),
|
||||
}));
|
||||
// Diagnostic attributes can't error if they encounter non meta item syntax.
|
||||
// However, the current syntax for diagnostic attributes is meta item syntax.
|
||||
// Therefore we can substitute with a dummy value on invalid syntax.
|
||||
if matches!(parts, [sym::rustc_dummy] | [sym::diagnostic, ..]) {
|
||||
match MetaItemListParser::new(
|
||||
&args.tokens,
|
||||
args.dspan.entire(),
|
||||
psess,
|
||||
ShouldEmit::ErrorsAndLints { recover: false },
|
||||
) {
|
||||
Ok(p) => return Some(ArgParser::List(p)),
|
||||
Err(e) => {
|
||||
// We can just dispose of the diagnostic and not bother with a lint,
|
||||
// because this will look like `#[diagnostic::attr()]` was used. This
|
||||
// is invalid for all diagnostic attrs, so a lint explaining the proper
|
||||
// form will be issued later.
|
||||
e.cancel();
|
||||
return Some(ArgParser::List(MetaItemListParser {
|
||||
sub_parsers: ThinVec::new(),
|
||||
span: args.dspan.entire(),
|
||||
}));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if args.delim != Delimiter::Parenthesis {
|
||||
|
|
@ -141,7 +154,9 @@ impl ArgParser {
|
|||
}
|
||||
AttrArgs::Eq { eq_span, expr } => Self::NameValue(NameValueParser {
|
||||
eq_span: *eq_span,
|
||||
value: expr_to_lit(psess, &expr, expr.span, should_emit)?,
|
||||
value: expr_to_lit(psess, &expr, expr.span, should_emit)
|
||||
.map_err(|e| should_emit.emit_err(e))
|
||||
.ok()??,
|
||||
value_span: expr.span,
|
||||
}),
|
||||
})
|
||||
|
|
@ -336,58 +351,53 @@ impl NameValueParser {
|
|||
}
|
||||
}
|
||||
|
||||
fn expr_to_lit(
|
||||
psess: &ParseSess,
|
||||
fn expr_to_lit<'sess>(
|
||||
psess: &'sess ParseSess,
|
||||
expr: &Expr,
|
||||
span: Span,
|
||||
should_emit: ShouldEmit,
|
||||
) -> Option<MetaItemLit> {
|
||||
) -> PResult<'sess, Option<MetaItemLit>> {
|
||||
if let ExprKind::Lit(token_lit) = expr.kind {
|
||||
let res = MetaItemLit::from_token_lit(token_lit, expr.span);
|
||||
match res {
|
||||
Ok(lit) => {
|
||||
if token_lit.suffix.is_some() {
|
||||
should_emit.emit_err(
|
||||
psess.dcx().create_err(SuffixedLiteralInAttribute { span: lit.span }),
|
||||
);
|
||||
None
|
||||
Err(psess.dcx().create_err(SuffixedLiteralInAttribute { span: lit.span }))
|
||||
} else {
|
||||
if !lit.kind.is_unsuffixed() {
|
||||
// Emit error and continue, we can still parse the attribute as if the suffix isn't there
|
||||
should_emit.emit_err(
|
||||
psess.dcx().create_err(SuffixedLiteralInAttribute { span: lit.span }),
|
||||
);
|
||||
if lit.kind.is_unsuffixed() {
|
||||
Ok(Some(lit))
|
||||
} else {
|
||||
Err(psess.dcx().create_err(SuffixedLiteralInAttribute { span: lit.span }))
|
||||
}
|
||||
|
||||
Some(lit)
|
||||
}
|
||||
}
|
||||
Err(err) => {
|
||||
let guar = report_lit_error(psess, err, token_lit, expr.span);
|
||||
let lit = MetaItemLit {
|
||||
symbol: token_lit.symbol,
|
||||
suffix: token_lit.suffix,
|
||||
kind: LitKind::Err(guar),
|
||||
span: expr.span,
|
||||
};
|
||||
Some(lit)
|
||||
let err = create_lit_error(psess, err, token_lit, expr.span);
|
||||
if matches!(should_emit, ShouldEmit::ErrorsAndLints { recover: false }) {
|
||||
Err(err)
|
||||
} else {
|
||||
let lit = MetaItemLit {
|
||||
symbol: token_lit.symbol,
|
||||
suffix: token_lit.suffix,
|
||||
kind: LitKind::Err(err.emit()),
|
||||
span: expr.span,
|
||||
};
|
||||
Ok(Some(lit))
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if matches!(should_emit, ShouldEmit::Nothing) {
|
||||
return None;
|
||||
return Ok(None);
|
||||
}
|
||||
|
||||
// Example cases:
|
||||
// - `#[foo = 1+1]`: results in `ast::ExprKind::BinOp`.
|
||||
// - `#[foo = include_str!("nonexistent-file.rs")]`:
|
||||
// results in `ast::ExprKind::Err`. In that case we delay
|
||||
// the error because an earlier error will have already
|
||||
// been reported.
|
||||
// results in `ast::ExprKind::Err`.
|
||||
let msg = "attribute value must be a literal";
|
||||
let err = psess.dcx().struct_span_err(span, msg);
|
||||
should_emit.emit_err(err);
|
||||
None
|
||||
Err(err)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -420,9 +430,12 @@ impl<'a, 'sess> MetaItemListParserContext<'a, 'sess> {
|
|||
|
||||
if !lit.kind.is_unsuffixed() {
|
||||
// Emit error and continue, we can still parse the attribute as if the suffix isn't there
|
||||
self.should_emit.emit_err(
|
||||
self.parser.dcx().create_err(SuffixedLiteralInAttribute { span: lit.span }),
|
||||
);
|
||||
let err = self.parser.dcx().create_err(SuffixedLiteralInAttribute { span: lit.span });
|
||||
if matches!(self.should_emit, ShouldEmit::ErrorsAndLints { recover: false }) {
|
||||
return Err(err);
|
||||
} else {
|
||||
self.should_emit.emit_err(err)
|
||||
};
|
||||
}
|
||||
|
||||
Ok(lit)
|
||||
|
|
|
|||
|
|
@ -525,6 +525,10 @@ pub(crate) enum AttributeParseErrorReason<'a> {
|
|||
byte_string: Option<Span>,
|
||||
},
|
||||
ExpectedIntegerLiteral,
|
||||
ExpectedIntegerLiteralInRange {
|
||||
lower_bound: isize,
|
||||
upper_bound: isize,
|
||||
},
|
||||
ExpectedAtLeastOneArgument,
|
||||
ExpectedSingleArgument,
|
||||
ExpectedList,
|
||||
|
|
@ -596,6 +600,17 @@ impl<'a, G: EmissionGuarantee> Diagnostic<'a, G> for AttributeParseError<'_> {
|
|||
AttributeParseErrorReason::ExpectedIntegerLiteral => {
|
||||
diag.span_label(self.span, "expected an integer literal here");
|
||||
}
|
||||
AttributeParseErrorReason::ExpectedIntegerLiteralInRange {
|
||||
lower_bound,
|
||||
upper_bound,
|
||||
} => {
|
||||
diag.span_label(
|
||||
self.span,
|
||||
format!(
|
||||
"expected an integer literal in the range of {lower_bound}..={upper_bound}"
|
||||
),
|
||||
);
|
||||
}
|
||||
AttributeParseErrorReason::ExpectedSingleArgument => {
|
||||
diag.span_label(self.span, "expected a single argument here");
|
||||
diag.code(E0805);
|
||||
|
|
|
|||
|
|
@ -45,7 +45,6 @@ pub(super) fn convert_typeck_constraints<'tcx>(
|
|||
{
|
||||
localize_statement_constraint(
|
||||
tcx,
|
||||
body,
|
||||
stmt,
|
||||
&outlives_constraint,
|
||||
point,
|
||||
|
|
@ -74,7 +73,6 @@ pub(super) fn convert_typeck_constraints<'tcx>(
|
|||
/// needed CFG `from`-`to` intra-block nodes.
|
||||
fn localize_statement_constraint<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
body: &Body<'tcx>,
|
||||
stmt: &Statement<'tcx>,
|
||||
outlives_constraint: &OutlivesConstraint<'tcx>,
|
||||
current_point: PointIndex,
|
||||
|
|
@ -114,28 +112,22 @@ fn localize_statement_constraint<'tcx>(
|
|||
},
|
||||
"there should be no common regions between the LHS and RHS of an assignment"
|
||||
);
|
||||
|
||||
let lhs_ty = body.local_decls[lhs.local].ty;
|
||||
let successor_point = current_point;
|
||||
compute_constraint_direction(
|
||||
tcx,
|
||||
outlives_constraint,
|
||||
&lhs_ty,
|
||||
current_point,
|
||||
successor_point,
|
||||
universal_regions,
|
||||
)
|
||||
}
|
||||
_ => {
|
||||
// For the other cases, we localize an outlives constraint to where it arises.
|
||||
LocalizedOutlivesConstraint {
|
||||
source: outlives_constraint.sup,
|
||||
from: current_point,
|
||||
target: outlives_constraint.sub,
|
||||
to: current_point,
|
||||
}
|
||||
// Assignments should be the only statement that can both generate constraints that
|
||||
// apply on entry (specific to the RHS place) *and* others that only apply on exit (the
|
||||
// subset of RHS regions that actually flow into the LHS): i.e., where midpoints would
|
||||
// be used to ensure the former happen before the latter, within the same MIR Location.
|
||||
}
|
||||
}
|
||||
|
||||
// We generally localize an outlives constraint to where it arises.
|
||||
LocalizedOutlivesConstraint {
|
||||
source: outlives_constraint.sup,
|
||||
from: current_point,
|
||||
target: outlives_constraint.sub,
|
||||
to: current_point,
|
||||
}
|
||||
}
|
||||
|
||||
/// For a given outlives constraint arising from a MIR terminator, localize the constraint with the
|
||||
|
|
@ -150,14 +142,12 @@ fn localize_terminator_constraint<'tcx>(
|
|||
universal_regions: &UniversalRegions<'tcx>,
|
||||
) -> LocalizedOutlivesConstraint {
|
||||
// FIXME: check if other terminators need the same handling as `Call`s, in particular
|
||||
// Assert/Yield/Drop. A handful of tests are failing with Drop related issues, as well as some
|
||||
// coroutine tests, and that may be why.
|
||||
// Assert/Yield/Drop.
|
||||
match &terminator.kind {
|
||||
// FIXME: also handle diverging calls.
|
||||
TerminatorKind::Call { destination, target: Some(target), .. } => {
|
||||
// Calls are similar to assignments, and thus follow the same pattern. If there is a
|
||||
// target for the call we also relate what flows into the destination here to entry to
|
||||
// that successor.
|
||||
// If there is a target for the call we also relate what flows into the destination here
|
||||
// to entry to that successor.
|
||||
let destination_ty = destination.ty(&body.local_decls, tcx);
|
||||
let successor_location = Location { block: *target, statement_index: 0 };
|
||||
let successor_point = liveness.point_from_location(successor_location);
|
||||
|
|
|
|||
|
|
@ -40,8 +40,11 @@ fn parse_cfg(cx: &ExtCtxt<'_>, span: Span, tts: TokenStream) -> Result<CfgEntry,
|
|||
return Err(cx.dcx().emit_err(errors::RequiresCfgPattern { span }));
|
||||
}
|
||||
|
||||
let meta = MetaItemOrLitParser::parse_single(&mut parser, ShouldEmit::ErrorsAndLints)
|
||||
.map_err(|diag| diag.emit())?;
|
||||
let meta = MetaItemOrLitParser::parse_single(
|
||||
&mut parser,
|
||||
ShouldEmit::ErrorsAndLints { recover: true },
|
||||
)
|
||||
.map_err(|diag| diag.emit())?;
|
||||
let cfg = AttributeParser::parse_single_args(
|
||||
cx.sess,
|
||||
span,
|
||||
|
|
@ -55,7 +58,7 @@ fn parse_cfg(cx: &ExtCtxt<'_>, span: Span, tts: TokenStream) -> Result<CfgEntry,
|
|||
// Doesn't matter what the target actually is here.
|
||||
Target::Crate,
|
||||
Some(cx.ecfg.features),
|
||||
ShouldEmit::ErrorsAndLints,
|
||||
ShouldEmit::ErrorsAndLints { recover: true },
|
||||
&meta,
|
||||
parse_cfg_entry,
|
||||
&CFG_TEMPLATE,
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ use rustc_expand::base::{Annotatable, ExtCtxt};
|
|||
use rustc_expand::config::StripUnconfigured;
|
||||
use rustc_expand::configure;
|
||||
use rustc_feature::Features;
|
||||
use rustc_parse::parser::{ForceCollect, Parser};
|
||||
use rustc_parse::parser::{AllowConstBlockItems, ForceCollect, Parser};
|
||||
use rustc_session::Session;
|
||||
use rustc_span::{Span, sym};
|
||||
use smallvec::SmallVec;
|
||||
|
|
@ -110,7 +110,8 @@ impl CfgEval<'_> {
|
|||
let res: PResult<'_, Annotatable> = try {
|
||||
match annotatable {
|
||||
Annotatable::Item(_) => {
|
||||
let item = parser.parse_item(ForceCollect::Yes)?.unwrap();
|
||||
let item =
|
||||
parser.parse_item(ForceCollect::Yes, AllowConstBlockItems::Yes)?.unwrap();
|
||||
Annotatable::Item(self.flat_map_item(item).pop().unwrap())
|
||||
}
|
||||
Annotatable::AssocItem(_, ctxt) => {
|
||||
|
|
|
|||
|
|
@ -986,16 +986,6 @@ impl<'a> MethodDef<'a> {
|
|||
f(cx, span, &substructure)
|
||||
}
|
||||
|
||||
fn get_ret_ty(
|
||||
&self,
|
||||
cx: &ExtCtxt<'_>,
|
||||
trait_: &TraitDef<'_>,
|
||||
generics: &Generics,
|
||||
type_ident: Ident,
|
||||
) -> Box<ast::Ty> {
|
||||
self.ret_ty.to_ty(cx, trait_.span, type_ident, generics)
|
||||
}
|
||||
|
||||
fn is_static(&self) -> bool {
|
||||
!self.explicit_self
|
||||
}
|
||||
|
|
@ -1068,10 +1058,14 @@ impl<'a> MethodDef<'a> {
|
|||
self_arg.into_iter().chain(nonself_args).collect()
|
||||
};
|
||||
|
||||
let ret_type = self.get_ret_ty(cx, trait_, generics, type_ident);
|
||||
let ret_type = if let Ty::Unit = &self.ret_ty {
|
||||
ast::FnRetTy::Default(span)
|
||||
} else {
|
||||
ast::FnRetTy::Ty(self.ret_ty.to_ty(cx, span, type_ident, generics))
|
||||
};
|
||||
|
||||
let method_ident = Ident::new(self.name, span);
|
||||
let fn_decl = cx.fn_decl(args, ast::FnRetTy::Ty(ret_type));
|
||||
let fn_decl = cx.fn_decl(args, ret_type);
|
||||
let body_block = body.into_block(cx, span);
|
||||
|
||||
let trait_lo_sp = span.shrink_to_lo();
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@ use rustc_expand::base::{
|
|||
};
|
||||
use rustc_expand::module::DirOwnership;
|
||||
use rustc_parse::lexer::StripTokens;
|
||||
use rustc_parse::parser::ForceCollect;
|
||||
use rustc_parse::parser::{AllowConstBlockItems, ForceCollect};
|
||||
use rustc_parse::{new_parser_from_file, unwrap_or_emit_fatal, utf8_error};
|
||||
use rustc_session::lint::builtin::INCOMPLETE_INCLUDE;
|
||||
use rustc_session::parse::ParseSess;
|
||||
|
|
@ -168,7 +168,7 @@ pub(crate) fn expand_include<'cx>(
|
|||
));
|
||||
let mut ret = SmallVec::new();
|
||||
loop {
|
||||
match p.parse_item(ForceCollect::No) {
|
||||
match p.parse_item(ForceCollect::No, AllowConstBlockItems::Yes) {
|
||||
Err(err) => {
|
||||
err.emit();
|
||||
break;
|
||||
|
|
|
|||
|
|
@ -56,6 +56,9 @@ pub(crate) fn conv_to_call_conv(
|
|||
CanonAbi::Rust | CanonAbi::C => default_call_conv,
|
||||
CanonAbi::RustCold => CallConv::Cold,
|
||||
|
||||
// Cranelift doesn't currently have anything for this.
|
||||
CanonAbi::RustPreserveNone => default_call_conv,
|
||||
|
||||
// Functions with this calling convention can only be called from assembly, but it is
|
||||
// possible to declare an `extern "custom"` block, so the backend still needs a calling
|
||||
// convention for declaring foreign functions.
|
||||
|
|
|
|||
|
|
@ -242,7 +242,7 @@ impl DebugContext {
|
|||
let generics = tcx.generics_of(enclosing_fn_def_id);
|
||||
let args = instance.args.truncate_to(tcx, generics);
|
||||
|
||||
type_names::push_generic_params(
|
||||
type_names::push_generic_args(
|
||||
tcx,
|
||||
tcx.normalize_erasing_regions(ty::TypingEnv::fully_monomorphized(), args),
|
||||
&mut name,
|
||||
|
|
|
|||
|
|
@ -1506,7 +1506,7 @@ fn codegen_regular_intrinsic_call<'tcx>(
|
|||
}
|
||||
|
||||
// FIXME implement variadics in cranelift
|
||||
sym::va_copy | sym::va_arg | sym::va_end => {
|
||||
sym::va_arg | sym::va_end => {
|
||||
fx.tcx.dcx().span_fatal(
|
||||
source_info.span,
|
||||
"Defining variadic functions is not yet supported by Cranelift",
|
||||
|
|
|
|||
|
|
@ -348,6 +348,31 @@ pub(super) fn codegen_simd_intrinsic_call<'tcx>(
|
|||
ret.write_cvalue(fx, ret_lane);
|
||||
}
|
||||
|
||||
sym::simd_splat => {
|
||||
intrinsic_args!(fx, args => (value); intrinsic);
|
||||
|
||||
if !ret.layout().ty.is_simd() {
|
||||
report_simd_type_validation_error(fx, intrinsic, span, ret.layout().ty);
|
||||
return;
|
||||
}
|
||||
let (lane_count, lane_ty) = ret.layout().ty.simd_size_and_type(fx.tcx);
|
||||
|
||||
if value.layout().ty != lane_ty {
|
||||
fx.tcx.dcx().span_fatal(
|
||||
span,
|
||||
format!(
|
||||
"[simd_splat] expected element type {lane_ty:?}, got {got:?}",
|
||||
got = value.layout().ty
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
for i in 0..lane_count {
|
||||
let ret_lane = ret.place_lane(fx, i.into());
|
||||
ret_lane.write_cvalue(fx, value);
|
||||
}
|
||||
}
|
||||
|
||||
sym::simd_neg
|
||||
| sym::simd_bswap
|
||||
| sym::simd_bitreverse
|
||||
|
|
|
|||
|
|
@ -243,6 +243,8 @@ impl<'gcc, 'tcx> FnAbiGccExt<'gcc, 'tcx> for FnAbi<'tcx, Ty<'tcx>> {
|
|||
pub fn conv_to_fn_attribute<'gcc>(conv: CanonAbi, arch: &Arch) -> Option<FnAttribute<'gcc>> {
|
||||
let attribute = match conv {
|
||||
CanonAbi::C | CanonAbi::Rust => return None,
|
||||
// gcc/gccjit does not have anything for this.
|
||||
CanonAbi::RustPreserveNone => return None,
|
||||
CanonAbi::RustCold => FnAttribute::Cold,
|
||||
// Functions with this calling convention can only be called from assembly, but it is
|
||||
// possible to declare an `extern "custom"` block, so the backend still needs a calling
|
||||
|
|
|
|||
|
|
@ -26,11 +26,11 @@ use std::sync::atomic::Ordering;
|
|||
use gccjit::{Context, OutputKind};
|
||||
use object::read::archive::ArchiveFile;
|
||||
use rustc_codegen_ssa::back::lto::{SerializedModule, ThinModule, ThinShared};
|
||||
use rustc_codegen_ssa::back::write::{CodegenContext, FatLtoInput};
|
||||
use rustc_codegen_ssa::back::write::{CodegenContext, FatLtoInput, SharedEmitter};
|
||||
use rustc_codegen_ssa::traits::*;
|
||||
use rustc_codegen_ssa::{ModuleCodegen, ModuleKind, looks_like_rust_object_file};
|
||||
use rustc_data_structures::memmap::Mmap;
|
||||
use rustc_errors::DiagCtxtHandle;
|
||||
use rustc_errors::{DiagCtxt, DiagCtxtHandle};
|
||||
use rustc_log::tracing::info;
|
||||
use rustc_middle::bug;
|
||||
use rustc_middle::dep_graph::WorkProduct;
|
||||
|
|
@ -112,10 +112,11 @@ fn save_as_file(obj: &[u8], path: &Path) -> Result<(), LtoBitcodeFromRlib> {
|
|||
/// for further optimization.
|
||||
pub(crate) fn run_fat(
|
||||
cgcx: &CodegenContext<GccCodegenBackend>,
|
||||
shared_emitter: &SharedEmitter,
|
||||
each_linked_rlib_for_lto: &[PathBuf],
|
||||
modules: Vec<FatLtoInput<GccCodegenBackend>>,
|
||||
) -> ModuleCodegen<GccContext> {
|
||||
let dcx = cgcx.create_dcx();
|
||||
let dcx = DiagCtxt::new(Box::new(shared_emitter.clone()));
|
||||
let dcx = dcx.handle();
|
||||
let lto_data = prepare_lto(cgcx, each_linked_rlib_for_lto, dcx);
|
||||
/*let symbols_below_threshold =
|
||||
|
|
@ -283,14 +284,13 @@ impl ModuleBufferMethods for ModuleBuffer {
|
|||
/// can simply be copied over from the incr. comp. cache.
|
||||
pub(crate) fn run_thin(
|
||||
cgcx: &CodegenContext<GccCodegenBackend>,
|
||||
dcx: DiagCtxtHandle<'_>,
|
||||
each_linked_rlib_for_lto: &[PathBuf],
|
||||
modules: Vec<(String, ThinBuffer)>,
|
||||
cached_modules: Vec<(SerializedModule<ModuleBuffer>, WorkProduct)>,
|
||||
) -> (Vec<ThinModule<GccCodegenBackend>>, Vec<WorkProduct>) {
|
||||
let dcx = cgcx.create_dcx();
|
||||
let dcx = dcx.handle();
|
||||
let lto_data = prepare_lto(cgcx, each_linked_rlib_for_lto, dcx);
|
||||
if cgcx.opts.cg.linker_plugin_lto.enabled() {
|
||||
if cgcx.use_linker_plugin_lto {
|
||||
unreachable!(
|
||||
"We should never reach this case if the LTO step \
|
||||
is deferred to the linker"
|
||||
|
|
@ -522,8 +522,6 @@ pub fn optimize_thin_module(
|
|||
thin_module: ThinModule<GccCodegenBackend>,
|
||||
_cgcx: &CodegenContext<GccCodegenBackend>,
|
||||
) -> ModuleCodegen<GccContext> {
|
||||
//let dcx = cgcx.create_dcx();
|
||||
|
||||
//let module_name = &thin_module.shared.module_names[thin_module.idx];
|
||||
/*let tm_factory_config = TargetMachineFactoryConfig::new(cgcx, module_name.to_str().unwrap());
|
||||
let tm = (cgcx.tm_factory)(tm_factory_config).map_err(|e| write::llvm_err(&dcx, e))?;*/
|
||||
|
|
|
|||
|
|
@ -2,8 +2,11 @@ use std::{env, fs};
|
|||
|
||||
use gccjit::{Context, OutputKind};
|
||||
use rustc_codegen_ssa::back::link::ensure_removed;
|
||||
use rustc_codegen_ssa::back::write::{BitcodeSection, CodegenContext, EmitObj, ModuleConfig};
|
||||
use rustc_codegen_ssa::back::write::{
|
||||
BitcodeSection, CodegenContext, EmitObj, ModuleConfig, SharedEmitter,
|
||||
};
|
||||
use rustc_codegen_ssa::{CompiledModule, ModuleCodegen};
|
||||
use rustc_errors::DiagCtxt;
|
||||
use rustc_fs_util::link_or_copy;
|
||||
use rustc_log::tracing::debug;
|
||||
use rustc_session::config::OutputType;
|
||||
|
|
@ -15,10 +18,11 @@ use crate::{GccCodegenBackend, GccContext, LtoMode};
|
|||
|
||||
pub(crate) fn codegen(
|
||||
cgcx: &CodegenContext<GccCodegenBackend>,
|
||||
shared_emitter: &SharedEmitter,
|
||||
module: ModuleCodegen<GccContext>,
|
||||
config: &ModuleConfig,
|
||||
) -> CompiledModule {
|
||||
let dcx = cgcx.create_dcx();
|
||||
let dcx = DiagCtxt::new(Box::new(shared_emitter.clone()));
|
||||
let dcx = dcx.handle();
|
||||
|
||||
let _timer = cgcx.prof.generic_activity_with_arg("GCC_module_codegen", &*module.name);
|
||||
|
|
|
|||
|
|
@ -391,9 +391,6 @@ impl<'a, 'gcc, 'tcx> IntrinsicCallBuilderMethods<'tcx> for Builder<'a, 'gcc, 'tc
|
|||
sym::breakpoint => {
|
||||
unimplemented!();
|
||||
}
|
||||
sym::va_copy => {
|
||||
unimplemented!();
|
||||
}
|
||||
sym::va_arg => {
|
||||
unimplemented!();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -121,6 +121,42 @@ pub fn generic_simd_intrinsic<'a, 'gcc, 'tcx>(
|
|||
return Ok(bx.vector_select(vector_mask, arg1, args[2].immediate()));
|
||||
}
|
||||
|
||||
#[cfg(feature = "master")]
|
||||
if name == sym::simd_splat {
|
||||
let (out_len, out_ty) = require_simd2!(ret_ty, SimdReturn);
|
||||
|
||||
require!(
|
||||
args[0].layout.ty == out_ty,
|
||||
InvalidMonomorphization::ExpectedVectorElementType {
|
||||
span,
|
||||
name,
|
||||
expected_element: out_ty,
|
||||
vector_type: ret_ty,
|
||||
}
|
||||
);
|
||||
|
||||
let vec_ty = llret_ty.unqualified().dyncast_vector().expect("vector return type");
|
||||
let elem_ty = vec_ty.get_element_type();
|
||||
|
||||
// Cast pointer type to usize (GCC does not support pointer SIMD vectors).
|
||||
let value = args[0];
|
||||
let scalar = if value.layout.ty.is_numeric() {
|
||||
value.immediate()
|
||||
} else if value.layout.ty.is_raw_ptr() {
|
||||
bx.ptrtoint(value.immediate(), elem_ty)
|
||||
} else {
|
||||
return_error!(InvalidMonomorphization::UnsupportedOperation {
|
||||
span,
|
||||
name,
|
||||
in_ty: ret_ty,
|
||||
in_elem: value.layout.ty
|
||||
});
|
||||
};
|
||||
|
||||
let elements = vec![scalar; out_len as usize];
|
||||
return Ok(bx.context.new_rvalue_from_vector(bx.location, llret_ty, &elements));
|
||||
}
|
||||
|
||||
// every intrinsic below takes a SIMD vector as its first argument
|
||||
require_simd!(
|
||||
args[0].layout.ty,
|
||||
|
|
|
|||
|
|
@ -84,7 +84,7 @@ use gccjit::{TargetInfo, Version};
|
|||
use rustc_ast::expand::allocator::AllocatorMethod;
|
||||
use rustc_codegen_ssa::back::lto::{SerializedModule, ThinModule};
|
||||
use rustc_codegen_ssa::back::write::{
|
||||
CodegenContext, FatLtoInput, ModuleConfig, TargetMachineFactoryFn,
|
||||
CodegenContext, FatLtoInput, ModuleConfig, SharedEmitter, TargetMachineFactoryFn,
|
||||
};
|
||||
use rustc_codegen_ssa::base::codegen_crate;
|
||||
use rustc_codegen_ssa::target_features::cfg_target_feature;
|
||||
|
|
@ -435,23 +435,25 @@ impl WriteBackendMethods for GccCodegenBackend {
|
|||
|
||||
fn run_and_optimize_fat_lto(
|
||||
cgcx: &CodegenContext<Self>,
|
||||
shared_emitter: &SharedEmitter,
|
||||
// FIXME(bjorn3): Limit LTO exports to these symbols
|
||||
_exported_symbols_for_lto: &[String],
|
||||
each_linked_rlib_for_lto: &[PathBuf],
|
||||
modules: Vec<FatLtoInput<Self>>,
|
||||
) -> ModuleCodegen<Self::Module> {
|
||||
back::lto::run_fat(cgcx, each_linked_rlib_for_lto, modules)
|
||||
back::lto::run_fat(cgcx, shared_emitter, each_linked_rlib_for_lto, modules)
|
||||
}
|
||||
|
||||
fn run_thin_lto(
|
||||
cgcx: &CodegenContext<Self>,
|
||||
dcx: DiagCtxtHandle<'_>,
|
||||
// FIXME(bjorn3): Limit LTO exports to these symbols
|
||||
_exported_symbols_for_lto: &[String],
|
||||
each_linked_rlib_for_lto: &[PathBuf],
|
||||
modules: Vec<(String, Self::ThinBuffer)>,
|
||||
cached_modules: Vec<(SerializedModule<Self::ModuleBuffer>, WorkProduct)>,
|
||||
) -> (Vec<ThinModule<Self>>, Vec<WorkProduct>) {
|
||||
back::lto::run_thin(cgcx, each_linked_rlib_for_lto, modules, cached_modules)
|
||||
back::lto::run_thin(cgcx, dcx, each_linked_rlib_for_lto, modules, cached_modules)
|
||||
}
|
||||
|
||||
fn print_pass_timings(&self) {
|
||||
|
|
@ -464,7 +466,7 @@ impl WriteBackendMethods for GccCodegenBackend {
|
|||
|
||||
fn optimize(
|
||||
_cgcx: &CodegenContext<Self>,
|
||||
_dcx: DiagCtxtHandle<'_>,
|
||||
_shared_emitter: &SharedEmitter,
|
||||
module: &mut ModuleCodegen<Self::Module>,
|
||||
config: &ModuleConfig,
|
||||
) {
|
||||
|
|
@ -473,6 +475,7 @@ impl WriteBackendMethods for GccCodegenBackend {
|
|||
|
||||
fn optimize_thin(
|
||||
cgcx: &CodegenContext<Self>,
|
||||
_shared_emitter: &SharedEmitter,
|
||||
thin: ThinModule<Self>,
|
||||
) -> ModuleCodegen<Self::Module> {
|
||||
back::lto::optimize_thin_module(thin, cgcx)
|
||||
|
|
@ -480,10 +483,11 @@ impl WriteBackendMethods for GccCodegenBackend {
|
|||
|
||||
fn codegen(
|
||||
cgcx: &CodegenContext<Self>,
|
||||
shared_emitter: &SharedEmitter,
|
||||
module: ModuleCodegen<Self::Module>,
|
||||
config: &ModuleConfig,
|
||||
) -> CompiledModule {
|
||||
back::write::codegen(cgcx, module, config)
|
||||
back::write::codegen(cgcx, shared_emitter, module, config)
|
||||
}
|
||||
|
||||
fn prepare_thin(module: ModuleCodegen<Self::Module>) -> (String, Self::ThinBuffer) {
|
||||
|
|
|
|||
|
|
@ -694,6 +694,10 @@ pub(crate) fn to_llvm_calling_convention(sess: &Session, abi: CanonAbi) -> llvm:
|
|||
match abi {
|
||||
CanonAbi::C | CanonAbi::Rust => llvm::CCallConv,
|
||||
CanonAbi::RustCold => llvm::PreserveMost,
|
||||
CanonAbi::RustPreserveNone => match &sess.target.arch {
|
||||
Arch::X86_64 | Arch::AArch64 => llvm::PreserveNone,
|
||||
_ => llvm::CCallConv,
|
||||
},
|
||||
// Functions with this calling convention can only be called from assembly, but it is
|
||||
// possible to declare an `extern "custom"` block, so the backend still needs a calling
|
||||
// convention for declaring foreign functions.
|
||||
|
|
|
|||
|
|
@ -370,7 +370,7 @@ fn create_alloc_family_attr(llcx: &llvm::Context) -> &llvm::Attribute {
|
|||
llvm::CreateAttrStringValue(llcx, "alloc-family", "__rust_alloc")
|
||||
}
|
||||
|
||||
/// Helper for `FnAbi::apply_attrs_llfn`:
|
||||
/// Helper for `FnAbiLlvmExt::apply_attrs_llfn`:
|
||||
/// Composite function which sets LLVM attributes for function depending on its AST (`#[attribute]`)
|
||||
/// attributes.
|
||||
pub(crate) fn llfn_attrs_from_instance<'ll, 'tcx>(
|
||||
|
|
@ -516,7 +516,16 @@ pub(crate) fn llfn_attrs_from_instance<'ll, 'tcx>(
|
|||
to_add.push(llvm::CreateAllocKindAttr(cx.llcx, AllocKindFlags::Free));
|
||||
// applies to argument place instead of function place
|
||||
let allocated_pointer = AttributeKind::AllocatedPointer.create_attr(cx.llcx);
|
||||
attributes::apply_to_llfn(llfn, AttributePlace::Argument(0), &[allocated_pointer]);
|
||||
let attrs: &[_] = if llvm_util::get_version() >= (21, 0, 0) {
|
||||
// "Does not capture provenance" means "if the function call stashes the pointer somewhere,
|
||||
// accessing that pointer after the function returns is UB". That is definitely the case here since
|
||||
// freeing will destroy the provenance.
|
||||
let captures_addr = AttributeKind::CapturesAddress.create_attr(cx.llcx);
|
||||
&[allocated_pointer, captures_addr]
|
||||
} else {
|
||||
&[allocated_pointer]
|
||||
};
|
||||
attributes::apply_to_llfn(llfn, AttributePlace::Argument(0), attrs);
|
||||
}
|
||||
if let Some(align) = codegen_fn_attrs.alignment {
|
||||
llvm::set_alignment(llfn, align);
|
||||
|
|
|
|||
|
|
@ -9,12 +9,12 @@ use std::{io, iter, slice};
|
|||
use object::read::archive::ArchiveFile;
|
||||
use object::{Object, ObjectSection};
|
||||
use rustc_codegen_ssa::back::lto::{SerializedModule, ThinModule, ThinShared};
|
||||
use rustc_codegen_ssa::back::write::{CodegenContext, FatLtoInput};
|
||||
use rustc_codegen_ssa::back::write::{CodegenContext, FatLtoInput, SharedEmitter};
|
||||
use rustc_codegen_ssa::traits::*;
|
||||
use rustc_codegen_ssa::{ModuleCodegen, ModuleKind, looks_like_rust_object_file};
|
||||
use rustc_data_structures::fx::FxHashMap;
|
||||
use rustc_data_structures::memmap::Mmap;
|
||||
use rustc_errors::DiagCtxtHandle;
|
||||
use rustc_errors::{DiagCtxt, DiagCtxtHandle};
|
||||
use rustc_hir::attrs::SanitizerSet;
|
||||
use rustc_middle::bug;
|
||||
use rustc_middle::dep_graph::WorkProduct;
|
||||
|
|
@ -150,17 +150,18 @@ fn get_bitcode_slice_from_object_data<'a>(
|
|||
/// for further optimization.
|
||||
pub(crate) fn run_fat(
|
||||
cgcx: &CodegenContext<LlvmCodegenBackend>,
|
||||
shared_emitter: &SharedEmitter,
|
||||
exported_symbols_for_lto: &[String],
|
||||
each_linked_rlib_for_lto: &[PathBuf],
|
||||
modules: Vec<FatLtoInput<LlvmCodegenBackend>>,
|
||||
) -> ModuleCodegen<ModuleLlvm> {
|
||||
let dcx = cgcx.create_dcx();
|
||||
let dcx = DiagCtxt::new(Box::new(shared_emitter.clone()));
|
||||
let dcx = dcx.handle();
|
||||
let (symbols_below_threshold, upstream_modules) =
|
||||
prepare_lto(cgcx, exported_symbols_for_lto, each_linked_rlib_for_lto, dcx);
|
||||
let symbols_below_threshold =
|
||||
symbols_below_threshold.iter().map(|c| c.as_ptr()).collect::<Vec<_>>();
|
||||
fat_lto(cgcx, dcx, modules, upstream_modules, &symbols_below_threshold)
|
||||
fat_lto(cgcx, dcx, shared_emitter, modules, upstream_modules, &symbols_below_threshold)
|
||||
}
|
||||
|
||||
/// Performs thin LTO by performing necessary global analysis and returning two
|
||||
|
|
@ -168,18 +169,17 @@ pub(crate) fn run_fat(
|
|||
/// can simply be copied over from the incr. comp. cache.
|
||||
pub(crate) fn run_thin(
|
||||
cgcx: &CodegenContext<LlvmCodegenBackend>,
|
||||
dcx: DiagCtxtHandle<'_>,
|
||||
exported_symbols_for_lto: &[String],
|
||||
each_linked_rlib_for_lto: &[PathBuf],
|
||||
modules: Vec<(String, ThinBuffer)>,
|
||||
cached_modules: Vec<(SerializedModule<ModuleBuffer>, WorkProduct)>,
|
||||
) -> (Vec<ThinModule<LlvmCodegenBackend>>, Vec<WorkProduct>) {
|
||||
let dcx = cgcx.create_dcx();
|
||||
let dcx = dcx.handle();
|
||||
let (symbols_below_threshold, upstream_modules) =
|
||||
prepare_lto(cgcx, exported_symbols_for_lto, each_linked_rlib_for_lto, dcx);
|
||||
let symbols_below_threshold =
|
||||
symbols_below_threshold.iter().map(|c| c.as_ptr()).collect::<Vec<_>>();
|
||||
if cgcx.opts.cg.linker_plugin_lto.enabled() {
|
||||
if cgcx.use_linker_plugin_lto {
|
||||
unreachable!(
|
||||
"We should never reach this case if the LTO step \
|
||||
is deferred to the linker"
|
||||
|
|
@ -197,6 +197,7 @@ pub(crate) fn prepare_thin(module: ModuleCodegen<ModuleLlvm>) -> (String, ThinBu
|
|||
fn fat_lto(
|
||||
cgcx: &CodegenContext<LlvmCodegenBackend>,
|
||||
dcx: DiagCtxtHandle<'_>,
|
||||
shared_emitter: &SharedEmitter,
|
||||
modules: Vec<FatLtoInput<LlvmCodegenBackend>>,
|
||||
mut serialized_modules: Vec<(SerializedModule<ModuleBuffer>, CString)>,
|
||||
symbols_below_threshold: &[*const libc::c_char],
|
||||
|
|
@ -265,8 +266,13 @@ fn fat_lto(
|
|||
// The linking steps below may produce errors and diagnostics within LLVM
|
||||
// which we'd like to handle and print, so set up our diagnostic handlers
|
||||
// (which get unregistered when they go out of scope below).
|
||||
let _handler =
|
||||
DiagnosticHandlers::new(cgcx, dcx, llcx, &module, CodegenDiagnosticsStage::LTO);
|
||||
let _handler = DiagnosticHandlers::new(
|
||||
cgcx,
|
||||
shared_emitter,
|
||||
llcx,
|
||||
&module,
|
||||
CodegenDiagnosticsStage::LTO,
|
||||
);
|
||||
|
||||
// For all other modules we codegened we'll need to link them into our own
|
||||
// bitcode. All modules were codegened in their own LLVM context, however,
|
||||
|
|
@ -720,10 +726,11 @@ impl Drop for ThinBuffer {
|
|||
}
|
||||
|
||||
pub(crate) fn optimize_thin_module(
|
||||
thin_module: ThinModule<LlvmCodegenBackend>,
|
||||
cgcx: &CodegenContext<LlvmCodegenBackend>,
|
||||
shared_emitter: &SharedEmitter,
|
||||
thin_module: ThinModule<LlvmCodegenBackend>,
|
||||
) -> ModuleCodegen<ModuleLlvm> {
|
||||
let dcx = cgcx.create_dcx();
|
||||
let dcx = DiagCtxt::new(Box::new(shared_emitter.clone()));
|
||||
let dcx = dcx.handle();
|
||||
|
||||
let module_name = &thin_module.shared.module_names[thin_module.idx];
|
||||
|
|
|
|||
|
|
@ -39,6 +39,7 @@ impl OwnedTargetMachine {
|
|||
debug_info_compression: llvm::CompressionKind,
|
||||
use_emulated_tls: bool,
|
||||
use_wasm_eh: bool,
|
||||
large_data_threshold: u64,
|
||||
) -> Result<Self, LlvmError<'static>> {
|
||||
// SAFETY: llvm::LLVMRustCreateTargetMachine copies pointed to data
|
||||
let tm_ptr = unsafe {
|
||||
|
|
@ -65,6 +66,7 @@ impl OwnedTargetMachine {
|
|||
debug_info_compression,
|
||||
use_emulated_tls,
|
||||
use_wasm_eh,
|
||||
large_data_threshold,
|
||||
)
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ use libc::{c_char, c_int, c_void, size_t};
|
|||
use rustc_codegen_ssa::back::link::ensure_removed;
|
||||
use rustc_codegen_ssa::back::versioned_llvm_target;
|
||||
use rustc_codegen_ssa::back::write::{
|
||||
BitcodeSection, CodegenContext, EmitObj, InlineAsmError, ModuleConfig,
|
||||
BitcodeSection, CodegenContext, EmitObj, InlineAsmError, ModuleConfig, SharedEmitter,
|
||||
TargetMachineFactoryConfig, TargetMachineFactoryFn,
|
||||
};
|
||||
use rustc_codegen_ssa::base::wants_wasm_eh;
|
||||
|
|
@ -18,7 +18,7 @@ use rustc_codegen_ssa::traits::*;
|
|||
use rustc_codegen_ssa::{CompiledModule, ModuleCodegen, ModuleKind};
|
||||
use rustc_data_structures::profiling::SelfProfilerRef;
|
||||
use rustc_data_structures::small_c_str::SmallCStr;
|
||||
use rustc_errors::{DiagCtxtHandle, Level};
|
||||
use rustc_errors::{DiagCtxt, DiagCtxtHandle, Level};
|
||||
use rustc_fs_util::{link_or_copy, path_to_c_string};
|
||||
use rustc_middle::ty::TyCtxt;
|
||||
use rustc_session::Session;
|
||||
|
|
@ -275,6 +275,8 @@ pub(crate) fn target_machine_factory(
|
|||
|
||||
let use_wasm_eh = wants_wasm_eh(sess);
|
||||
|
||||
let large_data_threshold = sess.opts.unstable_opts.large_data_threshold.unwrap_or(0);
|
||||
|
||||
let prof = SelfProfilerRef::clone(&sess.prof);
|
||||
Arc::new(move |config: TargetMachineFactoryConfig| {
|
||||
// Self-profile timer for invoking a factory to create a target machine.
|
||||
|
|
@ -316,6 +318,7 @@ pub(crate) fn target_machine_factory(
|
|||
debuginfo_compression,
|
||||
use_emulated_tls,
|
||||
use_wasm_eh,
|
||||
large_data_threshold,
|
||||
)
|
||||
})
|
||||
}
|
||||
|
|
@ -356,7 +359,7 @@ pub(crate) enum CodegenDiagnosticsStage {
|
|||
}
|
||||
|
||||
pub(crate) struct DiagnosticHandlers<'a> {
|
||||
data: *mut (&'a CodegenContext<LlvmCodegenBackend>, DiagCtxtHandle<'a>),
|
||||
data: *mut (&'a CodegenContext<LlvmCodegenBackend>, &'a SharedEmitter),
|
||||
llcx: &'a llvm::Context,
|
||||
old_handler: Option<&'a llvm::DiagnosticHandler>,
|
||||
}
|
||||
|
|
@ -364,7 +367,7 @@ pub(crate) struct DiagnosticHandlers<'a> {
|
|||
impl<'a> DiagnosticHandlers<'a> {
|
||||
pub(crate) fn new(
|
||||
cgcx: &'a CodegenContext<LlvmCodegenBackend>,
|
||||
dcx: DiagCtxtHandle<'a>,
|
||||
shared_emitter: &'a SharedEmitter,
|
||||
llcx: &'a llvm::Context,
|
||||
module: &ModuleCodegen<ModuleLlvm>,
|
||||
stage: CodegenDiagnosticsStage,
|
||||
|
|
@ -398,8 +401,8 @@ impl<'a> DiagnosticHandlers<'a> {
|
|||
})
|
||||
.and_then(|dir| dir.to_str().and_then(|p| CString::new(p).ok()));
|
||||
|
||||
let pgo_available = cgcx.opts.cg.profile_use.is_some();
|
||||
let data = Box::into_raw(Box::new((cgcx, dcx)));
|
||||
let pgo_available = cgcx.module_config.pgo_use.is_some();
|
||||
let data = Box::into_raw(Box::new((cgcx, shared_emitter)));
|
||||
unsafe {
|
||||
let old_handler = llvm::LLVMRustContextGetDiagnosticHandler(llcx);
|
||||
llvm::LLVMRustContextConfigureDiagnosticHandler(
|
||||
|
|
@ -461,12 +464,16 @@ unsafe extern "C" fn diagnostic_handler(info: &DiagnosticInfo, user: *mut c_void
|
|||
if user.is_null() {
|
||||
return;
|
||||
}
|
||||
let (cgcx, dcx) =
|
||||
unsafe { *(user as *const (&CodegenContext<LlvmCodegenBackend>, DiagCtxtHandle<'_>)) };
|
||||
let (cgcx, shared_emitter) =
|
||||
unsafe { *(user as *const (&CodegenContext<LlvmCodegenBackend>, &SharedEmitter)) };
|
||||
|
||||
let dcx = DiagCtxt::new(Box::new(shared_emitter.clone()));
|
||||
let dcx = dcx.handle();
|
||||
|
||||
match unsafe { llvm::diagnostic::Diagnostic::unpack(info) } {
|
||||
llvm::diagnostic::InlineAsm(inline) => {
|
||||
cgcx.diag_emitter.inline_asm_error(report_inline_asm(
|
||||
// FIXME use dcx
|
||||
shared_emitter.inline_asm_error(report_inline_asm(
|
||||
cgcx,
|
||||
inline.message,
|
||||
inline.level,
|
||||
|
|
@ -776,7 +783,7 @@ pub(crate) unsafe fn llvm_optimize(
|
|||
&*module.module_llvm.tm.raw(),
|
||||
to_pass_builder_opt_level(opt_level),
|
||||
opt_stage,
|
||||
cgcx.opts.cg.linker_plugin_lto.enabled(),
|
||||
cgcx.use_linker_plugin_lto,
|
||||
config.no_prepopulate_passes,
|
||||
config.verify_llvm_ir,
|
||||
config.lint_llvm_ir,
|
||||
|
|
@ -887,14 +894,18 @@ pub(crate) unsafe fn llvm_optimize(
|
|||
// Unsafe due to LLVM calls.
|
||||
pub(crate) fn optimize(
|
||||
cgcx: &CodegenContext<LlvmCodegenBackend>,
|
||||
dcx: DiagCtxtHandle<'_>,
|
||||
shared_emitter: &SharedEmitter,
|
||||
module: &mut ModuleCodegen<ModuleLlvm>,
|
||||
config: &ModuleConfig,
|
||||
) {
|
||||
let _timer = cgcx.prof.generic_activity_with_arg("LLVM_module_optimize", &*module.name);
|
||||
|
||||
let dcx = DiagCtxt::new(Box::new(shared_emitter.clone()));
|
||||
let dcx = dcx.handle();
|
||||
|
||||
let llcx = &*module.module_llvm.llcx;
|
||||
let _handlers = DiagnosticHandlers::new(cgcx, dcx, llcx, module, CodegenDiagnosticsStage::Opt);
|
||||
let _handlers =
|
||||
DiagnosticHandlers::new(cgcx, shared_emitter, llcx, module, CodegenDiagnosticsStage::Opt);
|
||||
|
||||
if config.emit_no_opt_bc {
|
||||
let out = cgcx.output_filenames.temp_path_ext_for_cgu(
|
||||
|
|
@ -911,7 +922,7 @@ pub(crate) fn optimize(
|
|||
let opt_stage = match cgcx.lto {
|
||||
Lto::Fat => llvm::OptStage::PreLinkFatLTO,
|
||||
Lto::Thin | Lto::ThinLocal => llvm::OptStage::PreLinkThinLTO,
|
||||
_ if cgcx.opts.cg.linker_plugin_lto.enabled() => llvm::OptStage::PreLinkThinLTO,
|
||||
_ if cgcx.use_linker_plugin_lto => llvm::OptStage::PreLinkThinLTO,
|
||||
_ => llvm::OptStage::PreLinkNoLTO,
|
||||
};
|
||||
|
||||
|
|
@ -974,19 +985,26 @@ pub(crate) fn optimize(
|
|||
|
||||
pub(crate) fn codegen(
|
||||
cgcx: &CodegenContext<LlvmCodegenBackend>,
|
||||
shared_emitter: &SharedEmitter,
|
||||
module: ModuleCodegen<ModuleLlvm>,
|
||||
config: &ModuleConfig,
|
||||
) -> CompiledModule {
|
||||
let dcx = cgcx.create_dcx();
|
||||
let _timer = cgcx.prof.generic_activity_with_arg("LLVM_module_codegen", &*module.name);
|
||||
|
||||
let dcx = DiagCtxt::new(Box::new(shared_emitter.clone()));
|
||||
let dcx = dcx.handle();
|
||||
|
||||
let _timer = cgcx.prof.generic_activity_with_arg("LLVM_module_codegen", &*module.name);
|
||||
{
|
||||
let llmod = module.module_llvm.llmod();
|
||||
let llcx = &*module.module_llvm.llcx;
|
||||
let tm = &*module.module_llvm.tm;
|
||||
let _handlers =
|
||||
DiagnosticHandlers::new(cgcx, dcx, llcx, &module, CodegenDiagnosticsStage::Codegen);
|
||||
let _handlers = DiagnosticHandlers::new(
|
||||
cgcx,
|
||||
shared_emitter,
|
||||
llcx,
|
||||
&module,
|
||||
CodegenDiagnosticsStage::Codegen,
|
||||
);
|
||||
|
||||
if cgcx.msvc_imps_needed {
|
||||
create_msvc_imps(cgcx, llcx, llmod);
|
||||
|
|
|
|||
|
|
@ -1384,12 +1384,12 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> {
|
|||
fn call(
|
||||
&mut self,
|
||||
llty: &'ll Type,
|
||||
fn_call_attrs: Option<&CodegenFnAttrs>,
|
||||
caller_attrs: Option<&CodegenFnAttrs>,
|
||||
fn_abi: Option<&FnAbi<'tcx, Ty<'tcx>>>,
|
||||
llfn: &'ll Value,
|
||||
args: &[&'ll Value],
|
||||
funclet: Option<&Funclet<'ll>>,
|
||||
instance: Option<Instance<'tcx>>,
|
||||
callee_instance: Option<Instance<'tcx>>,
|
||||
) -> &'ll Value {
|
||||
debug!("call {:?} with args ({:?})", llfn, args);
|
||||
|
||||
|
|
@ -1401,10 +1401,10 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> {
|
|||
}
|
||||
|
||||
// Emit CFI pointer type membership test
|
||||
self.cfi_type_test(fn_call_attrs, fn_abi, instance, llfn);
|
||||
self.cfi_type_test(caller_attrs, fn_abi, callee_instance, llfn);
|
||||
|
||||
// Emit KCFI operand bundle
|
||||
let kcfi_bundle = self.kcfi_operand_bundle(fn_call_attrs, fn_abi, instance, llfn);
|
||||
let kcfi_bundle = self.kcfi_operand_bundle(caller_attrs, fn_abi, callee_instance, llfn);
|
||||
if let Some(kcfi_bundle) = kcfi_bundle.as_ref().map(|b| b.as_ref()) {
|
||||
bundles.push(kcfi_bundle);
|
||||
}
|
||||
|
|
@ -1422,17 +1422,17 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> {
|
|||
)
|
||||
};
|
||||
|
||||
if let Some(instance) = instance {
|
||||
if let Some(callee_instance) = callee_instance {
|
||||
// Attributes on the function definition being called
|
||||
let fn_defn_attrs = self.cx.tcx.codegen_fn_attrs(instance.def_id());
|
||||
if let Some(fn_call_attrs) = fn_call_attrs
|
||||
let callee_attrs = self.cx.tcx.codegen_fn_attrs(callee_instance.def_id());
|
||||
if let Some(caller_attrs) = caller_attrs
|
||||
// If there is an inline attribute and a target feature that matches
|
||||
// we will add the attribute to the callsite otherwise we'll omit
|
||||
// this and not add the attribute to prevent soundness issues.
|
||||
&& let Some(inlining_rule) = attributes::inline_attr(&self.cx, self.cx.tcx, instance)
|
||||
&& let Some(inlining_rule) = attributes::inline_attr(&self.cx, self.cx.tcx, callee_instance)
|
||||
&& self.cx.tcx.is_target_feature_call_safe(
|
||||
&fn_defn_attrs.target_features,
|
||||
&fn_call_attrs.target_features.iter().cloned().chain(
|
||||
&callee_attrs.target_features,
|
||||
&caller_attrs.target_features.iter().cloned().chain(
|
||||
self.cx.tcx.sess.target_features.iter().map(|feat| TargetFeature {
|
||||
name: *feat,
|
||||
kind: TargetFeatureKind::Implied,
|
||||
|
|
@ -1457,14 +1457,15 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> {
|
|||
fn tail_call(
|
||||
&mut self,
|
||||
llty: Self::Type,
|
||||
fn_attrs: Option<&CodegenFnAttrs>,
|
||||
caller_attrs: Option<&CodegenFnAttrs>,
|
||||
fn_abi: &FnAbi<'tcx, Ty<'tcx>>,
|
||||
llfn: Self::Value,
|
||||
args: &[Self::Value],
|
||||
funclet: Option<&Self::Funclet>,
|
||||
instance: Option<Instance<'tcx>>,
|
||||
callee_instance: Option<Instance<'tcx>>,
|
||||
) {
|
||||
let call = self.call(llty, fn_attrs, Some(fn_abi), llfn, args, funclet, instance);
|
||||
let call =
|
||||
self.call(llty, caller_attrs, Some(fn_abi), llfn, args, funclet, callee_instance);
|
||||
llvm::LLVMSetTailCallKind(call, llvm::TailCallKind::MustTail);
|
||||
|
||||
match &fn_abi.ret.mode {
|
||||
|
|
|
|||
|
|
@ -221,6 +221,12 @@ pub(crate) unsafe fn create_module<'ll>(
|
|||
target_data_layout = target_data_layout.replace("-m:e", "");
|
||||
}
|
||||
}
|
||||
if llvm_version < (23, 0, 0) {
|
||||
if sess.target.arch == Arch::S390x {
|
||||
// LLVM 23 updated the s390x layout to specify the stack alignment: https://github.com/llvm/llvm-project/pull/176041
|
||||
target_data_layout = target_data_layout.replace("-S64", "");
|
||||
}
|
||||
}
|
||||
|
||||
// Ensure the data-layout values hardcoded remain the defaults.
|
||||
{
|
||||
|
|
|
|||
|
|
@ -92,7 +92,7 @@ pub(crate) fn needs_gdb_debug_scripts_section(cx: &CodegenCx<'_, '_>) -> bool {
|
|||
CrateType::Executable
|
||||
| CrateType::Dylib
|
||||
| CrateType::Cdylib
|
||||
| CrateType::Staticlib
|
||||
| CrateType::StaticLib
|
||||
| CrateType::Sdylib => {
|
||||
// These are crate types for which we will embed pretty printers since they
|
||||
// are treated as leaf crates.
|
||||
|
|
|
|||
|
|
@ -665,8 +665,8 @@ impl MsvcBasicName for ty::UintTy {
|
|||
|
||||
impl MsvcBasicName for ty::FloatTy {
|
||||
fn msvc_basic_name(self) -> &'static str {
|
||||
// FIXME(f16_f128): `f16` and `f128` have no MSVC representation. We could improve the
|
||||
// debuginfo. See: <https://github.com/rust-lang/rust/issues/121837>
|
||||
// FIXME(f128): `f128` has no MSVC representation. We could improve the debuginfo.
|
||||
// See: <https://github.com/rust-lang/rust/issues/121837>
|
||||
match self {
|
||||
ty::FloatTy::F16 => {
|
||||
bug!("`f16` should have been handled in `build_basic_type_di_node`")
|
||||
|
|
|
|||
|
|
@ -456,7 +456,7 @@ impl<'ll, 'tcx> DebugInfoCodegenMethods<'tcx> for CodegenCx<'ll, 'tcx> {
|
|||
let generics = tcx.generics_of(enclosing_fn_def_id);
|
||||
let args = instance.args.truncate_to(tcx, generics);
|
||||
|
||||
type_names::push_generic_params(
|
||||
type_names::push_generic_args(
|
||||
tcx,
|
||||
tcx.normalize_erasing_regions(self.typing_env(), args),
|
||||
&mut name,
|
||||
|
|
|
|||
|
|
@ -271,14 +271,6 @@ impl<'ll, 'tcx> IntrinsicCallBuilderMethods<'tcx> for Builder<'_, 'll, 'tcx> {
|
|||
return Ok(());
|
||||
}
|
||||
sym::breakpoint => self.call_intrinsic("llvm.debugtrap", &[], &[]),
|
||||
sym::va_copy => {
|
||||
let dest = args[0].immediate();
|
||||
self.call_intrinsic(
|
||||
"llvm.va_copy",
|
||||
&[self.val_ty(dest)],
|
||||
&[dest, args[1].immediate()],
|
||||
)
|
||||
}
|
||||
sym::va_arg => {
|
||||
match result.layout.backend_repr {
|
||||
BackendRepr::Scalar(scalar) => {
|
||||
|
|
@ -1592,6 +1584,31 @@ fn generic_simd_intrinsic<'ll, 'tcx>(
|
|||
return Ok(bx.select(m_i1s, args[1].immediate(), args[2].immediate()));
|
||||
}
|
||||
|
||||
if name == sym::simd_splat {
|
||||
let (_out_len, out_ty) = require_simd!(ret_ty, SimdReturn);
|
||||
|
||||
require!(
|
||||
args[0].layout.ty == out_ty,
|
||||
InvalidMonomorphization::ExpectedVectorElementType {
|
||||
span,
|
||||
name,
|
||||
expected_element: out_ty,
|
||||
vector_type: ret_ty,
|
||||
}
|
||||
);
|
||||
|
||||
// `insertelement <N x elem> poison, elem %x, i32 0`
|
||||
let poison_vec = bx.const_poison(llret_ty);
|
||||
let idx0 = bx.const_i32(0);
|
||||
let v0 = bx.insert_element(poison_vec, args[0].immediate(), idx0);
|
||||
|
||||
// `shufflevector <N x elem> v0, <N x elem> poison, <N x i32> zeroinitializer`
|
||||
// The masks is all zeros, so this splats lane 0 (which has our element in it).
|
||||
let splat = bx.shuffle_vector(v0, poison_vec, bx.const_null(llret_ty));
|
||||
|
||||
return Ok(splat);
|
||||
}
|
||||
|
||||
// every intrinsic below takes a SIMD vector as its first argument
|
||||
let (in_len, in_elem) = require_simd!(args[0].layout.ty, SimdInput);
|
||||
let in_ty = args[0].layout.ty;
|
||||
|
|
|
|||
|
|
@ -30,12 +30,13 @@ use llvm_util::target_config;
|
|||
use rustc_ast::expand::allocator::AllocatorMethod;
|
||||
use rustc_codegen_ssa::back::lto::{SerializedModule, ThinModule};
|
||||
use rustc_codegen_ssa::back::write::{
|
||||
CodegenContext, FatLtoInput, ModuleConfig, TargetMachineFactoryConfig, TargetMachineFactoryFn,
|
||||
CodegenContext, FatLtoInput, ModuleConfig, SharedEmitter, TargetMachineFactoryConfig,
|
||||
TargetMachineFactoryFn,
|
||||
};
|
||||
use rustc_codegen_ssa::traits::*;
|
||||
use rustc_codegen_ssa::{CodegenResults, CompiledModule, ModuleCodegen, TargetConfig};
|
||||
use rustc_data_structures::fx::FxIndexMap;
|
||||
use rustc_errors::DiagCtxtHandle;
|
||||
use rustc_errors::{DiagCtxt, DiagCtxtHandle};
|
||||
use rustc_metadata::EncodedMetadata;
|
||||
use rustc_middle::dep_graph::{WorkProduct, WorkProductId};
|
||||
use rustc_middle::ty::TyCtxt;
|
||||
|
|
@ -166,14 +167,20 @@ impl WriteBackendMethods for LlvmCodegenBackend {
|
|||
}
|
||||
fn run_and_optimize_fat_lto(
|
||||
cgcx: &CodegenContext<Self>,
|
||||
shared_emitter: &SharedEmitter,
|
||||
exported_symbols_for_lto: &[String],
|
||||
each_linked_rlib_for_lto: &[PathBuf],
|
||||
modules: Vec<FatLtoInput<Self>>,
|
||||
) -> ModuleCodegen<Self::Module> {
|
||||
let mut module =
|
||||
back::lto::run_fat(cgcx, exported_symbols_for_lto, each_linked_rlib_for_lto, modules);
|
||||
let mut module = back::lto::run_fat(
|
||||
cgcx,
|
||||
shared_emitter,
|
||||
exported_symbols_for_lto,
|
||||
each_linked_rlib_for_lto,
|
||||
modules,
|
||||
);
|
||||
|
||||
let dcx = cgcx.create_dcx();
|
||||
let dcx = DiagCtxt::new(Box::new(shared_emitter.clone()));
|
||||
let dcx = dcx.handle();
|
||||
back::lto::run_pass_manager(cgcx, dcx, &mut module, false);
|
||||
|
||||
|
|
@ -181,6 +188,7 @@ impl WriteBackendMethods for LlvmCodegenBackend {
|
|||
}
|
||||
fn run_thin_lto(
|
||||
cgcx: &CodegenContext<Self>,
|
||||
dcx: DiagCtxtHandle<'_>,
|
||||
exported_symbols_for_lto: &[String],
|
||||
each_linked_rlib_for_lto: &[PathBuf],
|
||||
modules: Vec<(String, Self::ThinBuffer)>,
|
||||
|
|
@ -188,6 +196,7 @@ impl WriteBackendMethods for LlvmCodegenBackend {
|
|||
) -> (Vec<ThinModule<Self>>, Vec<WorkProduct>) {
|
||||
back::lto::run_thin(
|
||||
cgcx,
|
||||
dcx,
|
||||
exported_symbols_for_lto,
|
||||
each_linked_rlib_for_lto,
|
||||
modules,
|
||||
|
|
@ -196,24 +205,26 @@ impl WriteBackendMethods for LlvmCodegenBackend {
|
|||
}
|
||||
fn optimize(
|
||||
cgcx: &CodegenContext<Self>,
|
||||
dcx: DiagCtxtHandle<'_>,
|
||||
shared_emitter: &SharedEmitter,
|
||||
module: &mut ModuleCodegen<Self::Module>,
|
||||
config: &ModuleConfig,
|
||||
) {
|
||||
back::write::optimize(cgcx, dcx, module, config)
|
||||
back::write::optimize(cgcx, shared_emitter, module, config)
|
||||
}
|
||||
fn optimize_thin(
|
||||
cgcx: &CodegenContext<Self>,
|
||||
shared_emitter: &SharedEmitter,
|
||||
thin: ThinModule<Self>,
|
||||
) -> ModuleCodegen<Self::Module> {
|
||||
back::lto::optimize_thin_module(thin, cgcx)
|
||||
back::lto::optimize_thin_module(cgcx, shared_emitter, thin)
|
||||
}
|
||||
fn codegen(
|
||||
cgcx: &CodegenContext<Self>,
|
||||
shared_emitter: &SharedEmitter,
|
||||
module: ModuleCodegen<Self::Module>,
|
||||
config: &ModuleConfig,
|
||||
) -> CompiledModule {
|
||||
back::write::codegen(cgcx, module, config)
|
||||
back::write::codegen(cgcx, shared_emitter, module, config)
|
||||
}
|
||||
fn prepare_thin(module: ModuleCodegen<Self::Module>) -> (String, Self::ThinBuffer) {
|
||||
back::lto::prepare_thin(module)
|
||||
|
|
|
|||
|
|
@ -167,6 +167,7 @@ pub(crate) enum CallConv {
|
|||
PreserveMost = 14,
|
||||
PreserveAll = 15,
|
||||
Tail = 18,
|
||||
PreserveNone = 21,
|
||||
X86StdcallCallConv = 64,
|
||||
X86FastcallCallConv = 65,
|
||||
ArmAapcsCallConv = 67,
|
||||
|
|
@ -2347,6 +2348,7 @@ unsafe extern "C" {
|
|||
DebugInfoCompression: CompressionKind,
|
||||
UseEmulatedTls: bool,
|
||||
UseWasmEH: bool,
|
||||
LargeDataThreshold: u64,
|
||||
) -> *mut TargetMachine;
|
||||
|
||||
pub(crate) fn LLVMRustAddLibraryInfo<'a>(
|
||||
|
|
|
|||
|
|
@ -48,8 +48,6 @@ codegen_ssa_error_creating_remark_dir = failed to create remark directory: {$err
|
|||
codegen_ssa_error_writing_def_file =
|
||||
error writing .DEF file: {$error}
|
||||
|
||||
codegen_ssa_expected_name_value_pair = expected name value pair
|
||||
|
||||
codegen_ssa_extern_funcs_not_found = some `extern` functions couldn't be found; some native libraries may need to be installed or have their path specified
|
||||
|
||||
codegen_ssa_extract_bundled_libs_archive_member = failed to get data from archive member '{$rlib}': {$error}
|
||||
|
|
@ -90,9 +88,6 @@ codegen_ssa_incorrect_cgu_reuse_type =
|
|||
|
||||
codegen_ssa_insufficient_vs_code_product = VS Code is a different product, and is not sufficient.
|
||||
|
||||
codegen_ssa_invalid_literal_value = invalid literal value
|
||||
.label = value must be an integer between `0` and `255`
|
||||
|
||||
codegen_ssa_invalid_monomorphization_basic_float_type = invalid monomorphization of `{$name}` intrinsic: expected basic float type, found `{$ty}`
|
||||
|
||||
codegen_ssa_invalid_monomorphization_basic_integer_or_ptr_type = invalid monomorphization of `{$name}` intrinsic: expected basic integer or pointer type, found `{$ty}`
|
||||
|
|
@ -225,9 +220,6 @@ codegen_ssa_no_natvis_directory = error enumerating natvis directory: {$error}
|
|||
|
||||
codegen_ssa_no_saved_object_file = cached cgu {$cgu_name} should have an object file, but doesn't
|
||||
|
||||
codegen_ssa_out_of_range_integer = integer value out of range
|
||||
.label = value must be between `0` and `255`
|
||||
|
||||
codegen_ssa_processing_dymutil_failed = processing debug info with `dsymutil` failed: {$status}
|
||||
.note = {$output}
|
||||
|
||||
|
|
@ -357,9 +349,6 @@ codegen_ssa_unable_to_run_dsymutil = unable to run `dsymutil`: {$error}
|
|||
|
||||
codegen_ssa_unable_to_write_debugger_visualizer = unable to write debugger visualizer file `{$path}`: {$error}
|
||||
|
||||
codegen_ssa_unexpected_parameter_name = unexpected parameter name
|
||||
.label = expected `{$prefix_nops}` or `{$entry_nops}`
|
||||
|
||||
codegen_ssa_unknown_archive_kind =
|
||||
don't know how to build archive of type: {$kind}
|
||||
|
||||
|
|
|
|||
|
|
@ -136,7 +136,7 @@ pub fn link_binary(
|
|||
)
|
||||
.build(&out_filename);
|
||||
}
|
||||
CrateType::Staticlib => {
|
||||
CrateType::StaticLib => {
|
||||
link_staticlib(
|
||||
sess,
|
||||
archive_builder_builder,
|
||||
|
|
@ -474,7 +474,7 @@ fn link_staticlib(
|
|||
|
||||
let res = each_linked_rlib(
|
||||
&codegen_results.crate_info,
|
||||
Some(CrateType::Staticlib),
|
||||
Some(CrateType::StaticLib),
|
||||
&mut |cnum, path| {
|
||||
let lto = are_upstream_rust_objects_already_included(sess)
|
||||
&& !ignored_for_lto(sess, &codegen_results.crate_info, cnum);
|
||||
|
|
@ -532,7 +532,7 @@ fn link_staticlib(
|
|||
let fmts = codegen_results
|
||||
.crate_info
|
||||
.dependency_formats
|
||||
.get(&CrateType::Staticlib)
|
||||
.get(&CrateType::StaticLib)
|
||||
.expect("no dependency formats for staticlib");
|
||||
|
||||
let mut all_rust_dylibs = vec![];
|
||||
|
|
@ -1210,7 +1210,7 @@ fn add_sanitizer_libraries(
|
|||
return;
|
||||
}
|
||||
|
||||
if matches!(crate_type, CrateType::Rlib | CrateType::Staticlib) {
|
||||
if matches!(crate_type, CrateType::Rlib | CrateType::StaticLib) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1827,9 +1827,9 @@ fn exported_symbols_for_non_proc_macro(
|
|||
// Mark allocator shim symbols as exported only if they were generated.
|
||||
if export_threshold == SymbolExportLevel::Rust
|
||||
&& needs_allocator_shim_for_linking(tcx.dependency_formats(()), crate_type)
|
||||
&& tcx.allocator_kind(()).is_some()
|
||||
&& let Some(kind) = tcx.allocator_kind(())
|
||||
{
|
||||
symbols.extend(allocator_shim_symbols(tcx));
|
||||
symbols.extend(allocator_shim_symbols(tcx, kind));
|
||||
}
|
||||
|
||||
symbols
|
||||
|
|
@ -1857,7 +1857,7 @@ pub(crate) fn linked_symbols(
|
|||
| CrateType::Cdylib
|
||||
| CrateType::Dylib
|
||||
| CrateType::Sdylib => (),
|
||||
CrateType::Staticlib | CrateType::Rlib => {
|
||||
CrateType::StaticLib | CrateType::Rlib => {
|
||||
// These are not linked, so no need to generate symbols.o for them.
|
||||
return Vec::new();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ use std::ffi::CString;
|
|||
use std::sync::Arc;
|
||||
|
||||
use rustc_data_structures::memmap::Mmap;
|
||||
use rustc_errors::DiagCtxtHandle;
|
||||
use rustc_hir::def_id::{CrateNum, LOCAL_CRATE};
|
||||
use rustc_middle::middle::exported_symbols::{ExportedSymbol, SymbolExportInfo, SymbolExportLevel};
|
||||
use rustc_middle::ty::TyCtxt;
|
||||
|
|
@ -66,7 +67,7 @@ fn crate_type_allows_lto(crate_type: CrateType) -> bool {
|
|||
match crate_type {
|
||||
CrateType::Executable
|
||||
| CrateType::Dylib
|
||||
| CrateType::Staticlib
|
||||
| CrateType::StaticLib
|
||||
| CrateType::Cdylib
|
||||
| CrateType::ProcMacro
|
||||
| CrateType::Sdylib => true,
|
||||
|
|
@ -117,35 +118,38 @@ pub(super) fn exported_symbols_for_lto(
|
|||
}
|
||||
|
||||
// Mark allocator shim symbols as exported only if they were generated.
|
||||
if export_threshold == SymbolExportLevel::Rust && allocator_kind_for_codegen(tcx).is_some() {
|
||||
symbols_below_threshold.extend(allocator_shim_symbols(tcx).map(|(name, _kind)| name));
|
||||
if export_threshold == SymbolExportLevel::Rust
|
||||
&& let Some(kind) = allocator_kind_for_codegen(tcx)
|
||||
{
|
||||
symbols_below_threshold.extend(allocator_shim_symbols(tcx, kind).map(|(name, _kind)| name));
|
||||
}
|
||||
|
||||
symbols_below_threshold
|
||||
}
|
||||
|
||||
pub(super) fn check_lto_allowed<B: WriteBackendMethods>(cgcx: &CodegenContext<B>) {
|
||||
pub(super) fn check_lto_allowed<B: WriteBackendMethods>(
|
||||
cgcx: &CodegenContext<B>,
|
||||
dcx: DiagCtxtHandle<'_>,
|
||||
) {
|
||||
if cgcx.lto == Lto::ThinLocal {
|
||||
// Crate local LTO is always allowed
|
||||
return;
|
||||
}
|
||||
|
||||
let dcx = cgcx.create_dcx();
|
||||
|
||||
// Make sure we actually can run LTO
|
||||
for crate_type in cgcx.crate_types.iter() {
|
||||
if !crate_type_allows_lto(*crate_type) {
|
||||
dcx.handle().emit_fatal(LtoDisallowed);
|
||||
} else if *crate_type == CrateType::Dylib {
|
||||
if !cgcx.opts.unstable_opts.dylib_lto {
|
||||
if !cgcx.dylib_lto {
|
||||
dcx.handle().emit_fatal(LtoDylib);
|
||||
}
|
||||
} else if *crate_type == CrateType::ProcMacro && !cgcx.opts.unstable_opts.dylib_lto {
|
||||
} else if *crate_type == CrateType::ProcMacro && !cgcx.dylib_lto {
|
||||
dcx.handle().emit_fatal(LtoProcMacro);
|
||||
}
|
||||
}
|
||||
|
||||
if cgcx.opts.cg.prefer_dynamic && !cgcx.opts.unstable_opts.dylib_lto {
|
||||
if cgcx.prefer_dynamic && !cgcx.dylib_lto {
|
||||
dcx.handle().emit_fatal(DynamicLinkingWithLTO);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,9 +1,7 @@
|
|||
use std::collections::hash_map::Entry::*;
|
||||
|
||||
use rustc_abi::{CanonAbi, X86Call};
|
||||
use rustc_ast::expand::allocator::{
|
||||
ALLOC_ERROR_HANDLER, ALLOCATOR_METHODS, NO_ALLOC_SHIM_IS_UNSTABLE, global_fn_name,
|
||||
};
|
||||
use rustc_ast::expand::allocator::{AllocatorKind, NO_ALLOC_SHIM_IS_UNSTABLE, global_fn_name};
|
||||
use rustc_data_structures::unord::UnordMap;
|
||||
use rustc_hir::def::DefKind;
|
||||
use rustc_hir::def_id::{CrateNum, DefId, DefIdMap, LOCAL_CRATE, LocalDefId};
|
||||
|
|
@ -21,6 +19,7 @@ use rustc_target::spec::{Arch, Os, TlsModel};
|
|||
use tracing::debug;
|
||||
|
||||
use crate::back::symbol_export;
|
||||
use crate::base::allocator_shim_contents;
|
||||
|
||||
fn threshold(tcx: TyCtxt<'_>) -> SymbolExportLevel {
|
||||
crates_export_threshold(tcx.crate_types())
|
||||
|
|
@ -28,7 +27,7 @@ fn threshold(tcx: TyCtxt<'_>) -> SymbolExportLevel {
|
|||
|
||||
fn crate_export_threshold(crate_type: CrateType) -> SymbolExportLevel {
|
||||
match crate_type {
|
||||
CrateType::Executable | CrateType::Staticlib | CrateType::ProcMacro | CrateType::Cdylib => {
|
||||
CrateType::Executable | CrateType::StaticLib | CrateType::ProcMacro | CrateType::Cdylib => {
|
||||
SymbolExportLevel::C
|
||||
}
|
||||
CrateType::Rlib | CrateType::Dylib | CrateType::Sdylib => SymbolExportLevel::Rust,
|
||||
|
|
@ -490,14 +489,12 @@ pub(crate) fn provide(providers: &mut Providers) {
|
|||
|
||||
pub(crate) fn allocator_shim_symbols(
|
||||
tcx: TyCtxt<'_>,
|
||||
kind: AllocatorKind,
|
||||
) -> impl Iterator<Item = (String, SymbolExportKind)> {
|
||||
ALLOCATOR_METHODS
|
||||
.iter()
|
||||
allocator_shim_contents(tcx, kind)
|
||||
.into_iter()
|
||||
.map(move |method| mangle_internal_symbol(tcx, global_fn_name(method.name).as_str()))
|
||||
.chain([
|
||||
mangle_internal_symbol(tcx, global_fn_name(ALLOC_ERROR_HANDLER).as_str()),
|
||||
mangle_internal_symbol(tcx, NO_ALLOC_SHIM_IS_UNSTABLE),
|
||||
])
|
||||
.chain([mangle_internal_symbol(tcx, NO_ALLOC_SHIM_IS_UNSTABLE)])
|
||||
.map(move |symbol_name| {
|
||||
let exported_symbol = ExportedSymbol::NoDefId(SymbolName::new(tcx, &symbol_name));
|
||||
|
||||
|
|
|
|||
|
|
@ -6,7 +6,6 @@ use std::sync::mpsc::{Receiver, Sender, channel};
|
|||
use std::{fs, io, mem, str, thread};
|
||||
|
||||
use rustc_abi::Size;
|
||||
use rustc_ast::attr;
|
||||
use rustc_data_structures::assert_matches;
|
||||
use rustc_data_structures::fx::FxIndexMap;
|
||||
use rustc_data_structures::jobserver::{self, Acquired};
|
||||
|
|
@ -15,10 +14,12 @@ use rustc_data_structures::profiling::{SelfProfilerRef, VerboseTimingGuard};
|
|||
use rustc_errors::emitter::Emitter;
|
||||
use rustc_errors::translation::Translator;
|
||||
use rustc_errors::{
|
||||
Diag, DiagArgMap, DiagCtxt, DiagMessage, ErrCode, FatalError, FatalErrorMarker, Level,
|
||||
MultiSpan, Style, Suggestions,
|
||||
Diag, DiagArgMap, DiagCtxt, DiagCtxtHandle, DiagMessage, ErrCode, FatalError, FatalErrorMarker,
|
||||
Level, MultiSpan, Style, Suggestions, catch_fatal_errors,
|
||||
};
|
||||
use rustc_fs_util::link_or_copy;
|
||||
use rustc_hir::attrs::AttributeKind;
|
||||
use rustc_hir::find_attr;
|
||||
use rustc_incremental::{
|
||||
copy_cgu_workproduct_to_incr_comp_cache_dir, in_incr_comp_dir, in_incr_comp_dir_sess,
|
||||
};
|
||||
|
|
@ -31,7 +32,7 @@ use rustc_session::config::{
|
|||
self, CrateType, Lto, OutFileName, OutputFilenames, OutputType, Passes, SwitchWithOptPath,
|
||||
};
|
||||
use rustc_span::source_map::SourceMap;
|
||||
use rustc_span::{FileName, InnerSpan, Span, SpanData, sym};
|
||||
use rustc_span::{FileName, InnerSpan, Span, SpanData};
|
||||
use rustc_target::spec::{MergeFunctions, SanitizerSet};
|
||||
use tracing::debug;
|
||||
|
||||
|
|
@ -326,15 +327,16 @@ pub struct CodegenContext<B: WriteBackendMethods> {
|
|||
// Resources needed when running LTO
|
||||
pub prof: SelfProfilerRef,
|
||||
pub lto: Lto,
|
||||
pub use_linker_plugin_lto: bool,
|
||||
pub dylib_lto: bool,
|
||||
pub prefer_dynamic: bool,
|
||||
pub save_temps: bool,
|
||||
pub fewer_names: bool,
|
||||
pub time_trace: bool,
|
||||
pub opts: Arc<config::Options>,
|
||||
pub crate_types: Vec<CrateType>,
|
||||
pub output_filenames: Arc<OutputFilenames>,
|
||||
pub invocation_temp: Option<String>,
|
||||
pub module_config: Arc<ModuleConfig>,
|
||||
pub allocator_config: Arc<ModuleConfig>,
|
||||
pub tm_factory: TargetMachineFactoryFn<B>,
|
||||
pub msvc_imps_needed: bool,
|
||||
pub is_pe_coff: bool,
|
||||
|
|
@ -347,8 +349,6 @@ pub struct CodegenContext<B: WriteBackendMethods> {
|
|||
pub split_dwarf_kind: rustc_session::config::SplitDwarfKind,
|
||||
pub pointer_size: Size,
|
||||
|
||||
/// Emitter to use for diagnostics produced during codegen.
|
||||
pub diag_emitter: SharedEmitter,
|
||||
/// LLVM optimizations for which we want to print remarks.
|
||||
pub remark: Passes,
|
||||
/// Directory into which should the LLVM optimization remarks be written.
|
||||
|
|
@ -363,14 +363,9 @@ pub struct CodegenContext<B: WriteBackendMethods> {
|
|||
pub parallel: bool,
|
||||
}
|
||||
|
||||
impl<B: WriteBackendMethods> CodegenContext<B> {
|
||||
pub fn create_dcx(&self) -> DiagCtxt {
|
||||
DiagCtxt::new(Box::new(self.diag_emitter.clone()))
|
||||
}
|
||||
}
|
||||
|
||||
fn generate_thin_lto_work<B: ExtraBackendMethods>(
|
||||
cgcx: &CodegenContext<B>,
|
||||
dcx: DiagCtxtHandle<'_>,
|
||||
exported_symbols_for_lto: &[String],
|
||||
each_linked_rlib_for_lto: &[PathBuf],
|
||||
needs_thin_lto: Vec<(String, B::ThinBuffer)>,
|
||||
|
|
@ -380,6 +375,7 @@ fn generate_thin_lto_work<B: ExtraBackendMethods>(
|
|||
|
||||
let (lto_modules, copy_jobs) = B::run_thin_lto(
|
||||
cgcx,
|
||||
dcx,
|
||||
exported_symbols_for_lto,
|
||||
each_linked_rlib_for_lto,
|
||||
needs_thin_lto,
|
||||
|
|
@ -408,6 +404,29 @@ struct CompiledModules {
|
|||
allocator_module: Option<CompiledModule>,
|
||||
}
|
||||
|
||||
enum MaybeLtoModules<B: WriteBackendMethods> {
|
||||
NoLto {
|
||||
modules: Vec<CompiledModule>,
|
||||
allocator_module: Option<CompiledModule>,
|
||||
},
|
||||
FatLto {
|
||||
cgcx: CodegenContext<B>,
|
||||
exported_symbols_for_lto: Arc<Vec<String>>,
|
||||
each_linked_rlib_file_for_lto: Vec<PathBuf>,
|
||||
needs_fat_lto: Vec<FatLtoInput<B>>,
|
||||
lto_import_only_modules:
|
||||
Vec<(SerializedModule<<B as WriteBackendMethods>::ModuleBuffer>, WorkProduct)>,
|
||||
},
|
||||
ThinLto {
|
||||
cgcx: CodegenContext<B>,
|
||||
exported_symbols_for_lto: Arc<Vec<String>>,
|
||||
each_linked_rlib_file_for_lto: Vec<PathBuf>,
|
||||
needs_thin_lto: Vec<(String, <B as WriteBackendMethods>::ThinBuffer)>,
|
||||
lto_import_only_modules:
|
||||
Vec<(SerializedModule<<B as WriteBackendMethods>::ModuleBuffer>, WorkProduct)>,
|
||||
},
|
||||
}
|
||||
|
||||
fn need_bitcode_in_object(tcx: TyCtxt<'_>) -> bool {
|
||||
let sess = tcx.sess;
|
||||
sess.opts.cg.embed_bitcode
|
||||
|
|
@ -435,7 +454,7 @@ pub(crate) fn start_async_codegen<B: ExtraBackendMethods>(
|
|||
let (coordinator_send, coordinator_receive) = channel();
|
||||
|
||||
let crate_attrs = tcx.hir_attrs(rustc_hir::CRATE_HIR_ID);
|
||||
let no_builtins = attr::contains_name(crate_attrs, sym::no_builtins);
|
||||
let no_builtins = find_attr!(crate_attrs, AttributeKind::NoBuiltins);
|
||||
|
||||
let crate_info = CrateInfo::new(tcx, target_cpu);
|
||||
|
||||
|
|
@ -797,20 +816,12 @@ pub(crate) enum ComputedLtoType {
|
|||
|
||||
pub(crate) fn compute_per_cgu_lto_type(
|
||||
sess_lto: &Lto,
|
||||
opts: &config::Options,
|
||||
linker_does_lto: bool,
|
||||
sess_crate_types: &[CrateType],
|
||||
module_kind: ModuleKind,
|
||||
) -> ComputedLtoType {
|
||||
// If the linker does LTO, we don't have to do it. Note that we
|
||||
// keep doing full LTO, if it is requested, as not to break the
|
||||
// assumption that the output will be a single module.
|
||||
let linker_does_lto = opts.cg.linker_plugin_lto.enabled();
|
||||
|
||||
// When we're automatically doing ThinLTO for multi-codegen-unit
|
||||
// builds we don't actually want to LTO the allocator module if
|
||||
// it shows up. This is due to various linker shenanigans that
|
||||
// we'll encounter later.
|
||||
let is_allocator = module_kind == ModuleKind::Allocator;
|
||||
|
||||
// We ignore a request for full crate graph LTO if the crate type
|
||||
// is only an rlib, as there is no full crate graph to process,
|
||||
|
|
@ -823,7 +834,7 @@ pub(crate) fn compute_per_cgu_lto_type(
|
|||
let is_rlib = matches!(sess_crate_types, [CrateType::Rlib]);
|
||||
|
||||
match sess_lto {
|
||||
Lto::ThinLocal if !linker_does_lto && !is_allocator => ComputedLtoType::Thin,
|
||||
Lto::ThinLocal if !linker_does_lto => ComputedLtoType::Thin,
|
||||
Lto::Thin if !linker_does_lto && !is_rlib => ComputedLtoType::Thin,
|
||||
Lto::Fat if !is_rlib => ComputedLtoType::Fat,
|
||||
_ => ComputedLtoType::No,
|
||||
|
|
@ -832,30 +843,24 @@ pub(crate) fn compute_per_cgu_lto_type(
|
|||
|
||||
fn execute_optimize_work_item<B: ExtraBackendMethods>(
|
||||
cgcx: &CodegenContext<B>,
|
||||
shared_emitter: SharedEmitter,
|
||||
mut module: ModuleCodegen<B::Module>,
|
||||
) -> WorkItemResult<B> {
|
||||
let _timer = cgcx.prof.generic_activity_with_arg("codegen_module_optimize", &*module.name);
|
||||
|
||||
let dcx = cgcx.create_dcx();
|
||||
let dcx = dcx.handle();
|
||||
|
||||
let module_config = match module.kind {
|
||||
ModuleKind::Regular => &cgcx.module_config,
|
||||
ModuleKind::Allocator => &cgcx.allocator_config,
|
||||
};
|
||||
|
||||
B::optimize(cgcx, dcx, &mut module, module_config);
|
||||
B::optimize(cgcx, &shared_emitter, &mut module, &cgcx.module_config);
|
||||
|
||||
// After we've done the initial round of optimizations we need to
|
||||
// decide whether to synchronously codegen this module or ship it
|
||||
// back to the coordinator thread for further LTO processing (which
|
||||
// has to wait for all the initial modules to be optimized).
|
||||
|
||||
let lto_type = compute_per_cgu_lto_type(&cgcx.lto, &cgcx.opts, &cgcx.crate_types, module.kind);
|
||||
let lto_type =
|
||||
compute_per_cgu_lto_type(&cgcx.lto, cgcx.use_linker_plugin_lto, &cgcx.crate_types);
|
||||
|
||||
// If we're doing some form of incremental LTO then we need to be sure to
|
||||
// save our module to disk first.
|
||||
let bitcode = if module_config.emit_pre_lto_bc {
|
||||
let bitcode = if cgcx.module_config.emit_pre_lto_bc {
|
||||
let filename = pre_lto_bitcode_filename(&module.name);
|
||||
cgcx.incr_comp_session_dir.as_ref().map(|path| path.join(&filename))
|
||||
} else {
|
||||
|
|
@ -864,7 +869,7 @@ fn execute_optimize_work_item<B: ExtraBackendMethods>(
|
|||
|
||||
match lto_type {
|
||||
ComputedLtoType::No => {
|
||||
let module = B::codegen(cgcx, module, module_config);
|
||||
let module = B::codegen(cgcx, &shared_emitter, module, &cgcx.module_config);
|
||||
WorkItemResult::Finished(module)
|
||||
}
|
||||
ComputedLtoType::Thin => {
|
||||
|
|
@ -894,12 +899,16 @@ fn execute_optimize_work_item<B: ExtraBackendMethods>(
|
|||
|
||||
fn execute_copy_from_cache_work_item<B: ExtraBackendMethods>(
|
||||
cgcx: &CodegenContext<B>,
|
||||
shared_emitter: SharedEmitter,
|
||||
module: CachedModuleCodegen,
|
||||
) -> CompiledModule {
|
||||
let _timer = cgcx
|
||||
.prof
|
||||
.generic_activity_with_arg("codegen_copy_artifacts_from_incr_cache", &*module.name);
|
||||
|
||||
let dcx = DiagCtxt::new(Box::new(shared_emitter));
|
||||
let dcx = dcx.handle();
|
||||
|
||||
let incr_comp_session_dir = cgcx.incr_comp_session_dir.as_ref().unwrap();
|
||||
|
||||
let mut links_from_incr_cache = Vec::new();
|
||||
|
|
@ -918,11 +927,7 @@ fn execute_copy_from_cache_work_item<B: ExtraBackendMethods>(
|
|||
Some(output_path)
|
||||
}
|
||||
Err(error) => {
|
||||
cgcx.create_dcx().handle().emit_err(errors::CopyPathBuf {
|
||||
source_file,
|
||||
output_path,
|
||||
error,
|
||||
});
|
||||
dcx.emit_err(errors::CopyPathBuf { source_file, output_path, error });
|
||||
None
|
||||
}
|
||||
}
|
||||
|
|
@ -965,7 +970,7 @@ fn execute_copy_from_cache_work_item<B: ExtraBackendMethods>(
|
|||
let bytecode = load_from_incr_cache(module_config.emit_bc, OutputType::Bitcode);
|
||||
let object = load_from_incr_cache(should_emit_obj, OutputType::Object);
|
||||
if should_emit_obj && object.is_none() {
|
||||
cgcx.create_dcx().handle().emit_fatal(errors::NoSavedObjectFile { cgu_name: &module.name })
|
||||
dcx.emit_fatal(errors::NoSavedObjectFile { cgu_name: &module.name })
|
||||
}
|
||||
|
||||
CompiledModule {
|
||||
|
|
@ -982,6 +987,7 @@ fn execute_copy_from_cache_work_item<B: ExtraBackendMethods>(
|
|||
|
||||
fn do_fat_lto<B: ExtraBackendMethods>(
|
||||
cgcx: &CodegenContext<B>,
|
||||
shared_emitter: SharedEmitter,
|
||||
exported_symbols_for_lto: &[String],
|
||||
each_linked_rlib_for_lto: &[PathBuf],
|
||||
mut needs_fat_lto: Vec<FatLtoInput<B>>,
|
||||
|
|
@ -989,7 +995,10 @@ fn do_fat_lto<B: ExtraBackendMethods>(
|
|||
) -> CompiledModule {
|
||||
let _timer = cgcx.prof.verbose_generic_activity("LLVM_fatlto");
|
||||
|
||||
check_lto_allowed(&cgcx);
|
||||
let dcx = DiagCtxt::new(Box::new(shared_emitter.clone()));
|
||||
let dcx = dcx.handle();
|
||||
|
||||
check_lto_allowed(&cgcx, dcx);
|
||||
|
||||
for (module, wp) in import_only_modules {
|
||||
needs_fat_lto.push(FatLtoInput::Serialized { name: wp.cgu_name, buffer: module })
|
||||
|
|
@ -997,15 +1006,17 @@ fn do_fat_lto<B: ExtraBackendMethods>(
|
|||
|
||||
let module = B::run_and_optimize_fat_lto(
|
||||
cgcx,
|
||||
&shared_emitter,
|
||||
exported_symbols_for_lto,
|
||||
each_linked_rlib_for_lto,
|
||||
needs_fat_lto,
|
||||
);
|
||||
B::codegen(cgcx, module, &cgcx.module_config)
|
||||
B::codegen(cgcx, &shared_emitter, module, &cgcx.module_config)
|
||||
}
|
||||
|
||||
fn do_thin_lto<'a, B: ExtraBackendMethods>(
|
||||
cgcx: &'a CodegenContext<B>,
|
||||
shared_emitter: SharedEmitter,
|
||||
exported_symbols_for_lto: Arc<Vec<String>>,
|
||||
each_linked_rlib_for_lto: Vec<PathBuf>,
|
||||
needs_thin_lto: Vec<(String, <B as WriteBackendMethods>::ThinBuffer)>,
|
||||
|
|
@ -1016,7 +1027,10 @@ fn do_thin_lto<'a, B: ExtraBackendMethods>(
|
|||
) -> Vec<CompiledModule> {
|
||||
let _timer = cgcx.prof.verbose_generic_activity("LLVM_thinlto");
|
||||
|
||||
check_lto_allowed(&cgcx);
|
||||
let dcx = DiagCtxt::new(Box::new(shared_emitter.clone()));
|
||||
let dcx = dcx.handle();
|
||||
|
||||
check_lto_allowed(&cgcx, dcx);
|
||||
|
||||
let (coordinator_send, coordinator_receive) = channel();
|
||||
|
||||
|
|
@ -1041,6 +1055,7 @@ fn do_thin_lto<'a, B: ExtraBackendMethods>(
|
|||
// we don't worry about tokens.
|
||||
for (work, cost) in generate_thin_lto_work(
|
||||
cgcx,
|
||||
dcx,
|
||||
&exported_symbols_for_lto,
|
||||
&each_linked_rlib_for_lto,
|
||||
needs_thin_lto,
|
||||
|
|
@ -1082,7 +1097,7 @@ fn do_thin_lto<'a, B: ExtraBackendMethods>(
|
|||
while used_token_count < tokens.len() + 1
|
||||
&& let Some((item, _)) = work_items.pop()
|
||||
{
|
||||
spawn_thin_lto_work(&cgcx, coordinator_send.clone(), item);
|
||||
spawn_thin_lto_work(&cgcx, shared_emitter.clone(), coordinator_send.clone(), item);
|
||||
used_token_count += 1;
|
||||
}
|
||||
} else {
|
||||
|
|
@ -1106,7 +1121,7 @@ fn do_thin_lto<'a, B: ExtraBackendMethods>(
|
|||
}
|
||||
Err(e) => {
|
||||
let msg = &format!("failed to acquire jobserver token: {e}");
|
||||
cgcx.diag_emitter.fatal(msg);
|
||||
shared_emitter.fatal(msg);
|
||||
codegen_aborted = Some(FatalError);
|
||||
}
|
||||
},
|
||||
|
|
@ -1144,12 +1159,13 @@ fn do_thin_lto<'a, B: ExtraBackendMethods>(
|
|||
|
||||
fn execute_thin_lto_work_item<B: ExtraBackendMethods>(
|
||||
cgcx: &CodegenContext<B>,
|
||||
shared_emitter: SharedEmitter,
|
||||
module: lto::ThinModule<B>,
|
||||
) -> CompiledModule {
|
||||
let _timer = cgcx.prof.generic_activity_with_arg("codegen_module_perform_lto", module.name());
|
||||
|
||||
let module = B::optimize_thin(cgcx, module);
|
||||
B::codegen(cgcx, module, &cgcx.module_config)
|
||||
let module = B::optimize_thin(cgcx, &shared_emitter, module);
|
||||
B::codegen(cgcx, &shared_emitter, module, &cgcx.module_config)
|
||||
}
|
||||
|
||||
/// Messages sent to the coordinator.
|
||||
|
|
@ -1245,9 +1261,9 @@ fn start_executing_work<B: ExtraBackendMethods>(
|
|||
coordinator_receive: Receiver<Message<B>>,
|
||||
regular_config: Arc<ModuleConfig>,
|
||||
allocator_config: Arc<ModuleConfig>,
|
||||
allocator_module: Option<ModuleCodegen<B::Module>>,
|
||||
mut allocator_module: Option<ModuleCodegen<B::Module>>,
|
||||
coordinator_send: Sender<Message<B>>,
|
||||
) -> thread::JoinHandle<Result<CompiledModules, ()>> {
|
||||
) -> thread::JoinHandle<Result<MaybeLtoModules<B>, ()>> {
|
||||
let sess = tcx.sess;
|
||||
|
||||
let mut each_linked_rlib_for_lto = Vec::new();
|
||||
|
|
@ -1292,18 +1308,18 @@ fn start_executing_work<B: ExtraBackendMethods>(
|
|||
let cgcx = CodegenContext::<B> {
|
||||
crate_types: tcx.crate_types().to_vec(),
|
||||
lto: sess.lto(),
|
||||
use_linker_plugin_lto: sess.opts.cg.linker_plugin_lto.enabled(),
|
||||
dylib_lto: sess.opts.unstable_opts.dylib_lto,
|
||||
prefer_dynamic: sess.opts.cg.prefer_dynamic,
|
||||
fewer_names: sess.fewer_names(),
|
||||
save_temps: sess.opts.cg.save_temps,
|
||||
time_trace: sess.opts.unstable_opts.llvm_time_trace,
|
||||
opts: Arc::new(sess.opts.clone()),
|
||||
prof: sess.prof.clone(),
|
||||
remark: sess.opts.cg.remark.clone(),
|
||||
remark_dir,
|
||||
incr_comp_session_dir: sess.incr_comp_session_dir_opt().map(|r| r.clone()),
|
||||
diag_emitter: shared_emitter.clone(),
|
||||
output_filenames: Arc::clone(tcx.output_filenames(())),
|
||||
module_config: regular_config,
|
||||
allocator_config,
|
||||
tm_factory: backend.target_machine_factory(tcx.sess, ol, backend_features),
|
||||
msvc_imps_needed: msvc_imps_needed(tcx),
|
||||
is_pe_coff: tcx.sess.target.is_like_windows,
|
||||
|
|
@ -1497,16 +1513,9 @@ fn start_executing_work<B: ExtraBackendMethods>(
|
|||
|
||||
let mut llvm_start_time: Option<VerboseTimingGuard<'_>> = None;
|
||||
|
||||
let compiled_allocator_module = allocator_module.and_then(|allocator_module| {
|
||||
match execute_optimize_work_item(&cgcx, allocator_module) {
|
||||
WorkItemResult::Finished(compiled_module) => return Some(compiled_module),
|
||||
WorkItemResult::NeedsFatLto(fat_lto_input) => needs_fat_lto.push(fat_lto_input),
|
||||
WorkItemResult::NeedsThinLto(name, thin_buffer) => {
|
||||
needs_thin_lto.push((name, thin_buffer))
|
||||
}
|
||||
}
|
||||
None
|
||||
});
|
||||
if let Some(allocator_module) = &mut allocator_module {
|
||||
B::optimize(&cgcx, &shared_emitter, allocator_module, &allocator_config);
|
||||
}
|
||||
|
||||
// Run the message loop while there's still anything that needs message
|
||||
// processing. Note that as soon as codegen is aborted we simply want to
|
||||
|
|
@ -1543,7 +1552,13 @@ fn start_executing_work<B: ExtraBackendMethods>(
|
|||
let (item, _) =
|
||||
work_items.pop().expect("queue empty - queue_full_enough() broken?");
|
||||
main_thread_state = MainThreadState::Lending;
|
||||
spawn_work(&cgcx, coordinator_send.clone(), &mut llvm_start_time, item);
|
||||
spawn_work(
|
||||
&cgcx,
|
||||
shared_emitter.clone(),
|
||||
coordinator_send.clone(),
|
||||
&mut llvm_start_time,
|
||||
item,
|
||||
);
|
||||
}
|
||||
}
|
||||
} else if codegen_state == Completed {
|
||||
|
|
@ -1561,7 +1576,13 @@ fn start_executing_work<B: ExtraBackendMethods>(
|
|||
MainThreadState::Idle => {
|
||||
if let Some((item, _)) = work_items.pop() {
|
||||
main_thread_state = MainThreadState::Lending;
|
||||
spawn_work(&cgcx, coordinator_send.clone(), &mut llvm_start_time, item);
|
||||
spawn_work(
|
||||
&cgcx,
|
||||
shared_emitter.clone(),
|
||||
coordinator_send.clone(),
|
||||
&mut llvm_start_time,
|
||||
item,
|
||||
);
|
||||
} else {
|
||||
// There is no unstarted work, so let the main thread
|
||||
// take over for a running worker. Otherwise the
|
||||
|
|
@ -1597,7 +1618,13 @@ fn start_executing_work<B: ExtraBackendMethods>(
|
|||
while running_with_own_token < tokens.len()
|
||||
&& let Some((item, _)) = work_items.pop()
|
||||
{
|
||||
spawn_work(&cgcx, coordinator_send.clone(), &mut llvm_start_time, item);
|
||||
spawn_work(
|
||||
&cgcx,
|
||||
shared_emitter.clone(),
|
||||
coordinator_send.clone(),
|
||||
&mut llvm_start_time,
|
||||
item,
|
||||
);
|
||||
running_with_own_token += 1;
|
||||
}
|
||||
}
|
||||
|
|
@ -1733,36 +1760,51 @@ fn start_executing_work<B: ExtraBackendMethods>(
|
|||
assert!(compiled_modules.is_empty());
|
||||
assert!(needs_thin_lto.is_empty());
|
||||
|
||||
// This uses the implicit token
|
||||
let module = do_fat_lto(
|
||||
&cgcx,
|
||||
&exported_symbols_for_lto,
|
||||
&each_linked_rlib_file_for_lto,
|
||||
if let Some(allocator_module) = allocator_module.take() {
|
||||
needs_fat_lto.push(FatLtoInput::InMemory(allocator_module));
|
||||
}
|
||||
|
||||
return Ok(MaybeLtoModules::FatLto {
|
||||
cgcx,
|
||||
exported_symbols_for_lto,
|
||||
each_linked_rlib_file_for_lto,
|
||||
needs_fat_lto,
|
||||
lto_import_only_modules,
|
||||
);
|
||||
compiled_modules.push(module);
|
||||
});
|
||||
} else if !needs_thin_lto.is_empty() || !lto_import_only_modules.is_empty() {
|
||||
assert!(compiled_modules.is_empty());
|
||||
assert!(needs_fat_lto.is_empty());
|
||||
|
||||
compiled_modules.extend(do_thin_lto(
|
||||
&cgcx,
|
||||
exported_symbols_for_lto,
|
||||
each_linked_rlib_file_for_lto,
|
||||
needs_thin_lto,
|
||||
lto_import_only_modules,
|
||||
));
|
||||
if cgcx.lto == Lto::ThinLocal {
|
||||
compiled_modules.extend(do_thin_lto(
|
||||
&cgcx,
|
||||
shared_emitter.clone(),
|
||||
exported_symbols_for_lto,
|
||||
each_linked_rlib_file_for_lto,
|
||||
needs_thin_lto,
|
||||
lto_import_only_modules,
|
||||
));
|
||||
} else {
|
||||
if let Some(allocator_module) = allocator_module.take() {
|
||||
let (name, thin_buffer) = B::prepare_thin(allocator_module);
|
||||
needs_thin_lto.push((name, thin_buffer));
|
||||
}
|
||||
|
||||
return Ok(MaybeLtoModules::ThinLto {
|
||||
cgcx,
|
||||
exported_symbols_for_lto,
|
||||
each_linked_rlib_file_for_lto,
|
||||
needs_thin_lto,
|
||||
lto_import_only_modules,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// Regardless of what order these modules completed in, report them to
|
||||
// the backend in the same order every time to ensure that we're handing
|
||||
// out deterministic results.
|
||||
compiled_modules.sort_by(|a, b| a.name.cmp(&b.name));
|
||||
|
||||
Ok(CompiledModules {
|
||||
Ok(MaybeLtoModules::NoLto {
|
||||
modules: compiled_modules,
|
||||
allocator_module: compiled_allocator_module,
|
||||
allocator_module: allocator_module.map(|allocator_module| {
|
||||
B::codegen(&cgcx, &shared_emitter, allocator_module, &allocator_config)
|
||||
}),
|
||||
})
|
||||
})
|
||||
.expect("failed to spawn coordinator thread");
|
||||
|
|
@ -1831,6 +1873,7 @@ pub(crate) struct WorkerFatalError;
|
|||
|
||||
fn spawn_work<'a, B: ExtraBackendMethods>(
|
||||
cgcx: &'a CodegenContext<B>,
|
||||
shared_emitter: SharedEmitter,
|
||||
coordinator_send: Sender<Message<B>>,
|
||||
llvm_start_time: &mut Option<VerboseTimingGuard<'a>>,
|
||||
work: WorkItem<B>,
|
||||
|
|
@ -1843,10 +1886,10 @@ fn spawn_work<'a, B: ExtraBackendMethods>(
|
|||
|
||||
B::spawn_named_thread(cgcx.time_trace, work.short_description(), move || {
|
||||
let result = std::panic::catch_unwind(AssertUnwindSafe(|| match work {
|
||||
WorkItem::Optimize(m) => execute_optimize_work_item(&cgcx, m),
|
||||
WorkItem::CopyPostLtoArtifacts(m) => {
|
||||
WorkItemResult::Finished(execute_copy_from_cache_work_item(&cgcx, m))
|
||||
}
|
||||
WorkItem::Optimize(m) => execute_optimize_work_item(&cgcx, shared_emitter, m),
|
||||
WorkItem::CopyPostLtoArtifacts(m) => WorkItemResult::Finished(
|
||||
execute_copy_from_cache_work_item(&cgcx, shared_emitter, m),
|
||||
),
|
||||
}));
|
||||
|
||||
let msg = match result {
|
||||
|
|
@ -1868,6 +1911,7 @@ fn spawn_work<'a, B: ExtraBackendMethods>(
|
|||
|
||||
fn spawn_thin_lto_work<'a, B: ExtraBackendMethods>(
|
||||
cgcx: &'a CodegenContext<B>,
|
||||
shared_emitter: SharedEmitter,
|
||||
coordinator_send: Sender<ThinLtoMessage>,
|
||||
work: ThinLtoWorkItem<B>,
|
||||
) {
|
||||
|
|
@ -1875,8 +1919,10 @@ fn spawn_thin_lto_work<'a, B: ExtraBackendMethods>(
|
|||
|
||||
B::spawn_named_thread(cgcx.time_trace, work.short_description(), move || {
|
||||
let result = std::panic::catch_unwind(AssertUnwindSafe(|| match work {
|
||||
ThinLtoWorkItem::CopyPostLtoArtifacts(m) => execute_copy_from_cache_work_item(&cgcx, m),
|
||||
ThinLtoWorkItem::ThinLto(m) => execute_thin_lto_work_item(&cgcx, m),
|
||||
ThinLtoWorkItem::CopyPostLtoArtifacts(m) => {
|
||||
execute_copy_from_cache_work_item(&cgcx, shared_emitter, m)
|
||||
}
|
||||
ThinLtoWorkItem::ThinLto(m) => execute_thin_lto_work_item(&cgcx, shared_emitter, m),
|
||||
}));
|
||||
|
||||
let msg = match result {
|
||||
|
|
@ -2052,13 +2098,13 @@ impl SharedEmitterMain {
|
|||
|
||||
pub struct Coordinator<B: ExtraBackendMethods> {
|
||||
sender: Sender<Message<B>>,
|
||||
future: Option<thread::JoinHandle<Result<CompiledModules, ()>>>,
|
||||
future: Option<thread::JoinHandle<Result<MaybeLtoModules<B>, ()>>>,
|
||||
// Only used for the Message type.
|
||||
phantom: PhantomData<B>,
|
||||
}
|
||||
|
||||
impl<B: ExtraBackendMethods> Coordinator<B> {
|
||||
fn join(mut self) -> std::thread::Result<Result<CompiledModules, ()>> {
|
||||
fn join(mut self) -> std::thread::Result<Result<MaybeLtoModules<B>, ()>> {
|
||||
self.future.take().unwrap().join()
|
||||
}
|
||||
}
|
||||
|
|
@ -2089,8 +2135,9 @@ pub struct OngoingCodegen<B: ExtraBackendMethods> {
|
|||
impl<B: ExtraBackendMethods> OngoingCodegen<B> {
|
||||
pub fn join(self, sess: &Session) -> (CodegenResults, FxIndexMap<WorkProductId, WorkProduct>) {
|
||||
self.shared_emitter_main.check(sess, true);
|
||||
let compiled_modules = sess.time("join_worker_thread", || match self.coordinator.join() {
|
||||
Ok(Ok(compiled_modules)) => compiled_modules,
|
||||
|
||||
let maybe_lto_modules = sess.time("join_worker_thread", || match self.coordinator.join() {
|
||||
Ok(Ok(maybe_lto_modules)) => maybe_lto_modules,
|
||||
Ok(Err(())) => {
|
||||
sess.dcx().abort_if_errors();
|
||||
panic!("expected abort due to worker thread errors")
|
||||
|
|
@ -2102,6 +2149,62 @@ impl<B: ExtraBackendMethods> OngoingCodegen<B> {
|
|||
|
||||
sess.dcx().abort_if_errors();
|
||||
|
||||
let (shared_emitter, shared_emitter_main) = SharedEmitter::new();
|
||||
|
||||
// Catch fatal errors to ensure shared_emitter_main.check() can emit the actual diagnostics
|
||||
let compiled_modules = catch_fatal_errors(|| match maybe_lto_modules {
|
||||
MaybeLtoModules::NoLto { modules, allocator_module } => {
|
||||
drop(shared_emitter);
|
||||
CompiledModules { modules, allocator_module }
|
||||
}
|
||||
MaybeLtoModules::FatLto {
|
||||
cgcx,
|
||||
exported_symbols_for_lto,
|
||||
each_linked_rlib_file_for_lto,
|
||||
needs_fat_lto,
|
||||
lto_import_only_modules,
|
||||
} => CompiledModules {
|
||||
modules: vec![do_fat_lto(
|
||||
&cgcx,
|
||||
shared_emitter,
|
||||
&exported_symbols_for_lto,
|
||||
&each_linked_rlib_file_for_lto,
|
||||
needs_fat_lto,
|
||||
lto_import_only_modules,
|
||||
)],
|
||||
allocator_module: None,
|
||||
},
|
||||
MaybeLtoModules::ThinLto {
|
||||
cgcx,
|
||||
exported_symbols_for_lto,
|
||||
each_linked_rlib_file_for_lto,
|
||||
needs_thin_lto,
|
||||
lto_import_only_modules,
|
||||
} => CompiledModules {
|
||||
modules: do_thin_lto(
|
||||
&cgcx,
|
||||
shared_emitter,
|
||||
exported_symbols_for_lto,
|
||||
each_linked_rlib_file_for_lto,
|
||||
needs_thin_lto,
|
||||
lto_import_only_modules,
|
||||
),
|
||||
allocator_module: None,
|
||||
},
|
||||
});
|
||||
|
||||
shared_emitter_main.check(sess, true);
|
||||
|
||||
sess.dcx().abort_if_errors();
|
||||
|
||||
let mut compiled_modules =
|
||||
compiled_modules.expect("fatal error emitted but not sent to SharedEmitter");
|
||||
|
||||
// Regardless of what order these modules completed in, report them to
|
||||
// the backend in the same order every time to ensure that we're handing
|
||||
// out deterministic results.
|
||||
compiled_modules.modules.sort_by(|a, b| a.name.cmp(&b.name));
|
||||
|
||||
let work_products =
|
||||
copy_all_cgu_workproducts_to_incr_comp_cache_dir(sess, &compiled_modules);
|
||||
produce_final_output_artifacts(sess, &compiled_modules, &self.output_filenames);
|
||||
|
|
|
|||
|
|
@ -49,9 +49,7 @@ use crate::meth::load_vtable;
|
|||
use crate::mir::operand::OperandValue;
|
||||
use crate::mir::place::PlaceRef;
|
||||
use crate::traits::*;
|
||||
use crate::{
|
||||
CachedModuleCodegen, CodegenLintLevels, CrateInfo, ModuleCodegen, ModuleKind, errors, meth, mir,
|
||||
};
|
||||
use crate::{CachedModuleCodegen, CodegenLintLevels, CrateInfo, ModuleCodegen, errors, meth, mir};
|
||||
|
||||
pub(crate) fn bin_op_to_icmp_predicate(op: BinOp, signed: bool) -> IntPredicate {
|
||||
match (op, signed) {
|
||||
|
|
@ -1011,7 +1009,7 @@ impl CrateInfo {
|
|||
info.linked_symbols
|
||||
.iter_mut()
|
||||
.filter(|(crate_type, _)| {
|
||||
!matches!(crate_type, CrateType::Rlib | CrateType::Staticlib)
|
||||
!matches!(crate_type, CrateType::Rlib | CrateType::StaticLib)
|
||||
})
|
||||
.for_each(|(_, linked_symbols)| {
|
||||
let mut symbols = missing_weak_lang_items
|
||||
|
|
@ -1043,7 +1041,7 @@ impl CrateInfo {
|
|||
// this is a rare use case and we don't want to slow down the common case.
|
||||
false
|
||||
}
|
||||
CrateType::Staticlib | CrateType::Rlib => {
|
||||
CrateType::StaticLib | CrateType::Rlib => {
|
||||
// We don't invoke the linker for these, so we don't need to collect the NatVis for
|
||||
// them.
|
||||
false
|
||||
|
|
@ -1126,9 +1124,8 @@ pub fn determine_cgu_reuse<'tcx>(tcx: TyCtxt<'tcx>, cgu: &CodegenUnit<'tcx>) ->
|
|||
// reuse pre-LTO artifacts
|
||||
match compute_per_cgu_lto_type(
|
||||
&tcx.sess.lto(),
|
||||
&tcx.sess.opts,
|
||||
tcx.sess.opts.cg.linker_plugin_lto.enabled(),
|
||||
tcx.crate_types(),
|
||||
ModuleKind::Regular,
|
||||
) {
|
||||
ComputedLtoType::No => CguReuse::PostLto,
|
||||
_ => CguReuse::PreLto,
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ use std::str::FromStr;
|
|||
|
||||
use rustc_abi::{Align, ExternAbi};
|
||||
use rustc_ast::expand::autodiff_attrs::{AutoDiffAttrs, DiffActivity, DiffMode};
|
||||
use rustc_ast::{LitKind, MetaItem, MetaItemInner, attr};
|
||||
use rustc_ast::{LitKind, MetaItem, MetaItemInner};
|
||||
use rustc_hir::attrs::{
|
||||
AttributeKind, EiiImplResolution, InlineAttr, Linkage, RtsanSetting, UsedBy,
|
||||
};
|
||||
|
|
@ -47,59 +47,6 @@ fn try_fn_sig<'tcx>(
|
|||
}
|
||||
}
|
||||
|
||||
// FIXME(jdonszelmann): remove when patchable_function_entry becomes a parsed attr
|
||||
fn parse_patchable_function_entry(
|
||||
tcx: TyCtxt<'_>,
|
||||
attr: &Attribute,
|
||||
) -> Option<PatchableFunctionEntry> {
|
||||
attr.meta_item_list().and_then(|l| {
|
||||
let mut prefix = None;
|
||||
let mut entry = None;
|
||||
for item in l {
|
||||
let Some(meta_item) = item.meta_item() else {
|
||||
tcx.dcx().emit_err(errors::ExpectedNameValuePair { span: item.span() });
|
||||
continue;
|
||||
};
|
||||
|
||||
let Some(name_value_lit) = meta_item.name_value_literal() else {
|
||||
tcx.dcx().emit_err(errors::ExpectedNameValuePair { span: item.span() });
|
||||
continue;
|
||||
};
|
||||
|
||||
let attrib_to_write = match meta_item.name() {
|
||||
Some(sym::prefix_nops) => &mut prefix,
|
||||
Some(sym::entry_nops) => &mut entry,
|
||||
_ => {
|
||||
tcx.dcx().emit_err(errors::UnexpectedParameterName {
|
||||
span: item.span(),
|
||||
prefix_nops: sym::prefix_nops,
|
||||
entry_nops: sym::entry_nops,
|
||||
});
|
||||
continue;
|
||||
}
|
||||
};
|
||||
|
||||
let rustc_ast::LitKind::Int(val, _) = name_value_lit.kind else {
|
||||
tcx.dcx().emit_err(errors::InvalidLiteralValue { span: name_value_lit.span });
|
||||
continue;
|
||||
};
|
||||
|
||||
let Ok(val) = val.get().try_into() else {
|
||||
tcx.dcx().emit_err(errors::OutOfRangeInteger { span: name_value_lit.span });
|
||||
continue;
|
||||
};
|
||||
|
||||
*attrib_to_write = Some(val);
|
||||
}
|
||||
|
||||
if let (None, None) = (prefix, entry) {
|
||||
tcx.dcx().span_err(attr.span(), "must specify at least one parameter");
|
||||
}
|
||||
|
||||
Some(PatchableFunctionEntry::from_prefix_and_entry(prefix.unwrap_or(0), entry.unwrap_or(0)))
|
||||
})
|
||||
}
|
||||
|
||||
/// Spans that are collected when processing built-in attributes,
|
||||
/// that are useful for emitting diagnostics later.
|
||||
#[derive(Default)]
|
||||
|
|
@ -121,250 +68,235 @@ fn process_builtin_attrs(
|
|||
let mut interesting_spans = InterestingAttributeDiagnosticSpans::default();
|
||||
let rust_target_features = tcx.rust_target_features(LOCAL_CRATE);
|
||||
|
||||
for attr in attrs.iter() {
|
||||
if let hir::Attribute::Parsed(p) = attr {
|
||||
match p {
|
||||
AttributeKind::Cold(_) => codegen_fn_attrs.flags |= CodegenFnAttrFlags::COLD,
|
||||
AttributeKind::ExportName { name, .. } => {
|
||||
codegen_fn_attrs.symbol_name = Some(*name)
|
||||
let parsed_attrs = attrs
|
||||
.iter()
|
||||
.filter_map(|attr| if let hir::Attribute::Parsed(attr) = attr { Some(attr) } else { None });
|
||||
for attr in parsed_attrs {
|
||||
match attr {
|
||||
AttributeKind::Cold(_) => codegen_fn_attrs.flags |= CodegenFnAttrFlags::COLD,
|
||||
AttributeKind::ExportName { name, .. } => codegen_fn_attrs.symbol_name = Some(*name),
|
||||
AttributeKind::Inline(inline, span) => {
|
||||
codegen_fn_attrs.inline = *inline;
|
||||
interesting_spans.inline = Some(*span);
|
||||
}
|
||||
AttributeKind::Naked(_) => codegen_fn_attrs.flags |= CodegenFnAttrFlags::NAKED,
|
||||
AttributeKind::Align { align, .. } => codegen_fn_attrs.alignment = Some(*align),
|
||||
AttributeKind::LinkName { name, .. } => {
|
||||
// FIXME Remove check for foreign functions once #[link_name] on non-foreign
|
||||
// functions is a hard error
|
||||
if tcx.is_foreign_item(did) {
|
||||
codegen_fn_attrs.symbol_name = Some(*name);
|
||||
}
|
||||
AttributeKind::Inline(inline, span) => {
|
||||
codegen_fn_attrs.inline = *inline;
|
||||
interesting_spans.inline = Some(*span);
|
||||
}
|
||||
AttributeKind::LinkOrdinal { ordinal, span } => {
|
||||
codegen_fn_attrs.link_ordinal = Some(*ordinal);
|
||||
interesting_spans.link_ordinal = Some(*span);
|
||||
}
|
||||
AttributeKind::LinkSection { name, .. } => codegen_fn_attrs.link_section = Some(*name),
|
||||
AttributeKind::NoMangle(attr_span) => {
|
||||
interesting_spans.no_mangle = Some(*attr_span);
|
||||
if tcx.opt_item_name(did.to_def_id()).is_some() {
|
||||
codegen_fn_attrs.flags |= CodegenFnAttrFlags::NO_MANGLE;
|
||||
} else {
|
||||
tcx.dcx()
|
||||
.span_delayed_bug(*attr_span, "no_mangle should be on a named function");
|
||||
}
|
||||
AttributeKind::Naked(_) => codegen_fn_attrs.flags |= CodegenFnAttrFlags::NAKED,
|
||||
AttributeKind::Align { align, .. } => codegen_fn_attrs.alignment = Some(*align),
|
||||
AttributeKind::LinkName { name, .. } => {
|
||||
// FIXME Remove check for foreign functions once #[link_name] on non-foreign
|
||||
// functions is a hard error
|
||||
if tcx.is_foreign_item(did) {
|
||||
codegen_fn_attrs.symbol_name = Some(*name);
|
||||
}
|
||||
}
|
||||
AttributeKind::LinkOrdinal { ordinal, span } => {
|
||||
codegen_fn_attrs.link_ordinal = Some(*ordinal);
|
||||
interesting_spans.link_ordinal = Some(*span);
|
||||
}
|
||||
AttributeKind::LinkSection { name, .. } => {
|
||||
codegen_fn_attrs.link_section = Some(*name)
|
||||
}
|
||||
AttributeKind::NoMangle(attr_span) => {
|
||||
interesting_spans.no_mangle = Some(*attr_span);
|
||||
if tcx.opt_item_name(did.to_def_id()).is_some() {
|
||||
codegen_fn_attrs.flags |= CodegenFnAttrFlags::NO_MANGLE;
|
||||
}
|
||||
AttributeKind::Optimize(optimize, _) => codegen_fn_attrs.optimize = *optimize,
|
||||
AttributeKind::TargetFeature { features, attr_span, was_forced } => {
|
||||
let Some(sig) = tcx.hir_node_by_def_id(did).fn_sig() else {
|
||||
tcx.dcx().span_delayed_bug(*attr_span, "target_feature applied to non-fn");
|
||||
continue;
|
||||
};
|
||||
let safe_target_features =
|
||||
matches!(sig.header.safety, hir::HeaderSafety::SafeTargetFeatures);
|
||||
codegen_fn_attrs.safe_target_features = safe_target_features;
|
||||
if safe_target_features && !was_forced {
|
||||
if tcx.sess.target.is_like_wasm || tcx.sess.opts.actually_rustdoc {
|
||||
// The `#[target_feature]` attribute is allowed on
|
||||
// WebAssembly targets on all functions. Prior to stabilizing
|
||||
// the `target_feature_11` feature, `#[target_feature]` was
|
||||
// only permitted on unsafe functions because on most targets
|
||||
// execution of instructions that are not supported is
|
||||
// considered undefined behavior. For WebAssembly which is a
|
||||
// 100% safe target at execution time it's not possible to
|
||||
// execute undefined instructions, and even if a future
|
||||
// feature was added in some form for this it would be a
|
||||
// deterministic trap. There is no undefined behavior when
|
||||
// executing WebAssembly so `#[target_feature]` is allowed
|
||||
// on safe functions (but again, only for WebAssembly)
|
||||
//
|
||||
// Note that this is also allowed if `actually_rustdoc` so
|
||||
// if a target is documenting some wasm-specific code then
|
||||
// it's not spuriously denied.
|
||||
//
|
||||
// Now that `#[target_feature]` is permitted on safe functions,
|
||||
// this exception must still exist for allowing the attribute on
|
||||
// `main`, `start`, and other functions that are not usually
|
||||
// allowed.
|
||||
} else {
|
||||
tcx.dcx().span_delayed_bug(
|
||||
*attr_span,
|
||||
"no_mangle should be on a named function",
|
||||
);
|
||||
check_target_feature_trait_unsafe(tcx, did, *attr_span);
|
||||
}
|
||||
}
|
||||
AttributeKind::Optimize(optimize, _) => codegen_fn_attrs.optimize = *optimize,
|
||||
AttributeKind::TargetFeature { features, attr_span, was_forced } => {
|
||||
let Some(sig) = tcx.hir_node_by_def_id(did).fn_sig() else {
|
||||
tcx.dcx().span_delayed_bug(*attr_span, "target_feature applied to non-fn");
|
||||
continue;
|
||||
from_target_feature_attr(
|
||||
tcx,
|
||||
did,
|
||||
features,
|
||||
*was_forced,
|
||||
rust_target_features,
|
||||
&mut codegen_fn_attrs.target_features,
|
||||
);
|
||||
}
|
||||
AttributeKind::TrackCaller(attr_span) => {
|
||||
let is_closure = tcx.is_closure_like(did.to_def_id());
|
||||
|
||||
if !is_closure
|
||||
&& let Some(fn_sig) = try_fn_sig(tcx, did, *attr_span)
|
||||
&& fn_sig.skip_binder().abi() != ExternAbi::Rust
|
||||
{
|
||||
tcx.dcx().emit_err(errors::RequiresRustAbi { span: *attr_span });
|
||||
}
|
||||
if is_closure
|
||||
&& !tcx.features().closure_track_caller()
|
||||
&& !attr_span.allows_unstable(sym::closure_track_caller)
|
||||
{
|
||||
feature_err(
|
||||
&tcx.sess,
|
||||
sym::closure_track_caller,
|
||||
*attr_span,
|
||||
"`#[track_caller]` on closures is currently unstable",
|
||||
)
|
||||
.emit();
|
||||
}
|
||||
codegen_fn_attrs.flags |= CodegenFnAttrFlags::TRACK_CALLER
|
||||
}
|
||||
AttributeKind::Used { used_by, .. } => match used_by {
|
||||
UsedBy::Compiler => codegen_fn_attrs.flags |= CodegenFnAttrFlags::USED_COMPILER,
|
||||
UsedBy::Linker => codegen_fn_attrs.flags |= CodegenFnAttrFlags::USED_LINKER,
|
||||
UsedBy::Default => {
|
||||
let used_form = if tcx.sess.target.os == Os::Illumos {
|
||||
// illumos' `ld` doesn't support a section header that would represent
|
||||
// `#[used(linker)]`, see
|
||||
// https://github.com/rust-lang/rust/issues/146169. For that target,
|
||||
// downgrade as if `#[used(compiler)]` was requested and hope for the
|
||||
// best.
|
||||
CodegenFnAttrFlags::USED_COMPILER
|
||||
} else {
|
||||
CodegenFnAttrFlags::USED_LINKER
|
||||
};
|
||||
let safe_target_features =
|
||||
matches!(sig.header.safety, hir::HeaderSafety::SafeTargetFeatures);
|
||||
codegen_fn_attrs.safe_target_features = safe_target_features;
|
||||
if safe_target_features && !was_forced {
|
||||
if tcx.sess.target.is_like_wasm || tcx.sess.opts.actually_rustdoc {
|
||||
// The `#[target_feature]` attribute is allowed on
|
||||
// WebAssembly targets on all functions. Prior to stabilizing
|
||||
// the `target_feature_11` feature, `#[target_feature]` was
|
||||
// only permitted on unsafe functions because on most targets
|
||||
// execution of instructions that are not supported is
|
||||
// considered undefined behavior. For WebAssembly which is a
|
||||
// 100% safe target at execution time it's not possible to
|
||||
// execute undefined instructions, and even if a future
|
||||
// feature was added in some form for this it would be a
|
||||
// deterministic trap. There is no undefined behavior when
|
||||
// executing WebAssembly so `#[target_feature]` is allowed
|
||||
// on safe functions (but again, only for WebAssembly)
|
||||
//
|
||||
// Note that this is also allowed if `actually_rustdoc` so
|
||||
// if a target is documenting some wasm-specific code then
|
||||
// it's not spuriously denied.
|
||||
//
|
||||
// Now that `#[target_feature]` is permitted on safe functions,
|
||||
// this exception must still exist for allowing the attribute on
|
||||
// `main`, `start`, and other functions that are not usually
|
||||
// allowed.
|
||||
} else {
|
||||
check_target_feature_trait_unsafe(tcx, did, *attr_span);
|
||||
codegen_fn_attrs.flags |= used_form;
|
||||
}
|
||||
},
|
||||
AttributeKind::FfiConst(_) => codegen_fn_attrs.flags |= CodegenFnAttrFlags::FFI_CONST,
|
||||
AttributeKind::FfiPure(_) => codegen_fn_attrs.flags |= CodegenFnAttrFlags::FFI_PURE,
|
||||
AttributeKind::StdInternalSymbol(_) => {
|
||||
codegen_fn_attrs.flags |= CodegenFnAttrFlags::RUSTC_STD_INTERNAL_SYMBOL
|
||||
}
|
||||
AttributeKind::Linkage(linkage, span) => {
|
||||
let linkage = Some(*linkage);
|
||||
|
||||
if tcx.is_foreign_item(did) {
|
||||
codegen_fn_attrs.import_linkage = linkage;
|
||||
|
||||
if tcx.is_mutable_static(did.into()) {
|
||||
let mut diag = tcx.dcx().struct_span_err(
|
||||
*span,
|
||||
"extern mutable statics are not allowed with `#[linkage]`",
|
||||
);
|
||||
diag.note(
|
||||
"marking the extern static mutable would allow changing which \
|
||||
symbol the static references rather than make the target of the \
|
||||
symbol mutable",
|
||||
);
|
||||
diag.emit();
|
||||
}
|
||||
} else {
|
||||
codegen_fn_attrs.linkage = linkage;
|
||||
}
|
||||
}
|
||||
AttributeKind::Sanitize { span, .. } => {
|
||||
interesting_spans.sanitize = Some(*span);
|
||||
}
|
||||
AttributeKind::ObjcClass { classname, .. } => {
|
||||
codegen_fn_attrs.objc_class = Some(*classname);
|
||||
}
|
||||
AttributeKind::ObjcSelector { methname, .. } => {
|
||||
codegen_fn_attrs.objc_selector = Some(*methname);
|
||||
}
|
||||
AttributeKind::EiiForeignItem => {
|
||||
codegen_fn_attrs.flags |= CodegenFnAttrFlags::EXTERNALLY_IMPLEMENTABLE_ITEM;
|
||||
}
|
||||
AttributeKind::EiiImpls(impls) => {
|
||||
for i in impls {
|
||||
let foreign_item = match i.resolution {
|
||||
EiiImplResolution::Macro(def_id) => {
|
||||
let Some(extern_item) = find_attr!(
|
||||
tcx.get_all_attrs(def_id),
|
||||
AttributeKind::EiiDeclaration(target) => target.foreign_item
|
||||
) else {
|
||||
tcx.dcx().span_delayed_bug(
|
||||
i.span,
|
||||
"resolved to something that's not an EII",
|
||||
);
|
||||
continue;
|
||||
};
|
||||
extern_item
|
||||
}
|
||||
}
|
||||
from_target_feature_attr(
|
||||
tcx,
|
||||
did,
|
||||
features,
|
||||
*was_forced,
|
||||
rust_target_features,
|
||||
&mut codegen_fn_attrs.target_features,
|
||||
);
|
||||
}
|
||||
AttributeKind::TrackCaller(attr_span) => {
|
||||
let is_closure = tcx.is_closure_like(did.to_def_id());
|
||||
EiiImplResolution::Known(decl) => decl.foreign_item,
|
||||
EiiImplResolution::Error(_eg) => continue,
|
||||
};
|
||||
|
||||
if !is_closure
|
||||
&& let Some(fn_sig) = try_fn_sig(tcx, did, *attr_span)
|
||||
&& fn_sig.skip_binder().abi() != ExternAbi::Rust
|
||||
// this is to prevent a bug where a single crate defines both the default and explicit implementation
|
||||
// for an EII. In that case, both of them may be part of the same final object file. I'm not 100% sure
|
||||
// what happens, either rustc deduplicates the symbol or llvm, or it's random/order-dependent.
|
||||
// However, the fact that the default one of has weak linkage isn't considered and you sometimes get that
|
||||
// the default implementation is used while an explicit implementation is given.
|
||||
if
|
||||
// if this is a default impl
|
||||
i.is_default
|
||||
// iterate over all implementations *in the current crate*
|
||||
// (this is ok since we generate codegen fn attrs in the local crate)
|
||||
// if any of them is *not default* then don't emit the alias.
|
||||
&& tcx.externally_implementable_items(LOCAL_CRATE).get(&foreign_item).expect("at least one").1.iter().any(|(_, imp)| !imp.is_default)
|
||||
{
|
||||
tcx.dcx().emit_err(errors::RequiresRustAbi { span: *attr_span });
|
||||
continue;
|
||||
}
|
||||
if is_closure
|
||||
&& !tcx.features().closure_track_caller()
|
||||
&& !attr_span.allows_unstable(sym::closure_track_caller)
|
||||
{
|
||||
feature_err(
|
||||
&tcx.sess,
|
||||
sym::closure_track_caller,
|
||||
*attr_span,
|
||||
"`#[track_caller]` on closures is currently unstable",
|
||||
)
|
||||
.emit();
|
||||
}
|
||||
codegen_fn_attrs.flags |= CodegenFnAttrFlags::TRACK_CALLER
|
||||
}
|
||||
AttributeKind::Used { used_by, .. } => match used_by {
|
||||
UsedBy::Compiler => codegen_fn_attrs.flags |= CodegenFnAttrFlags::USED_COMPILER,
|
||||
UsedBy::Linker => codegen_fn_attrs.flags |= CodegenFnAttrFlags::USED_LINKER,
|
||||
UsedBy::Default => {
|
||||
let used_form = if tcx.sess.target.os == Os::Illumos {
|
||||
// illumos' `ld` doesn't support a section header that would represent
|
||||
// `#[used(linker)]`, see
|
||||
// https://github.com/rust-lang/rust/issues/146169. For that target,
|
||||
// downgrade as if `#[used(compiler)]` was requested and hope for the
|
||||
// best.
|
||||
CodegenFnAttrFlags::USED_COMPILER
|
||||
} else {
|
||||
CodegenFnAttrFlags::USED_LINKER
|
||||
};
|
||||
codegen_fn_attrs.flags |= used_form;
|
||||
}
|
||||
},
|
||||
AttributeKind::FfiConst(_) => {
|
||||
codegen_fn_attrs.flags |= CodegenFnAttrFlags::FFI_CONST
|
||||
}
|
||||
AttributeKind::FfiPure(_) => codegen_fn_attrs.flags |= CodegenFnAttrFlags::FFI_PURE,
|
||||
AttributeKind::StdInternalSymbol(_) => {
|
||||
codegen_fn_attrs.flags |= CodegenFnAttrFlags::RUSTC_STD_INTERNAL_SYMBOL
|
||||
}
|
||||
AttributeKind::Linkage(linkage, span) => {
|
||||
let linkage = Some(*linkage);
|
||||
|
||||
if tcx.is_foreign_item(did) {
|
||||
codegen_fn_attrs.import_linkage = linkage;
|
||||
|
||||
if tcx.is_mutable_static(did.into()) {
|
||||
let mut diag = tcx.dcx().struct_span_err(
|
||||
*span,
|
||||
"extern mutable statics are not allowed with `#[linkage]`",
|
||||
);
|
||||
diag.note(
|
||||
"marking the extern static mutable would allow changing which \
|
||||
symbol the static references rather than make the target of the \
|
||||
symbol mutable",
|
||||
);
|
||||
diag.emit();
|
||||
}
|
||||
} else {
|
||||
codegen_fn_attrs.linkage = linkage;
|
||||
}
|
||||
}
|
||||
AttributeKind::Sanitize { span, .. } => {
|
||||
interesting_spans.sanitize = Some(*span);
|
||||
}
|
||||
AttributeKind::ObjcClass { classname, .. } => {
|
||||
codegen_fn_attrs.objc_class = Some(*classname);
|
||||
}
|
||||
AttributeKind::ObjcSelector { methname, .. } => {
|
||||
codegen_fn_attrs.objc_selector = Some(*methname);
|
||||
}
|
||||
AttributeKind::EiiForeignItem => {
|
||||
codegen_fn_attrs.foreign_item_symbol_aliases.push((
|
||||
foreign_item,
|
||||
if i.is_default { Linkage::LinkOnceAny } else { Linkage::External },
|
||||
Visibility::Default,
|
||||
));
|
||||
codegen_fn_attrs.flags |= CodegenFnAttrFlags::EXTERNALLY_IMPLEMENTABLE_ITEM;
|
||||
}
|
||||
AttributeKind::EiiImpls(impls) => {
|
||||
for i in impls {
|
||||
let foreign_item = match i.resolution {
|
||||
EiiImplResolution::Macro(def_id) => {
|
||||
let Some(extern_item) = find_attr!(
|
||||
tcx.get_all_attrs(def_id),
|
||||
AttributeKind::EiiDeclaration(target) => target.foreign_item
|
||||
) else {
|
||||
tcx.dcx().span_delayed_bug(
|
||||
i.span,
|
||||
"resolved to something that's not an EII",
|
||||
);
|
||||
continue;
|
||||
};
|
||||
extern_item
|
||||
}
|
||||
EiiImplResolution::Known(decl) => decl.foreign_item,
|
||||
EiiImplResolution::Error(_eg) => continue,
|
||||
};
|
||||
|
||||
// this is to prevent a bug where a single crate defines both the default and explicit implementation
|
||||
// for an EII. In that case, both of them may be part of the same final object file. I'm not 100% sure
|
||||
// what happens, either rustc deduplicates the symbol or llvm, or it's random/order-dependent.
|
||||
// However, the fact that the default one of has weak linkage isn't considered and you sometimes get that
|
||||
// the default implementation is used while an explicit implementation is given.
|
||||
if
|
||||
// if this is a default impl
|
||||
i.is_default
|
||||
// iterate over all implementations *in the current crate*
|
||||
// (this is ok since we generate codegen fn attrs in the local crate)
|
||||
// if any of them is *not default* then don't emit the alias.
|
||||
&& tcx.externally_implementable_items(LOCAL_CRATE).get(&foreign_item).expect("at least one").1.iter().any(|(_, imp)| !imp.is_default)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
codegen_fn_attrs.foreign_item_symbol_aliases.push((
|
||||
foreign_item,
|
||||
if i.is_default { Linkage::LinkOnceAny } else { Linkage::External },
|
||||
Visibility::Default,
|
||||
));
|
||||
codegen_fn_attrs.flags |= CodegenFnAttrFlags::EXTERNALLY_IMPLEMENTABLE_ITEM;
|
||||
}
|
||||
}
|
||||
AttributeKind::ThreadLocal => {
|
||||
codegen_fn_attrs.flags |= CodegenFnAttrFlags::THREAD_LOCAL
|
||||
}
|
||||
AttributeKind::InstructionSet(instruction_set) => {
|
||||
codegen_fn_attrs.instruction_set = Some(*instruction_set)
|
||||
}
|
||||
AttributeKind::RustcAllocator => {
|
||||
codegen_fn_attrs.flags |= CodegenFnAttrFlags::ALLOCATOR
|
||||
}
|
||||
AttributeKind::RustcDeallocator => {
|
||||
codegen_fn_attrs.flags |= CodegenFnAttrFlags::DEALLOCATOR
|
||||
}
|
||||
AttributeKind::RustcReallocator => {
|
||||
codegen_fn_attrs.flags |= CodegenFnAttrFlags::REALLOCATOR
|
||||
}
|
||||
AttributeKind::RustcAllocatorZeroed => {
|
||||
codegen_fn_attrs.flags |= CodegenFnAttrFlags::ALLOCATOR_ZEROED
|
||||
}
|
||||
AttributeKind::RustcNounwind => {
|
||||
codegen_fn_attrs.flags |= CodegenFnAttrFlags::NEVER_UNWIND
|
||||
}
|
||||
AttributeKind::RustcOffloadKernel => {
|
||||
codegen_fn_attrs.flags |= CodegenFnAttrFlags::OFFLOAD_KERNEL
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
let Some(name) = attr.name() else {
|
||||
continue;
|
||||
};
|
||||
|
||||
match name {
|
||||
sym::patchable_function_entry => {
|
||||
AttributeKind::ThreadLocal => {
|
||||
codegen_fn_attrs.flags |= CodegenFnAttrFlags::THREAD_LOCAL
|
||||
}
|
||||
AttributeKind::InstructionSet(instruction_set) => {
|
||||
codegen_fn_attrs.instruction_set = Some(*instruction_set)
|
||||
}
|
||||
AttributeKind::RustcAllocator => {
|
||||
codegen_fn_attrs.flags |= CodegenFnAttrFlags::ALLOCATOR
|
||||
}
|
||||
AttributeKind::RustcDeallocator => {
|
||||
codegen_fn_attrs.flags |= CodegenFnAttrFlags::DEALLOCATOR
|
||||
}
|
||||
AttributeKind::RustcReallocator => {
|
||||
codegen_fn_attrs.flags |= CodegenFnAttrFlags::REALLOCATOR
|
||||
}
|
||||
AttributeKind::RustcAllocatorZeroed => {
|
||||
codegen_fn_attrs.flags |= CodegenFnAttrFlags::ALLOCATOR_ZEROED
|
||||
}
|
||||
AttributeKind::RustcNounwind => {
|
||||
codegen_fn_attrs.flags |= CodegenFnAttrFlags::NEVER_UNWIND
|
||||
}
|
||||
AttributeKind::RustcOffloadKernel => {
|
||||
codegen_fn_attrs.flags |= CodegenFnAttrFlags::OFFLOAD_KERNEL
|
||||
}
|
||||
AttributeKind::PatchableFunctionEntry { prefix, entry } => {
|
||||
codegen_fn_attrs.patchable_function_entry =
|
||||
parse_patchable_function_entry(tcx, attr);
|
||||
Some(PatchableFunctionEntry::from_prefix_and_entry(*prefix, *entry));
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
|
|
@ -421,7 +353,7 @@ fn apply_overrides(tcx: TyCtxt<'_>, did: LocalDefId, codegen_fn_attrs: &mut Code
|
|||
// When `no_builtins` is applied at the crate level, we should add the
|
||||
// `no-builtins` attribute to each function to ensure it takes effect in LTO.
|
||||
let crate_attrs = tcx.hir_attrs(rustc_hir::CRATE_HIR_ID);
|
||||
let no_builtins = attr::contains_name(crate_attrs, sym::no_builtins);
|
||||
let no_builtins = find_attr!(crate_attrs, AttributeKind::NoBuiltins);
|
||||
if no_builtins {
|
||||
codegen_fn_attrs.flags |= CodegenFnAttrFlags::NO_BUILTINS;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -109,14 +109,14 @@ fn push_debuginfo_type_name<'tcx>(
|
|||
ty_and_layout,
|
||||
&|output, visited| {
|
||||
push_item_name(tcx, def.did(), true, output);
|
||||
push_generic_params_internal(tcx, args, output, visited);
|
||||
push_generic_args_internal(tcx, args, output, visited);
|
||||
},
|
||||
output,
|
||||
visited,
|
||||
);
|
||||
} else {
|
||||
push_item_name(tcx, def.did(), qualified, output);
|
||||
push_generic_params_internal(tcx, args, output, visited);
|
||||
push_generic_args_internal(tcx, args, output, visited);
|
||||
}
|
||||
}
|
||||
ty::Tuple(component_types) => {
|
||||
|
|
@ -253,19 +253,18 @@ fn push_debuginfo_type_name<'tcx>(
|
|||
);
|
||||
push_item_name(tcx, principal.def_id, qualified, output);
|
||||
let principal_has_generic_params =
|
||||
push_generic_params_internal(tcx, principal.args, output, visited);
|
||||
push_generic_args_internal(tcx, principal.args, output, visited);
|
||||
|
||||
let projection_bounds: SmallVec<[_; 4]> = trait_data
|
||||
.projection_bounds()
|
||||
.map(|bound| {
|
||||
let ExistentialProjection { def_id: item_def_id, term, .. } =
|
||||
tcx.instantiate_bound_regions_with_erased(bound);
|
||||
// FIXME(mgca): allow for consts here
|
||||
(item_def_id, term.expect_type())
|
||||
(item_def_id, term)
|
||||
})
|
||||
.collect();
|
||||
|
||||
if projection_bounds.len() != 0 {
|
||||
if !projection_bounds.is_empty() {
|
||||
if principal_has_generic_params {
|
||||
// push_generic_params_internal() above added a `>` but we actually
|
||||
// want to add more items to that list, so remove that again...
|
||||
|
|
@ -279,17 +278,17 @@ fn push_debuginfo_type_name<'tcx>(
|
|||
output.push('<');
|
||||
}
|
||||
|
||||
for (item_def_id, ty) in projection_bounds {
|
||||
for (item_def_id, term) in projection_bounds {
|
||||
if cpp_like_debuginfo {
|
||||
output.push_str("assoc$<");
|
||||
push_item_name(tcx, item_def_id, false, output);
|
||||
push_arg_separator(cpp_like_debuginfo, output);
|
||||
push_debuginfo_type_name(tcx, ty, true, output, visited);
|
||||
push_debuginfo_term_name(tcx, term, true, output, visited);
|
||||
push_close_angle_bracket(cpp_like_debuginfo, output);
|
||||
} else {
|
||||
push_item_name(tcx, item_def_id, false, output);
|
||||
output.push('=');
|
||||
push_debuginfo_type_name(tcx, ty, true, output, visited);
|
||||
push_debuginfo_term_name(tcx, term, true, output, visited);
|
||||
}
|
||||
push_arg_separator(cpp_like_debuginfo, output);
|
||||
}
|
||||
|
|
@ -533,7 +532,7 @@ pub fn compute_debuginfo_vtable_name<'tcx>(
|
|||
tcx.normalize_erasing_regions(ty::TypingEnv::fully_monomorphized(), trait_ref);
|
||||
push_item_name(tcx, trait_ref.def_id, true, &mut vtable_name);
|
||||
visited.clear();
|
||||
push_generic_params_internal(tcx, trait_ref.args, &mut vtable_name, &mut visited);
|
||||
push_generic_args_internal(tcx, trait_ref.args, &mut vtable_name, &mut visited);
|
||||
} else {
|
||||
vtable_name.push('_');
|
||||
}
|
||||
|
|
@ -631,7 +630,13 @@ fn push_unqualified_item_name(
|
|||
};
|
||||
}
|
||||
|
||||
fn push_generic_params_internal<'tcx>(
|
||||
pub fn push_generic_args<'tcx>(tcx: TyCtxt<'tcx>, args: GenericArgsRef<'tcx>, output: &mut String) {
|
||||
let _prof = tcx.prof.generic_activity("compute_debuginfo_type_name");
|
||||
let mut visited = FxHashSet::default();
|
||||
push_generic_args_internal(tcx, args, output, &mut visited);
|
||||
}
|
||||
|
||||
fn push_generic_args_internal<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
args: GenericArgsRef<'tcx>,
|
||||
output: &mut String,
|
||||
|
|
@ -646,14 +651,10 @@ fn push_generic_params_internal<'tcx>(
|
|||
|
||||
output.push('<');
|
||||
|
||||
for type_parameter in args {
|
||||
match type_parameter {
|
||||
GenericArgKind::Type(type_parameter) => {
|
||||
push_debuginfo_type_name(tcx, type_parameter, true, output, visited);
|
||||
}
|
||||
GenericArgKind::Const(ct) => {
|
||||
push_const_param(tcx, ct, output);
|
||||
}
|
||||
for arg in args {
|
||||
match arg {
|
||||
GenericArgKind::Type(ty) => push_debuginfo_type_name(tcx, ty, true, output, visited),
|
||||
GenericArgKind::Const(ct) => push_debuginfo_const_name(tcx, ct, output),
|
||||
other => bug!("Unexpected non-erasable generic: {:?}", other),
|
||||
}
|
||||
|
||||
|
|
@ -665,7 +666,20 @@ fn push_generic_params_internal<'tcx>(
|
|||
true
|
||||
}
|
||||
|
||||
fn push_const_param<'tcx>(tcx: TyCtxt<'tcx>, ct: ty::Const<'tcx>, output: &mut String) {
|
||||
fn push_debuginfo_term_name<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
term: ty::Term<'tcx>,
|
||||
qualified: bool,
|
||||
output: &mut String,
|
||||
visited: &mut FxHashSet<Ty<'tcx>>,
|
||||
) {
|
||||
match term.kind() {
|
||||
ty::TermKind::Ty(ty) => push_debuginfo_type_name(tcx, ty, qualified, output, visited),
|
||||
ty::TermKind::Const(ct) => push_debuginfo_const_name(tcx, ct, output),
|
||||
}
|
||||
}
|
||||
|
||||
fn push_debuginfo_const_name<'tcx>(tcx: TyCtxt<'tcx>, ct: ty::Const<'tcx>, output: &mut String) {
|
||||
match ct.kind() {
|
||||
ty::ConstKind::Param(param) => {
|
||||
write!(output, "{}", param.name)
|
||||
|
|
@ -715,16 +729,6 @@ fn push_const_param<'tcx>(tcx: TyCtxt<'tcx>, ct: ty::Const<'tcx>, output: &mut S
|
|||
.unwrap();
|
||||
}
|
||||
|
||||
pub fn push_generic_params<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
args: GenericArgsRef<'tcx>,
|
||||
output: &mut String,
|
||||
) {
|
||||
let _prof = tcx.prof.generic_activity("compute_debuginfo_type_name");
|
||||
let mut visited = FxHashSet::default();
|
||||
push_generic_params_internal(tcx, args, output, &mut visited);
|
||||
}
|
||||
|
||||
fn push_closure_or_coroutine_name<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
def_id: DefId,
|
||||
|
|
@ -767,7 +771,7 @@ fn push_closure_or_coroutine_name<'tcx>(
|
|||
// FIXME(async_closures): This is probably not going to be correct w.r.t.
|
||||
// multiple coroutine flavors. Maybe truncate to (parent + 1)?
|
||||
let args = args.truncate_to(tcx, generics);
|
||||
push_generic_params_internal(tcx, args, output, visited);
|
||||
push_generic_args_internal(tcx, args, output, visited);
|
||||
}
|
||||
|
||||
fn push_close_angle_bracket(cpp_like_debuginfo: bool, output: &mut String) {
|
||||
|
|
|
|||
|
|
@ -136,39 +136,6 @@ pub(crate) struct RequiresRustAbi {
|
|||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(codegen_ssa_expected_name_value_pair)]
|
||||
pub(crate) struct ExpectedNameValuePair {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(codegen_ssa_unexpected_parameter_name)]
|
||||
pub(crate) struct UnexpectedParameterName {
|
||||
#[primary_span]
|
||||
#[label]
|
||||
pub span: Span,
|
||||
pub prefix_nops: Symbol,
|
||||
pub entry_nops: Symbol,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(codegen_ssa_invalid_literal_value)]
|
||||
pub(crate) struct InvalidLiteralValue {
|
||||
#[primary_span]
|
||||
#[label]
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(codegen_ssa_out_of_range_integer)]
|
||||
pub(crate) struct OutOfRangeInteger {
|
||||
#[primary_span]
|
||||
#[label]
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(codegen_ssa_copy_path_buf)]
|
||||
pub(crate) struct CopyPathBuf {
|
||||
|
|
|
|||
|
|
@ -199,12 +199,12 @@ impl<'a, 'tcx> TerminatorCodegenHelper<'tcx> {
|
|||
// do an invoke, otherwise do a call.
|
||||
let fn_ty = bx.fn_decl_backend_type(fn_abi);
|
||||
|
||||
let fn_attrs = if bx.tcx().def_kind(fx.instance.def_id()).has_codegen_attrs() {
|
||||
let caller_attrs = if bx.tcx().def_kind(fx.instance.def_id()).has_codegen_attrs() {
|
||||
Some(bx.tcx().codegen_instance_attrs(fx.instance.def))
|
||||
} else {
|
||||
None
|
||||
};
|
||||
let fn_attrs = fn_attrs.as_deref();
|
||||
let caller_attrs = caller_attrs.as_deref();
|
||||
|
||||
if !fn_abi.can_unwind {
|
||||
unwind = mir::UnwindAction::Unreachable;
|
||||
|
|
@ -233,7 +233,7 @@ impl<'a, 'tcx> TerminatorCodegenHelper<'tcx> {
|
|||
};
|
||||
|
||||
if kind == CallKind::Tail {
|
||||
bx.tail_call(fn_ty, fn_attrs, fn_abi, fn_ptr, llargs, self.funclet(fx), instance);
|
||||
bx.tail_call(fn_ty, caller_attrs, fn_abi, fn_ptr, llargs, self.funclet(fx), instance);
|
||||
return MergingSucc::False;
|
||||
}
|
||||
|
||||
|
|
@ -245,7 +245,7 @@ impl<'a, 'tcx> TerminatorCodegenHelper<'tcx> {
|
|||
};
|
||||
let invokeret = bx.invoke(
|
||||
fn_ty,
|
||||
fn_attrs,
|
||||
caller_attrs,
|
||||
Some(fn_abi),
|
||||
fn_ptr,
|
||||
llargs,
|
||||
|
|
@ -268,8 +268,15 @@ impl<'a, 'tcx> TerminatorCodegenHelper<'tcx> {
|
|||
}
|
||||
MergingSucc::False
|
||||
} else {
|
||||
let llret =
|
||||
bx.call(fn_ty, fn_attrs, Some(fn_abi), fn_ptr, llargs, self.funclet(fx), instance);
|
||||
let llret = bx.call(
|
||||
fn_ty,
|
||||
caller_attrs,
|
||||
Some(fn_abi),
|
||||
fn_ptr,
|
||||
llargs,
|
||||
self.funclet(fx),
|
||||
instance,
|
||||
);
|
||||
if fx.mir[self.bb].is_cleanup {
|
||||
bx.apply_attrs_to_cleanup_callsite(llret);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1074,8 +1074,14 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
|||
if constant_ty.is_simd() {
|
||||
// However, some SIMD types do not actually use the vector ABI
|
||||
// (in particular, packed SIMD types do not). Ensure we exclude those.
|
||||
//
|
||||
// We also have to exclude vectors of pointers because `immediate_const_vector`
|
||||
// does not work for those.
|
||||
let layout = bx.layout_of(constant_ty);
|
||||
if let BackendRepr::SimdVector { .. } = layout.backend_repr {
|
||||
let (_, element_ty) = constant_ty.simd_size_and_type(bx.tcx());
|
||||
if let BackendRepr::SimdVector { .. } = layout.backend_repr
|
||||
&& element_ty.is_numeric()
|
||||
{
|
||||
let (llval, ty) = self.immediate_const_vector(bx, constant);
|
||||
return OperandRef {
|
||||
val: OperandValue::Immediate(llval),
|
||||
|
|
|
|||
|
|
@ -67,7 +67,7 @@ pub trait CodegenBackend {
|
|||
CrateType::Executable,
|
||||
CrateType::Dylib,
|
||||
CrateType::Rlib,
|
||||
CrateType::Staticlib,
|
||||
CrateType::StaticLib,
|
||||
CrateType::Cdylib,
|
||||
CrateType::ProcMacro,
|
||||
CrateType::Sdylib,
|
||||
|
|
|
|||
|
|
@ -600,10 +600,13 @@ pub trait BuilderMethods<'a, 'tcx>:
|
|||
///
|
||||
/// ## Arguments
|
||||
///
|
||||
/// The `fn_attrs`, `fn_abi`, and `instance` arguments are Options because they are advisory.
|
||||
/// They relate to optional codegen enhancements like LLVM CFI, and do not affect ABI per se.
|
||||
/// Any ABI-related transformations should be handled by different, earlier stages of codegen.
|
||||
/// For instance, in the caller of `BuilderMethods::call`.
|
||||
/// `caller_attrs` are the attributes of the surrounding caller; they have nothing to do with
|
||||
/// the callee.
|
||||
///
|
||||
/// The `caller_attrs`, `fn_abi`, and `callee_instance` arguments are Options because they are
|
||||
/// advisory. They relate to optional codegen enhancements like LLVM CFI, and do not affect ABI
|
||||
/// per se. Any ABI-related transformations should be handled by different, earlier stages of
|
||||
/// codegen. For instance, in the caller of `BuilderMethods::call`.
|
||||
///
|
||||
/// This means that a codegen backend which disregards `fn_attrs`, `fn_abi`, and `instance`
|
||||
/// should still do correct codegen, and code should not be miscompiled if they are omitted.
|
||||
|
|
@ -620,23 +623,23 @@ pub trait BuilderMethods<'a, 'tcx>:
|
|||
fn call(
|
||||
&mut self,
|
||||
llty: Self::Type,
|
||||
fn_attrs: Option<&CodegenFnAttrs>,
|
||||
caller_attrs: Option<&CodegenFnAttrs>,
|
||||
fn_abi: Option<&FnAbi<'tcx, Ty<'tcx>>>,
|
||||
fn_val: Self::Value,
|
||||
args: &[Self::Value],
|
||||
funclet: Option<&Self::Funclet>,
|
||||
instance: Option<Instance<'tcx>>,
|
||||
callee_instance: Option<Instance<'tcx>>,
|
||||
) -> Self::Value;
|
||||
|
||||
fn tail_call(
|
||||
&mut self,
|
||||
llty: Self::Type,
|
||||
fn_attrs: Option<&CodegenFnAttrs>,
|
||||
caller_attrs: Option<&CodegenFnAttrs>,
|
||||
fn_abi: &FnAbi<'tcx, Ty<'tcx>>,
|
||||
llfn: Self::Value,
|
||||
args: &[Self::Value],
|
||||
funclet: Option<&Self::Funclet>,
|
||||
instance: Option<Instance<'tcx>>,
|
||||
callee_instance: Option<Instance<'tcx>>,
|
||||
);
|
||||
|
||||
fn zext(&mut self, val: Self::Value, dest_ty: Self::Type) -> Self::Value;
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ use rustc_errors::DiagCtxtHandle;
|
|||
use rustc_middle::dep_graph::WorkProduct;
|
||||
|
||||
use crate::back::lto::{SerializedModule, ThinModule};
|
||||
use crate::back::write::{CodegenContext, FatLtoInput, ModuleConfig};
|
||||
use crate::back::write::{CodegenContext, FatLtoInput, ModuleConfig, SharedEmitter};
|
||||
use crate::{CompiledModule, ModuleCodegen};
|
||||
|
||||
pub trait WriteBackendMethods: Clone + 'static {
|
||||
|
|
@ -19,6 +19,7 @@ pub trait WriteBackendMethods: Clone + 'static {
|
|||
/// if necessary and running any further optimizations
|
||||
fn run_and_optimize_fat_lto(
|
||||
cgcx: &CodegenContext<Self>,
|
||||
shared_emitter: &SharedEmitter,
|
||||
exported_symbols_for_lto: &[String],
|
||||
each_linked_rlib_for_lto: &[PathBuf],
|
||||
modules: Vec<FatLtoInput<Self>>,
|
||||
|
|
@ -28,6 +29,7 @@ pub trait WriteBackendMethods: Clone + 'static {
|
|||
/// can simply be copied over from the incr. comp. cache.
|
||||
fn run_thin_lto(
|
||||
cgcx: &CodegenContext<Self>,
|
||||
dcx: DiagCtxtHandle<'_>,
|
||||
exported_symbols_for_lto: &[String],
|
||||
each_linked_rlib_for_lto: &[PathBuf],
|
||||
modules: Vec<(String, Self::ThinBuffer)>,
|
||||
|
|
@ -37,16 +39,18 @@ pub trait WriteBackendMethods: Clone + 'static {
|
|||
fn print_statistics(&self);
|
||||
fn optimize(
|
||||
cgcx: &CodegenContext<Self>,
|
||||
dcx: DiagCtxtHandle<'_>,
|
||||
shared_emitter: &SharedEmitter,
|
||||
module: &mut ModuleCodegen<Self::Module>,
|
||||
config: &ModuleConfig,
|
||||
);
|
||||
fn optimize_thin(
|
||||
cgcx: &CodegenContext<Self>,
|
||||
shared_emitter: &SharedEmitter,
|
||||
thin: ThinModule<Self>,
|
||||
) -> ModuleCodegen<Self::Module>;
|
||||
fn codegen(
|
||||
cgcx: &CodegenContext<Self>,
|
||||
shared_emitter: &SharedEmitter,
|
||||
module: ModuleCodegen<Self::Module>,
|
||||
config: &ModuleConfig,
|
||||
) -> CompiledModule;
|
||||
|
|
|
|||
|
|
@ -343,17 +343,18 @@ where
|
|||
|
||||
// Check the qualifs of the value of `const` items.
|
||||
let uneval = match constant.const_ {
|
||||
Const::Ty(_, ct)
|
||||
if matches!(
|
||||
ct.kind(),
|
||||
ty::ConstKind::Param(_) | ty::ConstKind::Error(_) | ty::ConstKind::Value(_)
|
||||
) =>
|
||||
{
|
||||
None
|
||||
}
|
||||
Const::Ty(_, c) => {
|
||||
bug!("expected ConstKind::Param or ConstKind::Value here, found {:?}", c)
|
||||
}
|
||||
Const::Ty(_, ct) => match ct.kind() {
|
||||
ty::ConstKind::Param(_) | ty::ConstKind::Error(_) => None,
|
||||
// Unevaluated consts in MIR bodies don't have associated MIR (e.g. `#[type_const]`).
|
||||
ty::ConstKind::Unevaluated(_) => None,
|
||||
// FIXME(mgca): Investigate whether using `None` for `ConstKind::Value` is overly
|
||||
// strict, and if instead we should be doing some kind of value-based analysis.
|
||||
ty::ConstKind::Value(_) => None,
|
||||
_ => bug!(
|
||||
"expected ConstKind::Param, ConstKind::Value, ConstKind::Unevaluated, or ConstKind::Error here, found {:?}",
|
||||
ct
|
||||
),
|
||||
},
|
||||
Const::Unevaluated(uv, _) => Some(uv),
|
||||
Const::Val(..) => None,
|
||||
};
|
||||
|
|
@ -364,10 +365,8 @@ where
|
|||
// check performed after the promotion. Verify that with an assertion.
|
||||
assert!(promoted.is_none() || Q::ALLOW_PROMOTED);
|
||||
|
||||
// Don't peak inside trait associated constants, also `#[type_const] const` items
|
||||
// don't have bodies so there's nothing to look at
|
||||
if promoted.is_none() && cx.tcx.trait_of_assoc(def).is_none() && !cx.tcx.is_type_const(def)
|
||||
{
|
||||
// Don't peak inside trait associated constants.
|
||||
if promoted.is_none() && cx.tcx.trait_of_assoc(def).is_none() {
|
||||
let qualifs = cx.tcx.at(constant.span).mir_const_qualif(def);
|
||||
|
||||
if !Q::in_qualifs(&qualifs) {
|
||||
|
|
|
|||
|
|
@ -66,6 +66,14 @@ impl<'tcx> InterpCx<'tcx, CompileTimeMachine<'tcx>> {
|
|||
|
||||
variant
|
||||
}
|
||||
ty::Slice(ty) => {
|
||||
let (variant, variant_place) = downcast(sym::Slice)?;
|
||||
let slice_place = self.project_field(&variant_place, FieldIdx::ZERO)?;
|
||||
|
||||
self.write_slice_type_info(slice_place, *ty)?;
|
||||
|
||||
variant
|
||||
}
|
||||
ty::Bool => {
|
||||
let (variant, _variant_place) = downcast(sym::Bool)?;
|
||||
variant
|
||||
|
|
@ -124,7 +132,6 @@ impl<'tcx> InterpCx<'tcx, CompileTimeMachine<'tcx>> {
|
|||
ty::Adt(_, _)
|
||||
| ty::Foreign(_)
|
||||
| ty::Pat(_, _)
|
||||
| ty::Slice(_)
|
||||
| ty::FnDef(..)
|
||||
| ty::FnPtr(..)
|
||||
| ty::UnsafeBinder(..)
|
||||
|
|
@ -254,6 +261,27 @@ impl<'tcx> InterpCx<'tcx, CompileTimeMachine<'tcx>> {
|
|||
interp_ok(())
|
||||
}
|
||||
|
||||
pub(crate) fn write_slice_type_info(
|
||||
&mut self,
|
||||
place: impl Writeable<'tcx, CtfeProvenance>,
|
||||
ty: Ty<'tcx>,
|
||||
) -> InterpResult<'tcx> {
|
||||
// Iterate over all fields of `type_info::Slice`.
|
||||
for (field_idx, field) in
|
||||
place.layout().ty.ty_adt_def().unwrap().non_enum_variant().fields.iter_enumerated()
|
||||
{
|
||||
let field_place = self.project_field(&place, field_idx)?;
|
||||
|
||||
match field.name {
|
||||
// Write the `TypeId` of the slice's elements to the `element_ty` field.
|
||||
sym::element_ty => self.write_type_id(ty, &field_place)?,
|
||||
other => span_bug!(self.tcx.def_span(field.did), "unimplemented field {other}"),
|
||||
}
|
||||
}
|
||||
|
||||
interp_ok(())
|
||||
}
|
||||
|
||||
fn write_int_type_info(
|
||||
&mut self,
|
||||
place: impl Writeable<'tcx, CtfeProvenance>,
|
||||
|
|
|
|||
|
|
@ -30,7 +30,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
|
|||
let dest = dest.force_mplace(self)?;
|
||||
|
||||
match intrinsic_name {
|
||||
sym::simd_insert => {
|
||||
sym::simd_insert | sym::simd_insert_dyn => {
|
||||
let index = u64::from(self.read_scalar(&args[1])?.to_u32()?);
|
||||
let elem = &args[2];
|
||||
let (input, input_len) = self.project_to_simd(&args[0])?;
|
||||
|
|
@ -39,7 +39,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
|
|||
// Bounds are not checked by typeck so we have to do it ourselves.
|
||||
if index >= input_len {
|
||||
throw_ub_format!(
|
||||
"`simd_insert` index {index} is out-of-bounds of vector with length {input_len}"
|
||||
"`{intrinsic_name}` index {index} is out-of-bounds of vector with length {input_len}"
|
||||
);
|
||||
}
|
||||
|
||||
|
|
@ -50,17 +50,26 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
|
|||
self.copy_op(&value, &place)?;
|
||||
}
|
||||
}
|
||||
sym::simd_extract => {
|
||||
sym::simd_extract | sym::simd_extract_dyn => {
|
||||
let index = u64::from(self.read_scalar(&args[1])?.to_u32()?);
|
||||
let (input, input_len) = self.project_to_simd(&args[0])?;
|
||||
// Bounds are not checked by typeck so we have to do it ourselves.
|
||||
if index >= input_len {
|
||||
throw_ub_format!(
|
||||
"`simd_extract` index {index} is out-of-bounds of vector with length {input_len}"
|
||||
"`{intrinsic_name}` index {index} is out-of-bounds of vector with length {input_len}"
|
||||
);
|
||||
}
|
||||
self.copy_op(&self.project_index(&input, index)?, &dest)?;
|
||||
}
|
||||
sym::simd_splat => {
|
||||
let elem = &args[0];
|
||||
let (dest, dest_len) = self.project_to_simd(&dest)?;
|
||||
|
||||
for i in 0..dest_len {
|
||||
let place = self.project_index(&dest, i)?;
|
||||
self.copy_op(elem, &place)?;
|
||||
}
|
||||
}
|
||||
sym::simd_neg
|
||||
| sym::simd_fabs
|
||||
| sym::simd_ceil
|
||||
|
|
|
|||
|
|
@ -10,7 +10,6 @@
|
|||
#![allow(internal_features)]
|
||||
#![allow(rustc::default_hash_types)]
|
||||
#![allow(rustc::potential_query_instability)]
|
||||
#![cfg_attr(bootstrap, feature(array_windows))]
|
||||
#![deny(unsafe_op_in_unsafe_fn)]
|
||||
#![feature(allocator_api)]
|
||||
#![feature(ascii_char)]
|
||||
|
|
@ -42,8 +41,11 @@
|
|||
// have to worry about it being moved to a different module in std during stabilization.
|
||||
// FIXME(#151359): Remove this when `feature(assert_matches)` is stable in stage0.
|
||||
// (This doesn't necessarily need to be fixed during the beta bump itself.)
|
||||
#[cfg(bootstrap)]
|
||||
pub use std::assert_matches::{assert_matches, debug_assert_matches};
|
||||
use std::fmt;
|
||||
#[cfg(not(bootstrap))]
|
||||
pub use std::{assert_matches, debug_assert_matches};
|
||||
|
||||
pub use atomic_ref::AtomicRef;
|
||||
pub use ena::{snapshot_vec, undo_log, unify};
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@ use std::ffi::OsString;
|
|||
use std::fmt::Write as _;
|
||||
use std::fs::{self, File};
|
||||
use std::io::{self, IsTerminal, Read, Write};
|
||||
use std::panic::{self, PanicHookInfo, catch_unwind};
|
||||
use std::panic::{self, PanicHookInfo};
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::process::{self, Command, Stdio};
|
||||
use std::sync::OnceLock;
|
||||
|
|
@ -32,15 +32,17 @@ use rustc_codegen_ssa::{CodegenErrors, CodegenResults};
|
|||
use rustc_data_structures::profiling::{
|
||||
TimePassesFormat, get_resident_set_size, print_time_passes_entry,
|
||||
};
|
||||
pub use rustc_errors::catch_fatal_errors;
|
||||
use rustc_errors::emitter::stderr_destination;
|
||||
use rustc_errors::registry::Registry;
|
||||
use rustc_errors::translation::Translator;
|
||||
use rustc_errors::{ColorConfig, DiagCtxt, ErrCode, FatalError, PResult, markdown};
|
||||
use rustc_errors::{ColorConfig, DiagCtxt, ErrCode, PResult, markdown};
|
||||
use rustc_feature::find_gated_cfg;
|
||||
// This avoids a false positive with `-Wunused_crate_dependencies`.
|
||||
// `rust_index` isn't used in this crate's code, but it must be named in the
|
||||
// `Cargo.toml` for the `rustc_randomized_layouts` feature.
|
||||
use rustc_index as _;
|
||||
use rustc_interface::passes::collect_crate_types;
|
||||
use rustc_interface::util::{self, get_codegen_backend};
|
||||
use rustc_interface::{Linker, create_and_enter_global_ctxt, interface, passes};
|
||||
use rustc_lint::unerased_lint_store;
|
||||
|
|
@ -55,10 +57,10 @@ use rustc_session::config::{
|
|||
};
|
||||
use rustc_session::getopts::{self, Matches};
|
||||
use rustc_session::lint::{Lint, LintId};
|
||||
use rustc_session::output::{CRATE_TYPES, collect_crate_types, invalid_output_for_target};
|
||||
use rustc_session::output::invalid_output_for_target;
|
||||
use rustc_session::{EarlyDiagCtxt, Session, config};
|
||||
use rustc_span::FileName;
|
||||
use rustc_span::def_id::LOCAL_CRATE;
|
||||
use rustc_span::{DUMMY_SP, FileName};
|
||||
use rustc_target::json::ToJson;
|
||||
use rustc_target::spec::{Target, TargetTuple};
|
||||
use tracing::trace;
|
||||
|
|
@ -697,6 +699,7 @@ fn print_crate_info(
|
|||
&codegen_backend.supported_crate_types(sess),
|
||||
codegen_backend.name(),
|
||||
attrs,
|
||||
DUMMY_SP,
|
||||
);
|
||||
for &style in &crate_types {
|
||||
let fname = rustc_session::output::filename_for_input(
|
||||
|
|
@ -848,7 +851,7 @@ fn print_crate_info(
|
|||
}
|
||||
}
|
||||
SupportedCrateTypes => {
|
||||
let supported_crate_types = CRATE_TYPES
|
||||
let supported_crate_types = CrateType::all()
|
||||
.iter()
|
||||
.filter(|(_, crate_type)| !invalid_output_for_target(sess, *crate_type))
|
||||
.filter(|(_, crate_type)| *crate_type != CrateType::Sdylib)
|
||||
|
|
@ -1377,21 +1380,6 @@ fn parse_crate_attrs<'a>(sess: &'a Session) -> PResult<'a, ast::AttrVec> {
|
|||
parser.parse_inner_attributes()
|
||||
}
|
||||
|
||||
/// Runs a closure and catches unwinds triggered by fatal errors.
|
||||
///
|
||||
/// The compiler currently unwinds with a special sentinel value to abort
|
||||
/// compilation on fatal errors. This function catches that sentinel and turns
|
||||
/// the panic into a `Result` instead.
|
||||
pub fn catch_fatal_errors<F: FnOnce() -> R, R>(f: F) -> Result<R, FatalError> {
|
||||
catch_unwind(panic::AssertUnwindSafe(f)).map_err(|value| {
|
||||
if value.is::<rustc_errors::FatalErrorMarker>() {
|
||||
FatalError
|
||||
} else {
|
||||
panic::resume_unwind(value);
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
/// Variant of `catch_fatal_errors` for the `interface::Result` return type
|
||||
/// that also computes the exit code.
|
||||
pub fn catch_with_exit_code(f: impl FnOnce()) -> i32 {
|
||||
|
|
@ -1548,10 +1536,11 @@ fn report_ice(
|
|||
using_internal_features: &AtomicBool,
|
||||
) {
|
||||
let translator = default_translator();
|
||||
let emitter = Box::new(rustc_errors::emitter::HumanEmitter::new(
|
||||
stderr_destination(rustc_errors::ColorConfig::Auto),
|
||||
translator,
|
||||
));
|
||||
let emitter =
|
||||
Box::new(rustc_errors::annotate_snippet_emitter_writer::AnnotateSnippetEmitter::new(
|
||||
stderr_destination(rustc_errors::ColorConfig::Auto),
|
||||
translator,
|
||||
));
|
||||
let dcx = rustc_errors::DiagCtxt::new(emitter);
|
||||
let dcx = dcx.handle();
|
||||
|
||||
|
|
|
|||
|
|
@ -17,7 +17,6 @@ rustc_error_messages = { path = "../rustc_error_messages" }
|
|||
rustc_fluent_macro = { path = "../rustc_fluent_macro" }
|
||||
rustc_hashes = { path = "../rustc_hashes" }
|
||||
rustc_index = { path = "../rustc_index" }
|
||||
rustc_lexer = { path = "../rustc_lexer" }
|
||||
rustc_lint_defs = { path = "../rustc_lint_defs" }
|
||||
rustc_macros = { path = "../rustc_macros" }
|
||||
rustc_serialize = { path = "../rustc_serialize" }
|
||||
|
|
|
|||
|
|
@ -15,10 +15,9 @@ use rustc_span::source_map::Spanned;
|
|||
use rustc_span::{DUMMY_SP, Span, Symbol};
|
||||
use tracing::debug;
|
||||
|
||||
use crate::snippet::Style;
|
||||
use crate::{
|
||||
CodeSuggestion, DiagCtxtHandle, DiagMessage, ErrCode, ErrorGuaranteed, ExplicitBug, Level,
|
||||
MultiSpan, StashKey, SubdiagMessage, Substitution, SubstitutionPart, SuggestionStyle,
|
||||
MultiSpan, StashKey, Style, SubdiagMessage, Substitution, SubstitutionPart, SuggestionStyle,
|
||||
Suggestions,
|
||||
};
|
||||
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -5,7 +5,6 @@
|
|||
// tidy-alphabetical-start
|
||||
#![allow(internal_features)]
|
||||
#![allow(rustc::direct_use_of_rustc_type_ir)]
|
||||
#![cfg_attr(bootstrap, feature(array_windows))]
|
||||
#![feature(assert_matches)]
|
||||
#![feature(associated_type_defaults)]
|
||||
#![feature(box_patterns)]
|
||||
|
|
@ -51,7 +50,7 @@ pub use diagnostic_impls::{
|
|||
IndicateAnonymousLifetime, SingleLabelManySpans,
|
||||
};
|
||||
pub use emitter::ColorConfig;
|
||||
use emitter::{ConfusionType, DynEmitter, Emitter, detect_confusion_type, is_different};
|
||||
use emitter::{DynEmitter, Emitter};
|
||||
use rustc_data_structures::fx::{FxHashSet, FxIndexMap, FxIndexSet};
|
||||
use rustc_data_structures::stable_hasher::StableHasher;
|
||||
use rustc_data_structures::sync::{DynSend, Lock};
|
||||
|
|
@ -66,10 +65,9 @@ use rustc_lint_defs::LintExpectationId;
|
|||
pub use rustc_lint_defs::{Applicability, listify, pluralize};
|
||||
use rustc_macros::{Decodable, Encodable};
|
||||
pub use rustc_span::ErrorGuaranteed;
|
||||
pub use rustc_span::fatal_error::{FatalError, FatalErrorMarker};
|
||||
pub use rustc_span::fatal_error::{FatalError, FatalErrorMarker, catch_fatal_errors};
|
||||
use rustc_span::source_map::SourceMap;
|
||||
use rustc_span::{BytePos, DUMMY_SP, Loc, Span};
|
||||
pub use snippet::Style;
|
||||
use rustc_span::{DUMMY_SP, Span};
|
||||
use tracing::debug;
|
||||
|
||||
use crate::emitter::TimingEvent;
|
||||
|
|
@ -87,8 +85,6 @@ pub mod json;
|
|||
mod lock;
|
||||
pub mod markdown;
|
||||
pub mod registry;
|
||||
mod snippet;
|
||||
mod styled_buffer;
|
||||
#[cfg(test)]
|
||||
mod tests;
|
||||
pub mod timings;
|
||||
|
|
@ -215,43 +211,6 @@ pub struct TrimmedSubstitutionPart {
|
|||
pub snippet: String,
|
||||
}
|
||||
|
||||
/// Used to translate between `Span`s and byte positions within a single output line in highlighted
|
||||
/// code of structured suggestions.
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub(crate) struct SubstitutionHighlight {
|
||||
start: usize,
|
||||
end: usize,
|
||||
}
|
||||
|
||||
impl SubstitutionPart {
|
||||
/// Try to turn a replacement into an addition when the span that is being
|
||||
/// overwritten matches either the prefix or suffix of the replacement.
|
||||
fn trim_trivial_replacements(self, sm: &SourceMap) -> TrimmedSubstitutionPart {
|
||||
let mut trimmed_part = TrimmedSubstitutionPart {
|
||||
original_span: self.span,
|
||||
span: self.span,
|
||||
snippet: self.snippet,
|
||||
};
|
||||
if trimmed_part.snippet.is_empty() {
|
||||
return trimmed_part;
|
||||
}
|
||||
let Ok(snippet) = sm.span_to_snippet(trimmed_part.span) else {
|
||||
return trimmed_part;
|
||||
};
|
||||
|
||||
if let Some((prefix, substr, suffix)) = as_substr(&snippet, &trimmed_part.snippet) {
|
||||
trimmed_part.span = Span::new(
|
||||
trimmed_part.span.lo() + BytePos(prefix as u32),
|
||||
trimmed_part.span.hi() - BytePos(suffix as u32),
|
||||
trimmed_part.span.ctxt(),
|
||||
trimmed_part.span.parent(),
|
||||
);
|
||||
trimmed_part.snippet = substr.to_string();
|
||||
}
|
||||
trimmed_part
|
||||
}
|
||||
}
|
||||
|
||||
impl TrimmedSubstitutionPart {
|
||||
pub fn is_addition(&self, sm: &SourceMap) -> bool {
|
||||
!self.snippet.is_empty() && !self.replaces_meaningful_content(sm)
|
||||
|
|
@ -303,229 +262,6 @@ fn as_substr<'a>(original: &'a str, suggestion: &'a str) -> Option<(usize, &'a s
|
|||
}
|
||||
}
|
||||
|
||||
impl CodeSuggestion {
|
||||
/// Returns the assembled code suggestions, whether they should be shown with an underline
|
||||
/// and whether the substitution only differs in capitalization.
|
||||
pub(crate) fn splice_lines(
|
||||
&self,
|
||||
sm: &SourceMap,
|
||||
) -> Vec<(String, Vec<TrimmedSubstitutionPart>, Vec<Vec<SubstitutionHighlight>>, ConfusionType)>
|
||||
{
|
||||
// For the `Vec<Vec<SubstitutionHighlight>>` value, the first level of the vector
|
||||
// corresponds to the output snippet's lines, while the second level corresponds to the
|
||||
// substrings within that line that should be highlighted.
|
||||
|
||||
use rustc_span::{CharPos, Pos};
|
||||
|
||||
/// Extracts a substring from the provided `line_opt` based on the specified low and high
|
||||
/// indices, appends it to the given buffer `buf`, and returns the count of newline
|
||||
/// characters in the substring for accurate highlighting. If `line_opt` is `None`, a
|
||||
/// newline character is appended to the buffer, and 0 is returned.
|
||||
///
|
||||
/// ## Returns
|
||||
///
|
||||
/// The count of newline characters in the extracted substring.
|
||||
fn push_trailing(
|
||||
buf: &mut String,
|
||||
line_opt: Option<&Cow<'_, str>>,
|
||||
lo: &Loc,
|
||||
hi_opt: Option<&Loc>,
|
||||
) -> usize {
|
||||
let mut line_count = 0;
|
||||
// Convert `CharPos` to `usize`, as `CharPos` is character offset
|
||||
// Extract low index and high index
|
||||
let (lo, hi_opt) = (lo.col.to_usize(), hi_opt.map(|hi| hi.col.to_usize()));
|
||||
if let Some(line) = line_opt {
|
||||
if let Some(lo) = line.char_indices().map(|(i, _)| i).nth(lo) {
|
||||
// Get high index while account for rare unicode and emoji with char_indices
|
||||
let hi_opt = hi_opt.and_then(|hi| line.char_indices().map(|(i, _)| i).nth(hi));
|
||||
match hi_opt {
|
||||
// If high index exist, take string from low to high index
|
||||
Some(hi) if hi > lo => {
|
||||
// count how many '\n' exist
|
||||
line_count = line[lo..hi].matches('\n').count();
|
||||
buf.push_str(&line[lo..hi])
|
||||
}
|
||||
Some(_) => (),
|
||||
// If high index absence, take string from low index till end string.len
|
||||
None => {
|
||||
// count how many '\n' exist
|
||||
line_count = line[lo..].matches('\n').count();
|
||||
buf.push_str(&line[lo..])
|
||||
}
|
||||
}
|
||||
}
|
||||
// If high index is None
|
||||
if hi_opt.is_none() {
|
||||
buf.push('\n');
|
||||
}
|
||||
}
|
||||
line_count
|
||||
}
|
||||
|
||||
assert!(!self.substitutions.is_empty());
|
||||
|
||||
self.substitutions
|
||||
.iter()
|
||||
.filter(|subst| {
|
||||
// Suggestions coming from macros can have malformed spans. This is a heavy
|
||||
// handed approach to avoid ICEs by ignoring the suggestion outright.
|
||||
let invalid = subst.parts.iter().any(|item| sm.is_valid_span(item.span).is_err());
|
||||
if invalid {
|
||||
debug!("splice_lines: suggestion contains an invalid span: {:?}", subst);
|
||||
}
|
||||
!invalid
|
||||
})
|
||||
.cloned()
|
||||
.filter_map(|mut substitution| {
|
||||
// Assumption: all spans are in the same file, and all spans
|
||||
// are disjoint. Sort in ascending order.
|
||||
substitution.parts.sort_by_key(|part| part.span.lo());
|
||||
|
||||
// Find the bounding span.
|
||||
let lo = substitution.parts.iter().map(|part| part.span.lo()).min()?;
|
||||
let hi = substitution.parts.iter().map(|part| part.span.hi()).max()?;
|
||||
let bounding_span = Span::with_root_ctxt(lo, hi);
|
||||
// The different spans might belong to different contexts, if so ignore suggestion.
|
||||
let lines = sm.span_to_lines(bounding_span).ok()?;
|
||||
assert!(!lines.lines.is_empty() || bounding_span.is_dummy());
|
||||
|
||||
// We can't splice anything if the source is unavailable.
|
||||
if !sm.ensure_source_file_source_present(&lines.file) {
|
||||
return None;
|
||||
}
|
||||
|
||||
let mut highlights = vec![];
|
||||
// To build up the result, we do this for each span:
|
||||
// - push the line segment trailing the previous span
|
||||
// (at the beginning a "phantom" span pointing at the start of the line)
|
||||
// - push lines between the previous and current span (if any)
|
||||
// - if the previous and current span are not on the same line
|
||||
// push the line segment leading up to the current span
|
||||
// - splice in the span substitution
|
||||
//
|
||||
// Finally push the trailing line segment of the last span
|
||||
let sf = &lines.file;
|
||||
let mut prev_hi = sm.lookup_char_pos(bounding_span.lo());
|
||||
prev_hi.col = CharPos::from_usize(0);
|
||||
let mut prev_line =
|
||||
lines.lines.get(0).and_then(|line0| sf.get_line(line0.line_index));
|
||||
let mut buf = String::new();
|
||||
|
||||
let mut line_highlight = vec![];
|
||||
// We need to keep track of the difference between the existing code and the added
|
||||
// or deleted code in order to point at the correct column *after* substitution.
|
||||
let mut acc = 0;
|
||||
let mut confusion_type = ConfusionType::None;
|
||||
|
||||
let trimmed_parts = substitution
|
||||
.parts
|
||||
.into_iter()
|
||||
// If this is a replacement of, e.g. `"a"` into `"ab"`, adjust the
|
||||
// suggestion and snippet to look as if we just suggested to add
|
||||
// `"b"`, which is typically much easier for the user to understand.
|
||||
.map(|part| part.trim_trivial_replacements(sm))
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
for part in &trimmed_parts {
|
||||
let part_confusion = detect_confusion_type(sm, &part.snippet, part.span);
|
||||
confusion_type = confusion_type.combine(part_confusion);
|
||||
let cur_lo = sm.lookup_char_pos(part.span.lo());
|
||||
if prev_hi.line == cur_lo.line {
|
||||
let mut count =
|
||||
push_trailing(&mut buf, prev_line.as_ref(), &prev_hi, Some(&cur_lo));
|
||||
while count > 0 {
|
||||
highlights.push(std::mem::take(&mut line_highlight));
|
||||
acc = 0;
|
||||
count -= 1;
|
||||
}
|
||||
} else {
|
||||
acc = 0;
|
||||
highlights.push(std::mem::take(&mut line_highlight));
|
||||
let mut count = push_trailing(&mut buf, prev_line.as_ref(), &prev_hi, None);
|
||||
while count > 0 {
|
||||
highlights.push(std::mem::take(&mut line_highlight));
|
||||
count -= 1;
|
||||
}
|
||||
// push lines between the previous and current span (if any)
|
||||
for idx in prev_hi.line..(cur_lo.line - 1) {
|
||||
if let Some(line) = sf.get_line(idx) {
|
||||
buf.push_str(line.as_ref());
|
||||
buf.push('\n');
|
||||
highlights.push(std::mem::take(&mut line_highlight));
|
||||
}
|
||||
}
|
||||
if let Some(cur_line) = sf.get_line(cur_lo.line - 1) {
|
||||
let end = match cur_line.char_indices().nth(cur_lo.col.to_usize()) {
|
||||
Some((i, _)) => i,
|
||||
None => cur_line.len(),
|
||||
};
|
||||
buf.push_str(&cur_line[..end]);
|
||||
}
|
||||
}
|
||||
// Add a whole line highlight per line in the snippet.
|
||||
let len: isize = part
|
||||
.snippet
|
||||
.split('\n')
|
||||
.next()
|
||||
.unwrap_or(&part.snippet)
|
||||
.chars()
|
||||
.map(|c| match c {
|
||||
'\t' => 4,
|
||||
_ => 1,
|
||||
})
|
||||
.sum();
|
||||
if !is_different(sm, &part.snippet, part.span) {
|
||||
// Account for cases where we are suggesting the same code that's already
|
||||
// there. This shouldn't happen often, but in some cases for multipart
|
||||
// suggestions it's much easier to handle it here than in the origin.
|
||||
} else {
|
||||
line_highlight.push(SubstitutionHighlight {
|
||||
start: (cur_lo.col.0 as isize + acc) as usize,
|
||||
end: (cur_lo.col.0 as isize + acc + len) as usize,
|
||||
});
|
||||
}
|
||||
buf.push_str(&part.snippet);
|
||||
let cur_hi = sm.lookup_char_pos(part.span.hi());
|
||||
// Account for the difference between the width of the current code and the
|
||||
// snippet being suggested, so that the *later* suggestions are correctly
|
||||
// aligned on the screen. Note that cur_hi and cur_lo can be on different
|
||||
// lines, so cur_hi.col can be smaller than cur_lo.col
|
||||
acc += len - (cur_hi.col.0 as isize - cur_lo.col.0 as isize);
|
||||
prev_hi = cur_hi;
|
||||
prev_line = sf.get_line(prev_hi.line - 1);
|
||||
for line in part.snippet.split('\n').skip(1) {
|
||||
acc = 0;
|
||||
highlights.push(std::mem::take(&mut line_highlight));
|
||||
let end: usize = line
|
||||
.chars()
|
||||
.map(|c| match c {
|
||||
'\t' => 4,
|
||||
_ => 1,
|
||||
})
|
||||
.sum();
|
||||
line_highlight.push(SubstitutionHighlight { start: 0, end });
|
||||
}
|
||||
}
|
||||
highlights.push(std::mem::take(&mut line_highlight));
|
||||
// if the replacement already ends with a newline, don't print the next line
|
||||
if !buf.ends_with('\n') {
|
||||
push_trailing(&mut buf, prev_line.as_ref(), &prev_hi, None);
|
||||
}
|
||||
// remove trailing newlines
|
||||
while buf.ends_with('\n') {
|
||||
buf.pop();
|
||||
}
|
||||
if highlights.iter().all(|parts| parts.is_empty()) {
|
||||
None
|
||||
} else {
|
||||
Some((buf, trimmed_parts, highlights, confusion_type))
|
||||
}
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
}
|
||||
|
||||
/// Signifies that the compiler died with an explicit call to `.bug`
|
||||
/// or `.span_bug` rather than a failed assertion, etc.
|
||||
pub struct ExplicitBug;
|
||||
|
|
@ -1961,15 +1697,6 @@ impl Level {
|
|||
pub fn is_failure_note(&self) -> bool {
|
||||
matches!(*self, FailureNote)
|
||||
}
|
||||
|
||||
// Can this level be used in a subdiagnostic message?
|
||||
fn can_be_subdiag(&self) -> bool {
|
||||
match self {
|
||||
Bug | DelayedBug | Fatal | Error | ForceWarning | FailureNote | Allow | Expect => false,
|
||||
|
||||
Warning | Note | Help | OnceNote | OnceHelp => true,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl IntoDiagArg for Level {
|
||||
|
|
@ -1978,6 +1705,24 @@ impl IntoDiagArg for Level {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Encodable, Decodable)]
|
||||
pub enum Style {
|
||||
MainHeaderMsg,
|
||||
HeaderMsg,
|
||||
LineAndColumn,
|
||||
LineNumber,
|
||||
Quotation,
|
||||
UnderlinePrimary,
|
||||
UnderlineSecondary,
|
||||
LabelPrimary,
|
||||
LabelSecondary,
|
||||
NoStyle,
|
||||
Level(Level),
|
||||
Highlight,
|
||||
Addition,
|
||||
Removal,
|
||||
}
|
||||
|
||||
// FIXME(eddyb) this doesn't belong here AFAICT, should be moved to callsite.
|
||||
pub fn elided_lifetime_in_path_suggestion(
|
||||
source_map: &SourceMap,
|
||||
|
|
|
|||
|
|
@ -1,214 +0,0 @@
|
|||
// Code for annotating snippets.
|
||||
|
||||
use rustc_macros::{Decodable, Encodable};
|
||||
|
||||
use crate::{Level, Loc};
|
||||
|
||||
#[derive(Clone, Debug, PartialOrd, Ord, PartialEq, Eq)]
|
||||
pub(crate) struct Line {
|
||||
pub line_index: usize,
|
||||
pub annotations: Vec<Annotation>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, PartialOrd, Ord, PartialEq, Eq, Default)]
|
||||
pub(crate) struct AnnotationColumn {
|
||||
/// the (0-indexed) column for *display* purposes, counted in characters, not utf-8 bytes
|
||||
pub display: usize,
|
||||
/// the (0-indexed) column in the file, counted in characters, not utf-8 bytes.
|
||||
///
|
||||
/// this may be different from `self.display`,
|
||||
/// e.g. if the file contains hard tabs, because we convert tabs to spaces for error messages.
|
||||
///
|
||||
/// for example:
|
||||
/// ```text
|
||||
/// (hard tab)hello
|
||||
/// ^ this is display column 4, but file column 1
|
||||
/// ```
|
||||
///
|
||||
/// we want to keep around the correct file offset so that column numbers in error messages
|
||||
/// are correct. (motivated by <https://github.com/rust-lang/rust/issues/109537>)
|
||||
pub file: usize,
|
||||
}
|
||||
|
||||
impl AnnotationColumn {
|
||||
pub(crate) fn from_loc(loc: &Loc) -> AnnotationColumn {
|
||||
AnnotationColumn { display: loc.col_display, file: loc.col.0 }
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialOrd, Ord, PartialEq, Eq)]
|
||||
pub(crate) struct MultilineAnnotation {
|
||||
pub depth: usize,
|
||||
pub line_start: usize,
|
||||
pub line_end: usize,
|
||||
pub start_col: AnnotationColumn,
|
||||
pub end_col: AnnotationColumn,
|
||||
pub is_primary: bool,
|
||||
pub label: Option<String>,
|
||||
pub overlaps_exactly: bool,
|
||||
}
|
||||
|
||||
impl MultilineAnnotation {
|
||||
pub(crate) fn increase_depth(&mut self) {
|
||||
self.depth += 1;
|
||||
}
|
||||
|
||||
/// Compare two `MultilineAnnotation`s considering only the `Span` they cover.
|
||||
pub(crate) fn same_span(&self, other: &MultilineAnnotation) -> bool {
|
||||
self.line_start == other.line_start
|
||||
&& self.line_end == other.line_end
|
||||
&& self.start_col == other.start_col
|
||||
&& self.end_col == other.end_col
|
||||
}
|
||||
|
||||
pub(crate) fn as_start(&self) -> Annotation {
|
||||
Annotation {
|
||||
start_col: self.start_col,
|
||||
end_col: AnnotationColumn {
|
||||
// these might not correspond to the same place anymore,
|
||||
// but that's okay for our purposes
|
||||
display: self.start_col.display + 1,
|
||||
file: self.start_col.file + 1,
|
||||
},
|
||||
is_primary: self.is_primary,
|
||||
label: None,
|
||||
annotation_type: AnnotationType::MultilineStart(self.depth),
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn as_end(&self) -> Annotation {
|
||||
Annotation {
|
||||
start_col: AnnotationColumn {
|
||||
// these might not correspond to the same place anymore,
|
||||
// but that's okay for our purposes
|
||||
display: self.end_col.display.saturating_sub(1),
|
||||
file: self.end_col.file.saturating_sub(1),
|
||||
},
|
||||
end_col: self.end_col,
|
||||
is_primary: self.is_primary,
|
||||
label: self.label.clone(),
|
||||
annotation_type: AnnotationType::MultilineEnd(self.depth),
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn as_line(&self) -> Annotation {
|
||||
Annotation {
|
||||
start_col: Default::default(),
|
||||
end_col: Default::default(),
|
||||
is_primary: self.is_primary,
|
||||
label: None,
|
||||
annotation_type: AnnotationType::MultilineLine(self.depth),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialOrd, Ord, PartialEq, Eq)]
|
||||
pub(crate) enum AnnotationType {
|
||||
/// Annotation under a single line of code
|
||||
Singleline,
|
||||
|
||||
// The Multiline type above is replaced with the following three in order
|
||||
// to reuse the current label drawing code.
|
||||
//
|
||||
// Each of these corresponds to one part of the following diagram:
|
||||
//
|
||||
// x | foo(1 + bar(x,
|
||||
// | _________^ < MultilineStart
|
||||
// x | | y), < MultilineLine
|
||||
// | |______________^ label < MultilineEnd
|
||||
// x | z);
|
||||
/// Annotation marking the first character of a fully shown multiline span
|
||||
MultilineStart(usize),
|
||||
/// Annotation marking the last character of a fully shown multiline span
|
||||
MultilineEnd(usize),
|
||||
/// Line at the left enclosing the lines of a fully shown multiline span
|
||||
// Just a placeholder for the drawing algorithm, to know that it shouldn't skip the first 4
|
||||
// and last 2 lines of code. The actual line is drawn in `emit_message_default` and not in
|
||||
// `draw_multiline_line`.
|
||||
MultilineLine(usize),
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialOrd, Ord, PartialEq, Eq)]
|
||||
pub(crate) struct Annotation {
|
||||
/// Start column.
|
||||
/// Note that it is important that this field goes
|
||||
/// first, so that when we sort, we sort orderings by start
|
||||
/// column.
|
||||
pub start_col: AnnotationColumn,
|
||||
|
||||
/// End column within the line (exclusive)
|
||||
pub end_col: AnnotationColumn,
|
||||
|
||||
/// Is this annotation derived from primary span
|
||||
pub is_primary: bool,
|
||||
|
||||
/// Optional label to display adjacent to the annotation.
|
||||
pub label: Option<String>,
|
||||
|
||||
/// Is this a single line, multiline or multiline span minimized down to a
|
||||
/// smaller span.
|
||||
pub annotation_type: AnnotationType,
|
||||
}
|
||||
|
||||
impl Annotation {
|
||||
/// Whether this annotation is a vertical line placeholder.
|
||||
pub(crate) fn is_line(&self) -> bool {
|
||||
matches!(self.annotation_type, AnnotationType::MultilineLine(_))
|
||||
}
|
||||
|
||||
/// Length of this annotation as displayed in the stderr output
|
||||
pub(crate) fn len(&self) -> usize {
|
||||
// Account for usize underflows
|
||||
self.end_col.display.abs_diff(self.start_col.display)
|
||||
}
|
||||
|
||||
pub(crate) fn has_label(&self) -> bool {
|
||||
if let Some(ref label) = self.label {
|
||||
// Consider labels with no text as effectively not being there
|
||||
// to avoid weird output with unnecessary vertical lines, like:
|
||||
//
|
||||
// X | fn foo(x: u32) {
|
||||
// | -------^------
|
||||
// | | |
|
||||
// | |
|
||||
// |
|
||||
//
|
||||
// Note that this would be the complete output users would see.
|
||||
!label.is_empty()
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn takes_space(&self) -> bool {
|
||||
// Multiline annotations always have to keep vertical space.
|
||||
matches!(
|
||||
self.annotation_type,
|
||||
AnnotationType::MultilineStart(_) | AnnotationType::MultilineEnd(_)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub(crate) struct StyledString {
|
||||
pub text: String,
|
||||
pub style: Style,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Encodable, Decodable)]
|
||||
pub enum Style {
|
||||
MainHeaderMsg,
|
||||
HeaderMsg,
|
||||
LineAndColumn,
|
||||
LineNumber,
|
||||
Quotation,
|
||||
UnderlinePrimary,
|
||||
UnderlineSecondary,
|
||||
LabelPrimary,
|
||||
LabelSecondary,
|
||||
NoStyle,
|
||||
Level(Level),
|
||||
Highlight,
|
||||
Addition,
|
||||
Removal,
|
||||
}
|
||||
|
|
@ -1,163 +0,0 @@
|
|||
// Code for creating styled buffers
|
||||
|
||||
use crate::snippet::{Style, StyledString};
|
||||
|
||||
#[derive(Debug)]
|
||||
pub(crate) struct StyledBuffer {
|
||||
lines: Vec<Vec<StyledChar>>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
struct StyledChar {
|
||||
chr: char,
|
||||
style: Style,
|
||||
}
|
||||
|
||||
impl StyledChar {
|
||||
const SPACE: Self = StyledChar::new(' ', Style::NoStyle);
|
||||
|
||||
const fn new(chr: char, style: Style) -> Self {
|
||||
StyledChar { chr, style }
|
||||
}
|
||||
}
|
||||
|
||||
impl StyledBuffer {
|
||||
pub(crate) fn new() -> StyledBuffer {
|
||||
StyledBuffer { lines: vec![] }
|
||||
}
|
||||
|
||||
/// Returns content of `StyledBuffer` split by lines and line styles
|
||||
pub(crate) fn render(&self) -> Vec<Vec<StyledString>> {
|
||||
// Tabs are assumed to have been replaced by spaces in calling code.
|
||||
debug_assert!(self.lines.iter().all(|r| !r.iter().any(|sc| sc.chr == '\t')));
|
||||
|
||||
let mut output: Vec<Vec<StyledString>> = vec![];
|
||||
let mut styled_vec: Vec<StyledString> = vec![];
|
||||
|
||||
for styled_line in &self.lines {
|
||||
let mut current_style = Style::NoStyle;
|
||||
let mut current_text = String::new();
|
||||
|
||||
for sc in styled_line {
|
||||
if sc.style != current_style {
|
||||
if !current_text.is_empty() {
|
||||
styled_vec.push(StyledString { text: current_text, style: current_style });
|
||||
}
|
||||
current_style = sc.style;
|
||||
current_text = String::new();
|
||||
}
|
||||
current_text.push(sc.chr);
|
||||
}
|
||||
if !current_text.is_empty() {
|
||||
styled_vec.push(StyledString { text: current_text, style: current_style });
|
||||
}
|
||||
|
||||
// We're done with the row, push and keep going
|
||||
output.push(styled_vec);
|
||||
|
||||
styled_vec = vec![];
|
||||
}
|
||||
|
||||
output
|
||||
}
|
||||
|
||||
fn ensure_lines(&mut self, line: usize) {
|
||||
if line >= self.lines.len() {
|
||||
self.lines.resize(line + 1, Vec::new());
|
||||
}
|
||||
}
|
||||
|
||||
/// Sets `chr` with `style` for given `line`, `col`.
|
||||
/// If `line` does not exist in our buffer, adds empty lines up to the given
|
||||
/// and fills the last line with unstyled whitespace.
|
||||
pub(crate) fn putc(&mut self, line: usize, col: usize, chr: char, style: Style) {
|
||||
self.ensure_lines(line);
|
||||
if col >= self.lines[line].len() {
|
||||
self.lines[line].resize(col + 1, StyledChar::SPACE);
|
||||
}
|
||||
self.lines[line][col] = StyledChar::new(chr, style);
|
||||
}
|
||||
|
||||
/// Sets `string` with `style` for given `line`, starting from `col`.
|
||||
/// If `line` does not exist in our buffer, adds empty lines up to the given
|
||||
/// and fills the last line with unstyled whitespace.
|
||||
pub(crate) fn puts(&mut self, line: usize, col: usize, string: &str, style: Style) {
|
||||
let mut n = col;
|
||||
for c in string.chars() {
|
||||
self.putc(line, n, c, style);
|
||||
n += 1;
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn replace(&mut self, line: usize, start: usize, end: usize, string: &str) {
|
||||
if start == end {
|
||||
return;
|
||||
}
|
||||
if start > self.lines[line].len() || end > self.lines[line].len() {
|
||||
return;
|
||||
}
|
||||
let _ = self.lines[line].drain(start..(end - string.chars().count()));
|
||||
for (i, c) in string.chars().enumerate() {
|
||||
self.lines[line][start + i] = StyledChar::new(c, Style::LineNumber);
|
||||
}
|
||||
}
|
||||
|
||||
/// For given `line` inserts `string` with `style` before old content of that line,
|
||||
/// adding lines if needed
|
||||
pub(crate) fn prepend(&mut self, line: usize, string: &str, style: Style) {
|
||||
self.ensure_lines(line);
|
||||
let string_len = string.chars().count();
|
||||
|
||||
if !self.lines[line].is_empty() {
|
||||
// Push the old content over to make room for new content
|
||||
for _ in 0..string_len {
|
||||
self.lines[line].insert(0, StyledChar::SPACE);
|
||||
}
|
||||
}
|
||||
|
||||
self.puts(line, 0, string, style);
|
||||
}
|
||||
|
||||
/// For given `line` inserts `string` with `style` after old content of that line,
|
||||
/// adding lines if needed
|
||||
pub(crate) fn append(&mut self, line: usize, string: &str, style: Style) {
|
||||
if line >= self.lines.len() {
|
||||
self.puts(line, 0, string, style);
|
||||
} else {
|
||||
let col = self.lines[line].len();
|
||||
self.puts(line, col, string, style);
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn num_lines(&self) -> usize {
|
||||
self.lines.len()
|
||||
}
|
||||
|
||||
/// Set `style` for `line`, `col_start..col_end` range if:
|
||||
/// 1. That line and column range exist in `StyledBuffer`
|
||||
/// 2. `overwrite` is `true` or existing style is `Style::NoStyle` or `Style::Quotation`
|
||||
pub(crate) fn set_style_range(
|
||||
&mut self,
|
||||
line: usize,
|
||||
col_start: usize,
|
||||
col_end: usize,
|
||||
style: Style,
|
||||
overwrite: bool,
|
||||
) {
|
||||
for col in col_start..col_end {
|
||||
self.set_style(line, col, style, overwrite);
|
||||
}
|
||||
}
|
||||
|
||||
/// Set `style` for `line`, `col` if:
|
||||
/// 1. That line and column exist in `StyledBuffer`
|
||||
/// 2. `overwrite` is `true` or existing style is `Style::NoStyle` or `Style::Quotation`
|
||||
fn set_style(&mut self, line: usize, col: usize, style: Style, overwrite: bool) {
|
||||
if let Some(ref mut line) = self.lines.get_mut(line)
|
||||
&& let Some(StyledChar { style: s, .. }) = line.get_mut(col)
|
||||
&& (overwrite || matches!(s, Style::NoStyle | Style::Quotation))
|
||||
{
|
||||
*s = style;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -7,8 +7,7 @@ pub use rustc_error_messages::{FluentArgs, LazyFallbackBundle};
|
|||
use tracing::{debug, trace};
|
||||
|
||||
use crate::error::{TranslateError, TranslateErrorKind};
|
||||
use crate::snippet::Style;
|
||||
use crate::{DiagArg, DiagMessage, FluentBundle};
|
||||
use crate::{DiagArg, DiagMessage, FluentBundle, Style};
|
||||
|
||||
/// Convert diagnostic arguments (a rustc internal type that exists to implement
|
||||
/// `Encodable`/`Decodable`) into `FluentArgs` which is necessary to perform translation.
|
||||
|
|
|
|||
|
|
@ -22,7 +22,7 @@ use rustc_hir::limit::Limit;
|
|||
use rustc_hir::{Stability, find_attr};
|
||||
use rustc_lint_defs::RegisteredTools;
|
||||
use rustc_parse::MACRO_ARGUMENTS;
|
||||
use rustc_parse::parser::{ForceCollect, Parser};
|
||||
use rustc_parse::parser::{AllowConstBlockItems, ForceCollect, Parser};
|
||||
use rustc_session::Session;
|
||||
use rustc_session::parse::ParseSess;
|
||||
use rustc_span::def_id::{CrateNum, DefId, LocalDefId};
|
||||
|
|
@ -1472,7 +1472,7 @@ pub(crate) fn stream_pretty_printing_compatibility_hack(
|
|||
let mut parser = Parser::new(psess, stream.clone(), None);
|
||||
// No need to collect tokens for this simple check.
|
||||
parser
|
||||
.parse_item(ForceCollect::No)
|
||||
.parse_item(ForceCollect::No, AllowConstBlockItems::No)
|
||||
.expect("failed to reparse item")
|
||||
.expect("an actual item")
|
||||
}
|
||||
|
|
|
|||
|
|
@ -393,9 +393,10 @@ impl<'a> StripUnconfigured<'a> {
|
|||
|
||||
/// Determines if a node with the given attributes should be included in this configuration.
|
||||
fn in_cfg(&self, attrs: &[Attribute]) -> bool {
|
||||
attrs
|
||||
.iter()
|
||||
.all(|attr| !is_cfg(attr) || self.cfg_true(attr, ShouldEmit::ErrorsAndLints).as_bool())
|
||||
attrs.iter().all(|attr| {
|
||||
!is_cfg(attr)
|
||||
|| self.cfg_true(attr, ShouldEmit::ErrorsAndLints { recover: true }).as_bool()
|
||||
})
|
||||
}
|
||||
|
||||
pub(crate) fn cfg_true(&self, attr: &Attribute, emit_errors: ShouldEmit) -> EvalConfigResult {
|
||||
|
|
|
|||
|
|
@ -25,8 +25,8 @@ use rustc_hir::Target;
|
|||
use rustc_hir::def::MacroKinds;
|
||||
use rustc_hir::limit::Limit;
|
||||
use rustc_parse::parser::{
|
||||
AttemptLocalParseRecovery, CommaRecoveryMode, ForceCollect, Parser, RecoverColon, RecoverComma,
|
||||
token_descr,
|
||||
AllowConstBlockItems, AttemptLocalParseRecovery, CommaRecoveryMode, ForceCollect, Parser,
|
||||
RecoverColon, RecoverComma, token_descr,
|
||||
};
|
||||
use rustc_session::Session;
|
||||
use rustc_session::lint::builtin::{UNUSED_ATTRIBUTES, UNUSED_DOC_COMMENTS};
|
||||
|
|
@ -1099,7 +1099,7 @@ pub fn parse_ast_fragment<'a>(
|
|||
Ok(match kind {
|
||||
AstFragmentKind::Items => {
|
||||
let mut items = SmallVec::new();
|
||||
while let Some(item) = this.parse_item(ForceCollect::No)? {
|
||||
while let Some(item) = this.parse_item(ForceCollect::No, AllowConstBlockItems::Yes)? {
|
||||
items.push(item);
|
||||
}
|
||||
AstFragment::Items(items)
|
||||
|
|
@ -2170,7 +2170,7 @@ impl<'a, 'b> InvocationCollector<'a, 'b> {
|
|||
call.span(),
|
||||
self.cx.current_expansion.lint_node_id,
|
||||
Some(self.cx.ecfg.features),
|
||||
ShouldEmit::ErrorsAndLints,
|
||||
ShouldEmit::ErrorsAndLints { recover: true },
|
||||
);
|
||||
|
||||
let current_span = if let Some(sp) = span { sp.to(attr.span) } else { attr.span };
|
||||
|
|
@ -2220,7 +2220,7 @@ impl<'a, 'b> InvocationCollector<'a, 'b> {
|
|||
// Target doesn't matter for `cfg` parsing.
|
||||
Target::Crate,
|
||||
self.cfg().features,
|
||||
ShouldEmit::ErrorsAndLints,
|
||||
ShouldEmit::ErrorsAndLints { recover: true },
|
||||
parse_cfg,
|
||||
&CFG_TEMPLATE,
|
||||
) else {
|
||||
|
|
|
|||
|
|
@ -1,6 +1,5 @@
|
|||
// tidy-alphabetical-start
|
||||
#![allow(internal_features)]
|
||||
#![cfg_attr(bootstrap, feature(array_windows))]
|
||||
#![feature(associated_type_defaults)]
|
||||
#![feature(if_let_guard)]
|
||||
#![feature(macro_metavar_expr)]
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
use rustc_ast::tokenstream::TokenStream;
|
||||
use rustc_errors::ErrorGuaranteed;
|
||||
use rustc_middle::ty::{self, TyCtxt};
|
||||
use rustc_parse::parser::{ForceCollect, Parser};
|
||||
use rustc_parse::parser::{AllowConstBlockItems, ForceCollect, Parser};
|
||||
use rustc_session::Session;
|
||||
use rustc_session::config::ProcMacroExecutionStrategy;
|
||||
use rustc_span::profiling::SpannedEventArgRecorder;
|
||||
|
|
@ -160,7 +160,10 @@ impl MultiItemModifier for DeriveProcMacro {
|
|||
let mut items = vec![];
|
||||
|
||||
loop {
|
||||
match parser.parse_item(ForceCollect::No) {
|
||||
match parser.parse_item(
|
||||
ForceCollect::No,
|
||||
if is_stmt { AllowConstBlockItems::No } else { AllowConstBlockItems::Yes },
|
||||
) {
|
||||
Ok(None) => break,
|
||||
Ok(Some(item)) => {
|
||||
if is_stmt {
|
||||
|
|
|
|||
|
|
@ -431,8 +431,6 @@ impl ToInternal<rustc_errors::Level> for Level {
|
|||
}
|
||||
}
|
||||
|
||||
pub(crate) struct FreeFunctions;
|
||||
|
||||
pub(crate) struct Rustc<'a, 'b> {
|
||||
ecx: &'a mut ExtCtxt<'b>,
|
||||
def_site: Span,
|
||||
|
|
@ -461,13 +459,28 @@ impl<'a, 'b> Rustc<'a, 'b> {
|
|||
}
|
||||
|
||||
impl server::Types for Rustc<'_, '_> {
|
||||
type FreeFunctions = FreeFunctions;
|
||||
type TokenStream = TokenStream;
|
||||
type Span = Span;
|
||||
type Symbol = Symbol;
|
||||
}
|
||||
|
||||
impl server::FreeFunctions for Rustc<'_, '_> {
|
||||
impl server::Server for Rustc<'_, '_> {
|
||||
fn globals(&mut self) -> ExpnGlobals<Self::Span> {
|
||||
ExpnGlobals {
|
||||
def_site: self.def_site,
|
||||
call_site: self.call_site,
|
||||
mixed_site: self.mixed_site,
|
||||
}
|
||||
}
|
||||
|
||||
fn intern_symbol(string: &str) -> Self::Symbol {
|
||||
Symbol::intern(string)
|
||||
}
|
||||
|
||||
fn with_symbol_string(symbol: &Self::Symbol, f: impl FnOnce(&str)) {
|
||||
f(symbol.as_str())
|
||||
}
|
||||
|
||||
fn injected_env_var(&mut self, var: &str) -> Option<String> {
|
||||
self.ecx.sess.opts.logical_env.get(var).cloned()
|
||||
}
|
||||
|
|
@ -552,14 +565,20 @@ impl server::FreeFunctions for Rustc<'_, '_> {
|
|||
}
|
||||
diag.emit();
|
||||
}
|
||||
}
|
||||
|
||||
impl server::TokenStream for Rustc<'_, '_> {
|
||||
fn is_empty(&mut self, stream: &Self::TokenStream) -> bool {
|
||||
fn ts_drop(&mut self, stream: Self::TokenStream) {
|
||||
drop(stream);
|
||||
}
|
||||
|
||||
fn ts_clone(&mut self, stream: &Self::TokenStream) -> Self::TokenStream {
|
||||
stream.clone()
|
||||
}
|
||||
|
||||
fn ts_is_empty(&mut self, stream: &Self::TokenStream) -> bool {
|
||||
stream.is_empty()
|
||||
}
|
||||
|
||||
fn from_str(&mut self, src: &str) -> Self::TokenStream {
|
||||
fn ts_from_str(&mut self, src: &str) -> Self::TokenStream {
|
||||
unwrap_or_emit_fatal(source_str_to_stream(
|
||||
self.psess(),
|
||||
FileName::proc_macro_source_code(src),
|
||||
|
|
@ -568,11 +587,11 @@ impl server::TokenStream for Rustc<'_, '_> {
|
|||
))
|
||||
}
|
||||
|
||||
fn to_string(&mut self, stream: &Self::TokenStream) -> String {
|
||||
fn ts_to_string(&mut self, stream: &Self::TokenStream) -> String {
|
||||
pprust::tts_to_string(stream)
|
||||
}
|
||||
|
||||
fn expand_expr(&mut self, stream: &Self::TokenStream) -> Result<Self::TokenStream, ()> {
|
||||
fn ts_expand_expr(&mut self, stream: &Self::TokenStream) -> Result<Self::TokenStream, ()> {
|
||||
// Parse the expression from our tokenstream.
|
||||
let expr: PResult<'_, _> = try {
|
||||
let mut p = Parser::new(self.psess(), stream.clone(), Some("proc_macro expand expr"));
|
||||
|
|
@ -633,14 +652,14 @@ impl server::TokenStream for Rustc<'_, '_> {
|
|||
}
|
||||
}
|
||||
|
||||
fn from_token_tree(
|
||||
fn ts_from_token_tree(
|
||||
&mut self,
|
||||
tree: TokenTree<Self::TokenStream, Self::Span, Self::Symbol>,
|
||||
) -> Self::TokenStream {
|
||||
Self::TokenStream::new((tree, &mut *self).to_internal().into_iter().collect::<Vec<_>>())
|
||||
}
|
||||
|
||||
fn concat_trees(
|
||||
fn ts_concat_trees(
|
||||
&mut self,
|
||||
base: Option<Self::TokenStream>,
|
||||
trees: Vec<TokenTree<Self::TokenStream, Self::Span, Self::Symbol>>,
|
||||
|
|
@ -654,7 +673,7 @@ impl server::TokenStream for Rustc<'_, '_> {
|
|||
stream
|
||||
}
|
||||
|
||||
fn concat_streams(
|
||||
fn ts_concat_streams(
|
||||
&mut self,
|
||||
base: Option<Self::TokenStream>,
|
||||
streams: Vec<Self::TokenStream>,
|
||||
|
|
@ -666,16 +685,14 @@ impl server::TokenStream for Rustc<'_, '_> {
|
|||
stream
|
||||
}
|
||||
|
||||
fn into_trees(
|
||||
fn ts_into_trees(
|
||||
&mut self,
|
||||
stream: Self::TokenStream,
|
||||
) -> Vec<TokenTree<Self::TokenStream, Self::Span, Self::Symbol>> {
|
||||
FromInternal::from_internal((stream, self))
|
||||
}
|
||||
}
|
||||
|
||||
impl server::Span for Rustc<'_, '_> {
|
||||
fn debug(&mut self, span: Self::Span) -> String {
|
||||
fn span_debug(&mut self, span: Self::Span) -> String {
|
||||
if self.ecx.ecfg.span_debug {
|
||||
format!("{span:?}")
|
||||
} else {
|
||||
|
|
@ -683,7 +700,7 @@ impl server::Span for Rustc<'_, '_> {
|
|||
}
|
||||
}
|
||||
|
||||
fn file(&mut self, span: Self::Span) -> String {
|
||||
fn span_file(&mut self, span: Self::Span) -> String {
|
||||
self.psess()
|
||||
.source_map()
|
||||
.lookup_char_pos(span.lo())
|
||||
|
|
@ -693,7 +710,7 @@ impl server::Span for Rustc<'_, '_> {
|
|||
.to_string()
|
||||
}
|
||||
|
||||
fn local_file(&mut self, span: Self::Span) -> Option<String> {
|
||||
fn span_local_file(&mut self, span: Self::Span) -> Option<String> {
|
||||
self.psess()
|
||||
.source_map()
|
||||
.lookup_char_pos(span.lo())
|
||||
|
|
@ -708,15 +725,15 @@ impl server::Span for Rustc<'_, '_> {
|
|||
})
|
||||
}
|
||||
|
||||
fn parent(&mut self, span: Self::Span) -> Option<Self::Span> {
|
||||
fn span_parent(&mut self, span: Self::Span) -> Option<Self::Span> {
|
||||
span.parent_callsite()
|
||||
}
|
||||
|
||||
fn source(&mut self, span: Self::Span) -> Self::Span {
|
||||
fn span_source(&mut self, span: Self::Span) -> Self::Span {
|
||||
span.source_callsite()
|
||||
}
|
||||
|
||||
fn byte_range(&mut self, span: Self::Span) -> Range<usize> {
|
||||
fn span_byte_range(&mut self, span: Self::Span) -> Range<usize> {
|
||||
let source_map = self.psess().source_map();
|
||||
|
||||
let relative_start_pos = source_map.lookup_byte_offset(span.lo()).pos;
|
||||
|
|
@ -724,25 +741,25 @@ impl server::Span for Rustc<'_, '_> {
|
|||
|
||||
Range { start: relative_start_pos.0 as usize, end: relative_end_pos.0 as usize }
|
||||
}
|
||||
fn start(&mut self, span: Self::Span) -> Self::Span {
|
||||
fn span_start(&mut self, span: Self::Span) -> Self::Span {
|
||||
span.shrink_to_lo()
|
||||
}
|
||||
|
||||
fn end(&mut self, span: Self::Span) -> Self::Span {
|
||||
fn span_end(&mut self, span: Self::Span) -> Self::Span {
|
||||
span.shrink_to_hi()
|
||||
}
|
||||
|
||||
fn line(&mut self, span: Self::Span) -> usize {
|
||||
fn span_line(&mut self, span: Self::Span) -> usize {
|
||||
let loc = self.psess().source_map().lookup_char_pos(span.lo());
|
||||
loc.line
|
||||
}
|
||||
|
||||
fn column(&mut self, span: Self::Span) -> usize {
|
||||
fn span_column(&mut self, span: Self::Span) -> usize {
|
||||
let loc = self.psess().source_map().lookup_char_pos(span.lo());
|
||||
loc.col.to_usize() + 1
|
||||
}
|
||||
|
||||
fn join(&mut self, first: Self::Span, second: Self::Span) -> Option<Self::Span> {
|
||||
fn span_join(&mut self, first: Self::Span, second: Self::Span) -> Option<Self::Span> {
|
||||
let self_loc = self.psess().source_map().lookup_char_pos(first.lo());
|
||||
let other_loc = self.psess().source_map().lookup_char_pos(second.lo());
|
||||
|
||||
|
|
@ -753,7 +770,7 @@ impl server::Span for Rustc<'_, '_> {
|
|||
Some(first.to(second))
|
||||
}
|
||||
|
||||
fn subspan(
|
||||
fn span_subspan(
|
||||
&mut self,
|
||||
span: Self::Span,
|
||||
start: Bound<usize>,
|
||||
|
|
@ -789,11 +806,11 @@ impl server::Span for Rustc<'_, '_> {
|
|||
Some(span.with_lo(new_lo).with_hi(new_hi))
|
||||
}
|
||||
|
||||
fn resolved_at(&mut self, span: Self::Span, at: Self::Span) -> Self::Span {
|
||||
fn span_resolved_at(&mut self, span: Self::Span, at: Self::Span) -> Self::Span {
|
||||
span.with_ctxt(at.ctxt())
|
||||
}
|
||||
|
||||
fn source_text(&mut self, span: Self::Span) -> Option<String> {
|
||||
fn span_source_text(&mut self, span: Self::Span) -> Option<String> {
|
||||
self.psess().source_map().span_to_snippet(span).ok()
|
||||
}
|
||||
|
||||
|
|
@ -821,11 +838,11 @@ impl server::Span for Rustc<'_, '_> {
|
|||
/// span from the metadata of `my_proc_macro` (which we have access to,
|
||||
/// since we've loaded `my_proc_macro` from disk in order to execute it).
|
||||
/// In this way, we have obtained a span pointing into `my_proc_macro`
|
||||
fn save_span(&mut self, span: Self::Span) -> usize {
|
||||
fn span_save_span(&mut self, span: Self::Span) -> usize {
|
||||
self.psess().save_proc_macro_span(span)
|
||||
}
|
||||
|
||||
fn recover_proc_macro_span(&mut self, id: usize) -> Self::Span {
|
||||
fn span_recover_proc_macro_span(&mut self, id: usize) -> Self::Span {
|
||||
let (resolver, krate, def_site) = (&*self.ecx.resolver, self.krate, self.def_site);
|
||||
*self.rebased_spans.entry(id).or_insert_with(|| {
|
||||
// FIXME: `SyntaxContext` for spans from proc macro crates is lost during encoding,
|
||||
|
|
@ -833,29 +850,9 @@ impl server::Span for Rustc<'_, '_> {
|
|||
resolver.get_proc_macro_quoted_span(krate, id).with_ctxt(def_site.ctxt())
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl server::Symbol for Rustc<'_, '_> {
|
||||
fn normalize_and_validate_ident(&mut self, string: &str) -> Result<Self::Symbol, ()> {
|
||||
fn symbol_normalize_and_validate_ident(&mut self, string: &str) -> Result<Self::Symbol, ()> {
|
||||
let sym = nfc_normalize(string);
|
||||
if rustc_lexer::is_ident(sym.as_str()) { Ok(sym) } else { Err(()) }
|
||||
}
|
||||
}
|
||||
|
||||
impl server::Server for Rustc<'_, '_> {
|
||||
fn globals(&mut self) -> ExpnGlobals<Self::Span> {
|
||||
ExpnGlobals {
|
||||
def_site: self.def_site,
|
||||
call_site: self.call_site,
|
||||
mixed_site: self.mixed_site,
|
||||
}
|
||||
}
|
||||
|
||||
fn intern_symbol(string: &str) -> Self::Symbol {
|
||||
Symbol::intern(string)
|
||||
}
|
||||
|
||||
fn with_symbol_string(symbol: &Self::Symbol, f: impl FnOnce(&str)) {
|
||||
f(symbol.as_str())
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1315,13 +1315,13 @@ pub static BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
|
|||
"`#[rustc_deny_explicit_impl]` enforces that a trait can have no user-provided impls"
|
||||
),
|
||||
rustc_attr!(
|
||||
rustc_do_not_implement_via_object,
|
||||
rustc_dyn_incompatible_trait,
|
||||
AttributeType::Normal,
|
||||
template!(Word),
|
||||
ErrorFollowing,
|
||||
EncodeCrossCrate::No,
|
||||
"`#[rustc_do_not_implement_via_object]` opts out of the automatic trait impl for trait objects \
|
||||
(`impl Trait for dyn Trait`)"
|
||||
"`#[rustc_dyn_incompatible_trait]` marks a trait as dyn-incompatible, \
|
||||
even if it otherwise satisfies the requirements to be dyn-compatible."
|
||||
),
|
||||
rustc_attr!(
|
||||
rustc_has_incoherent_inherent_impls, AttributeType::Normal, template!(Word),
|
||||
|
|
|
|||
|
|
@ -61,7 +61,7 @@ declare_features! (
|
|||
/// Allows a test to fail without failing the whole suite.
|
||||
(removed, allow_fail, "1.60.0", Some(46488), Some("removed due to no clear use cases"), 93416),
|
||||
/// Allows users to enforce equality of associated constants `TraitImpl<AssocConst=3>`.
|
||||
(removed, associated_const_equality, "CURRENT_RUSTC_VERSION", Some(92827),
|
||||
(removed, associated_const_equality, "1.94.0", Some(92827),
|
||||
Some("merged into `min_generic_const_args`")),
|
||||
(removed, await_macro, "1.38.0", Some(50547),
|
||||
Some("subsumed by `.await` syntax"), 62293),
|
||||
|
|
@ -275,7 +275,7 @@ declare_features! (
|
|||
(removed, static_nobundle, "1.63.0", Some(37403),
|
||||
Some(r#"subsumed by `#[link(kind = "static", modifiers = "-bundle", ...)]`"#), 95818),
|
||||
/// Allows string patterns to dereference values to match them.
|
||||
(removed, string_deref_patterns, "CURRENT_RUSTC_VERSION", Some(87121), Some("superseded by `deref_patterns`"), 150530),
|
||||
(removed, string_deref_patterns, "1.94.0", Some(87121), Some("superseded by `deref_patterns`"), 150530),
|
||||
(removed, struct_inherit, "1.0.0", None, None),
|
||||
(removed, test_removed_feature, "1.0.0", None, None),
|
||||
/// Allows using items which are missing stability attributes
|
||||
|
|
|
|||
|
|
@ -222,7 +222,7 @@ declare_features! (
|
|||
/// Allows writing custom MIR
|
||||
(internal, custom_mir, "1.65.0", None),
|
||||
/// Implementation details of externally implementable items
|
||||
(internal, eii_internals, "CURRENT_RUSTC_VERSION", None),
|
||||
(internal, eii_internals, "1.94.0", None),
|
||||
/// Outputs useful `assert!` messages
|
||||
(unstable, generic_assert, "1.63.0", None),
|
||||
/// Allows using the #[rustc_intrinsic] attribute.
|
||||
|
|
@ -414,6 +414,8 @@ declare_features! (
|
|||
(unstable, cmse_nonsecure_entry, "1.48.0", Some(75835)),
|
||||
/// Allows `async {}` expressions in const contexts.
|
||||
(unstable, const_async_blocks, "1.53.0", Some(85368)),
|
||||
/// Allows `const { ... }` as a shorthand for `const _: () = const { ... };` for module items.
|
||||
(unstable, const_block_items, "CURRENT_RUSTC_VERSION", Some(149226)),
|
||||
/// Allows `const || {}` closures in const contexts.
|
||||
(incomplete, const_closures, "1.68.0", Some(106003)),
|
||||
/// Allows using `[const] Destruct` bounds and calling drop impls in const contexts.
|
||||
|
|
@ -477,7 +479,7 @@ declare_features! (
|
|||
/// Allows using `#[export_stable]` which indicates that an item is exportable.
|
||||
(incomplete, export_stable, "1.88.0", Some(139939)),
|
||||
/// Externally implementable items
|
||||
(unstable, extern_item_impls, "CURRENT_RUSTC_VERSION", Some(125418)),
|
||||
(unstable, extern_item_impls, "1.94.0", Some(125418)),
|
||||
/// Allows defining `extern type`s.
|
||||
(unstable, extern_types, "1.23.0", Some(43467)),
|
||||
/// Allow using 128-bit (quad precision) floating point numbers.
|
||||
|
|
@ -632,6 +634,8 @@ declare_features! (
|
|||
(unstable, rtm_target_feature, "1.35.0", Some(150258)),
|
||||
/// Allows `extern "rust-cold"`.
|
||||
(unstable, rust_cold_cc, "1.63.0", Some(97544)),
|
||||
/// Allows `extern "rust-preserve-none"`.
|
||||
(unstable, rust_preserve_none_cc, "CURRENT_RUSTC_VERSION", Some(151401)),
|
||||
/// Target features on s390x.
|
||||
(unstable, s390x_target_feature, "1.82.0", Some(150259)),
|
||||
/// Allows the use of the `sanitize` attribute.
|
||||
|
|
@ -667,7 +671,7 @@ declare_features! (
|
|||
/// Allows using `try {...}` expressions.
|
||||
(unstable, try_blocks, "1.29.0", Some(31436)),
|
||||
/// Allows using `try bikeshed TargetType {...}` expressions.
|
||||
(unstable, try_blocks_heterogeneous, "CURRENT_RUSTC_VERSION", Some(149488)),
|
||||
(unstable, try_blocks_heterogeneous, "1.94.0", Some(149488)),
|
||||
/// Allows `impl Trait` to be used inside type aliases (RFC 2515).
|
||||
(unstable, type_alias_impl_trait, "1.38.0", Some(63063)),
|
||||
/// Allows creation of instances of a struct by moving fields that have
|
||||
|
|
|
|||
|
|
@ -8,10 +8,7 @@ use fluent_syntax::ast::{
|
|||
Attribute, Entry, Expression, Identifier, InlineExpression, Message, Pattern, PatternElement,
|
||||
};
|
||||
use fluent_syntax::parser::ParserError;
|
||||
#[cfg(not(bootstrap))]
|
||||
use proc_macro::tracked::path;
|
||||
#[cfg(bootstrap)]
|
||||
use proc_macro::tracked_path::path;
|
||||
use proc_macro::{Diagnostic, Level, Span};
|
||||
use proc_macro2::TokenStream;
|
||||
use quote::quote;
|
||||
|
|
|
|||
|
|
@ -1,8 +1,7 @@
|
|||
// tidy-alphabetical-start
|
||||
#![allow(rustc::default_hash_types)]
|
||||
#![cfg_attr(bootstrap, feature(track_path))]
|
||||
#![cfg_attr(not(bootstrap), feature(proc_macro_tracked_path))]
|
||||
#![feature(proc_macro_diagnostic)]
|
||||
#![feature(proc_macro_tracked_path)]
|
||||
// tidy-alphabetical-end
|
||||
|
||||
use proc_macro::TokenStream;
|
||||
|
|
|
|||
|
|
@ -588,6 +588,108 @@ pub enum CollapseMacroDebuginfo {
|
|||
Yes = 3,
|
||||
}
|
||||
|
||||
/// Crate type, as specified by `#![crate_type]`
|
||||
#[derive(Copy, Clone, Debug, Hash, PartialEq, Default, PartialOrd, Eq, Ord)]
|
||||
#[derive(HashStable_Generic, Encodable, Decodable, PrintAttribute)]
|
||||
pub enum CrateType {
|
||||
/// `#![crate_type = "bin"]`
|
||||
Executable,
|
||||
/// `#![crate_type = "dylib"]`
|
||||
Dylib,
|
||||
/// `#![crate_type = "rlib"]` or `#![crate_type = "lib"]`
|
||||
#[default]
|
||||
Rlib,
|
||||
/// `#![crate_type = "staticlib"]`
|
||||
StaticLib,
|
||||
/// `#![crate_type = "cdylib"]`
|
||||
Cdylib,
|
||||
/// `#![crate_type = "proc-macro"]`
|
||||
ProcMacro,
|
||||
/// `#![crate_type = "sdylib"]`
|
||||
// Unstable; feature(export_stable)
|
||||
Sdylib,
|
||||
}
|
||||
|
||||
impl CrateType {
|
||||
/// Pairs of each `#[crate_type] = "..."` value and the crate type it resolves to
|
||||
pub fn all() -> &'static [(Symbol, Self)] {
|
||||
debug_assert_eq!(CrateType::default(), CrateType::Rlib);
|
||||
&[
|
||||
(rustc_span::sym::lib, CrateType::Rlib),
|
||||
(rustc_span::sym::rlib, CrateType::Rlib),
|
||||
(rustc_span::sym::dylib, CrateType::Dylib),
|
||||
(rustc_span::sym::cdylib, CrateType::Cdylib),
|
||||
(rustc_span::sym::staticlib, CrateType::StaticLib),
|
||||
(rustc_span::sym::proc_dash_macro, CrateType::ProcMacro),
|
||||
(rustc_span::sym::bin, CrateType::Executable),
|
||||
(rustc_span::sym::sdylib, CrateType::Sdylib),
|
||||
]
|
||||
}
|
||||
|
||||
/// Same as [`CrateType::all`], but does not include unstable options.
|
||||
/// Used for diagnostics.
|
||||
pub fn all_stable() -> &'static [(Symbol, Self)] {
|
||||
debug_assert_eq!(CrateType::default(), CrateType::Rlib);
|
||||
&[
|
||||
(rustc_span::sym::lib, CrateType::Rlib),
|
||||
(rustc_span::sym::rlib, CrateType::Rlib),
|
||||
(rustc_span::sym::dylib, CrateType::Dylib),
|
||||
(rustc_span::sym::cdylib, CrateType::Cdylib),
|
||||
(rustc_span::sym::staticlib, CrateType::StaticLib),
|
||||
(rustc_span::sym::proc_dash_macro, CrateType::ProcMacro),
|
||||
(rustc_span::sym::bin, CrateType::Executable),
|
||||
]
|
||||
}
|
||||
|
||||
pub fn has_metadata(self) -> bool {
|
||||
match self {
|
||||
CrateType::Rlib | CrateType::Dylib | CrateType::ProcMacro => true,
|
||||
CrateType::Executable
|
||||
| CrateType::Cdylib
|
||||
| CrateType::StaticLib
|
||||
| CrateType::Sdylib => false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<Symbol> for CrateType {
|
||||
type Error = ();
|
||||
|
||||
fn try_from(value: Symbol) -> Result<Self, Self::Error> {
|
||||
Ok(match value {
|
||||
rustc_span::sym::bin => CrateType::Executable,
|
||||
rustc_span::sym::dylib => CrateType::Dylib,
|
||||
rustc_span::sym::staticlib => CrateType::StaticLib,
|
||||
rustc_span::sym::cdylib => CrateType::Cdylib,
|
||||
rustc_span::sym::rlib => CrateType::Rlib,
|
||||
rustc_span::sym::lib => CrateType::default(),
|
||||
rustc_span::sym::proc_dash_macro => CrateType::ProcMacro,
|
||||
rustc_span::sym::sdylib => CrateType::Sdylib,
|
||||
_ => return Err(()),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl std::fmt::Display for CrateType {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
match *self {
|
||||
CrateType::Executable => "bin".fmt(f),
|
||||
CrateType::Dylib => "dylib".fmt(f),
|
||||
CrateType::Rlib => "rlib".fmt(f),
|
||||
CrateType::StaticLib => "staticlib".fmt(f),
|
||||
CrateType::Cdylib => "cdylib".fmt(f),
|
||||
CrateType::ProcMacro => "proc-macro".fmt(f),
|
||||
CrateType::Sdylib => "sdylib".fmt(f),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl IntoDiagArg for CrateType {
|
||||
fn into_diag_arg(self, _: &mut Option<std::path::PathBuf>) -> DiagArgValue {
|
||||
self.to_string().into_diag_arg(&mut None)
|
||||
}
|
||||
}
|
||||
|
||||
/// Represents parsed *built-in* inert attributes.
|
||||
///
|
||||
/// ## Overview
|
||||
|
|
@ -687,6 +789,9 @@ pub enum AttributeKind {
|
|||
/// Represents `#[collapse_debuginfo]`.
|
||||
CollapseDebugInfo(CollapseMacroDebuginfo),
|
||||
|
||||
/// Represents `#[compiler_builtins]`.
|
||||
CompilerBuiltins,
|
||||
|
||||
/// Represents `#[rustc_confusables]`.
|
||||
Confusables {
|
||||
symbols: ThinVec<Symbol>,
|
||||
|
|
@ -716,6 +821,9 @@ pub enum AttributeKind {
|
|||
/// Represents `#[crate_name = ...]`
|
||||
CrateName { name: Symbol, name_span: Span, attr_span: Span },
|
||||
|
||||
/// Represents `#![crate_type = ...]`
|
||||
CrateType(ThinVec<CrateType>),
|
||||
|
||||
/// Represents `#[custom_mir]`.
|
||||
CustomMir(Option<(MirDialect, Span)>, Option<(MirPhase, Span)>, Span),
|
||||
|
||||
|
|
@ -728,9 +836,6 @@ pub enum AttributeKind {
|
|||
/// Represents [`#[deprecated]`](https://doc.rust-lang.org/stable/reference/attributes/diagnostics.html#the-deprecated-attribute).
|
||||
Deprecation { deprecation: Deprecation, span: Span },
|
||||
|
||||
/// Represents `#[rustc_do_not_implement_via_object]`.
|
||||
DoNotImplementViaObject(Span),
|
||||
|
||||
/// Represents `#[diagnostic::do_not_recommend]`.
|
||||
DoNotRecommend { attr_span: Span },
|
||||
|
||||
|
|
@ -746,6 +851,9 @@ pub enum AttributeKind {
|
|||
/// Represents `#[rustc_dummy]`.
|
||||
Dummy,
|
||||
|
||||
/// Represents `#[rustc_dyn_incompatible_trait]`.
|
||||
DynIncompatibleTrait(Span),
|
||||
|
||||
/// Implementation detail of `#[eii]`
|
||||
EiiDeclaration(EiiDecl),
|
||||
|
||||
|
|
@ -843,6 +951,12 @@ pub enum AttributeKind {
|
|||
/// Represents `#[needs_allocator]`
|
||||
NeedsAllocator,
|
||||
|
||||
/// Represents `#[needs_panic_runtime]`
|
||||
NeedsPanicRuntime,
|
||||
|
||||
/// Represents `#[no_builtins]`
|
||||
NoBuiltins,
|
||||
|
||||
/// Represents `#[no_core]`
|
||||
NoCore(Span),
|
||||
|
||||
|
|
@ -873,12 +987,18 @@ pub enum AttributeKind {
|
|||
/// Represents `#[optimize(size|speed)]`
|
||||
Optimize(OptimizeAttr, Span),
|
||||
|
||||
/// Represents `#[panic_runtime]`
|
||||
PanicRuntime,
|
||||
|
||||
/// Represents `#[rustc_paren_sugar]`.
|
||||
ParenSugar(Span),
|
||||
|
||||
/// Represents `#[rustc_pass_by_value]` (used by the `rustc_pass_by_value` lint).
|
||||
PassByValue(Span),
|
||||
|
||||
/// Represents `#[patchable_function_entry]`
|
||||
PatchableFunctionEntry { prefix: u8, entry: u8 },
|
||||
|
||||
/// Represents `#[path]`
|
||||
Path(Symbol, Span),
|
||||
|
||||
|
|
@ -900,6 +1020,9 @@ pub enum AttributeKind {
|
|||
/// Represents `#[proc_macro_derive]`
|
||||
ProcMacroDerive { trait_name: Symbol, helper_attrs: ThinVec<Symbol>, span: Span },
|
||||
|
||||
/// Represents `#[profiler_runtime]`
|
||||
ProfilerRuntime,
|
||||
|
||||
/// Represents `#[rustc_pub_transparent]` (used by the `repr_transparent_external_private_fields` lint).
|
||||
PubTransparent(Span),
|
||||
|
||||
|
|
@ -1007,6 +1130,12 @@ pub enum AttributeKind {
|
|||
/// Represents `#[rustc_simd_monomorphize_lane_limit = "N"]`.
|
||||
RustcSimdMonomorphizeLaneLimit(Limit),
|
||||
|
||||
/// Represents `#[rustc_variance]`
|
||||
RustcVariance,
|
||||
|
||||
/// Represents `#[rustc_variance_of_opaques]`
|
||||
RustcVarianceOfOpaques,
|
||||
|
||||
/// Represents `#[sanitize]`
|
||||
///
|
||||
/// the on set and off set are distjoint since there's a third option: unset.
|
||||
|
|
|
|||
|
|
@ -32,6 +32,7 @@ impl AttributeKind {
|
|||
Coinductive(..) => No,
|
||||
Cold(..) => No,
|
||||
CollapseDebugInfo(..) => Yes,
|
||||
CompilerBuiltins => No,
|
||||
Confusables { .. } => Yes,
|
||||
ConstContinue(..) => No,
|
||||
ConstStability { .. } => Yes,
|
||||
|
|
@ -39,15 +40,16 @@ impl AttributeKind {
|
|||
Coroutine(..) => No,
|
||||
Coverage(..) => No,
|
||||
CrateName { .. } => No,
|
||||
CrateType(_) => No,
|
||||
CustomMir(_, _, _) => Yes,
|
||||
DebuggerVisualizer(..) => No,
|
||||
DenyExplicitImpl(..) => No,
|
||||
Deprecation { .. } => Yes,
|
||||
DoNotImplementViaObject(..) => No,
|
||||
DoNotRecommend { .. } => Yes,
|
||||
Doc(_) => Yes,
|
||||
DocComment { .. } => Yes,
|
||||
Dummy => No,
|
||||
DynIncompatibleTrait(..) => No,
|
||||
EiiDeclaration(_) => Yes,
|
||||
EiiForeignItem => No,
|
||||
EiiImpls(..) => No,
|
||||
|
|
@ -76,6 +78,8 @@ impl AttributeKind {
|
|||
MustUse { .. } => Yes,
|
||||
Naked(..) => No,
|
||||
NeedsAllocator => No,
|
||||
NeedsPanicRuntime => No,
|
||||
NoBuiltins => Yes,
|
||||
NoCore(..) => No,
|
||||
NoImplicitPrelude(..) => No,
|
||||
NoLink => No,
|
||||
|
|
@ -86,8 +90,10 @@ impl AttributeKind {
|
|||
ObjcClass { .. } => No,
|
||||
ObjcSelector { .. } => No,
|
||||
Optimize(..) => No,
|
||||
PanicRuntime => No,
|
||||
ParenSugar(..) => No,
|
||||
PassByValue(..) => Yes,
|
||||
PatchableFunctionEntry { .. } => Yes,
|
||||
Path(..) => No,
|
||||
PatternComplexityLimit { .. } => No,
|
||||
PinV2(..) => Yes,
|
||||
|
|
@ -95,6 +101,7 @@ impl AttributeKind {
|
|||
ProcMacro(..) => No,
|
||||
ProcMacroAttribute(..) => No,
|
||||
ProcMacroDerive { .. } => No,
|
||||
ProfilerRuntime => No,
|
||||
PubTransparent(..) => Yes,
|
||||
RecursionLimit { .. } => No,
|
||||
Repr { .. } => No,
|
||||
|
|
@ -129,6 +136,8 @@ impl AttributeKind {
|
|||
RustcScalableVector { .. } => Yes,
|
||||
RustcShouldNotBeCalledOnConstItems(..) => Yes,
|
||||
RustcSimdMonomorphizeLaneLimit(..) => Yes, // Affects layout computation, which needs to work cross-crate
|
||||
RustcVariance => No,
|
||||
RustcVarianceOfOpaques => No,
|
||||
Sanitize { .. } => No,
|
||||
ShouldPanic { .. } => No,
|
||||
SkipDuringMethodDispatch { .. } => No,
|
||||
|
|
|
|||
|
|
@ -171,7 +171,7 @@ macro_rules! print_tup {
|
|||
|
||||
print_tup!(A B C D E F G H);
|
||||
print_skip!(Span, (), ErrorGuaranteed);
|
||||
print_disp!(u16, u128, usize, bool, NonZero<u32>, Limit);
|
||||
print_disp!(u8, u16, u128, usize, bool, NonZero<u32>, Limit);
|
||||
print_debug!(
|
||||
Symbol,
|
||||
Ident,
|
||||
|
|
|
|||
|
|
@ -171,6 +171,7 @@ impl Target {
|
|||
ast::ItemKind::Use(..) => Target::Use,
|
||||
ast::ItemKind::Static { .. } => Target::Static,
|
||||
ast::ItemKind::Const(..) => Target::Const,
|
||||
ast::ItemKind::ConstBlock(..) => Target::Const,
|
||||
ast::ItemKind::Fn { .. } => Target::Fn,
|
||||
ast::ItemKind::Mod(..) => Target::Mod,
|
||||
ast::ItemKind::ForeignMod { .. } => Target::ForeignMod,
|
||||
|
|
|
|||
|
|
@ -165,6 +165,11 @@ hir_analysis_drop_impl_reservation = reservation `Drop` impls are not supported
|
|||
hir_analysis_duplicate_precise_capture = cannot capture parameter `{$name}` twice
|
||||
.label = parameter captured again here
|
||||
|
||||
hir_analysis_dyn_trait_assoc_item_binding_mentions_self =
|
||||
{$kind} binding in trait object type mentions `Self`
|
||||
.label = contains a mention of `Self`
|
||||
.binding_label = this binding mentions `Self`
|
||||
|
||||
hir_analysis_eii_with_generics =
|
||||
`{$impl_name}` cannot have generic parameters other than lifetimes
|
||||
.label = required by this attribute
|
||||
|
|
@ -330,6 +335,31 @@ hir_analysis_manual_implementation =
|
|||
hir_analysis_method_should_return_future = method should be `async` or return a future, but it is synchronous
|
||||
.note = this method is `async` so it expects a future to be returned
|
||||
|
||||
hir_analysis_missing_generic_params =
|
||||
the {$descr} {$parameterCount ->
|
||||
[one] parameter
|
||||
*[other] parameters
|
||||
} {$parameters} must be explicitly specified
|
||||
.label = {$descr} {$parameterCount ->
|
||||
[one] parameter
|
||||
*[other] parameters
|
||||
} {$parameters} must be specified for this
|
||||
.suggestion = explicitly specify the {$descr} {$parameterCount ->
|
||||
[one] parameter
|
||||
*[other] parameters
|
||||
}
|
||||
.no_suggestion_label = missing {$parameterCount ->
|
||||
[one] reference
|
||||
*[other] references
|
||||
} to {$parameters}
|
||||
.note = because the parameter {$parameterCount ->
|
||||
[one] default references
|
||||
*[other] defaults reference
|
||||
} `Self`, the {$parameterCount ->
|
||||
[one] parameter
|
||||
*[other] parameters
|
||||
} must be specified on the trait object type
|
||||
|
||||
hir_analysis_missing_one_of_trait_item = not all trait items implemented, missing one of: `{$missing_items_msg}`
|
||||
.label = missing one of `{$missing_items_msg}` in implementation
|
||||
.note = required because of this annotation
|
||||
|
|
@ -346,34 +376,6 @@ hir_analysis_missing_trait_item_unstable = not all trait items implemented, miss
|
|||
.some_note = use of unstable library feature `{$feature}`: {$reason}
|
||||
.none_note = use of unstable library feature `{$feature}`
|
||||
|
||||
hir_analysis_missing_type_params =
|
||||
the type {$parameterCount ->
|
||||
[one] parameter
|
||||
*[other] parameters
|
||||
} {$parameters} must be explicitly specified
|
||||
.label = type {$parameterCount ->
|
||||
[one] parameter
|
||||
*[other] parameters
|
||||
} {$parameters} must be specified for this
|
||||
.suggestion = set the type {$parameterCount ->
|
||||
[one] parameter
|
||||
*[other] parameters
|
||||
} to the desired {$parameterCount ->
|
||||
[one] type
|
||||
*[other] types
|
||||
}
|
||||
.no_suggestion_label = missing {$parameterCount ->
|
||||
[one] reference
|
||||
*[other] references
|
||||
} to {$parameters}
|
||||
.note = because the parameter {$parameterCount ->
|
||||
[one] default references
|
||||
*[other] defaults reference
|
||||
} `Self`, the {$parameterCount ->
|
||||
[one] parameter
|
||||
*[other] parameters
|
||||
} must be specified on the object type
|
||||
|
||||
hir_analysis_no_variant_named = no variant named `{$ident}` found for enum `{$ty}`
|
||||
|
||||
hir_analysis_not_supported_delegation = {$descr}
|
||||
|
|
@ -481,9 +483,6 @@ hir_analysis_self_in_impl_self =
|
|||
`Self` is not valid in the self type of an impl block
|
||||
.note = replace `Self` with a different type
|
||||
|
||||
hir_analysis_self_in_type_alias = `Self` is not allowed in type aliases
|
||||
.label = `Self` is only available in impls, traits, and concrete type definitions
|
||||
|
||||
hir_analysis_self_ty_not_captured = `impl Trait` must mention the `Self` type of the trait in `use<...>`
|
||||
.label = `Self` type parameter is implicitly captured by this `impl Trait`
|
||||
.note = currently, all type parameters are required to be mentioned in the precise captures list
|
||||
|
|
|
|||
|
|
@ -24,6 +24,7 @@ use rustc_middle::ty::{
|
|||
TypeVisitable, TypeVisitableExt, fold_regions,
|
||||
};
|
||||
use rustc_session::lint::builtin::UNINHABITED_STATIC;
|
||||
use rustc_span::source_map::Spanned;
|
||||
use rustc_target::spec::{AbiMap, AbiMapping};
|
||||
use rustc_trait_selection::error_reporting::InferCtxtErrorExt;
|
||||
use rustc_trait_selection::error_reporting::traits::on_unimplemented::OnUnimplementedDirective;
|
||||
|
|
@ -192,6 +193,12 @@ fn check_static_inhabited(tcx: TyCtxt<'_>, def_id: LocalDefId) {
|
|||
tcx.dcx().emit_err(errors::TooLargeStatic { span });
|
||||
return;
|
||||
}
|
||||
// SIMD types with invalid layout (e.g., zero-length) should emit an error
|
||||
Err(e @ LayoutError::InvalidSimd { .. }) => {
|
||||
let ty_span = tcx.ty_span(def_id);
|
||||
tcx.dcx().emit_err(Spanned { span: ty_span, node: e.into_diagnostic() });
|
||||
return;
|
||||
}
|
||||
// Generic statics are rejected, but we still reach this case.
|
||||
Err(e) => {
|
||||
tcx.dcx().span_delayed_bug(span, format!("{e:?}"));
|
||||
|
|
|
|||
|
|
@ -1960,7 +1960,7 @@ fn compare_generic_param_kinds<'tcx>(
|
|||
trait_item: ty::AssocItem,
|
||||
delay: bool,
|
||||
) -> Result<(), ErrorGuaranteed> {
|
||||
assert_eq!(impl_item.as_tag(), trait_item.as_tag());
|
||||
assert_eq!(impl_item.tag(), trait_item.tag());
|
||||
|
||||
let ty_const_params_of = |def_id| {
|
||||
tcx.generics_of(def_id).own_params.iter().filter(|param| {
|
||||
|
|
|
|||
|
|
@ -216,6 +216,7 @@ fn intrinsic_operation_unsafety(tcx: TyCtxt<'_>, intrinsic_id: LocalDefId) -> hi
|
|||
| sym::type_name
|
||||
| sym::type_of
|
||||
| sym::ub_checks
|
||||
| sym::va_copy
|
||||
| sym::variant_count
|
||||
| sym::vtable_for
|
||||
| sym::wrapping_add
|
||||
|
|
@ -629,14 +630,13 @@ pub(crate) fn check_intrinsic_type(
|
|||
)
|
||||
}
|
||||
|
||||
sym::va_start | sym::va_end => {
|
||||
(0, 0, vec![mk_va_list_ty(hir::Mutability::Mut).0], tcx.types.unit)
|
||||
}
|
||||
|
||||
sym::va_copy => {
|
||||
let (va_list_ref_ty, va_list_ty) = mk_va_list_ty(hir::Mutability::Not);
|
||||
let va_list_ptr_ty = Ty::new_mut_ptr(tcx, va_list_ty);
|
||||
(0, 0, vec![va_list_ptr_ty, va_list_ref_ty], tcx.types.unit)
|
||||
(0, 0, vec![va_list_ref_ty], va_list_ty)
|
||||
}
|
||||
|
||||
sym::va_start | sym::va_end => {
|
||||
(0, 0, vec![mk_va_list_ty(hir::Mutability::Mut).0], tcx.types.unit)
|
||||
}
|
||||
|
||||
sym::va_arg => (1, 0, vec![mk_va_list_ty(hir::Mutability::Mut).0], param(0)),
|
||||
|
|
@ -746,6 +746,7 @@ pub(crate) fn check_intrinsic_type(
|
|||
sym::simd_extract | sym::simd_extract_dyn => {
|
||||
(2, 0, vec![param(0), tcx.types.u32], param(1))
|
||||
}
|
||||
sym::simd_splat => (2, 0, vec![param(1)], param(0)),
|
||||
sym::simd_cast
|
||||
| sym::simd_as
|
||||
| sym::simd_cast_ptr
|
||||
|
|
|
|||
|
|
@ -211,9 +211,7 @@ fn check_object_overlap<'tcx>(
|
|||
// This is a WF error tested by `coherence-impl-trait-for-trait-dyn-compatible.rs`.
|
||||
} else {
|
||||
let mut supertrait_def_ids = elaborate::supertrait_def_ids(tcx, component_def_id);
|
||||
if supertrait_def_ids
|
||||
.any(|d| d == trait_def_id && tcx.trait_def(d).implement_via_object)
|
||||
{
|
||||
if supertrait_def_ids.any(|d| d == trait_def_id) {
|
||||
let span = tcx.def_span(impl_def_id);
|
||||
return Err(struct_span_code_err!(
|
||||
tcx.dcx(),
|
||||
|
|
|
|||
|
|
@ -924,7 +924,8 @@ fn trait_def(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::TraitDef {
|
|||
);
|
||||
|
||||
let deny_explicit_impl = find_attr!(attrs, AttributeKind::DenyExplicitImpl(_));
|
||||
let implement_via_object = !find_attr!(attrs, AttributeKind::DoNotImplementViaObject(_));
|
||||
let force_dyn_incompatible =
|
||||
find_attr!(attrs, AttributeKind::DynIncompatibleTrait(span) => *span);
|
||||
|
||||
ty::TraitDef {
|
||||
def_id: def_id.to_def_id(),
|
||||
|
|
@ -939,7 +940,7 @@ fn trait_def(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::TraitDef {
|
|||
skip_boxed_slice_during_method_dispatch,
|
||||
specialization_kind,
|
||||
must_implement_one_of,
|
||||
implement_via_object,
|
||||
force_dyn_incompatible,
|
||||
deny_explicit_impl,
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,11 +4,11 @@ use rustc_abi::ExternAbi;
|
|||
use rustc_errors::codes::*;
|
||||
use rustc_errors::{
|
||||
Applicability, Diag, DiagCtxtHandle, DiagSymbolList, Diagnostic, EmissionGuarantee, Level,
|
||||
MultiSpan,
|
||||
MultiSpan, listify,
|
||||
};
|
||||
use rustc_hir::limit::Limit;
|
||||
use rustc_macros::{Diagnostic, LintDiagnostic, Subdiagnostic};
|
||||
use rustc_middle::ty::Ty;
|
||||
use rustc_middle::ty::{self, Ty};
|
||||
use rustc_span::{Ident, Span, Symbol};
|
||||
|
||||
use crate::fluent_generated as fluent;
|
||||
|
|
@ -400,35 +400,58 @@ pub(crate) struct UnconstrainedOpaqueType {
|
|||
pub what: &'static str,
|
||||
}
|
||||
|
||||
pub(crate) struct MissingTypeParams {
|
||||
pub(crate) struct MissingGenericParams {
|
||||
pub span: Span,
|
||||
pub def_span: Span,
|
||||
pub span_snippet: Option<String>,
|
||||
pub missing_type_params: Vec<Symbol>,
|
||||
pub missing_generic_params: Vec<(Symbol, ty::GenericParamDefKind)>,
|
||||
pub empty_generic_args: bool,
|
||||
}
|
||||
|
||||
// Manual implementation of `Diagnostic` to be able to call `span_to_snippet`.
|
||||
impl<'a, G: EmissionGuarantee> Diagnostic<'a, G> for MissingTypeParams {
|
||||
// FIXME: This doesn't need to be a manual impl!
|
||||
impl<'a, G: EmissionGuarantee> Diagnostic<'a, G> for MissingGenericParams {
|
||||
#[track_caller]
|
||||
fn into_diag(self, dcx: DiagCtxtHandle<'a>, level: Level) -> Diag<'a, G> {
|
||||
let mut err = Diag::new(dcx, level, fluent::hir_analysis_missing_type_params);
|
||||
let mut err = Diag::new(dcx, level, fluent::hir_analysis_missing_generic_params);
|
||||
err.span(self.span);
|
||||
err.code(E0393);
|
||||
err.arg("parameterCount", self.missing_type_params.len());
|
||||
err.arg(
|
||||
"parameters",
|
||||
self.missing_type_params
|
||||
.iter()
|
||||
.map(|n| format!("`{n}`"))
|
||||
.collect::<Vec<_>>()
|
||||
.join(", "),
|
||||
);
|
||||
|
||||
err.span_label(self.def_span, fluent::hir_analysis_label);
|
||||
|
||||
enum Descr {
|
||||
Generic,
|
||||
Type,
|
||||
Const,
|
||||
}
|
||||
|
||||
let mut descr = None;
|
||||
for (_, kind) in &self.missing_generic_params {
|
||||
descr = match (&descr, kind) {
|
||||
(None, ty::GenericParamDefKind::Type { .. }) => Some(Descr::Type),
|
||||
(None, ty::GenericParamDefKind::Const { .. }) => Some(Descr::Const),
|
||||
(Some(Descr::Type), ty::GenericParamDefKind::Const { .. })
|
||||
| (Some(Descr::Const), ty::GenericParamDefKind::Type { .. }) => {
|
||||
Some(Descr::Generic)
|
||||
}
|
||||
_ => continue,
|
||||
}
|
||||
}
|
||||
|
||||
err.arg(
|
||||
"descr",
|
||||
match descr.unwrap() {
|
||||
Descr::Generic => "generic",
|
||||
Descr::Type => "type",
|
||||
Descr::Const => "const",
|
||||
},
|
||||
);
|
||||
err.arg("parameterCount", self.missing_generic_params.len());
|
||||
err.arg(
|
||||
"parameters",
|
||||
listify(&self.missing_generic_params, |(n, _)| format!("`{n}`")).unwrap(),
|
||||
);
|
||||
|
||||
let mut suggested = false;
|
||||
// Don't suggest setting the type params if there are some already: the order is
|
||||
// Don't suggest setting the generic params if there are some already: The order is
|
||||
// tricky to get right and the user will already know what the syntax is.
|
||||
if let Some(snippet) = self.span_snippet
|
||||
&& self.empty_generic_args
|
||||
|
|
@ -438,16 +461,16 @@ impl<'a, G: EmissionGuarantee> Diagnostic<'a, G> for MissingTypeParams {
|
|||
// we would have to preserve the right order. For now, as clearly the user is
|
||||
// aware of the syntax, we do nothing.
|
||||
} else {
|
||||
// The user wrote `Iterator`, so we don't have a type we can suggest, but at
|
||||
// least we can clue them to the correct syntax `Iterator<Type>`.
|
||||
// The user wrote `Trait`, so we don't have a type we can suggest, but at
|
||||
// least we can clue them to the correct syntax `Trait</* Term */>`.
|
||||
err.span_suggestion_verbose(
|
||||
self.span.shrink_to_hi(),
|
||||
fluent::hir_analysis_suggestion,
|
||||
format!(
|
||||
"<{}>",
|
||||
self.missing_type_params
|
||||
self.missing_generic_params
|
||||
.iter()
|
||||
.map(|n| n.to_string())
|
||||
.map(|(n, _)| format!("/* {n} */"))
|
||||
.collect::<Vec<_>>()
|
||||
.join(", ")
|
||||
),
|
||||
|
|
@ -1609,11 +1632,14 @@ pub(crate) enum SupertraitItemShadowee {
|
|||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(hir_analysis_self_in_type_alias, code = E0411)]
|
||||
pub(crate) struct SelfInTypeAlias {
|
||||
#[diag(hir_analysis_dyn_trait_assoc_item_binding_mentions_self)]
|
||||
pub(crate) struct DynTraitAssocItemBindingMentionsSelf {
|
||||
#[primary_span]
|
||||
#[label]
|
||||
pub span: Span,
|
||||
pub kind: &'static str,
|
||||
#[label(hir_analysis_binding_label)]
|
||||
pub binding: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
|
|
|
|||
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