commit
c2aeeaf19d
625 changed files with 10776 additions and 6209 deletions
|
|
@ -4630,7 +4630,6 @@ dependencies = [
|
|||
name = "rustc_session"
|
||||
version = "0.0.0"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"getopts",
|
||||
"libc",
|
||||
"rand 0.9.2",
|
||||
|
|
@ -4657,6 +4656,7 @@ dependencies = [
|
|||
name = "rustc_span"
|
||||
version = "0.0.0"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"blake3",
|
||||
"derive-where",
|
||||
"indexmap",
|
||||
|
|
|
|||
|
|
@ -191,6 +191,31 @@
|
|||
# Currently, this is only supported for the `x86_64-unknown-linux-gnu` target.
|
||||
#gcc.download-ci-gcc = false
|
||||
|
||||
# Provide a directory of prebuilt libgccjit.so dylibs for given (host, target) compilation pairs.
|
||||
# This is useful when you want to cross-compile `rustc` to another target since GCC is not a
|
||||
# multi-target compiler.
|
||||
# You have to use a directory structure that looks like this:
|
||||
# `<libgccjit-libs-dir>/<host>/<target>/libgccjit.so`.
|
||||
# For example:
|
||||
#
|
||||
# ```
|
||||
# <libgccjit-libs-dir>
|
||||
# ├── m68k-unknown-linux-gnu
|
||||
# │ └── m68k-unknown-linux-gnu
|
||||
# │ └── libgccjit.so
|
||||
# └── x86_64-unknown-linux-gnu
|
||||
# ├── m68k-unknown-linux-gnu
|
||||
# │ └── libgccjit.so
|
||||
# └── x86_64-unknown-linux-gnu
|
||||
# └── libgccjit.so
|
||||
# ```
|
||||
# The directory above would allow you to cross-compile rustc from x64 to m68k
|
||||
#
|
||||
# Note that this option has priority over `gcc.download-ci-gcc`.
|
||||
# If you set both, bootstrap will first try to load libgccjit.so from this directory.
|
||||
# Only if it isn't found, it will try to download it from CI or build it locally.
|
||||
#gcc.libgccjit-libs-dir = "/path/to/libgccjit-libs-dir"
|
||||
|
||||
# =============================================================================
|
||||
# General build configuration options
|
||||
# =============================================================================
|
||||
|
|
|
|||
|
|
@ -2107,6 +2107,19 @@ pub struct MacroDef {
|
|||
pub body: Box<DelimArgs>,
|
||||
/// `true` if macro was defined with `macro_rules`.
|
||||
pub macro_rules: bool,
|
||||
|
||||
/// If this is a macro used for externally implementable items,
|
||||
/// it refers to an extern item which is its "target". This requires
|
||||
/// name resolution so can't just be an attribute, so we store it in this field.
|
||||
pub eii_extern_target: Option<EiiExternTarget>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Encodable, Decodable, Debug, HashStable_Generic, Walkable)]
|
||||
pub struct EiiExternTarget {
|
||||
/// path to the extern item we're targetting
|
||||
pub extern_item_path: Path,
|
||||
pub impl_unsafe: bool,
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(Clone, Encodable, Decodable, Debug, Copy, Hash, Eq, PartialEq)]
|
||||
|
|
@ -3746,6 +3759,21 @@ pub struct Fn {
|
|||
pub contract: Option<Box<FnContract>>,
|
||||
pub define_opaque: Option<ThinVec<(NodeId, Path)>>,
|
||||
pub body: Option<Box<Block>>,
|
||||
|
||||
/// This function is an implementation of an externally implementable item (EII).
|
||||
/// This means, there was an EII declared somewhere and this function is the
|
||||
/// implementation that should be run when the declaration is called.
|
||||
pub eii_impls: ThinVec<EiiImpl>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Encodable, Decodable, Debug, Walkable)]
|
||||
pub struct EiiImpl {
|
||||
pub node_id: NodeId,
|
||||
pub eii_macro_path: Path,
|
||||
pub impl_safety: Safety,
|
||||
pub span: Span,
|
||||
pub inner_span: Span,
|
||||
pub is_default: bool,
|
||||
}
|
||||
|
||||
#[derive(Clone, Encodable, Decodable, Debug, Walkable)]
|
||||
|
|
@ -4112,7 +4140,7 @@ mod size_asserts {
|
|||
static_assert_size!(Block, 32);
|
||||
static_assert_size!(Expr, 72);
|
||||
static_assert_size!(ExprKind, 40);
|
||||
static_assert_size!(Fn, 184);
|
||||
static_assert_size!(Fn, 192);
|
||||
static_assert_size!(ForeignItem, 80);
|
||||
static_assert_size!(ForeignItemKind, 16);
|
||||
static_assert_size!(GenericArg, 24);
|
||||
|
|
|
|||
|
|
@ -393,6 +393,7 @@ macro_rules! common_visitor_and_walkers {
|
|||
ThinVec<Pat>,
|
||||
ThinVec<Box<Ty>>,
|
||||
ThinVec<TyPat>,
|
||||
ThinVec<EiiImpl>,
|
||||
);
|
||||
|
||||
// This macro generates `impl Visitable` and `impl MutVisitable` that forward to `Walkable`
|
||||
|
|
@ -486,6 +487,8 @@ macro_rules! common_visitor_and_walkers {
|
|||
WhereEqPredicate,
|
||||
WhereRegionPredicate,
|
||||
YieldKind,
|
||||
EiiExternTarget,
|
||||
EiiImpl,
|
||||
);
|
||||
|
||||
/// Each method of this trait is a hook to be potentially
|
||||
|
|
@ -920,13 +923,13 @@ macro_rules! common_visitor_and_walkers {
|
|||
_ctxt,
|
||||
// Visibility is visited as a part of the item.
|
||||
_vis,
|
||||
Fn { defaultness, ident, sig, generics, contract, body, define_opaque },
|
||||
Fn { defaultness, ident, sig, generics, contract, body, define_opaque, eii_impls },
|
||||
) => {
|
||||
let FnSig { header, decl, span } = sig;
|
||||
visit_visitable!($($mut)? vis,
|
||||
defaultness, ident, header, generics, decl,
|
||||
contract, body, span, define_opaque
|
||||
)
|
||||
contract, body, span, define_opaque, eii_impls
|
||||
);
|
||||
}
|
||||
FnKind::Closure(binder, coroutine_kind, decl, body) =>
|
||||
visit_visitable!($($mut)? vis, binder, coroutine_kind, decl, body),
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ use rustc_abi::ExternAbi;
|
|||
use rustc_ast::visit::AssocCtxt;
|
||||
use rustc_ast::*;
|
||||
use rustc_errors::{E0570, ErrorGuaranteed, struct_span_code_err};
|
||||
use rustc_hir::attrs::AttributeKind;
|
||||
use rustc_hir::attrs::{AttributeKind, EiiDecl};
|
||||
use rustc_hir::def::{DefKind, PerNS, Res};
|
||||
use rustc_hir::def_id::{CRATE_DEF_ID, LocalDefId};
|
||||
use rustc_hir::{
|
||||
|
|
@ -11,6 +11,7 @@ use rustc_hir::{
|
|||
use rustc_index::{IndexSlice, IndexVec};
|
||||
use rustc_middle::span_bug;
|
||||
use rustc_middle::ty::{ResolverAstLowering, TyCtxt};
|
||||
use rustc_span::def_id::DefId;
|
||||
use rustc_span::edit_distance::find_best_match_for_name;
|
||||
use rustc_span::{DUMMY_SP, DesugaringKind, Ident, Span, Symbol, kw, sym};
|
||||
use smallvec::{SmallVec, smallvec};
|
||||
|
|
@ -133,10 +134,92 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
}
|
||||
}
|
||||
|
||||
fn generate_extra_attrs_for_item_kind(
|
||||
&mut self,
|
||||
id: NodeId,
|
||||
i: &ItemKind,
|
||||
) -> Vec<hir::Attribute> {
|
||||
match i {
|
||||
ItemKind::Fn(box Fn { eii_impls, .. }) if eii_impls.is_empty() => Vec::new(),
|
||||
ItemKind::Fn(box Fn { eii_impls, .. }) => {
|
||||
vec![hir::Attribute::Parsed(AttributeKind::EiiImpls(
|
||||
eii_impls
|
||||
.iter()
|
||||
.flat_map(
|
||||
|EiiImpl {
|
||||
node_id,
|
||||
eii_macro_path,
|
||||
impl_safety,
|
||||
span,
|
||||
inner_span,
|
||||
is_default,
|
||||
}| {
|
||||
self.lower_path_simple_eii(*node_id, eii_macro_path).map(|did| {
|
||||
hir::attrs::EiiImpl {
|
||||
eii_macro: did,
|
||||
span: self.lower_span(*span),
|
||||
inner_span: self.lower_span(*inner_span),
|
||||
impl_marked_unsafe: self
|
||||
.lower_safety(*impl_safety, hir::Safety::Safe)
|
||||
.is_unsafe(),
|
||||
is_default: *is_default,
|
||||
}
|
||||
})
|
||||
},
|
||||
)
|
||||
.collect(),
|
||||
))]
|
||||
}
|
||||
ItemKind::MacroDef(
|
||||
_,
|
||||
MacroDef {
|
||||
eii_extern_target: Some(EiiExternTarget { extern_item_path, impl_unsafe, span }),
|
||||
..
|
||||
},
|
||||
) => self
|
||||
.lower_path_simple_eii(id, extern_item_path)
|
||||
.map(|did| {
|
||||
vec![hir::Attribute::Parsed(AttributeKind::EiiExternTarget(EiiDecl {
|
||||
eii_extern_target: did,
|
||||
impl_unsafe: *impl_unsafe,
|
||||
span: self.lower_span(*span),
|
||||
}))]
|
||||
})
|
||||
.unwrap_or_default(),
|
||||
ItemKind::ExternCrate(..)
|
||||
| ItemKind::Use(..)
|
||||
| ItemKind::Static(..)
|
||||
| ItemKind::Const(..)
|
||||
| ItemKind::Mod(..)
|
||||
| ItemKind::ForeignMod(..)
|
||||
| ItemKind::GlobalAsm(..)
|
||||
| ItemKind::TyAlias(..)
|
||||
| ItemKind::Enum(..)
|
||||
| ItemKind::Struct(..)
|
||||
| ItemKind::Union(..)
|
||||
| ItemKind::Trait(..)
|
||||
| ItemKind::TraitAlias(..)
|
||||
| ItemKind::Impl(..)
|
||||
| ItemKind::MacCall(..)
|
||||
| ItemKind::MacroDef(..)
|
||||
| ItemKind::Delegation(..)
|
||||
| ItemKind::DelegationMac(..) => Vec::new(),
|
||||
}
|
||||
}
|
||||
|
||||
fn lower_item(&mut self, i: &Item) -> &'hir hir::Item<'hir> {
|
||||
let vis_span = self.lower_span(i.vis.span);
|
||||
let hir_id = hir::HirId::make_owner(self.current_hir_id_owner.def_id);
|
||||
let attrs = self.lower_attrs(hir_id, &i.attrs, i.span, Target::from_ast_item(i));
|
||||
|
||||
let extra_hir_attributes = self.generate_extra_attrs_for_item_kind(i.id, &i.kind);
|
||||
let attrs = self.lower_attrs_with_extra(
|
||||
hir_id,
|
||||
&i.attrs,
|
||||
i.span,
|
||||
Target::from_ast_item(i),
|
||||
&extra_hir_attributes,
|
||||
);
|
||||
|
||||
let kind = self.lower_item_kind(i.span, i.id, hir_id, attrs, vis_span, &i.kind);
|
||||
let item = hir::Item {
|
||||
owner_id: hir_id.expect_owner(),
|
||||
|
|
@ -144,6 +227,10 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
vis_span,
|
||||
span: self.lower_span(i.span),
|
||||
has_delayed_lints: !self.delayed_lints.is_empty(),
|
||||
eii: find_attr!(
|
||||
attrs,
|
||||
AttributeKind::EiiImpls(..) | AttributeKind::EiiExternTarget(..)
|
||||
),
|
||||
};
|
||||
self.arena.alloc(item)
|
||||
}
|
||||
|
|
@ -435,7 +522,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
);
|
||||
hir::ItemKind::TraitAlias(constness, ident, generics, bounds)
|
||||
}
|
||||
ItemKind::MacroDef(ident, MacroDef { body, macro_rules }) => {
|
||||
ItemKind::MacroDef(ident, MacroDef { body, macro_rules, eii_extern_target: _ }) => {
|
||||
let ident = self.lower_ident(*ident);
|
||||
let body = Box::new(self.lower_delim_args(body));
|
||||
let def_id = self.local_def_id(id);
|
||||
|
|
@ -446,7 +533,11 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
def_kind.descr(def_id.to_def_id())
|
||||
);
|
||||
};
|
||||
let macro_def = self.arena.alloc(ast::MacroDef { body, macro_rules: *macro_rules });
|
||||
let macro_def = self.arena.alloc(ast::MacroDef {
|
||||
body,
|
||||
macro_rules: *macro_rules,
|
||||
eii_extern_target: None,
|
||||
});
|
||||
hir::ItemKind::Macro(ident, macro_def, macro_kinds)
|
||||
}
|
||||
ItemKind::Delegation(box delegation) => {
|
||||
|
|
@ -465,6 +556,16 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
}
|
||||
}
|
||||
|
||||
fn lower_path_simple_eii(&mut self, id: NodeId, path: &Path) -> Option<DefId> {
|
||||
let res = self.resolver.get_partial_res(id)?;
|
||||
let Some(did) = res.expect_full_res().opt_def_id() else {
|
||||
self.dcx().span_delayed_bug(path.span, "should have errored in resolve");
|
||||
return None;
|
||||
};
|
||||
|
||||
Some(did)
|
||||
}
|
||||
|
||||
#[instrument(level = "debug", skip(self))]
|
||||
fn lower_use_tree(
|
||||
&mut self,
|
||||
|
|
@ -573,6 +674,10 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
vis_span,
|
||||
span: this.lower_span(use_tree.span),
|
||||
has_delayed_lints: !this.delayed_lints.is_empty(),
|
||||
eii: find_attr!(
|
||||
attrs,
|
||||
AttributeKind::EiiImpls(..) | AttributeKind::EiiExternTarget(..)
|
||||
),
|
||||
};
|
||||
hir::OwnerNode::Item(this.arena.alloc(item))
|
||||
});
|
||||
|
|
|
|||
|
|
@ -971,11 +971,23 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
target_span: Span,
|
||||
target: Target,
|
||||
) -> &'hir [hir::Attribute] {
|
||||
if attrs.is_empty() {
|
||||
self.lower_attrs_with_extra(id, attrs, target_span, target, &[])
|
||||
}
|
||||
|
||||
fn lower_attrs_with_extra(
|
||||
&mut self,
|
||||
id: HirId,
|
||||
attrs: &[Attribute],
|
||||
target_span: Span,
|
||||
target: Target,
|
||||
extra_hir_attributes: &[hir::Attribute],
|
||||
) -> &'hir [hir::Attribute] {
|
||||
if attrs.is_empty() && extra_hir_attributes.is_empty() {
|
||||
&[]
|
||||
} else {
|
||||
let lowered_attrs =
|
||||
let mut lowered_attrs =
|
||||
self.lower_attrs_vec(attrs, self.lower_span(target_span), id, target);
|
||||
lowered_attrs.extend(extra_hir_attributes.iter().cloned());
|
||||
|
||||
assert_eq!(id.owner, self.current_hir_id_owner);
|
||||
let ret = self.arena.alloc_from_iter(lowered_attrs);
|
||||
|
|
|
|||
|
|
@ -1179,11 +1179,16 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
|
|||
contract: _,
|
||||
body,
|
||||
define_opaque: _,
|
||||
eii_impls,
|
||||
},
|
||||
) => {
|
||||
self.visit_attrs_vis_ident(&item.attrs, &item.vis, ident);
|
||||
self.check_defaultness(item.span, *defaultness);
|
||||
|
||||
for EiiImpl { eii_macro_path, .. } in eii_impls {
|
||||
self.visit_path(eii_macro_path);
|
||||
}
|
||||
|
||||
let is_intrinsic = item.attrs.iter().any(|a| a.has_name(sym::rustc_intrinsic));
|
||||
if body.is_none() && !is_intrinsic && !self.is_sdylib_interface {
|
||||
self.dcx().emit_err(errors::FnWithoutBody {
|
||||
|
|
|
|||
|
|
@ -865,6 +865,17 @@ pub trait PrintState<'a>: std::ops::Deref<Target = pp::Printer> + std::ops::Dere
|
|||
sp: Span,
|
||||
print_visibility: impl FnOnce(&mut Self),
|
||||
) {
|
||||
if let Some(eii_extern_target) = ¯o_def.eii_extern_target {
|
||||
self.word("#[eii_extern_target(");
|
||||
self.print_path(&eii_extern_target.extern_item_path, false, 0);
|
||||
if eii_extern_target.impl_unsafe {
|
||||
self.word(",");
|
||||
self.space();
|
||||
self.word("unsafe");
|
||||
}
|
||||
self.word(")]");
|
||||
self.hardbreak();
|
||||
}
|
||||
let (kw, has_bang) = if macro_def.macro_rules {
|
||||
("macro_rules", true)
|
||||
} else {
|
||||
|
|
@ -2162,6 +2173,15 @@ impl<'a> State<'a> {
|
|||
|
||||
fn print_meta_item(&mut self, item: &ast::MetaItem) {
|
||||
let ib = self.ibox(INDENT_UNIT);
|
||||
|
||||
match item.unsafety {
|
||||
ast::Safety::Unsafe(_) => {
|
||||
self.word("unsafe");
|
||||
self.popen();
|
||||
}
|
||||
ast::Safety::Default | ast::Safety::Safe(_) => {}
|
||||
}
|
||||
|
||||
match &item.kind {
|
||||
ast::MetaItemKind::Word => self.print_path(&item.path, false, 0),
|
||||
ast::MetaItemKind::NameValue(value) => {
|
||||
|
|
@ -2177,6 +2197,12 @@ impl<'a> State<'a> {
|
|||
self.pclose();
|
||||
}
|
||||
}
|
||||
|
||||
match item.unsafety {
|
||||
ast::Safety::Unsafe(_) => self.pclose(),
|
||||
ast::Safety::Default | ast::Safety::Safe(_) => {}
|
||||
}
|
||||
|
||||
self.end(ib);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
use ast::StaticItem;
|
||||
use itertools::{Itertools, Position};
|
||||
use rustc_ast::{self as ast, ModKind, TraitAlias};
|
||||
use rustc_ast::{self as ast, EiiImpl, ModKind, Safety, TraitAlias};
|
||||
use rustc_span::Ident;
|
||||
|
||||
use crate::pp::BoxMarker;
|
||||
|
|
@ -671,10 +671,25 @@ impl<'a> State<'a> {
|
|||
}
|
||||
|
||||
fn print_fn_full(&mut self, vis: &ast::Visibility, attrs: &[ast::Attribute], func: &ast::Fn) {
|
||||
let ast::Fn { defaultness, ident, generics, sig, contract, body, define_opaque } = func;
|
||||
let ast::Fn { defaultness, ident, generics, sig, contract, body, define_opaque, eii_impls } =
|
||||
func;
|
||||
|
||||
self.print_define_opaques(define_opaque.as_deref());
|
||||
|
||||
for EiiImpl { eii_macro_path, impl_safety, .. } in eii_impls {
|
||||
self.word("#[");
|
||||
if let Safety::Unsafe(..) = impl_safety {
|
||||
self.word("unsafe");
|
||||
self.popen();
|
||||
}
|
||||
self.print_path(eii_macro_path, false, 0);
|
||||
if let Safety::Unsafe(..) = impl_safety {
|
||||
self.pclose();
|
||||
}
|
||||
self.word("]");
|
||||
self.hardbreak();
|
||||
}
|
||||
|
||||
let body_cb_ib = body.as_ref().map(|body| (body, self.head("")));
|
||||
|
||||
self.print_visibility(vis);
|
||||
|
|
|
|||
|
|
@ -50,11 +50,6 @@ attr_parsing_expects_feature_list =
|
|||
attr_parsing_expects_features =
|
||||
`{$name}` expects feature names
|
||||
|
||||
attr_parsing_ill_formed_attribute_input = {$num_suggestions ->
|
||||
[1] attribute must be of the form {$suggestions}
|
||||
*[other] valid forms for the attribute are {$suggestions}
|
||||
}
|
||||
|
||||
attr_parsing_import_name_type_raw =
|
||||
import name type can only be used with link kind `raw-dylib`
|
||||
|
||||
|
|
@ -213,10 +208,6 @@ attr_parsing_stability_outside_std = stability attributes may not be used outsid
|
|||
attr_parsing_suffixed_literal_in_attribute = suffixed literals are not allowed in attributes
|
||||
.help = instead of using a suffixed literal (`1u8`, `1.0f32`, etc.), use an unsuffixed version (`1`, `1.0`, etc.)
|
||||
|
||||
attr_parsing_unknown_meta_item =
|
||||
unknown meta item '{$item}'
|
||||
.label = expected one of {$expected}
|
||||
|
||||
attr_parsing_unknown_version_literal =
|
||||
unknown version literal format, assuming it refers to a future version
|
||||
|
||||
|
|
|
|||
|
|
@ -42,7 +42,7 @@ pub fn parse_cfg<S: Stage>(
|
|||
args: &ArgParser,
|
||||
) -> Option<CfgEntry> {
|
||||
let ArgParser::List(list) = args else {
|
||||
cx.expected_list(cx.attr_span);
|
||||
cx.expected_list(cx.attr_span, args);
|
||||
return None;
|
||||
};
|
||||
let Some(single) = list.single() else {
|
||||
|
|
|
|||
|
|
@ -25,7 +25,7 @@ impl<S: Stage> SingleAttributeParser<S> for OptimizeParser {
|
|||
|
||||
fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option<AttributeKind> {
|
||||
let Some(list) = args.list() else {
|
||||
cx.expected_list(cx.attr_span);
|
||||
cx.expected_list(cx.attr_span, args);
|
||||
return None;
|
||||
};
|
||||
|
||||
|
|
@ -478,7 +478,7 @@ fn parse_tf_attribute<S: Stage>(
|
|||
) -> impl IntoIterator<Item = (Symbol, Span)> {
|
||||
let mut features = Vec::new();
|
||||
let ArgParser::List(list) = args else {
|
||||
cx.expected_list(cx.attr_span);
|
||||
cx.expected_list(cx.attr_span, args);
|
||||
return features;
|
||||
};
|
||||
if list.is_empty() {
|
||||
|
|
@ -601,7 +601,7 @@ impl<S: Stage> SingleAttributeParser<S> for SanitizeParser {
|
|||
|
||||
fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option<AttributeKind> {
|
||||
let Some(list) = args.list() else {
|
||||
cx.expected_list(cx.attr_span);
|
||||
cx.expected_list(cx.attr_span, args);
|
||||
return None;
|
||||
};
|
||||
|
||||
|
|
@ -699,3 +699,12 @@ impl<S: Stage> NoArgsAttributeParser<S> for RustcPassIndirectlyInNonRusticAbisPa
|
|||
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Struct)]);
|
||||
const CREATE: fn(Span) -> AttributeKind = AttributeKind::RustcPassIndirectlyInNonRusticAbis;
|
||||
}
|
||||
|
||||
pub(crate) struct EiiExternItemParser;
|
||||
|
||||
impl<S: Stage> NoArgsAttributeParser<S> for EiiExternItemParser {
|
||||
const PATH: &[Symbol] = &[sym::rustc_eii_extern_item];
|
||||
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
|
||||
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::ForeignFn)]);
|
||||
const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::EiiExternItem;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@ impl<S: Stage> AttributeParser<S> for ConfusablesParser {
|
|||
template!(List: &[r#""name1", "name2", ..."#]),
|
||||
|this, cx, args| {
|
||||
let Some(list) = args.list() else {
|
||||
cx.expected_list(cx.attr_span);
|
||||
cx.expected_list(cx.attr_span, args);
|
||||
return;
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@ impl<S: Stage> CombineAttributeParser<S> for DebuggerViualizerParser {
|
|||
args: &ArgParser,
|
||||
) -> impl IntoIterator<Item = Self::Item> {
|
||||
let Some(l) = args.list() else {
|
||||
cx.expected_list(args.span().unwrap_or(cx.attr_span));
|
||||
cx.expected_list(cx.attr_span, args);
|
||||
return None;
|
||||
};
|
||||
let Some(single) = l.single() else {
|
||||
|
|
|
|||
|
|
@ -110,13 +110,12 @@ impl<S: Stage> SingleAttributeParser<S> for DeprecationParser {
|
|||
Some(get(cx, name, param.span(), param.args(), &suggestion)?);
|
||||
}
|
||||
_ => {
|
||||
cx.unknown_key(
|
||||
cx.expected_specific_argument(
|
||||
param.span(),
|
||||
param.path().to_string(),
|
||||
if features.deprecated_suggestion() {
|
||||
&["since", "note", "suggestion"]
|
||||
&[sym::since, sym::note, sym::suggestion]
|
||||
} else {
|
||||
&["since", "note"]
|
||||
&[sym::since, sym::note]
|
||||
},
|
||||
);
|
||||
return None;
|
||||
|
|
|
|||
|
|
@ -106,7 +106,7 @@ impl DocParser {
|
|||
}
|
||||
Some(sym::attr) => {
|
||||
let Some(list) = args.list() else {
|
||||
cx.expected_list(cx.attr_span);
|
||||
cx.expected_list(cx.attr_span, args);
|
||||
return;
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -76,7 +76,7 @@ impl<S: Stage> CombineAttributeParser<S> for LinkParser {
|
|||
return None;
|
||||
}
|
||||
_ => {
|
||||
cx.expected_list(cx.attr_span);
|
||||
cx.expected_list(cx.attr_span, args);
|
||||
return None;
|
||||
}
|
||||
};
|
||||
|
|
@ -379,7 +379,7 @@ impl LinkParser {
|
|||
return true;
|
||||
}
|
||||
let Some(link_cfg) = item.args().list() else {
|
||||
cx.expected_list(item.span());
|
||||
cx.expected_list(item.span(), item.args());
|
||||
return true;
|
||||
};
|
||||
let Some(link_cfg) = link_cfg.single() else {
|
||||
|
|
|
|||
|
|
@ -1,9 +1,7 @@
|
|||
use rustc_errors::DiagArgValue;
|
||||
use rustc_hir::attrs::MacroUseArgs;
|
||||
use rustc_session::lint::builtin::INVALID_MACRO_EXPORT_ARGUMENTS;
|
||||
|
||||
use super::prelude::*;
|
||||
use crate::session_diagnostics::IllFormedAttributeInputLint;
|
||||
|
||||
pub(crate) struct MacroEscapeParser;
|
||||
impl<S: Stage> NoArgsAttributeParser<S> for MacroEscapeParser {
|
||||
|
|
@ -101,15 +99,8 @@ impl<S: Stage> AttributeParser<S> for MacroUseParser {
|
|||
}
|
||||
}
|
||||
}
|
||||
ArgParser::NameValue(_) => {
|
||||
let suggestions = cx.suggestions();
|
||||
cx.emit_err(IllFormedAttributeInputLint {
|
||||
num_suggestions: suggestions.len(),
|
||||
suggestions: DiagArgValue::StrListSepByAnd(
|
||||
suggestions.into_iter().map(|s| format!("`{s}`").into()).collect(),
|
||||
),
|
||||
span,
|
||||
});
|
||||
ArgParser::NameValue(nv) => {
|
||||
cx.expected_list_or_no_args(nv.args_span());
|
||||
}
|
||||
}
|
||||
},
|
||||
|
|
@ -164,16 +155,8 @@ impl<S: Stage> SingleAttributeParser<S> for MacroExportParser {
|
|||
}
|
||||
}
|
||||
}
|
||||
ArgParser::NameValue(_) => {
|
||||
let span = cx.attr_span;
|
||||
let suggestions = cx.suggestions();
|
||||
cx.emit_err(IllFormedAttributeInputLint {
|
||||
num_suggestions: suggestions.len(),
|
||||
suggestions: DiagArgValue::StrListSepByAnd(
|
||||
suggestions.into_iter().map(|s| format!("`{s}`").into()).collect(),
|
||||
),
|
||||
span,
|
||||
});
|
||||
ArgParser::NameValue(nv) => {
|
||||
cx.expected_list_or_no_args(nv.args_span());
|
||||
return None;
|
||||
}
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,7 +1,4 @@
|
|||
use rustc_errors::DiagArgValue;
|
||||
|
||||
use super::prelude::*;
|
||||
use crate::session_diagnostics::IllFormedAttributeInputLint;
|
||||
|
||||
pub(crate) struct MustUseParser;
|
||||
|
||||
|
|
@ -44,15 +41,8 @@ impl<S: Stage> SingleAttributeParser<S> for MustUseParser {
|
|||
};
|
||||
Some(value_str)
|
||||
}
|
||||
ArgParser::List(_) => {
|
||||
let suggestions = cx.suggestions();
|
||||
cx.emit_err(IllFormedAttributeInputLint {
|
||||
num_suggestions: suggestions.len(),
|
||||
suggestions: DiagArgValue::StrListSepByAnd(
|
||||
suggestions.into_iter().map(|s| format!("`{s}`").into()).collect(),
|
||||
),
|
||||
span: cx.attr_span,
|
||||
});
|
||||
ArgParser::List(list) => {
|
||||
cx.expected_nv_or_no_args(list.span);
|
||||
return None;
|
||||
}
|
||||
},
|
||||
|
|
|
|||
|
|
@ -65,7 +65,7 @@ fn parse_derive_like<S: Stage>(
|
|||
if args.no_args().is_ok() && !trait_name_mandatory {
|
||||
return Some((None, ThinVec::new()));
|
||||
}
|
||||
cx.expected_list(cx.attr_span);
|
||||
cx.expected_list(cx.attr_span, args);
|
||||
return None;
|
||||
};
|
||||
let mut items = list.mixed();
|
||||
|
|
@ -96,7 +96,7 @@ fn parse_derive_like<S: Stage>(
|
|||
let mut attributes = ThinVec::new();
|
||||
if let Some(attrs) = items.next() {
|
||||
let Some(attr_list) = attrs.meta_item() else {
|
||||
cx.expected_list(attrs.span());
|
||||
cx.unexpected_literal(attrs.span());
|
||||
return None;
|
||||
};
|
||||
if !attr_list.path().word_is(sym::attributes) {
|
||||
|
|
@ -104,7 +104,7 @@ fn parse_derive_like<S: Stage>(
|
|||
return None;
|
||||
}
|
||||
let Some(attr_list) = attr_list.args().list() else {
|
||||
cx.expected_list(attrs.span());
|
||||
cx.expected_list(attrs.span(), attr_list.args());
|
||||
return None;
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -27,7 +27,7 @@ impl<S: Stage> SingleAttributeParser<S> for CustomMirParser {
|
|||
|
||||
fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option<AttributeKind> {
|
||||
let Some(list) = args.list() else {
|
||||
cx.expected_list(cx.attr_span);
|
||||
cx.expected_list(cx.attr_span, args);
|
||||
return None;
|
||||
};
|
||||
|
||||
|
|
@ -46,9 +46,8 @@ impl<S: Stage> SingleAttributeParser<S> for CustomMirParser {
|
|||
extract_value(cx, sym::dialect, arg, meta_item.span(), &mut dialect, &mut failed);
|
||||
} else if let Some(arg) = meta_item.word_is(sym::phase) {
|
||||
extract_value(cx, sym::phase, arg, meta_item.span(), &mut phase, &mut failed);
|
||||
} else if let Some(word) = meta_item.path().word() {
|
||||
let word = word.to_string();
|
||||
cx.unknown_key(meta_item.span(), word, &["dialect", "phase"]);
|
||||
} else if let Some(..) = meta_item.path().word() {
|
||||
cx.expected_specific_argument(meta_item.span(), &[sym::dialect, sym::phase]);
|
||||
failed = true;
|
||||
} else {
|
||||
cx.expected_name_value(meta_item.span(), None);
|
||||
|
|
|
|||
|
|
@ -33,7 +33,7 @@ impl<S: Stage> CombineAttributeParser<S> for ReprParser {
|
|||
let mut reprs = Vec::new();
|
||||
|
||||
let Some(list) = args.list() else {
|
||||
cx.expected_list(cx.attr_span);
|
||||
cx.expected_list(cx.attr_span, args);
|
||||
return reprs;
|
||||
};
|
||||
|
||||
|
|
@ -278,7 +278,7 @@ impl AlignParser {
|
|||
fn parse<S: Stage>(&mut self, cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) {
|
||||
match args {
|
||||
ArgParser::NoArgs | ArgParser::NameValue(_) => {
|
||||
cx.expected_list(cx.attr_span);
|
||||
cx.expected_list(cx.attr_span, args);
|
||||
}
|
||||
ArgParser::List(list) => {
|
||||
let Some(align) = list.single() else {
|
||||
|
|
|
|||
|
|
@ -295,7 +295,7 @@ pub(crate) fn parse_stability<S: Stage>(
|
|||
let mut since = None;
|
||||
|
||||
let ArgParser::List(list) = args else {
|
||||
cx.expected_list(cx.attr_span);
|
||||
cx.expected_list(cx.attr_span, args);
|
||||
return None;
|
||||
};
|
||||
|
||||
|
|
@ -315,11 +315,7 @@ pub(crate) fn parse_stability<S: Stage>(
|
|||
insert_value_into_option_or_error(cx, ¶m, &mut since, word.unwrap())?
|
||||
}
|
||||
_ => {
|
||||
cx.emit_err(session_diagnostics::UnknownMetaItem {
|
||||
span: param_span,
|
||||
item: param.path().to_string(),
|
||||
expected: &["feature", "since"],
|
||||
});
|
||||
cx.expected_specific_argument(param_span, &[sym::feature, sym::since]);
|
||||
return None;
|
||||
}
|
||||
}
|
||||
|
|
@ -371,7 +367,7 @@ pub(crate) fn parse_unstability<S: Stage>(
|
|||
let mut old_name = None;
|
||||
|
||||
let ArgParser::List(list) = args else {
|
||||
cx.expected_list(cx.attr_span);
|
||||
cx.expected_list(cx.attr_span, args);
|
||||
return None;
|
||||
};
|
||||
|
||||
|
|
@ -426,11 +422,17 @@ pub(crate) fn parse_unstability<S: Stage>(
|
|||
insert_value_into_option_or_error(cx, ¶m, &mut old_name, word.unwrap())?
|
||||
}
|
||||
_ => {
|
||||
cx.emit_err(session_diagnostics::UnknownMetaItem {
|
||||
span: param.span(),
|
||||
item: param.path().to_string(),
|
||||
expected: &["feature", "reason", "issue", "soft", "implied_by", "old_name"],
|
||||
});
|
||||
cx.expected_specific_argument(
|
||||
param.span(),
|
||||
&[
|
||||
sym::feature,
|
||||
sym::reason,
|
||||
sym::issue,
|
||||
sym::soft,
|
||||
sym::implied_by,
|
||||
sym::old_name,
|
||||
],
|
||||
);
|
||||
return None;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -22,7 +22,7 @@ impl<S: Stage> SingleAttributeParser<S> for SkipDuringMethodDispatchParser {
|
|||
let mut array = false;
|
||||
let mut boxed_slice = false;
|
||||
let Some(args) = args.list() else {
|
||||
cx.expected_list(cx.attr_span);
|
||||
cx.expected_list(cx.attr_span, args);
|
||||
return None;
|
||||
};
|
||||
if args.is_empty() {
|
||||
|
|
|
|||
|
|
@ -43,7 +43,7 @@ pub(crate) fn parse_single_integer<S: Stage>(
|
|||
args: &ArgParser,
|
||||
) -> Option<u128> {
|
||||
let Some(list) = args.list() else {
|
||||
cx.expected_list(cx.attr_span);
|
||||
cx.expected_list(cx.attr_span, args);
|
||||
return None;
|
||||
};
|
||||
let Some(single) = list.single() else {
|
||||
|
|
|
|||
|
|
@ -20,8 +20,8 @@ use crate::attributes::allow_unstable::{
|
|||
};
|
||||
use crate::attributes::body::CoroutineParser;
|
||||
use crate::attributes::codegen_attrs::{
|
||||
ColdParser, CoverageParser, ExportNameParser, ForceTargetFeatureParser, NakedParser,
|
||||
NoMangleParser, ObjcClassParser, ObjcSelectorParser, OptimizeParser,
|
||||
ColdParser, CoverageParser, EiiExternItemParser, ExportNameParser, ForceTargetFeatureParser,
|
||||
NakedParser, NoMangleParser, ObjcClassParser, ObjcSelectorParser, OptimizeParser,
|
||||
RustcPassIndirectlyInNonRusticAbisParser, SanitizeParser, TargetFeatureParser,
|
||||
TrackCallerParser, UsedParser,
|
||||
};
|
||||
|
|
@ -77,7 +77,7 @@ use crate::attributes::transparency::TransparencyParser;
|
|||
use crate::attributes::{AttributeParser as _, Combine, Single, WithoutArgs};
|
||||
use crate::parser::{ArgParser, RefPathParser};
|
||||
use crate::session_diagnostics::{
|
||||
AttributeParseError, AttributeParseErrorReason, ParsedDescription, UnknownMetaItem,
|
||||
AttributeParseError, AttributeParseErrorReason, ParsedDescription,
|
||||
};
|
||||
use crate::target_checking::AllowedTargets;
|
||||
|
||||
|
|
@ -227,6 +227,7 @@ attribute_parsers!(
|
|||
Single<WithoutArgs<CoroutineParser>>,
|
||||
Single<WithoutArgs<DenyExplicitImplParser>>,
|
||||
Single<WithoutArgs<DoNotImplementViaObjectParser>>,
|
||||
Single<WithoutArgs<EiiExternItemParser>>,
|
||||
Single<WithoutArgs<ExportStableParser>>,
|
||||
Single<WithoutArgs<FfiConstParser>>,
|
||||
Single<WithoutArgs<FfiPureParser>>,
|
||||
|
|
@ -425,13 +426,20 @@ impl<'f, 'sess: 'f, S: Stage> SharedContext<'f, 'sess, S> {
|
|||
}
|
||||
|
||||
impl<'f, 'sess: 'f, S: Stage> AcceptContext<'f, 'sess, S> {
|
||||
pub(crate) fn unknown_key(
|
||||
fn emit_parse_error(
|
||||
&self,
|
||||
span: Span,
|
||||
found: String,
|
||||
options: &[&'static str],
|
||||
reason: AttributeParseErrorReason<'_>,
|
||||
) -> ErrorGuaranteed {
|
||||
self.emit_err(UnknownMetaItem { span, item: found, expected: options })
|
||||
self.emit_err(AttributeParseError {
|
||||
span,
|
||||
attr_span: self.attr_span,
|
||||
template: self.template.clone(),
|
||||
path: self.attr_path.clone(),
|
||||
description: self.parsed_description,
|
||||
reason,
|
||||
suggestions: self.suggestions(),
|
||||
})
|
||||
}
|
||||
|
||||
/// error that a string literal was expected.
|
||||
|
|
@ -443,133 +451,69 @@ impl<'f, 'sess: 'f, S: Stage> AcceptContext<'f, 'sess, S> {
|
|||
span: Span,
|
||||
actual_literal: Option<&MetaItemLit>,
|
||||
) -> ErrorGuaranteed {
|
||||
self.emit_err(AttributeParseError {
|
||||
self.emit_parse_error(
|
||||
span,
|
||||
attr_span: self.attr_span,
|
||||
template: self.template.clone(),
|
||||
path: self.attr_path.clone(),
|
||||
description: self.parsed_description,
|
||||
reason: AttributeParseErrorReason::ExpectedStringLiteral {
|
||||
AttributeParseErrorReason::ExpectedStringLiteral {
|
||||
byte_string: actual_literal.and_then(|i| {
|
||||
i.kind.is_bytestr().then(|| self.sess().source_map().start_point(i.span))
|
||||
}),
|
||||
},
|
||||
suggestions: self.suggestions(),
|
||||
})
|
||||
)
|
||||
}
|
||||
|
||||
pub(crate) fn expected_integer_literal(&self, span: Span) -> ErrorGuaranteed {
|
||||
self.emit_err(AttributeParseError {
|
||||
span,
|
||||
attr_span: self.attr_span,
|
||||
template: self.template.clone(),
|
||||
path: self.attr_path.clone(),
|
||||
description: self.parsed_description,
|
||||
reason: AttributeParseErrorReason::ExpectedIntegerLiteral,
|
||||
suggestions: self.suggestions(),
|
||||
})
|
||||
self.emit_parse_error(span, AttributeParseErrorReason::ExpectedIntegerLiteral)
|
||||
}
|
||||
|
||||
pub(crate) fn expected_list(&self, span: Span) -> ErrorGuaranteed {
|
||||
self.emit_err(AttributeParseError {
|
||||
span,
|
||||
attr_span: self.attr_span,
|
||||
template: self.template.clone(),
|
||||
path: self.attr_path.clone(),
|
||||
description: self.parsed_description,
|
||||
reason: AttributeParseErrorReason::ExpectedList,
|
||||
suggestions: self.suggestions(),
|
||||
})
|
||||
pub(crate) fn expected_list(&self, span: Span, args: &ArgParser) -> ErrorGuaranteed {
|
||||
let span = match args {
|
||||
ArgParser::NoArgs => span,
|
||||
ArgParser::List(list) => list.span,
|
||||
ArgParser::NameValue(nv) => nv.args_span(),
|
||||
};
|
||||
self.emit_parse_error(span, AttributeParseErrorReason::ExpectedList)
|
||||
}
|
||||
|
||||
pub(crate) fn expected_no_args(&self, args_span: Span) -> ErrorGuaranteed {
|
||||
self.emit_err(AttributeParseError {
|
||||
span: args_span,
|
||||
attr_span: self.attr_span,
|
||||
template: self.template.clone(),
|
||||
path: self.attr_path.clone(),
|
||||
description: self.parsed_description,
|
||||
reason: AttributeParseErrorReason::ExpectedNoArgs,
|
||||
suggestions: self.suggestions(),
|
||||
})
|
||||
pub(crate) fn expected_list_or_no_args(&self, span: Span) -> ErrorGuaranteed {
|
||||
self.emit_parse_error(span, AttributeParseErrorReason::ExpectedListOrNoArgs)
|
||||
}
|
||||
|
||||
pub(crate) fn expected_nv_or_no_args(&self, span: Span) -> ErrorGuaranteed {
|
||||
self.emit_parse_error(span, AttributeParseErrorReason::ExpectedNameValueOrNoArgs)
|
||||
}
|
||||
|
||||
pub(crate) fn expected_no_args(&self, span: Span) -> ErrorGuaranteed {
|
||||
self.emit_parse_error(span, AttributeParseErrorReason::ExpectedNoArgs)
|
||||
}
|
||||
|
||||
/// emit an error that a `name` was expected here
|
||||
pub(crate) fn expected_identifier(&self, span: Span) -> ErrorGuaranteed {
|
||||
self.emit_err(AttributeParseError {
|
||||
span,
|
||||
attr_span: self.attr_span,
|
||||
template: self.template.clone(),
|
||||
path: self.attr_path.clone(),
|
||||
description: self.parsed_description,
|
||||
reason: AttributeParseErrorReason::ExpectedIdentifier,
|
||||
suggestions: self.suggestions(),
|
||||
})
|
||||
self.emit_parse_error(span, AttributeParseErrorReason::ExpectedIdentifier)
|
||||
}
|
||||
|
||||
/// emit an error that a `name = value` pair was expected at this span. The symbol can be given for
|
||||
/// a nicer error message talking about the specific name that was found lacking a value.
|
||||
pub(crate) fn expected_name_value(&self, span: Span, name: Option<Symbol>) -> ErrorGuaranteed {
|
||||
self.emit_err(AttributeParseError {
|
||||
span,
|
||||
attr_span: self.attr_span,
|
||||
template: self.template.clone(),
|
||||
path: self.attr_path.clone(),
|
||||
description: self.parsed_description,
|
||||
reason: AttributeParseErrorReason::ExpectedNameValue(name),
|
||||
suggestions: self.suggestions(),
|
||||
})
|
||||
self.emit_parse_error(span, AttributeParseErrorReason::ExpectedNameValue(name))
|
||||
}
|
||||
|
||||
/// emit an error that a `name = value` pair was found where that name was already seen.
|
||||
pub(crate) fn duplicate_key(&self, span: Span, key: Symbol) -> ErrorGuaranteed {
|
||||
self.emit_err(AttributeParseError {
|
||||
span,
|
||||
attr_span: self.attr_span,
|
||||
template: self.template.clone(),
|
||||
path: self.attr_path.clone(),
|
||||
description: self.parsed_description,
|
||||
reason: AttributeParseErrorReason::DuplicateKey(key),
|
||||
suggestions: self.suggestions(),
|
||||
})
|
||||
self.emit_parse_error(span, AttributeParseErrorReason::DuplicateKey(key))
|
||||
}
|
||||
|
||||
/// an error that should be emitted when a [`MetaItemOrLitParser`](crate::parser::MetaItemOrLitParser)
|
||||
/// was expected *not* to be a literal, but instead a meta item.
|
||||
pub(crate) fn unexpected_literal(&self, span: Span) -> ErrorGuaranteed {
|
||||
self.emit_err(AttributeParseError {
|
||||
span,
|
||||
attr_span: self.attr_span,
|
||||
template: self.template.clone(),
|
||||
path: self.attr_path.clone(),
|
||||
description: self.parsed_description,
|
||||
reason: AttributeParseErrorReason::UnexpectedLiteral,
|
||||
suggestions: self.suggestions(),
|
||||
})
|
||||
self.emit_parse_error(span, AttributeParseErrorReason::UnexpectedLiteral)
|
||||
}
|
||||
|
||||
pub(crate) fn expected_single_argument(&self, span: Span) -> ErrorGuaranteed {
|
||||
self.emit_err(AttributeParseError {
|
||||
span,
|
||||
attr_span: self.attr_span,
|
||||
template: self.template.clone(),
|
||||
path: self.attr_path.clone(),
|
||||
description: self.parsed_description,
|
||||
reason: AttributeParseErrorReason::ExpectedSingleArgument,
|
||||
suggestions: self.suggestions(),
|
||||
})
|
||||
self.emit_parse_error(span, AttributeParseErrorReason::ExpectedSingleArgument)
|
||||
}
|
||||
|
||||
pub(crate) fn expected_at_least_one_argument(&self, span: Span) -> ErrorGuaranteed {
|
||||
self.emit_err(AttributeParseError {
|
||||
span,
|
||||
attr_span: self.attr_span,
|
||||
template: self.template.clone(),
|
||||
path: self.attr_path.clone(),
|
||||
description: self.parsed_description,
|
||||
reason: AttributeParseErrorReason::ExpectedAtLeastOneArgument,
|
||||
suggestions: self.suggestions(),
|
||||
})
|
||||
self.emit_parse_error(span, AttributeParseErrorReason::ExpectedAtLeastOneArgument)
|
||||
}
|
||||
|
||||
/// produces an error along the lines of `expected one of [foo, meow]`
|
||||
|
|
@ -578,19 +522,14 @@ impl<'f, 'sess: 'f, S: Stage> AcceptContext<'f, 'sess, S> {
|
|||
span: Span,
|
||||
possibilities: &[Symbol],
|
||||
) -> ErrorGuaranteed {
|
||||
self.emit_err(AttributeParseError {
|
||||
self.emit_parse_error(
|
||||
span,
|
||||
attr_span: self.attr_span,
|
||||
template: self.template.clone(),
|
||||
path: self.attr_path.clone(),
|
||||
description: self.parsed_description,
|
||||
reason: AttributeParseErrorReason::ExpectedSpecificArgument {
|
||||
AttributeParseErrorReason::ExpectedSpecificArgument {
|
||||
possibilities,
|
||||
strings: false,
|
||||
list: false,
|
||||
},
|
||||
suggestions: self.suggestions(),
|
||||
})
|
||||
)
|
||||
}
|
||||
|
||||
/// produces an error along the lines of `expected one of [foo, meow] as an argument`.
|
||||
|
|
@ -600,19 +539,14 @@ impl<'f, 'sess: 'f, S: Stage> AcceptContext<'f, 'sess, S> {
|
|||
span: Span,
|
||||
possibilities: &[Symbol],
|
||||
) -> ErrorGuaranteed {
|
||||
self.emit_err(AttributeParseError {
|
||||
self.emit_parse_error(
|
||||
span,
|
||||
attr_span: self.attr_span,
|
||||
template: self.template.clone(),
|
||||
path: self.attr_path.clone(),
|
||||
description: self.parsed_description,
|
||||
reason: AttributeParseErrorReason::ExpectedSpecificArgument {
|
||||
AttributeParseErrorReason::ExpectedSpecificArgument {
|
||||
possibilities,
|
||||
strings: false,
|
||||
list: true,
|
||||
},
|
||||
suggestions: self.suggestions(),
|
||||
})
|
||||
)
|
||||
}
|
||||
|
||||
/// produces an error along the lines of `expected one of ["foo", "meow"]`
|
||||
|
|
@ -621,19 +555,14 @@ impl<'f, 'sess: 'f, S: Stage> AcceptContext<'f, 'sess, S> {
|
|||
span: Span,
|
||||
possibilities: &[Symbol],
|
||||
) -> ErrorGuaranteed {
|
||||
self.emit_err(AttributeParseError {
|
||||
self.emit_parse_error(
|
||||
span,
|
||||
attr_span: self.attr_span,
|
||||
template: self.template.clone(),
|
||||
path: self.attr_path.clone(),
|
||||
description: self.parsed_description,
|
||||
reason: AttributeParseErrorReason::ExpectedSpecificArgument {
|
||||
AttributeParseErrorReason::ExpectedSpecificArgument {
|
||||
possibilities,
|
||||
strings: true,
|
||||
list: false,
|
||||
},
|
||||
suggestions: self.suggestions(),
|
||||
})
|
||||
)
|
||||
}
|
||||
|
||||
pub(crate) fn warn_empty_attribute(&mut self, span: Span) {
|
||||
|
|
|
|||
|
|
@ -177,7 +177,7 @@ impl ArgParser {
|
|||
match self {
|
||||
Self::NoArgs => Ok(()),
|
||||
Self::List(args) => Err(args.span),
|
||||
Self::NameValue(args) => Err(args.eq_span.to(args.value_span)),
|
||||
Self::NameValue(args) => Err(args.args_span()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -314,6 +314,10 @@ impl NameValueParser {
|
|||
pub fn value_as_str(&self) -> Option<Symbol> {
|
||||
self.value_as_lit().kind.str()
|
||||
}
|
||||
|
||||
pub fn args_span(&self) -> Span {
|
||||
self.eq_span.to(self.value_span)
|
||||
}
|
||||
}
|
||||
|
||||
fn expr_to_lit(
|
||||
|
|
|
|||
|
|
@ -64,26 +64,6 @@ pub(crate) struct DocAttributeNotAttribute {
|
|||
pub attribute: Symbol,
|
||||
}
|
||||
|
||||
/// Error code: E0541
|
||||
pub(crate) struct UnknownMetaItem<'a> {
|
||||
pub span: Span,
|
||||
pub item: String,
|
||||
pub expected: &'a [&'a str],
|
||||
}
|
||||
|
||||
// Manual implementation to be able to format `expected` items correctly.
|
||||
impl<'a, G: EmissionGuarantee> Diagnostic<'a, G> for UnknownMetaItem<'_> {
|
||||
fn into_diag(self, dcx: DiagCtxtHandle<'a>, level: Level) -> Diag<'a, G> {
|
||||
let expected = self.expected.iter().map(|name| format!("`{name}`")).collect::<Vec<_>>();
|
||||
Diag::new(dcx, level, fluent::attr_parsing_unknown_meta_item)
|
||||
.with_span(self.span)
|
||||
.with_code(E0541)
|
||||
.with_arg("item", self.item)
|
||||
.with_arg("expected", expected.join(", "))
|
||||
.with_span_label(self.span, fluent::attr_parsing_label)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(attr_parsing_missing_since, code = E0542)]
|
||||
pub(crate) struct MissingSince {
|
||||
|
|
@ -400,15 +380,6 @@ pub(crate) struct UnusedMultiple {
|
|||
pub name: Symbol,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(attr_parsing_ill_formed_attribute_input)]
|
||||
pub(crate) struct IllFormedAttributeInputLint {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
pub num_suggestions: usize,
|
||||
pub suggestions: DiagArgValue,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(attr_parsing_null_on_export, code = E0648)]
|
||||
pub(crate) struct NullOnExport {
|
||||
|
|
@ -539,6 +510,8 @@ pub(crate) enum AttributeParseErrorReason<'a> {
|
|||
ExpectedAtLeastOneArgument,
|
||||
ExpectedSingleArgument,
|
||||
ExpectedList,
|
||||
ExpectedListOrNoArgs,
|
||||
ExpectedNameValueOrNoArgs,
|
||||
UnexpectedLiteral,
|
||||
ExpectedNameValue(Option<Symbol>),
|
||||
DuplicateKey(Symbol),
|
||||
|
|
@ -611,6 +584,12 @@ impl<'a, G: EmissionGuarantee> Diagnostic<'a, G> for AttributeParseError<'_> {
|
|||
AttributeParseErrorReason::ExpectedList => {
|
||||
diag.span_label(self.span, "expected this to be a list");
|
||||
}
|
||||
AttributeParseErrorReason::ExpectedListOrNoArgs => {
|
||||
diag.span_label(self.span, "expected a list or no arguments here");
|
||||
}
|
||||
AttributeParseErrorReason::ExpectedNameValueOrNoArgs => {
|
||||
diag.span_label(self.span, "didn't expect a list here");
|
||||
}
|
||||
AttributeParseErrorReason::DuplicateKey(key) => {
|
||||
diag.span_label(self.span, format!("found `{key}` used as a key more than once"));
|
||||
diag.code(E0538);
|
||||
|
|
|
|||
|
|
@ -80,7 +80,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
|||
let OutlivesConstraint { sup, sub, locations, category, span, .. } = constraint;
|
||||
let (name, arg) = match locations {
|
||||
Locations::All(span) => {
|
||||
("All", tcx.sess.source_map().span_to_embeddable_string(*span))
|
||||
("All", tcx.sess.source_map().span_to_diagnostic_string(*span))
|
||||
}
|
||||
Locations::Single(loc) => ("Single", format!("{loc:?}")),
|
||||
};
|
||||
|
|
|
|||
|
|
@ -152,6 +152,17 @@ builtin_macros_derive_path_args_value = traits in `#[derive(...)]` don't accept
|
|||
|
||||
builtin_macros_duplicate_macro_attribute = duplicated attribute
|
||||
|
||||
builtin_macros_eii_extern_target_expected_list = `#[eii_extern_target(...)]` expects a list of one or two elements
|
||||
builtin_macros_eii_extern_target_expected_macro = `#[eii_extern_target(...)]` is only valid on macros
|
||||
builtin_macros_eii_extern_target_expected_unsafe = expected this argument to be "unsafe"
|
||||
.note = the second argument is optional
|
||||
|
||||
builtin_macros_eii_only_once = `#[{$name}]` can only be specified once
|
||||
.note = specified again here
|
||||
|
||||
builtin_macros_eii_shared_macro_expected_function = `#[{$name}]` is only valid on functions
|
||||
builtin_macros_eii_shared_macro_expected_max_one_argument = `#[{$name}]` expected no arguments or a single argument: `#[{$name}(default)]`
|
||||
|
||||
builtin_macros_env_not_defined = environment variable `{$var}` not defined at compile time
|
||||
.cargo = Cargo sets build script variables at run time. Use `std::env::var({$var_expr})` instead
|
||||
.cargo_typo = there is a similar Cargo environment variable: `{$suggested_var}`
|
||||
|
|
|
|||
|
|
@ -90,6 +90,7 @@ fn generate_handler(cx: &ExtCtxt<'_>, handler: Ident, span: Span, sig_span: Span
|
|||
contract: None,
|
||||
body,
|
||||
define_opaque: None,
|
||||
eii_impls: ThinVec::new(),
|
||||
}));
|
||||
|
||||
let attrs = thin_vec![cx.attr_word(sym::rustc_std_internal_symbol, span)];
|
||||
|
|
|
|||
|
|
@ -346,6 +346,7 @@ mod llvm_enzyme {
|
|||
contract: None,
|
||||
body: Some(d_body),
|
||||
define_opaque: None,
|
||||
eii_impls: ThinVec::new(),
|
||||
});
|
||||
let mut rustc_ad_attr =
|
||||
Box::new(ast::NormalAttr::from_ident(Ident::with_dummy_span(sym::rustc_autodiff)));
|
||||
|
|
|
|||
|
|
@ -1092,6 +1092,7 @@ impl<'a> MethodDef<'a> {
|
|||
contract: None,
|
||||
body: Some(body_block),
|
||||
define_opaque: None,
|
||||
eii_impls: ThinVec::new(),
|
||||
})),
|
||||
tokens: None,
|
||||
})
|
||||
|
|
|
|||
447
compiler/rustc_builtin_macros/src/eii.rs
Normal file
447
compiler/rustc_builtin_macros/src/eii.rs
Normal file
|
|
@ -0,0 +1,447 @@
|
|||
use rustc_ast::token::{Delimiter, TokenKind};
|
||||
use rustc_ast::tokenstream::{DelimSpacing, DelimSpan, Spacing, TokenStream, TokenTree};
|
||||
use rustc_ast::{
|
||||
DUMMY_NODE_ID, EiiExternTarget, EiiImpl, ItemKind, Stmt, StmtKind, ast, token, tokenstream,
|
||||
};
|
||||
use rustc_ast_pretty::pprust::path_to_string;
|
||||
use rustc_expand::base::{Annotatable, ExtCtxt};
|
||||
use rustc_span::{Ident, Span, kw, sym};
|
||||
use thin_vec::{ThinVec, thin_vec};
|
||||
|
||||
use crate::errors::{
|
||||
EiiExternTargetExpectedList, EiiExternTargetExpectedMacro, EiiExternTargetExpectedUnsafe,
|
||||
EiiMacroExpectedMaxOneArgument, EiiOnlyOnce, EiiSharedMacroExpectedFunction,
|
||||
};
|
||||
|
||||
/// ```rust
|
||||
/// #[eii]
|
||||
/// fn panic_handler();
|
||||
///
|
||||
/// // or:
|
||||
///
|
||||
/// #[eii(panic_handler)]
|
||||
/// fn panic_handler();
|
||||
///
|
||||
/// // expansion:
|
||||
///
|
||||
/// extern "Rust" {
|
||||
/// fn panic_handler();
|
||||
/// }
|
||||
///
|
||||
/// #[rustc_builtin_macro(eii_shared_macro)]
|
||||
/// #[eii_extern_target(panic_handler)]
|
||||
/// macro panic_handler() {}
|
||||
/// ```
|
||||
pub(crate) fn eii(
|
||||
ecx: &mut ExtCtxt<'_>,
|
||||
span: Span,
|
||||
meta_item: &ast::MetaItem,
|
||||
item: Annotatable,
|
||||
) -> Vec<Annotatable> {
|
||||
eii_(ecx, span, meta_item, item, false)
|
||||
}
|
||||
|
||||
pub(crate) fn unsafe_eii(
|
||||
ecx: &mut ExtCtxt<'_>,
|
||||
span: Span,
|
||||
meta_item: &ast::MetaItem,
|
||||
item: Annotatable,
|
||||
) -> Vec<Annotatable> {
|
||||
eii_(ecx, span, meta_item, item, true)
|
||||
}
|
||||
|
||||
fn eii_(
|
||||
ecx: &mut ExtCtxt<'_>,
|
||||
span: Span,
|
||||
meta_item: &ast::MetaItem,
|
||||
item: Annotatable,
|
||||
impl_unsafe: bool,
|
||||
) -> Vec<Annotatable> {
|
||||
let span = ecx.with_def_site_ctxt(span);
|
||||
|
||||
let (item, stmt) = if let Annotatable::Item(item) = item {
|
||||
(item, false)
|
||||
} else if let Annotatable::Stmt(ref stmt) = item
|
||||
&& let StmtKind::Item(ref item) = stmt.kind
|
||||
{
|
||||
(item.clone(), true)
|
||||
} else {
|
||||
ecx.dcx().emit_err(EiiSharedMacroExpectedFunction {
|
||||
span,
|
||||
name: path_to_string(&meta_item.path),
|
||||
});
|
||||
return vec![item];
|
||||
};
|
||||
|
||||
let orig_item = item.clone();
|
||||
|
||||
let item = *item;
|
||||
|
||||
let ast::Item { attrs, id: _, span: item_span, vis, kind: ItemKind::Fn(mut func), tokens: _ } =
|
||||
item
|
||||
else {
|
||||
ecx.dcx().emit_err(EiiSharedMacroExpectedFunction {
|
||||
span,
|
||||
name: path_to_string(&meta_item.path),
|
||||
});
|
||||
return vec![Annotatable::Item(Box::new(item))];
|
||||
};
|
||||
|
||||
// Detect when this is the *second* eii attribute on an item.
|
||||
let mut new_attrs = ThinVec::new();
|
||||
for i in attrs {
|
||||
if i.has_name(sym::eii) {
|
||||
ecx.dcx().emit_err(EiiOnlyOnce {
|
||||
span: i.span,
|
||||
first_span: span,
|
||||
name: path_to_string(&meta_item.path),
|
||||
});
|
||||
} else {
|
||||
new_attrs.push(i);
|
||||
}
|
||||
}
|
||||
let attrs = new_attrs;
|
||||
|
||||
let macro_name = if meta_item.is_word() {
|
||||
func.ident
|
||||
} else if let Some([first]) = meta_item.meta_item_list()
|
||||
&& let Some(m) = first.meta_item()
|
||||
&& m.path.segments.len() == 1
|
||||
{
|
||||
m.path.segments[0].ident
|
||||
} else {
|
||||
ecx.dcx().emit_err(EiiMacroExpectedMaxOneArgument {
|
||||
span: meta_item.span,
|
||||
name: path_to_string(&meta_item.path),
|
||||
});
|
||||
return vec![Annotatable::Item(orig_item)];
|
||||
};
|
||||
|
||||
let mut return_items = Vec::new();
|
||||
|
||||
if func.body.is_some() {
|
||||
let mut default_func = func.clone();
|
||||
func.body = None;
|
||||
default_func.eii_impls.push(ast::EiiImpl {
|
||||
node_id: DUMMY_NODE_ID,
|
||||
eii_macro_path: ast::Path::from_ident(macro_name),
|
||||
impl_safety: if impl_unsafe { ast::Safety::Unsafe(span) } else { ast::Safety::Default },
|
||||
span,
|
||||
inner_span: macro_name.span,
|
||||
is_default: true, // important!
|
||||
});
|
||||
|
||||
return_items.push(Box::new(ast::Item {
|
||||
attrs: ThinVec::new(),
|
||||
id: ast::DUMMY_NODE_ID,
|
||||
span,
|
||||
vis: ast::Visibility { span, kind: ast::VisibilityKind::Inherited, tokens: None },
|
||||
kind: ast::ItemKind::Const(Box::new(ast::ConstItem {
|
||||
ident: Ident { name: kw::Underscore, span },
|
||||
defaultness: ast::Defaultness::Final,
|
||||
generics: ast::Generics::default(),
|
||||
ty: Box::new(ast::Ty {
|
||||
id: DUMMY_NODE_ID,
|
||||
kind: ast::TyKind::Tup(ThinVec::new()),
|
||||
span,
|
||||
tokens: None,
|
||||
}),
|
||||
rhs: Some(ast::ConstItemRhs::Body(Box::new(ast::Expr {
|
||||
id: DUMMY_NODE_ID,
|
||||
kind: ast::ExprKind::Block(
|
||||
Box::new(ast::Block {
|
||||
stmts: thin_vec![ast::Stmt {
|
||||
id: DUMMY_NODE_ID,
|
||||
kind: ast::StmtKind::Item(Box::new(ast::Item {
|
||||
attrs: thin_vec![], // FIXME: re-add some original attrs
|
||||
id: DUMMY_NODE_ID,
|
||||
span: item_span,
|
||||
vis: ast::Visibility {
|
||||
span,
|
||||
kind: ast::VisibilityKind::Inherited,
|
||||
tokens: None
|
||||
},
|
||||
kind: ItemKind::Fn(default_func),
|
||||
tokens: None,
|
||||
})),
|
||||
span
|
||||
}],
|
||||
id: DUMMY_NODE_ID,
|
||||
rules: ast::BlockCheckMode::Default,
|
||||
span,
|
||||
tokens: None,
|
||||
}),
|
||||
None,
|
||||
),
|
||||
span,
|
||||
attrs: ThinVec::new(),
|
||||
tokens: None,
|
||||
}))),
|
||||
define_opaque: None,
|
||||
})),
|
||||
tokens: None,
|
||||
}))
|
||||
}
|
||||
|
||||
let decl_span = span.to(func.sig.span);
|
||||
|
||||
let abi = match func.sig.header.ext {
|
||||
// extern "X" fn => extern "X" {}
|
||||
ast::Extern::Explicit(lit, _) => Some(lit),
|
||||
// extern fn => extern {}
|
||||
ast::Extern::Implicit(_) => None,
|
||||
// fn => extern "Rust" {}
|
||||
ast::Extern::None => Some(ast::StrLit {
|
||||
symbol: sym::Rust,
|
||||
suffix: None,
|
||||
symbol_unescaped: sym::Rust,
|
||||
style: ast::StrStyle::Cooked,
|
||||
span,
|
||||
}),
|
||||
};
|
||||
|
||||
// ABI has been moved to the extern {} block, so we remove it from the fn item.
|
||||
func.sig.header.ext = ast::Extern::None;
|
||||
|
||||
// And mark safe functions explicitly as `safe fn`.
|
||||
if func.sig.header.safety == ast::Safety::Default {
|
||||
func.sig.header.safety = ast::Safety::Safe(func.sig.span);
|
||||
}
|
||||
|
||||
// extern "…" { safe fn item(); }
|
||||
let mut extern_item_attrs = attrs.clone();
|
||||
extern_item_attrs.push(ast::Attribute {
|
||||
kind: ast::AttrKind::Normal(Box::new(ast::NormalAttr {
|
||||
item: ast::AttrItem {
|
||||
unsafety: ast::Safety::Default,
|
||||
// Add the rustc_eii_extern_item on the foreign item. Usually, foreign items are mangled.
|
||||
// This attribute makes sure that we later know that this foreign item's symbol should not be.
|
||||
path: ast::Path::from_ident(Ident::new(sym::rustc_eii_extern_item, span)),
|
||||
args: ast::AttrArgs::Empty,
|
||||
tokens: None,
|
||||
},
|
||||
tokens: None,
|
||||
})),
|
||||
id: ecx.sess.psess.attr_id_generator.mk_attr_id(),
|
||||
style: ast::AttrStyle::Outer,
|
||||
span,
|
||||
});
|
||||
|
||||
let extern_block = Box::new(ast::Item {
|
||||
attrs: ast::AttrVec::default(),
|
||||
id: ast::DUMMY_NODE_ID,
|
||||
span,
|
||||
vis: ast::Visibility { span, kind: ast::VisibilityKind::Inherited, tokens: None },
|
||||
kind: ast::ItemKind::ForeignMod(ast::ForeignMod {
|
||||
extern_span: span,
|
||||
safety: ast::Safety::Unsafe(span),
|
||||
abi,
|
||||
items: From::from([Box::new(ast::ForeignItem {
|
||||
attrs: extern_item_attrs,
|
||||
id: ast::DUMMY_NODE_ID,
|
||||
span: item_span,
|
||||
vis,
|
||||
kind: ast::ForeignItemKind::Fn(func.clone()),
|
||||
tokens: None,
|
||||
})]),
|
||||
}),
|
||||
tokens: None,
|
||||
});
|
||||
|
||||
let mut macro_attrs = attrs.clone();
|
||||
macro_attrs.push(
|
||||
// #[builtin_macro(eii_shared_macro)]
|
||||
ast::Attribute {
|
||||
kind: ast::AttrKind::Normal(Box::new(ast::NormalAttr {
|
||||
item: ast::AttrItem {
|
||||
unsafety: ast::Safety::Default,
|
||||
path: ast::Path::from_ident(Ident::new(sym::rustc_builtin_macro, span)),
|
||||
args: ast::AttrArgs::Delimited(ast::DelimArgs {
|
||||
dspan: DelimSpan::from_single(span),
|
||||
delim: Delimiter::Parenthesis,
|
||||
tokens: TokenStream::new(vec![tokenstream::TokenTree::token_alone(
|
||||
token::TokenKind::Ident(sym::eii_shared_macro, token::IdentIsRaw::No),
|
||||
span,
|
||||
)]),
|
||||
}),
|
||||
tokens: None,
|
||||
},
|
||||
tokens: None,
|
||||
})),
|
||||
id: ecx.sess.psess.attr_id_generator.mk_attr_id(),
|
||||
style: ast::AttrStyle::Outer,
|
||||
span,
|
||||
},
|
||||
);
|
||||
|
||||
let macro_def = Box::new(ast::Item {
|
||||
attrs: macro_attrs,
|
||||
id: ast::DUMMY_NODE_ID,
|
||||
span,
|
||||
// pub
|
||||
vis: ast::Visibility { span, kind: ast::VisibilityKind::Public, tokens: None },
|
||||
kind: ast::ItemKind::MacroDef(
|
||||
// macro macro_name
|
||||
macro_name,
|
||||
ast::MacroDef {
|
||||
// { () => {} }
|
||||
body: Box::new(ast::DelimArgs {
|
||||
dspan: DelimSpan::from_single(span),
|
||||
delim: Delimiter::Brace,
|
||||
tokens: TokenStream::from_iter([
|
||||
TokenTree::Delimited(
|
||||
DelimSpan::from_single(span),
|
||||
DelimSpacing::new(Spacing::Alone, Spacing::Alone),
|
||||
Delimiter::Parenthesis,
|
||||
TokenStream::default(),
|
||||
),
|
||||
TokenTree::token_alone(TokenKind::FatArrow, span),
|
||||
TokenTree::Delimited(
|
||||
DelimSpan::from_single(span),
|
||||
DelimSpacing::new(Spacing::Alone, Spacing::Alone),
|
||||
Delimiter::Brace,
|
||||
TokenStream::default(),
|
||||
),
|
||||
]),
|
||||
}),
|
||||
macro_rules: false,
|
||||
// #[eii_extern_target(func.ident)]
|
||||
eii_extern_target: Some(ast::EiiExternTarget {
|
||||
extern_item_path: ast::Path::from_ident(func.ident),
|
||||
impl_unsafe,
|
||||
span: decl_span,
|
||||
}),
|
||||
},
|
||||
),
|
||||
tokens: None,
|
||||
});
|
||||
|
||||
return_items.push(extern_block);
|
||||
return_items.push(macro_def);
|
||||
|
||||
if stmt {
|
||||
return_items
|
||||
.into_iter()
|
||||
.map(|i| {
|
||||
Annotatable::Stmt(Box::new(Stmt {
|
||||
id: DUMMY_NODE_ID,
|
||||
kind: StmtKind::Item(i),
|
||||
span,
|
||||
}))
|
||||
})
|
||||
.collect()
|
||||
} else {
|
||||
return_items.into_iter().map(|i| Annotatable::Item(i)).collect()
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn eii_extern_target(
|
||||
ecx: &mut ExtCtxt<'_>,
|
||||
span: Span,
|
||||
meta_item: &ast::MetaItem,
|
||||
mut item: Annotatable,
|
||||
) -> Vec<Annotatable> {
|
||||
let i = if let Annotatable::Item(ref mut item) = item {
|
||||
item
|
||||
} else if let Annotatable::Stmt(ref mut stmt) = item
|
||||
&& let StmtKind::Item(ref mut item) = stmt.kind
|
||||
{
|
||||
item
|
||||
} else {
|
||||
ecx.dcx().emit_err(EiiExternTargetExpectedMacro { span });
|
||||
return vec![item];
|
||||
};
|
||||
|
||||
let ItemKind::MacroDef(_, d) = &mut i.kind else {
|
||||
ecx.dcx().emit_err(EiiExternTargetExpectedMacro { span });
|
||||
return vec![item];
|
||||
};
|
||||
|
||||
let Some(list) = meta_item.meta_item_list() else {
|
||||
ecx.dcx().emit_err(EiiExternTargetExpectedList { span: meta_item.span });
|
||||
return vec![item];
|
||||
};
|
||||
|
||||
if list.len() > 2 {
|
||||
ecx.dcx().emit_err(EiiExternTargetExpectedList { span: meta_item.span });
|
||||
return vec![item];
|
||||
}
|
||||
|
||||
let Some(extern_item_path) = list.get(0).and_then(|i| i.meta_item()).map(|i| i.path.clone())
|
||||
else {
|
||||
ecx.dcx().emit_err(EiiExternTargetExpectedList { span: meta_item.span });
|
||||
return vec![item];
|
||||
};
|
||||
|
||||
let impl_unsafe = if let Some(i) = list.get(1) {
|
||||
if i.lit().and_then(|i| i.kind.str()).is_some_and(|i| i == kw::Unsafe) {
|
||||
true
|
||||
} else {
|
||||
ecx.dcx().emit_err(EiiExternTargetExpectedUnsafe { span: i.span() });
|
||||
return vec![item];
|
||||
}
|
||||
} else {
|
||||
false
|
||||
};
|
||||
|
||||
d.eii_extern_target = Some(EiiExternTarget { extern_item_path, impl_unsafe, span });
|
||||
|
||||
// Return the original item and the new methods.
|
||||
vec![item]
|
||||
}
|
||||
|
||||
/// all Eiis share this function as the implementation for their attribute.
|
||||
pub(crate) fn eii_shared_macro(
|
||||
ecx: &mut ExtCtxt<'_>,
|
||||
span: Span,
|
||||
meta_item: &ast::MetaItem,
|
||||
mut item: Annotatable,
|
||||
) -> Vec<Annotatable> {
|
||||
let i = if let Annotatable::Item(ref mut item) = item {
|
||||
item
|
||||
} else if let Annotatable::Stmt(ref mut stmt) = item
|
||||
&& let StmtKind::Item(ref mut item) = stmt.kind
|
||||
{
|
||||
item
|
||||
} else {
|
||||
ecx.dcx().emit_err(EiiSharedMacroExpectedFunction {
|
||||
span,
|
||||
name: path_to_string(&meta_item.path),
|
||||
});
|
||||
return vec![item];
|
||||
};
|
||||
|
||||
let ItemKind::Fn(f) = &mut i.kind else {
|
||||
ecx.dcx().emit_err(EiiSharedMacroExpectedFunction {
|
||||
span,
|
||||
name: path_to_string(&meta_item.path),
|
||||
});
|
||||
return vec![item];
|
||||
};
|
||||
|
||||
let is_default = if meta_item.is_word() {
|
||||
false
|
||||
} else if let Some([first]) = meta_item.meta_item_list()
|
||||
&& let Some(m) = first.meta_item()
|
||||
&& m.path.segments.len() == 1
|
||||
{
|
||||
m.path.segments[0].ident.name == kw::Default
|
||||
} else {
|
||||
ecx.dcx().emit_err(EiiMacroExpectedMaxOneArgument {
|
||||
span: meta_item.span,
|
||||
name: path_to_string(&meta_item.path),
|
||||
});
|
||||
return vec![item];
|
||||
};
|
||||
|
||||
f.eii_impls.push(EiiImpl {
|
||||
node_id: DUMMY_NODE_ID,
|
||||
eii_macro_path: meta_item.path.clone(),
|
||||
impl_safety: meta_item.unsafety,
|
||||
span,
|
||||
inner_span: meta_item.path.span,
|
||||
is_default,
|
||||
});
|
||||
|
||||
vec![item]
|
||||
}
|
||||
|
|
@ -1010,3 +1010,51 @@ pub(crate) struct CfgSelectUnreachable {
|
|||
#[label]
|
||||
pub wildcard_span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(builtin_macros_eii_extern_target_expected_macro)]
|
||||
pub(crate) struct EiiExternTargetExpectedMacro {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(builtin_macros_eii_extern_target_expected_list)]
|
||||
pub(crate) struct EiiExternTargetExpectedList {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(builtin_macros_eii_extern_target_expected_unsafe)]
|
||||
pub(crate) struct EiiExternTargetExpectedUnsafe {
|
||||
#[primary_span]
|
||||
#[note]
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(builtin_macros_eii_shared_macro_expected_function)]
|
||||
pub(crate) struct EiiSharedMacroExpectedFunction {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
pub name: String,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(builtin_macros_eii_only_once)]
|
||||
pub(crate) struct EiiOnlyOnce {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
#[note]
|
||||
pub first_span: Span,
|
||||
pub name: String,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(builtin_macros_eii_shared_macro_expected_max_one_argument)]
|
||||
pub(crate) struct EiiMacroExpectedMaxOneArgument {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
pub name: String,
|
||||
}
|
||||
|
|
|
|||
|
|
@ -84,6 +84,7 @@ impl AllocFnFactory<'_, '_> {
|
|||
contract: None,
|
||||
body,
|
||||
define_opaque: None,
|
||||
eii_impls: ThinVec::new(),
|
||||
}));
|
||||
let item = self.cx.item(self.span, self.attrs(method), kind);
|
||||
self.cx.stmt_item(self.ty_span, item)
|
||||
|
|
|
|||
|
|
@ -38,6 +38,7 @@ mod define_opaque;
|
|||
mod derive;
|
||||
mod deriving;
|
||||
mod edition_panic;
|
||||
mod eii;
|
||||
mod env;
|
||||
mod errors;
|
||||
mod format;
|
||||
|
|
@ -117,9 +118,13 @@ pub fn register_builtin_macros(resolver: &mut dyn ResolverExpand) {
|
|||
define_opaque: define_opaque::expand,
|
||||
derive: derive::Expander { is_const: false },
|
||||
derive_const: derive::Expander { is_const: true },
|
||||
eii: eii::eii,
|
||||
eii_extern_target: eii::eii_extern_target,
|
||||
eii_shared_macro: eii::eii_shared_macro,
|
||||
global_allocator: global_allocator::expand,
|
||||
test: test::expand_test,
|
||||
test_case: test::expand_test_case,
|
||||
unsafe_eii: eii::unsafe_eii,
|
||||
// tidy-alphabetical-end
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -68,13 +68,10 @@ pub(crate) fn expand_file(
|
|||
let topmost = cx.expansion_cause().unwrap_or(sp);
|
||||
let loc = cx.source_map().lookup_char_pos(topmost.lo());
|
||||
|
||||
use rustc_session::RemapFileNameExt;
|
||||
use rustc_session::config::RemapPathScopeComponents;
|
||||
use rustc_span::RemapPathScopeComponents;
|
||||
ExpandResult::Ready(MacEager::expr(cx.expr_str(
|
||||
topmost,
|
||||
Symbol::intern(
|
||||
&loc.file.name.for_scope(cx.sess, RemapPathScopeComponents::MACRO).to_string_lossy(),
|
||||
),
|
||||
Symbol::intern(&loc.file.name.display(RemapPathScopeComponents::MACRO).to_string_lossy()),
|
||||
)))
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ use rustc_errors::{Applicability, Diag, Level};
|
|||
use rustc_expand::base::*;
|
||||
use rustc_hir::Attribute;
|
||||
use rustc_hir::attrs::AttributeKind;
|
||||
use rustc_span::{ErrorGuaranteed, FileNameDisplayPreference, Ident, Span, Symbol, sym};
|
||||
use rustc_span::{ErrorGuaranteed, Ident, RemapPathScopeComponents, Span, Symbol, sym};
|
||||
use thin_vec::{ThinVec, thin_vec};
|
||||
use tracing::debug;
|
||||
|
||||
|
|
@ -445,7 +445,7 @@ fn get_location_info(cx: &ExtCtxt<'_>, fn_: &ast::Fn) -> (Symbol, usize, usize,
|
|||
cx.sess.source_map().span_to_location_info(span);
|
||||
|
||||
let file_name = match source_file {
|
||||
Some(sf) => sf.name.display(FileNameDisplayPreference::Remapped).to_string(),
|
||||
Some(sf) => sf.name.display(RemapPathScopeComponents::MACRO).to_string(),
|
||||
None => "no-location".to_string(),
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -345,6 +345,7 @@ fn mk_main(cx: &mut TestCtxt<'_>) -> Box<ast::Item> {
|
|||
contract: None,
|
||||
body: Some(main_body),
|
||||
define_opaque: None,
|
||||
eii_impls: ThinVec::new(),
|
||||
}));
|
||||
|
||||
let main = Box::new(ast::Item {
|
||||
|
|
|
|||
|
|
@ -6,7 +6,10 @@ use std::path::{Component, Path};
|
|||
use cranelift_codegen::MachSrcLoc;
|
||||
use cranelift_codegen::binemit::CodeOffset;
|
||||
use gimli::write::{FileId, FileInfo, LineProgram, LineString, LineStringTable};
|
||||
use rustc_span::{FileName, Pos, SourceFile, SourceFileAndLine, SourceFileHashAlgorithm, hygiene};
|
||||
use rustc_span::{
|
||||
FileName, Pos, RemapPathScopeComponents, SourceFile, SourceFileAndLine,
|
||||
SourceFileHashAlgorithm, hygiene,
|
||||
};
|
||||
|
||||
use crate::debuginfo::FunctionDebugContext;
|
||||
use crate::debuginfo::emit::address_for_func;
|
||||
|
|
@ -95,7 +98,7 @@ impl DebugContext {
|
|||
match &source_file.name {
|
||||
FileName::Real(path) => {
|
||||
let (dir_path, file_name) =
|
||||
split_path_dir_and_file(path.to_path(self.filename_display_preference));
|
||||
split_path_dir_and_file(path.path(RemapPathScopeComponents::DEBUGINFO));
|
||||
let dir_name = osstr_as_utf8_bytes(dir_path.as_os_str());
|
||||
let file_name = osstr_as_utf8_bytes(file_name);
|
||||
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@ use rustc_hir::def::DefKind;
|
|||
use rustc_hir::def_id::DefIdMap;
|
||||
use rustc_session::Session;
|
||||
use rustc_session::config::DebugInfo;
|
||||
use rustc_span::{FileNameDisplayPreference, SourceFileHash, StableSourceFileId};
|
||||
use rustc_span::{RemapPathScopeComponents, SourceFileHash, StableSourceFileId};
|
||||
use rustc_target::callconv::FnAbi;
|
||||
|
||||
pub(crate) use self::emit::{DebugReloc, DebugRelocName};
|
||||
|
|
@ -44,7 +44,6 @@ pub(crate) struct DebugContext {
|
|||
namespace_map: DefIdMap<UnitEntryId>,
|
||||
array_size_type: Option<UnitEntryId>,
|
||||
|
||||
filename_display_preference: FileNameDisplayPreference,
|
||||
embed_source: bool,
|
||||
}
|
||||
|
||||
|
|
@ -102,18 +101,18 @@ impl DebugContext {
|
|||
|
||||
let mut dwarf = DwarfUnit::new(encoding);
|
||||
|
||||
use rustc_session::config::RemapPathScopeComponents;
|
||||
|
||||
let filename_display_preference =
|
||||
tcx.sess.filename_display_preference(RemapPathScopeComponents::DEBUGINFO);
|
||||
|
||||
let producer = producer(tcx.sess);
|
||||
let comp_dir =
|
||||
tcx.sess.opts.working_dir.to_string_lossy(filename_display_preference).to_string();
|
||||
let comp_dir = tcx
|
||||
.sess
|
||||
.source_map()
|
||||
.working_dir()
|
||||
.path(RemapPathScopeComponents::DEBUGINFO)
|
||||
.to_string_lossy();
|
||||
|
||||
let (name, file_info) = match tcx.sess.local_crate_source_file() {
|
||||
Some(path) => {
|
||||
let name = path.to_string_lossy(filename_display_preference).to_string();
|
||||
let name =
|
||||
path.path(RemapPathScopeComponents::DEBUGINFO).to_string_lossy().into_owned();
|
||||
(name, None)
|
||||
}
|
||||
None => (tcx.crate_name(LOCAL_CRATE).to_string(), None),
|
||||
|
|
@ -137,7 +136,7 @@ impl DebugContext {
|
|||
|
||||
{
|
||||
let name = dwarf.strings.add(format!("{name}/@/{cgu_name}"));
|
||||
let comp_dir = dwarf.strings.add(comp_dir);
|
||||
let comp_dir = dwarf.strings.add(&*comp_dir);
|
||||
|
||||
let root = dwarf.unit.root();
|
||||
let root = dwarf.unit.get_mut(root);
|
||||
|
|
@ -180,7 +179,6 @@ impl DebugContext {
|
|||
stack_pointer_register,
|
||||
namespace_map: DefIdMap::default(),
|
||||
array_size_type,
|
||||
filename_display_preference,
|
||||
embed_source,
|
||||
})
|
||||
}
|
||||
|
|
|
|||
|
|
@ -297,29 +297,11 @@ impl<'gcc, 'tcx> DebugInfoCodegenMethods<'tcx> for CodegenCx<'gcc, 'tcx> {
|
|||
let pos = span.lo();
|
||||
let DebugLoc { file, line, col } = self.lookup_debug_loc(pos);
|
||||
match file.name {
|
||||
rustc_span::FileName::Real(ref name) => match *name {
|
||||
rustc_span::RealFileName::LocalPath(ref name) => {
|
||||
if let Some(name) = name.to_str() {
|
||||
self.context.new_location(name, line as i32, col as i32)
|
||||
} else {
|
||||
Location::null()
|
||||
}
|
||||
}
|
||||
rustc_span::RealFileName::Remapped {
|
||||
ref local_path,
|
||||
virtual_name: ref _unused,
|
||||
} => {
|
||||
if let Some(name) = local_path.as_ref() {
|
||||
if let Some(name) = name.to_str() {
|
||||
self.context.new_location(name, line as i32, col as i32)
|
||||
} else {
|
||||
Location::null()
|
||||
}
|
||||
} else {
|
||||
Location::null()
|
||||
}
|
||||
}
|
||||
},
|
||||
rustc_span::FileName::Real(ref name) => self.context.new_location(
|
||||
name.path(rustc_span::RemapPathScopeComponents::DEBUGINFO).to_string_lossy(),
|
||||
line as i32,
|
||||
col as i32,
|
||||
),
|
||||
_ => Location::null(),
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -98,7 +98,6 @@ use rustc_middle::ty::TyCtxt;
|
|||
use rustc_middle::util::Providers;
|
||||
use rustc_session::Session;
|
||||
use rustc_session::config::{OptLevel, OutputFilenames};
|
||||
use rustc_session::filesearch::make_target_lib_path;
|
||||
use rustc_span::Symbol;
|
||||
use rustc_target::spec::{Arch, RelocModel};
|
||||
use tempfile::TempDir;
|
||||
|
|
@ -207,18 +206,38 @@ impl CodegenBackend for GccCodegenBackend {
|
|||
}
|
||||
|
||||
fn init(&self, sess: &Session) {
|
||||
fn file_path(sysroot_path: &Path, sess: &Session) -> PathBuf {
|
||||
let rustlib_path =
|
||||
rustc_target::relative_target_rustlib_path(sysroot_path, &sess.host.llvm_target);
|
||||
sysroot_path
|
||||
.join(rustlib_path)
|
||||
.join("codegen-backends")
|
||||
.join("lib")
|
||||
.join(sess.target.llvm_target.as_ref())
|
||||
.join("libgccjit.so")
|
||||
}
|
||||
|
||||
// We use all_paths() instead of only path() in case the path specified by --sysroot is
|
||||
// invalid.
|
||||
// This is the case for instance in Rust for Linux where they specify --sysroot=/dev/null.
|
||||
for path in sess.opts.sysroot.all_paths() {
|
||||
let libgccjit_target_lib_file =
|
||||
make_target_lib_path(path, &sess.target.llvm_target).join("libgccjit.so");
|
||||
let libgccjit_target_lib_file = file_path(path, sess);
|
||||
if let Ok(true) = fs::exists(&libgccjit_target_lib_file) {
|
||||
load_libgccjit_if_needed(&libgccjit_target_lib_file);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if !gccjit::is_loaded() {
|
||||
let mut paths = vec![];
|
||||
for path in sess.opts.sysroot.all_paths() {
|
||||
let libgccjit_target_lib_file = file_path(path, sess);
|
||||
paths.push(libgccjit_target_lib_file);
|
||||
}
|
||||
|
||||
panic!("Could not load libgccjit.so. Attempted paths: {:#?}", paths);
|
||||
}
|
||||
|
||||
#[cfg(feature = "master")]
|
||||
{
|
||||
let target_cpu = target_cpu(sess);
|
||||
|
|
|
|||
|
|
@ -21,10 +21,8 @@ use rustc_errors::{DiagCtxtHandle, Level};
|
|||
use rustc_fs_util::{link_or_copy, path_to_c_string};
|
||||
use rustc_middle::ty::TyCtxt;
|
||||
use rustc_session::Session;
|
||||
use rustc_session::config::{
|
||||
self, Lto, OutputType, Passes, RemapPathScopeComponents, SplitDwarfKind, SwitchWithOptPath,
|
||||
};
|
||||
use rustc_span::{BytePos, InnerSpan, Pos, SpanData, SyntaxContext, sym};
|
||||
use rustc_session::config::{self, Lto, OutputType, Passes, SplitDwarfKind, SwitchWithOptPath};
|
||||
use rustc_span::{BytePos, InnerSpan, Pos, RemapPathScopeComponents, SpanData, SyntaxContext, sym};
|
||||
use rustc_target::spec::{
|
||||
Arch, CodeModel, FloatAbi, RelocModel, SanitizerSet, SplitDebuginfo, TlsModel,
|
||||
};
|
||||
|
|
@ -248,6 +246,7 @@ pub(crate) fn target_machine_factory(
|
|||
!sess.opts.unstable_opts.use_ctors_section.unwrap_or(sess.target.use_ctors_section);
|
||||
|
||||
let path_mapping = sess.source_map().path_mapping().clone();
|
||||
let working_dir = sess.source_map().working_dir().clone();
|
||||
|
||||
let use_emulated_tls = matches!(sess.tls_model(), TlsModel::Emulated);
|
||||
|
||||
|
|
@ -271,9 +270,6 @@ pub(crate) fn target_machine_factory(
|
|||
}
|
||||
};
|
||||
|
||||
let file_name_display_preference =
|
||||
sess.filename_display_preference(RemapPathScopeComponents::DEBUGINFO);
|
||||
|
||||
let use_wasm_eh = wants_wasm_eh(sess);
|
||||
|
||||
let prof = SelfProfilerRef::clone(&sess.prof);
|
||||
|
|
@ -284,8 +280,9 @@ pub(crate) fn target_machine_factory(
|
|||
let path_to_cstring_helper = |path: Option<PathBuf>| -> CString {
|
||||
let path = path.unwrap_or_default();
|
||||
let path = path_mapping
|
||||
.to_real_filename(path)
|
||||
.to_string_lossy(file_name_display_preference)
|
||||
.to_real_filename(&working_dir, path)
|
||||
.path(RemapPathScopeComponents::DEBUGINFO)
|
||||
.to_string_lossy()
|
||||
.into_owned();
|
||||
CString::new(path).unwrap()
|
||||
};
|
||||
|
|
|
|||
|
|
@ -7,9 +7,7 @@ use rustc_codegen_ssa::traits::{BaseTypeCodegenMethods, ConstCodegenMethods};
|
|||
use rustc_data_structures::fx::FxIndexMap;
|
||||
use rustc_index::IndexVec;
|
||||
use rustc_middle::ty::TyCtxt;
|
||||
use rustc_session::RemapFileNameExt;
|
||||
use rustc_session::config::RemapPathScopeComponents;
|
||||
use rustc_span::{SourceFile, StableSourceFileId};
|
||||
use rustc_span::{RemapPathScopeComponents, SourceFile, StableSourceFileId};
|
||||
use tracing::debug;
|
||||
|
||||
use crate::common::CodegenCx;
|
||||
|
|
@ -127,10 +125,7 @@ impl GlobalFileTable {
|
|||
|
||||
for file in all_files {
|
||||
raw_file_table.entry(file.stable_id).or_insert_with(|| {
|
||||
file.name
|
||||
.for_scope(tcx.sess, RemapPathScopeComponents::COVERAGE)
|
||||
.to_string_lossy()
|
||||
.into_owned()
|
||||
file.name.display(RemapPathScopeComponents::COVERAGE).to_string_lossy().into_owned()
|
||||
});
|
||||
}
|
||||
|
||||
|
|
@ -145,9 +140,10 @@ impl GlobalFileTable {
|
|||
// resolve any other entries that are stored as relative paths.
|
||||
let base_dir = tcx
|
||||
.sess
|
||||
.opts
|
||||
.working_dir
|
||||
.for_scope(tcx.sess, RemapPathScopeComponents::COVERAGE)
|
||||
.psess
|
||||
.source_map()
|
||||
.working_dir()
|
||||
.path(RemapPathScopeComponents::COVERAGE)
|
||||
.to_string_lossy();
|
||||
table.push(base_dir.as_ref());
|
||||
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
use std::borrow::Cow;
|
||||
use std::fmt::{self, Write};
|
||||
use std::hash::{Hash, Hasher};
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::path::PathBuf;
|
||||
use std::sync::Arc;
|
||||
use std::{iter, ptr};
|
||||
|
||||
|
|
@ -19,9 +19,7 @@ use rustc_middle::ty::{
|
|||
self, AdtKind, CoroutineArgsExt, ExistentialTraitRef, Instance, Ty, TyCtxt, Visibility,
|
||||
};
|
||||
use rustc_session::config::{self, DebugInfo, Lto};
|
||||
use rustc_span::{
|
||||
DUMMY_SP, FileName, FileNameDisplayPreference, SourceFile, Span, Symbol, hygiene,
|
||||
};
|
||||
use rustc_span::{DUMMY_SP, FileName, RemapPathScopeComponents, SourceFile, Span, Symbol, hygiene};
|
||||
use rustc_symbol_mangling::typeid_for_trait_ref;
|
||||
use rustc_target::spec::DebuginfoKind;
|
||||
use smallvec::smallvec;
|
||||
|
|
@ -555,79 +553,38 @@ pub(crate) fn file_metadata<'ll>(cx: &CodegenCx<'ll, '_>, source_file: &SourceFi
|
|||
) -> &'ll DIFile {
|
||||
debug!(?source_file.name);
|
||||
|
||||
let filename_display_preference =
|
||||
cx.sess().filename_display_preference(RemapPathScopeComponents::DEBUGINFO);
|
||||
|
||||
use rustc_session::config::RemapPathScopeComponents;
|
||||
let (directory, file_name) = match &source_file.name {
|
||||
FileName::Real(filename) => {
|
||||
let working_directory = &cx.sess().opts.working_dir;
|
||||
debug!(?working_directory);
|
||||
let (working_directory, embeddable_name) =
|
||||
filename.embeddable_name(RemapPathScopeComponents::DEBUGINFO);
|
||||
|
||||
if filename_display_preference == FileNameDisplayPreference::Remapped {
|
||||
let filename = cx
|
||||
.sess()
|
||||
.source_map()
|
||||
.path_mapping()
|
||||
.to_embeddable_absolute_path(filename.clone(), working_directory);
|
||||
debug!(?working_directory, ?embeddable_name);
|
||||
|
||||
// Construct the absolute path of the file
|
||||
let abs_path = filename.remapped_path_if_available();
|
||||
debug!(?abs_path);
|
||||
|
||||
if let Ok(rel_path) =
|
||||
abs_path.strip_prefix(working_directory.remapped_path_if_available())
|
||||
{
|
||||
// If the compiler's working directory (which also is the DW_AT_comp_dir of
|
||||
// the compilation unit) is a prefix of the path we are about to emit, then
|
||||
// only emit the part relative to the working directory. Because of path
|
||||
// remapping we sometimes see strange things here: `abs_path` might
|
||||
// actually look like a relative path (e.g.
|
||||
// `<crate-name-and-version>/src/lib.rs`), so if we emit it without taking
|
||||
// the working directory into account, downstream tooling will interpret it
|
||||
// as `<working-directory>/<crate-name-and-version>/src/lib.rs`, which
|
||||
// makes no sense. Usually in such cases the working directory will also be
|
||||
// remapped to `<crate-name-and-version>` or some other prefix of the path
|
||||
// we are remapping, so we end up with
|
||||
// `<crate-name-and-version>/<crate-name-and-version>/src/lib.rs`.
|
||||
// By moving the working directory portion into the `directory` part of the
|
||||
// DIFile, we allow LLVM to emit just the relative path for DWARF, while
|
||||
// still emitting the correct absolute path for CodeView.
|
||||
(
|
||||
working_directory.to_string_lossy(FileNameDisplayPreference::Remapped),
|
||||
rel_path.to_string_lossy().into_owned(),
|
||||
)
|
||||
} else {
|
||||
("".into(), abs_path.to_string_lossy().into_owned())
|
||||
}
|
||||
if let Ok(rel_path) = embeddable_name.strip_prefix(working_directory) {
|
||||
// If the compiler's working directory (which also is the DW_AT_comp_dir of
|
||||
// the compilation unit) is a prefix of the path we are about to emit, then
|
||||
// only emit the part relative to the working directory. Because of path
|
||||
// remapping we sometimes see strange things here: `abs_path` might
|
||||
// actually look like a relative path (e.g.
|
||||
// `<crate-name-and-version>/src/lib.rs`), so if we emit it without taking
|
||||
// the working directory into account, downstream tooling will interpret it
|
||||
// as `<working-directory>/<crate-name-and-version>/src/lib.rs`, which
|
||||
// makes no sense. Usually in such cases the working directory will also be
|
||||
// remapped to `<crate-name-and-version>` or some other prefix of the path
|
||||
// we are remapping, so we end up with
|
||||
// `<crate-name-and-version>/<crate-name-and-version>/src/lib.rs`.
|
||||
//
|
||||
// By moving the working directory portion into the `directory` part of the
|
||||
// DIFile, we allow LLVM to emit just the relative path for DWARF, while
|
||||
// still emitting the correct absolute path for CodeView.
|
||||
(working_directory.to_string_lossy(), rel_path.to_string_lossy().into_owned())
|
||||
} else {
|
||||
let working_directory = working_directory.local_path_if_available();
|
||||
let filename = filename.local_path_if_available();
|
||||
|
||||
debug!(?working_directory, ?filename);
|
||||
|
||||
let abs_path: Cow<'_, Path> = if filename.is_absolute() {
|
||||
filename.into()
|
||||
} else {
|
||||
let mut p = PathBuf::new();
|
||||
p.push(working_directory);
|
||||
p.push(filename);
|
||||
p.into()
|
||||
};
|
||||
|
||||
if let Ok(rel_path) = abs_path.strip_prefix(working_directory) {
|
||||
(
|
||||
working_directory.to_string_lossy(),
|
||||
rel_path.to_string_lossy().into_owned(),
|
||||
)
|
||||
} else {
|
||||
("".into(), abs_path.to_string_lossy().into_owned())
|
||||
}
|
||||
("".into(), embeddable_name.to_string_lossy().into_owned())
|
||||
}
|
||||
}
|
||||
other => {
|
||||
debug!(?other);
|
||||
("".into(), other.display(filename_display_preference).to_string())
|
||||
("".into(), other.display(RemapPathScopeComponents::DEBUGINFO).to_string())
|
||||
}
|
||||
};
|
||||
|
||||
|
|
@ -889,12 +846,10 @@ pub(crate) fn build_compile_unit_di_node<'ll, 'tcx>(
|
|||
codegen_unit_name: &str,
|
||||
debug_context: &CodegenUnitDebugContext<'ll, 'tcx>,
|
||||
) -> &'ll DIDescriptor {
|
||||
use rustc_session::RemapFileNameExt;
|
||||
use rustc_session::config::RemapPathScopeComponents;
|
||||
let mut name_in_debuginfo = tcx
|
||||
.sess
|
||||
.local_crate_source_file()
|
||||
.map(|src| src.for_scope(&tcx.sess, RemapPathScopeComponents::DEBUGINFO).to_path_buf())
|
||||
.map(|src| src.path(RemapPathScopeComponents::DEBUGINFO).to_path_buf())
|
||||
.unwrap_or_else(|| PathBuf::from(tcx.crate_name(LOCAL_CRATE).as_str()));
|
||||
|
||||
// To avoid breaking split DWARF, we need to ensure that each codegen unit
|
||||
|
|
@ -923,12 +878,7 @@ pub(crate) fn build_compile_unit_di_node<'ll, 'tcx>(
|
|||
let producer = format!("clang LLVM ({rustc_producer})");
|
||||
|
||||
let name_in_debuginfo = name_in_debuginfo.to_string_lossy();
|
||||
let work_dir = tcx
|
||||
.sess
|
||||
.opts
|
||||
.working_dir
|
||||
.for_scope(tcx.sess, RemapPathScopeComponents::DEBUGINFO)
|
||||
.to_string_lossy();
|
||||
let work_dir = tcx.sess.psess.source_map().working_dir();
|
||||
let output_filenames = tcx.output_filenames(());
|
||||
let split_name = if tcx.sess.target_can_use_split_dwarf()
|
||||
&& let Some(f) = output_filenames.split_dwarf_path(
|
||||
|
|
@ -938,14 +888,15 @@ pub(crate) fn build_compile_unit_di_node<'ll, 'tcx>(
|
|||
tcx.sess.invocation_temp.as_deref(),
|
||||
) {
|
||||
// We get a path relative to the working directory from split_dwarf_path
|
||||
Some(tcx.sess.source_map().path_mapping().to_real_filename(f))
|
||||
Some(tcx.sess.source_map().path_mapping().to_real_filename(work_dir, f))
|
||||
} else {
|
||||
None
|
||||
};
|
||||
let split_name = split_name
|
||||
.as_ref()
|
||||
.map(|f| f.for_scope(tcx.sess, RemapPathScopeComponents::DEBUGINFO).to_string_lossy())
|
||||
.map(|f| f.path(RemapPathScopeComponents::DEBUGINFO).to_string_lossy())
|
||||
.unwrap_or_default();
|
||||
let work_dir = work_dir.path(RemapPathScopeComponents::DEBUGINFO).to_string_lossy();
|
||||
let kind = DebugEmissionKind::from_generic(tcx.sess.opts.debuginfo);
|
||||
|
||||
let dwarf_version = tcx.sess.dwarf_version();
|
||||
|
|
|
|||
|
|
@ -2583,4 +2583,12 @@ unsafe extern "C" {
|
|||
|
||||
pub(crate) fn LLVMRustSetNoSanitizeAddress(Global: &Value);
|
||||
pub(crate) fn LLVMRustSetNoSanitizeHWAddress(Global: &Value);
|
||||
|
||||
pub(crate) fn LLVMAddAlias2<'ll>(
|
||||
M: &'ll Module,
|
||||
ValueTy: &Type,
|
||||
AddressSpace: c_uint,
|
||||
Aliasee: &Value,
|
||||
Name: *const c_char,
|
||||
) -> &'ll Value;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ use std::ptr;
|
|||
use std::string::FromUtf8Error;
|
||||
|
||||
use libc::c_uint;
|
||||
use rustc_abi::{Align, Size, WrappingRange};
|
||||
use rustc_abi::{AddressSpace, Align, Size, WrappingRange};
|
||||
use rustc_llvm::RustString;
|
||||
|
||||
pub(crate) use self::CallConv::*;
|
||||
|
|
@ -452,3 +452,14 @@ pub(crate) fn append_module_inline_asm<'ll>(llmod: &'ll Module, asm: &[u8]) {
|
|||
LLVMAppendModuleInlineAsm(llmod, asm.as_ptr(), asm.len());
|
||||
}
|
||||
}
|
||||
|
||||
/// Safe wrapper for `LLVMAddAlias2`
|
||||
pub(crate) fn add_alias<'ll>(
|
||||
module: &'ll Module,
|
||||
ty: &Type,
|
||||
address_space: AddressSpace,
|
||||
aliasee: &Value,
|
||||
name: &CStr,
|
||||
) -> &'ll Value {
|
||||
unsafe { LLVMAddAlias2(module, ty, address_space.0, aliasee, name.as_ptr()) }
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,3 +1,6 @@
|
|||
use std::ffi::CString;
|
||||
|
||||
use rustc_abi::AddressSpace;
|
||||
use rustc_codegen_ssa::traits::*;
|
||||
use rustc_hir::attrs::Linkage;
|
||||
use rustc_hir::def::DefKind;
|
||||
|
|
@ -7,6 +10,7 @@ use rustc_middle::mir::mono::Visibility;
|
|||
use rustc_middle::ty::layout::{FnAbiOf, HasTypingEnv, LayoutOf};
|
||||
use rustc_middle::ty::{self, Instance, TypeVisitableExt};
|
||||
use rustc_session::config::CrateType;
|
||||
use rustc_span::Symbol;
|
||||
use rustc_target::spec::{Arch, RelocModel};
|
||||
use tracing::debug;
|
||||
|
||||
|
|
@ -41,6 +45,9 @@ impl<'tcx> PreDefineCodegenMethods<'tcx> for CodegenCx<'_, 'tcx> {
|
|||
llvm::set_visibility(g, base::visibility_to_llvm(visibility));
|
||||
self.assume_dso_local(g, false);
|
||||
|
||||
let attrs = self.tcx.codegen_instance_attrs(instance.def);
|
||||
self.add_aliases(g, &attrs.foreign_item_symbol_aliases);
|
||||
|
||||
self.instances.borrow_mut().insert(instance, g);
|
||||
}
|
||||
|
||||
|
|
@ -78,11 +85,31 @@ impl<'tcx> PreDefineCodegenMethods<'tcx> for CodegenCx<'_, 'tcx> {
|
|||
|
||||
self.assume_dso_local(lldecl, false);
|
||||
|
||||
self.add_aliases(lldecl, &attrs.foreign_item_symbol_aliases);
|
||||
|
||||
self.instances.borrow_mut().insert(instance, lldecl);
|
||||
}
|
||||
}
|
||||
|
||||
impl CodegenCx<'_, '_> {
|
||||
fn add_aliases(&self, aliasee: &llvm::Value, aliases: &[(Symbol, Linkage, Visibility)]) {
|
||||
let ty = self.get_type_of_global(aliasee);
|
||||
|
||||
for (alias, linkage, visibility) in aliases {
|
||||
tracing::debug!("ALIAS: {alias:?} {linkage:?} {visibility:?}");
|
||||
let lldecl = llvm::add_alias(
|
||||
self.llmod,
|
||||
ty,
|
||||
AddressSpace::ZERO,
|
||||
aliasee,
|
||||
&CString::new(alias.as_str()).unwrap(),
|
||||
);
|
||||
|
||||
llvm::set_visibility(lldecl, base::visibility_to_llvm(*visibility));
|
||||
llvm::set_linkage(lldecl, base::linkage_to_llvm(*linkage));
|
||||
}
|
||||
}
|
||||
|
||||
/// Whether a definition or declaration can be assumed to be local to a group of
|
||||
/// libraries that form a single DSO or executable.
|
||||
/// Marks the local as DSO if so.
|
||||
|
|
|
|||
|
|
@ -277,7 +277,7 @@ pub fn each_linked_rlib(
|
|||
}
|
||||
let crate_name = info.crate_name[&cnum];
|
||||
let used_crate_source = &info.used_crate_source[&cnum];
|
||||
if let Some((path, _)) = &used_crate_source.rlib {
|
||||
if let Some(path) = &used_crate_source.rlib {
|
||||
f(cnum, path);
|
||||
} else if used_crate_source.rmeta.is_some() {
|
||||
return Err(errors::LinkRlibError::OnlyRmetaFound { crate_name });
|
||||
|
|
@ -541,7 +541,7 @@ fn link_staticlib(
|
|||
};
|
||||
let crate_name = codegen_results.crate_info.crate_name[&cnum];
|
||||
let used_crate_source = &codegen_results.crate_info.used_crate_source[&cnum];
|
||||
if let Some((path, _)) = &used_crate_source.dylib {
|
||||
if let Some(path) = &used_crate_source.dylib {
|
||||
all_rust_dylibs.push(&**path);
|
||||
} else if used_crate_source.rmeta.is_some() {
|
||||
sess.dcx().emit_fatal(errors::LinkRlibError::OnlyRmetaFound { crate_name });
|
||||
|
|
@ -619,7 +619,6 @@ fn link_dwarf_object(sess: &Session, cg_results: &CodegenResults, executable_out
|
|||
.used_crate_source
|
||||
.items()
|
||||
.filter_map(|(_, csource)| csource.rlib.as_ref())
|
||||
.map(|(path, _)| path)
|
||||
.into_sorted_stable_ord();
|
||||
|
||||
for input_rlib in input_rlibs {
|
||||
|
|
@ -2173,12 +2172,7 @@ fn add_rpath_args(
|
|||
.crate_info
|
||||
.used_crates
|
||||
.iter()
|
||||
.filter_map(|cnum| {
|
||||
codegen_results.crate_info.used_crate_source[cnum]
|
||||
.dylib
|
||||
.as_ref()
|
||||
.map(|(path, _)| &**path)
|
||||
})
|
||||
.filter_map(|cnum| codegen_results.crate_info.used_crate_source[cnum].dylib.as_deref())
|
||||
.collect::<Vec<_>>();
|
||||
let rpath_config = RPathConfig {
|
||||
libs: &*libs,
|
||||
|
|
@ -2656,7 +2650,7 @@ fn add_native_libs_from_crate(
|
|||
|
||||
if link_static && cnum != LOCAL_CRATE && !bundled_libs.is_empty() {
|
||||
// If rlib contains native libs as archives, unpack them to tmpdir.
|
||||
let rlib = &codegen_results.crate_info.used_crate_source[&cnum].rlib.as_ref().unwrap().0;
|
||||
let rlib = codegen_results.crate_info.used_crate_source[&cnum].rlib.as_ref().unwrap();
|
||||
archive_builder_builder
|
||||
.extract_bundled_libs(rlib, tmpdir, bundled_libs)
|
||||
.unwrap_or_else(|e| sess.dcx().emit_fatal(e));
|
||||
|
|
@ -2827,7 +2821,7 @@ fn add_upstream_rust_crates(
|
|||
}
|
||||
Linkage::Dynamic => {
|
||||
let src = &codegen_results.crate_info.used_crate_source[&cnum];
|
||||
add_dynamic_crate(cmd, sess, &src.dylib.as_ref().unwrap().0);
|
||||
add_dynamic_crate(cmd, sess, src.dylib.as_ref().unwrap());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -2955,7 +2949,7 @@ fn add_static_crate(
|
|||
bundled_lib_file_names: &FxIndexSet<Symbol>,
|
||||
) {
|
||||
let src = &codegen_results.crate_info.used_crate_source[&cnum];
|
||||
let cratepath = &src.rlib.as_ref().unwrap().0;
|
||||
let cratepath = src.rlib.as_ref().unwrap();
|
||||
|
||||
let mut link_upstream =
|
||||
|path: &Path| cmd.link_staticlib_by_path(&rehome_lib_path(sess, path), false);
|
||||
|
|
|
|||
|
|
@ -127,7 +127,10 @@ fn reachable_non_generics_provider(tcx: TyCtxt<'_>, _: LocalCrate) -> DefIdMap<S
|
|||
|| codegen_attrs.flags.contains(CodegenFnAttrFlags::USED_LINKER),
|
||||
rustc_std_internal_symbol: codegen_attrs
|
||||
.flags
|
||||
.contains(CodegenFnAttrFlags::RUSTC_STD_INTERNAL_SYMBOL),
|
||||
.contains(CodegenFnAttrFlags::RUSTC_STD_INTERNAL_SYMBOL)
|
||||
|| codegen_attrs
|
||||
.flags
|
||||
.contains(CodegenFnAttrFlags::EXTERNALLY_IMPLEMENTABLE_ITEM),
|
||||
};
|
||||
(def_id.to_def_id(), info)
|
||||
})
|
||||
|
|
@ -519,10 +522,12 @@ fn symbol_export_level(tcx: TyCtxt<'_>, sym_def_id: DefId) -> SymbolExportLevel
|
|||
let is_extern = codegen_fn_attrs.contains_extern_indicator();
|
||||
let std_internal =
|
||||
codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::RUSTC_STD_INTERNAL_SYMBOL);
|
||||
let eii = codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::EXTERNALLY_IMPLEMENTABLE_ITEM);
|
||||
|
||||
if is_extern && !std_internal {
|
||||
if is_extern && !std_internal && !eii {
|
||||
let target = &tcx.sess.target.llvm_target;
|
||||
// WebAssembly cannot export data symbols, so reduce their export level
|
||||
// FIXME(jdonszelmann) don't do a substring match here.
|
||||
if target.contains("emscripten") {
|
||||
if let DefKind::Static { .. } = tcx.def_kind(sym_def_id) {
|
||||
return SymbolExportLevel::Rust;
|
||||
|
|
|
|||
|
|
@ -3,19 +3,22 @@ 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_hir::attrs::{AttributeKind, InlineAttr, InstructionSetAttr, RtsanSetting, UsedBy};
|
||||
use rustc_hir::attrs::{
|
||||
AttributeKind, InlineAttr, InstructionSetAttr, Linkage, RtsanSetting, UsedBy,
|
||||
};
|
||||
use rustc_hir::def::DefKind;
|
||||
use rustc_hir::def_id::{DefId, LOCAL_CRATE, LocalDefId};
|
||||
use rustc_hir::{self as hir, Attribute, LangItem, find_attr, lang_items};
|
||||
use rustc_middle::middle::codegen_fn_attrs::{
|
||||
CodegenFnAttrFlags, CodegenFnAttrs, PatchableFunctionEntry, SanitizerFnAttrs,
|
||||
};
|
||||
use rustc_middle::mir::mono::Visibility;
|
||||
use rustc_middle::query::Providers;
|
||||
use rustc_middle::span_bug;
|
||||
use rustc_middle::ty::{self as ty, TyCtxt};
|
||||
use rustc_middle::ty::{self as ty, Instance, TyCtxt};
|
||||
use rustc_session::lint;
|
||||
use rustc_session::parse::feature_err;
|
||||
use rustc_span::{Ident, Span, sym};
|
||||
use rustc_span::{Ident, Span, Symbol, sym};
|
||||
use rustc_target::spec::Os;
|
||||
|
||||
use crate::errors;
|
||||
|
|
@ -310,6 +313,43 @@ fn process_builtin_attrs(
|
|||
AttributeKind::ObjcSelector { methname, .. } => {
|
||||
codegen_fn_attrs.objc_selector = Some(*methname);
|
||||
}
|
||||
AttributeKind::EiiExternItem => {
|
||||
codegen_fn_attrs.flags |= CodegenFnAttrFlags::EXTERNALLY_IMPLEMENTABLE_ITEM;
|
||||
}
|
||||
AttributeKind::EiiImpls(impls) => {
|
||||
for i in impls {
|
||||
let extern_item = find_attr!(
|
||||
tcx.get_all_attrs(i.eii_macro),
|
||||
AttributeKind::EiiExternTarget(target) => target.eii_extern_target
|
||||
)
|
||||
.expect("eii should have declaration macro with extern target attribute");
|
||||
|
||||
let symbol_name = tcx.symbol_name(Instance::mono(tcx, extern_item));
|
||||
|
||||
// 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(&i.eii_macro).expect("at least one").1.iter().any(|(_, imp)| !imp.is_default)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
codegen_fn_attrs.foreign_item_symbol_aliases.push((
|
||||
Symbol::intern(symbol_name.name),
|
||||
if i.is_default { Linkage::LinkOnceAny } else { Linkage::External },
|
||||
Visibility::Default,
|
||||
));
|
||||
codegen_fn_attrs.flags |= CodegenFnAttrFlags::EXTERNALLY_IMPLEMENTABLE_ITEM;
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
|
@ -411,6 +451,12 @@ fn apply_overrides(tcx: TyCtxt<'_>, did: LocalDefId, codegen_fn_attrs: &mut Code
|
|||
// * `#[rustc_std_internal_symbol]` mangles the symbol name in a special way
|
||||
// both for exports and imports through foreign items. This is handled further,
|
||||
// during symbol mangling logic.
|
||||
} else if codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::EXTERNALLY_IMPLEMENTABLE_ITEM)
|
||||
{
|
||||
// * externally implementable items keep their mangled symbol name.
|
||||
// multiple EIIs can have the same name, so not mangling them would be a bug.
|
||||
// Implementing an EII does the appropriate name resolution to make sure the implementations
|
||||
// get the same symbol name as the *mangled* foreign item they refer to so that's all good.
|
||||
} else if codegen_fn_attrs.symbol_name.is_some() {
|
||||
// * This can be overridden with the `#[link_name]` attribute
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -208,15 +208,10 @@ impl<'tcx> CompileTimeInterpCx<'tcx> {
|
|||
let topmost = span.ctxt().outer_expn().expansion_cause().unwrap_or(span);
|
||||
let caller = self.tcx.sess.source_map().lookup_char_pos(topmost.lo());
|
||||
|
||||
use rustc_session::RemapFileNameExt;
|
||||
use rustc_session::config::RemapPathScopeComponents;
|
||||
use rustc_span::RemapPathScopeComponents;
|
||||
(
|
||||
Symbol::intern(
|
||||
&caller
|
||||
.file
|
||||
.name
|
||||
.for_scope(self.tcx.sess, RemapPathScopeComponents::DIAGNOSTICS)
|
||||
.to_string_lossy(),
|
||||
&caller.file.name.display(RemapPathScopeComponents::DIAGNOSTICS).to_string_lossy(),
|
||||
),
|
||||
u32::try_from(caller.line).unwrap(),
|
||||
u32::try_from(caller.col_display).unwrap().checked_add(1).unwrap(),
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
use std::hash::BuildHasherDefault;
|
||||
|
||||
pub use rustc_hash::{FxHashMap, FxHashSet, FxHasher};
|
||||
pub use rustc_hash::{FxBuildHasher, FxHashMap, FxHashSet, FxHasher};
|
||||
|
||||
pub type StdEntry<'a, K, V> = std::collections::hash_map::Entry<'a, K, V>;
|
||||
|
||||
|
|
|
|||
|
|
@ -181,7 +181,7 @@ impl<'tcx> pprust_hir::PpAnn for HirTypedAnn<'tcx> {
|
|||
}
|
||||
|
||||
fn get_source(sess: &Session) -> (String, FileName) {
|
||||
let src_name = sess.io.input.source_name();
|
||||
let src_name = sess.io.input.file_name(&sess);
|
||||
let src = String::clone(
|
||||
sess.source_map()
|
||||
.get_source_file(&src_name)
|
||||
|
|
|
|||
|
|
@ -1,8 +1,10 @@
|
|||
#### Note: this error code is no longer emitted by the compiler.
|
||||
|
||||
An unknown meta item was used.
|
||||
|
||||
Erroneous code example:
|
||||
|
||||
```compile_fail,E0541
|
||||
```compile_fail (no longer emitted)
|
||||
#[deprecated(
|
||||
since="1.0.0",
|
||||
// error: unknown meta item
|
||||
|
|
|
|||
68
compiler/rustc_error_codes/src/error_codes/E0806.md
Normal file
68
compiler/rustc_error_codes/src/error_codes/E0806.md
Normal file
|
|
@ -0,0 +1,68 @@
|
|||
An externally implementable item is not compatible with its declaration.
|
||||
|
||||
Erroneous code example:
|
||||
|
||||
```rust,edition2021,compile_fail,E0806
|
||||
#![feature(extern_item_impls)]
|
||||
|
||||
#[eii(foo)]
|
||||
fn x();
|
||||
|
||||
#[foo]
|
||||
fn y(a: u64) -> u64 {
|
||||
//~^ ERROR E0806
|
||||
a
|
||||
}
|
||||
|
||||
|
||||
fn main() {}
|
||||
```
|
||||
|
||||
The error here is caused by the fact that `y` implements the
|
||||
externally implementable item `foo`.
|
||||
It can only do so if the signature of the implementation `y` matches
|
||||
that of the declaration of `foo`.
|
||||
So, to fix this, `y`'s signature must be changed to match that of `x`:
|
||||
|
||||
```rust,edition2021
|
||||
#![feature(extern_item_impls)]
|
||||
|
||||
#[eii(foo)]
|
||||
fn x();
|
||||
|
||||
#[foo]
|
||||
fn y() {}
|
||||
|
||||
|
||||
fn main() {}
|
||||
```
|
||||
|
||||
One common way this can be triggered is by using the wrong
|
||||
signature for `#[panic_handler]`.
|
||||
The signature is provided by `core`.
|
||||
|
||||
```rust,edition2021,ignore
|
||||
#![no_std]
|
||||
|
||||
#[panic_handler]
|
||||
fn on_panic() -> ! {
|
||||
//~^ ERROR E0806
|
||||
|
||||
loop {}
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
```
|
||||
|
||||
Should be:
|
||||
|
||||
```rust,edition2021,ignore
|
||||
#![no_std]
|
||||
|
||||
#[panic_handler]
|
||||
fn on_panic(info: &core::panic::PanicInfo<'_>) -> ! {
|
||||
loop {}
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
```
|
||||
|
|
@ -543,6 +543,7 @@ macro_rules! error_codes {
|
|||
0803,
|
||||
0804,
|
||||
0805,
|
||||
0806,
|
||||
);
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@
|
|||
|
||||
use std::error::Report;
|
||||
use std::io::{self, Write};
|
||||
use std::path::Path;
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::sync::{Arc, Mutex};
|
||||
use std::vec;
|
||||
|
||||
|
|
@ -20,9 +20,9 @@ use derive_setters::Setters;
|
|||
use rustc_data_structures::sync::IntoDynSyncSend;
|
||||
use rustc_error_messages::FluentArgs;
|
||||
use rustc_lint_defs::Applicability;
|
||||
use rustc_span::Span;
|
||||
use rustc_span::hygiene::ExpnData;
|
||||
use rustc_span::source_map::{FilePathMapping, SourceMap};
|
||||
use rustc_span::{FileName, RealFileName, Span};
|
||||
use serde::Serialize;
|
||||
|
||||
use crate::annotate_snippet_emitter_writer::AnnotateSnippetEmitter;
|
||||
|
|
@ -490,8 +490,14 @@ impl DiagnosticSpan {
|
|||
None => {
|
||||
span = rustc_span::DUMMY_SP;
|
||||
empty_source_map = Arc::new(SourceMap::new(FilePathMapping::empty()));
|
||||
empty_source_map
|
||||
.new_source_file(std::path::PathBuf::from("empty.rs").into(), String::new());
|
||||
empty_source_map.new_source_file(
|
||||
FileName::Real(
|
||||
empty_source_map
|
||||
.path_mapping()
|
||||
.to_real_filename(&RealFileName::empty(), PathBuf::from("empty.rs")),
|
||||
),
|
||||
String::new(),
|
||||
);
|
||||
&empty_source_map
|
||||
}
|
||||
};
|
||||
|
|
|
|||
|
|
@ -36,11 +36,15 @@ impl<T: Write> Write for Shared<T> {
|
|||
}
|
||||
}
|
||||
|
||||
fn filename(sm: &SourceMap, path: &str) -> FileName {
|
||||
FileName::Real(sm.path_mapping().to_real_filename(sm.working_dir(), PathBuf::from(path)))
|
||||
}
|
||||
|
||||
/// Test the span yields correct positions in JSON.
|
||||
fn test_positions(code: &str, span: (u32, u32), expected_output: SpanTestData) {
|
||||
rustc_span::create_default_session_globals_then(|| {
|
||||
let sm = Arc::new(SourceMap::new(FilePathMapping::empty()));
|
||||
sm.new_source_file(Path::new("test.rs").to_owned().into(), code.to_owned());
|
||||
sm.new_source_file(filename(&sm, "test.rs"), code.to_owned());
|
||||
let translator =
|
||||
Translator::with_fallback_bundle(vec![crate::DEFAULT_LOCALE_RESOURCE], false);
|
||||
|
||||
|
|
|
|||
|
|
@ -470,7 +470,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
|
|||
FileName::Real(name) => name
|
||||
.into_local_path()
|
||||
.expect("attempting to resolve a file path in an external file"),
|
||||
other => PathBuf::from(other.prefer_local().to_string()),
|
||||
other => PathBuf::from(other.prefer_local_unconditionally().to_string()),
|
||||
};
|
||||
let dir_path = file_path.parent().unwrap_or(&file_path).to_owned();
|
||||
self.cx.root_path = dir_path.clone();
|
||||
|
|
|
|||
|
|
@ -138,10 +138,7 @@ pub(crate) fn update_macro_stats(
|
|||
if false {
|
||||
let name = ExpnKind::Macro(macro_kind, name).descr();
|
||||
let crate_name = &ecx.ecfg.crate_name;
|
||||
let span = ecx
|
||||
.sess
|
||||
.source_map()
|
||||
.span_to_string(span, rustc_span::FileNameDisplayPreference::Local);
|
||||
let span = ecx.sess.source_map().span_to_diagnostic_string(span);
|
||||
eprint!(
|
||||
"\
|
||||
-------------------------------\n\
|
||||
|
|
|
|||
|
|
@ -961,6 +961,11 @@ pub static BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
|
|||
allow_internal_unsafe, Normal, template!(Word), WarnFollowing,
|
||||
EncodeCrossCrate::No, "allow_internal_unsafe side-steps the unsafe_code lint",
|
||||
),
|
||||
gated!(
|
||||
rustc_eii_extern_item, Normal, template!(Word),
|
||||
ErrorFollowing, EncodeCrossCrate::Yes, eii_internals,
|
||||
"used internally to mark types with a `transparent` representation when it is guaranteed by the documentation",
|
||||
),
|
||||
rustc_attr!(
|
||||
rustc_allowed_through_unstable_modules, Normal, template!(NameValueStr: "deprecation message"),
|
||||
WarnFollowing, EncodeCrossCrate::No,
|
||||
|
|
|
|||
|
|
@ -221,6 +221,8 @@ declare_features! (
|
|||
(internal, compiler_builtins, "1.13.0", None),
|
||||
/// Allows writing custom MIR
|
||||
(internal, custom_mir, "1.65.0", None),
|
||||
/// Implementation details of externally implementatble items
|
||||
(internal, eii_internals, "CURRENT_RUSTC_VERSION", None),
|
||||
/// Outputs useful `assert!` messages
|
||||
(unstable, generic_assert, "1.63.0", None),
|
||||
/// Allows using the #[rustc_intrinsic] attribute.
|
||||
|
|
@ -501,6 +503,8 @@ declare_features! (
|
|||
(incomplete, explicit_tail_calls, "1.72.0", Some(112788)),
|
||||
/// Allows using `#[export_stable]` which indicates that an item is exportable.
|
||||
(incomplete, export_stable, "1.88.0", Some(139939)),
|
||||
/// Externally implementatble items
|
||||
(unstable, extern_item_impls, "CURRENT_RUSTC_VERSION", Some(125418)),
|
||||
/// Allows defining `extern type`s.
|
||||
(unstable, extern_types, "1.23.0", Some(43467)),
|
||||
/// Allow using 128-bit (quad precision) floating point numbers.
|
||||
|
|
|
|||
|
|
@ -19,6 +19,23 @@ use crate::attrs::pretty_printing::PrintAttribute;
|
|||
use crate::limit::Limit;
|
||||
use crate::{DefaultBodyStability, PartialConstStability, RustcVersion, Stability};
|
||||
|
||||
#[derive(Copy, Clone, Debug, HashStable_Generic, Encodable, Decodable, PrintAttribute)]
|
||||
pub struct EiiImpl {
|
||||
pub eii_macro: DefId,
|
||||
pub impl_marked_unsafe: bool,
|
||||
pub span: Span,
|
||||
pub inner_span: Span,
|
||||
pub is_default: bool,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, HashStable_Generic, Encodable, Decodable, PrintAttribute)]
|
||||
pub struct EiiDecl {
|
||||
pub eii_extern_target: DefId,
|
||||
/// whether or not it is unsafe to implement this EII
|
||||
pub impl_unsafe: bool,
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, PartialEq, Encodable, Decodable, Debug, HashStable_Generic, PrintAttribute)]
|
||||
pub enum InlineAttr {
|
||||
None,
|
||||
|
|
@ -692,6 +709,15 @@ pub enum AttributeKind {
|
|||
/// Represents `#[rustc_dummy]`.
|
||||
Dummy,
|
||||
|
||||
/// Implementation detail of `#[eii]`
|
||||
EiiExternItem,
|
||||
|
||||
/// Implementation detail of `#[eii]`
|
||||
EiiExternTarget(EiiDecl),
|
||||
|
||||
/// Implementation detail of `#[eii]`
|
||||
EiiImpls(ThinVec<EiiImpl>),
|
||||
|
||||
/// Represents [`#[export_name]`](https://doc.rust-lang.org/reference/abi.html#the-export_name-attribute).
|
||||
ExportName {
|
||||
/// The name to export this item with.
|
||||
|
|
|
|||
|
|
@ -43,6 +43,9 @@ impl AttributeKind {
|
|||
Doc(_) => Yes,
|
||||
DocComment { .. } => Yes,
|
||||
Dummy => No,
|
||||
EiiExternItem => No,
|
||||
EiiExternTarget(_) => Yes,
|
||||
EiiImpls(..) => No,
|
||||
ExportName { .. } => Yes,
|
||||
ExportStable => No,
|
||||
FfiConst(..) => No,
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ use rustc_ast::token::{CommentKind, DocFragmentKind};
|
|||
use rustc_ast::{AttrStyle, IntTy, UintTy};
|
||||
use rustc_ast_pretty::pp::Printer;
|
||||
use rustc_data_structures::fx::FxIndexMap;
|
||||
use rustc_span::def_id::DefId;
|
||||
use rustc_span::hygiene::Transparency;
|
||||
use rustc_span::{ErrorGuaranteed, Ident, Span, Symbol};
|
||||
use rustc_target::spec::SanitizerSet;
|
||||
|
|
@ -170,4 +171,5 @@ print_debug!(
|
|||
DocFragmentKind,
|
||||
Transparency,
|
||||
SanitizerSet,
|
||||
DefId,
|
||||
);
|
||||
|
|
|
|||
|
|
@ -4164,6 +4164,9 @@ pub struct Item<'hir> {
|
|||
pub span: Span,
|
||||
pub vis_span: Span,
|
||||
pub has_delayed_lints: bool,
|
||||
/// hint to speed up collection: true if the item is a static or function and has
|
||||
/// either an `EiiImpls` or `EiiExternTarget` attribute
|
||||
pub eii: bool,
|
||||
}
|
||||
|
||||
impl<'hir> Item<'hir> {
|
||||
|
|
|
|||
|
|
@ -532,7 +532,7 @@ pub fn walk_param<'v, V: Visitor<'v>>(visitor: &mut V, param: &'v Param<'v>) ->
|
|||
}
|
||||
|
||||
pub fn walk_item<'v, V: Visitor<'v>>(visitor: &mut V, item: &'v Item<'v>) -> V::Result {
|
||||
let Item { owner_id: _, kind, span: _, vis_span: _, has_delayed_lints: _ } = item;
|
||||
let Item { owner_id: _, kind, span: _, vis_span: _, has_delayed_lints: _, eii: _ } = item;
|
||||
try_visit!(visitor.visit_id(item.hir_id()));
|
||||
match *kind {
|
||||
ItemKind::ExternCrate(orig_name, ident) => {
|
||||
|
|
|
|||
|
|
@ -165,6 +165,10 @@ 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_eii_with_generics =
|
||||
#[{$eii_name}] cannot have generic parameters other than lifetimes
|
||||
.label = required by this attribute
|
||||
|
||||
hir_analysis_empty_specialization = specialization impl does not specialize any associated items
|
||||
.note = impl is a specialization of this impl
|
||||
|
||||
|
|
@ -300,6 +304,13 @@ hir_analysis_lifetime_not_captured = `impl Trait` captures lifetime parameter, b
|
|||
.label = lifetime captured due to being mentioned in the bounds of the `impl Trait`
|
||||
.param_label = this lifetime parameter is captured
|
||||
|
||||
hir_analysis_lifetimes_or_bounds_mismatch_on_eii =
|
||||
lifetime parameters or bounds of `{$ident}` do not match the declaration
|
||||
.label = lifetimes do not match
|
||||
.generics_label = lifetimes in impl do not match this signature
|
||||
.where_label = this `where` clause might not match the one in the declaration
|
||||
.bounds_label = this bound might be missing in the implementation
|
||||
|
||||
hir_analysis_lifetimes_or_bounds_mismatch_on_trait =
|
||||
lifetime parameters or bounds on {$item_kind} `{$ident}` do not match the trait declaration
|
||||
.label = lifetimes do not match {$item_kind} in trait
|
||||
|
|
|
|||
433
compiler/rustc_hir_analysis/src/check/compare_eii.rs
Normal file
433
compiler/rustc_hir_analysis/src/check/compare_eii.rs
Normal file
|
|
@ -0,0 +1,433 @@
|
|||
//! This module is very similar to `compare_impl_item`.
|
||||
//! Most logic is taken from there,
|
||||
//! since in a very similar way we're comparing some declaration of a signature to an implementation.
|
||||
//! The major difference is that we don't bother with self types, since for EIIs we're comparing freestanding item.
|
||||
|
||||
use std::borrow::Cow;
|
||||
use std::iter;
|
||||
|
||||
use rustc_data_structures::fx::FxIndexSet;
|
||||
use rustc_errors::{Applicability, E0806, struct_span_code_err};
|
||||
use rustc_hir::def_id::{DefId, LocalDefId};
|
||||
use rustc_hir::{self as hir, FnSig, HirId, ItemKind};
|
||||
use rustc_infer::infer::{self, InferCtxt, TyCtxtInferExt};
|
||||
use rustc_infer::traits::{ObligationCause, ObligationCauseCode};
|
||||
use rustc_middle::ty::error::{ExpectedFound, TypeError};
|
||||
use rustc_middle::ty::{self, TyCtxt, TypeVisitableExt, TypingMode};
|
||||
use rustc_span::{ErrorGuaranteed, Ident, Span, Symbol};
|
||||
use rustc_trait_selection::error_reporting::InferCtxtErrorExt;
|
||||
use rustc_trait_selection::regions::InferCtxtRegionExt;
|
||||
use rustc_trait_selection::traits::{self, ObligationCtxt};
|
||||
use tracing::{debug, instrument};
|
||||
|
||||
use super::potentially_plural_count;
|
||||
use crate::check::compare_impl_item::{
|
||||
CheckNumberOfEarlyBoundRegionsError, check_number_of_early_bound_regions,
|
||||
};
|
||||
use crate::errors::{EiiWithGenerics, LifetimesOrBoundsMismatchOnEii};
|
||||
|
||||
/// Checks whether the signature of some `external_impl`, matches
|
||||
/// the signature of `declaration`, which it is supposed to be compatible
|
||||
/// with in order to implement the item.
|
||||
pub(crate) fn compare_eii_function_types<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
external_impl: LocalDefId,
|
||||
declaration: DefId,
|
||||
eii_name: Symbol,
|
||||
eii_attr_span: Span,
|
||||
) -> Result<(), ErrorGuaranteed> {
|
||||
check_is_structurally_compatible(tcx, external_impl, declaration, eii_name, eii_attr_span)?;
|
||||
|
||||
let external_impl_span = tcx.def_span(external_impl);
|
||||
let cause = ObligationCause::new(
|
||||
external_impl_span,
|
||||
external_impl,
|
||||
ObligationCauseCode::CompareEii { external_impl, declaration },
|
||||
);
|
||||
|
||||
// FIXME(eii): even if we don't support generic functions, we should support explicit outlive bounds here
|
||||
let param_env = tcx.param_env(declaration);
|
||||
|
||||
let infcx = &tcx.infer_ctxt().build(TypingMode::non_body_analysis());
|
||||
let ocx = ObligationCtxt::new_with_diagnostics(infcx);
|
||||
|
||||
// We now need to check that the signature of the implementation is
|
||||
// compatible with that of the declaration. We do this by
|
||||
// checking that `impl_fty <: trait_fty`.
|
||||
//
|
||||
// FIXME: We manually instantiate the declaration here as we need
|
||||
// to manually compute its implied bounds. Otherwise this could just
|
||||
// be ocx.sub(impl_sig, trait_sig).
|
||||
|
||||
let mut wf_tys = FxIndexSet::default();
|
||||
let norm_cause = ObligationCause::misc(external_impl_span, external_impl);
|
||||
|
||||
let declaration_sig = tcx.fn_sig(declaration).instantiate_identity();
|
||||
let declaration_sig = tcx.liberate_late_bound_regions(external_impl.into(), declaration_sig);
|
||||
debug!(?declaration_sig);
|
||||
|
||||
let unnormalized_external_impl_sig = infcx.instantiate_binder_with_fresh_vars(
|
||||
external_impl_span,
|
||||
infer::BoundRegionConversionTime::HigherRankedType,
|
||||
tcx.fn_sig(external_impl).instantiate(
|
||||
tcx,
|
||||
infcx.fresh_args_for_item(external_impl_span, external_impl.to_def_id()),
|
||||
),
|
||||
);
|
||||
let external_impl_sig = ocx.normalize(&norm_cause, param_env, unnormalized_external_impl_sig);
|
||||
debug!(?external_impl_sig);
|
||||
|
||||
// Next, add all inputs and output as well-formed tys. Importantly,
|
||||
// we have to do this before normalization, since the normalized ty may
|
||||
// not contain the input parameters. See issue #87748.
|
||||
wf_tys.extend(declaration_sig.inputs_and_output.iter());
|
||||
let declaration_sig = ocx.normalize(&norm_cause, param_env, declaration_sig);
|
||||
// We also have to add the normalized declaration
|
||||
// as we don't normalize during implied bounds computation.
|
||||
wf_tys.extend(external_impl_sig.inputs_and_output.iter());
|
||||
|
||||
// FIXME: Copied over from compare impl items, same issue:
|
||||
// We'd want to keep more accurate spans than "the method signature" when
|
||||
// processing the comparison between the trait and impl fn, but we sadly lose them
|
||||
// and point at the whole signature when a trait bound or specific input or output
|
||||
// type would be more appropriate. In other places we have a `Vec<Span>`
|
||||
// corresponding to their `Vec<Predicate>`, but we don't have that here.
|
||||
// Fixing this would improve the output of test `issue-83765.rs`.
|
||||
let result = ocx.sup(&cause, param_env, declaration_sig, external_impl_sig);
|
||||
|
||||
if let Err(terr) = result {
|
||||
debug!(?external_impl_sig, ?declaration_sig, ?terr, "sub_types failed");
|
||||
|
||||
let emitted = report_eii_mismatch(
|
||||
infcx,
|
||||
cause,
|
||||
param_env,
|
||||
terr,
|
||||
(declaration, declaration_sig),
|
||||
(external_impl, external_impl_sig),
|
||||
eii_attr_span,
|
||||
eii_name,
|
||||
);
|
||||
return Err(emitted);
|
||||
}
|
||||
|
||||
if !(declaration_sig, external_impl_sig).references_error() {
|
||||
for ty in unnormalized_external_impl_sig.inputs_and_output {
|
||||
ocx.register_obligation(traits::Obligation::new(
|
||||
infcx.tcx,
|
||||
cause.clone(),
|
||||
param_env,
|
||||
ty::ClauseKind::WellFormed(ty.into()),
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
// Check that all obligations are satisfied by the implementation's
|
||||
// version.
|
||||
let errors = ocx.evaluate_obligations_error_on_ambiguity();
|
||||
if !errors.is_empty() {
|
||||
let reported = infcx.err_ctxt().report_fulfillment_errors(errors);
|
||||
return Err(reported);
|
||||
}
|
||||
|
||||
// Finally, resolve all regions. This catches wily misuses of
|
||||
// lifetime parameters.
|
||||
let errors = infcx.resolve_regions(external_impl, param_env, wf_tys);
|
||||
if !errors.is_empty() {
|
||||
return Err(infcx
|
||||
.tainted_by_errors()
|
||||
.unwrap_or_else(|| infcx.err_ctxt().report_region_errors(external_impl, &errors)));
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Checks a bunch of different properties of the impl/trait methods for
|
||||
/// compatibility, such as asyncness, number of argument, self receiver kind,
|
||||
/// and number of early- and late-bound generics.
|
||||
///
|
||||
/// Corresponds to `check_method_is_structurally_compatible` for impl method compatibility checks.
|
||||
fn check_is_structurally_compatible<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
external_impl: LocalDefId,
|
||||
declaration: DefId,
|
||||
eii_name: Symbol,
|
||||
eii_attr_span: Span,
|
||||
) -> Result<(), ErrorGuaranteed> {
|
||||
check_no_generics(tcx, external_impl, declaration, eii_name, eii_attr_span)?;
|
||||
check_number_of_arguments(tcx, external_impl, declaration, eii_name, eii_attr_span)?;
|
||||
check_early_region_bounds(tcx, external_impl, declaration, eii_attr_span)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// externally implementable items can't have generics
|
||||
fn check_no_generics<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
external_impl: LocalDefId,
|
||||
_declaration: DefId,
|
||||
eii_name: Symbol,
|
||||
eii_attr_span: Span,
|
||||
) -> Result<(), ErrorGuaranteed> {
|
||||
let generics = tcx.generics_of(external_impl);
|
||||
if generics.own_requires_monomorphization() {
|
||||
tcx.dcx().emit_err(EiiWithGenerics {
|
||||
span: tcx.def_span(external_impl),
|
||||
attr: eii_attr_span,
|
||||
eii_name,
|
||||
});
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn check_early_region_bounds<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
external_impl: LocalDefId,
|
||||
declaration: DefId,
|
||||
eii_attr_span: Span,
|
||||
) -> Result<(), ErrorGuaranteed> {
|
||||
let external_impl_generics = tcx.generics_of(external_impl.to_def_id());
|
||||
let external_impl_params = external_impl_generics.own_counts().lifetimes;
|
||||
|
||||
let declaration_generics = tcx.generics_of(declaration);
|
||||
let declaration_params = declaration_generics.own_counts().lifetimes;
|
||||
|
||||
let Err(CheckNumberOfEarlyBoundRegionsError { span, generics_span, bounds_span, where_span }) =
|
||||
check_number_of_early_bound_regions(
|
||||
tcx,
|
||||
external_impl,
|
||||
declaration,
|
||||
external_impl_generics,
|
||||
external_impl_params,
|
||||
declaration_generics,
|
||||
declaration_params,
|
||||
)
|
||||
else {
|
||||
return Ok(());
|
||||
};
|
||||
|
||||
let mut diag = tcx.dcx().create_err(LifetimesOrBoundsMismatchOnEii {
|
||||
span,
|
||||
ident: tcx.item_name(external_impl.to_def_id()),
|
||||
generics_span,
|
||||
bounds_span,
|
||||
where_span,
|
||||
});
|
||||
|
||||
diag.span_label(eii_attr_span, format!("required because of this attribute"));
|
||||
return Err(diag.emit());
|
||||
}
|
||||
|
||||
fn check_number_of_arguments<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
external_impl: LocalDefId,
|
||||
declaration: DefId,
|
||||
eii_name: Symbol,
|
||||
eii_attr_span: Span,
|
||||
) -> Result<(), ErrorGuaranteed> {
|
||||
let external_impl_fty = tcx.fn_sig(external_impl);
|
||||
let declaration_fty = tcx.fn_sig(declaration);
|
||||
let declaration_number_args = declaration_fty.skip_binder().inputs().skip_binder().len();
|
||||
let external_impl_number_args = external_impl_fty.skip_binder().inputs().skip_binder().len();
|
||||
|
||||
// if the number of args are equal, we're trivially done
|
||||
if declaration_number_args == external_impl_number_args {
|
||||
Ok(())
|
||||
} else {
|
||||
Err(report_number_of_arguments_mismatch(
|
||||
tcx,
|
||||
external_impl,
|
||||
declaration,
|
||||
eii_name,
|
||||
eii_attr_span,
|
||||
declaration_number_args,
|
||||
external_impl_number_args,
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
fn report_number_of_arguments_mismatch<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
external_impl: LocalDefId,
|
||||
declaration: DefId,
|
||||
eii_name: Symbol,
|
||||
eii_attr_span: Span,
|
||||
declaration_number_args: usize,
|
||||
external_impl_number_args: usize,
|
||||
) -> ErrorGuaranteed {
|
||||
let external_impl_name = tcx.item_name(external_impl.to_def_id());
|
||||
|
||||
let declaration_span = declaration
|
||||
.as_local()
|
||||
.and_then(|def_id| {
|
||||
let declaration_sig = get_declaration_sig(tcx, def_id).expect("foreign item sig");
|
||||
let pos = declaration_number_args.saturating_sub(1);
|
||||
declaration_sig.decl.inputs.get(pos).map(|arg| {
|
||||
if pos == 0 {
|
||||
arg.span
|
||||
} else {
|
||||
arg.span.with_lo(declaration_sig.decl.inputs[0].span.lo())
|
||||
}
|
||||
})
|
||||
})
|
||||
.or_else(|| tcx.hir_span_if_local(declaration))
|
||||
.unwrap_or_else(|| tcx.def_span(declaration));
|
||||
|
||||
let (_, external_impl_sig, _, _) = &tcx.hir_expect_item(external_impl).expect_fn();
|
||||
let pos = external_impl_number_args.saturating_sub(1);
|
||||
let impl_span = external_impl_sig
|
||||
.decl
|
||||
.inputs
|
||||
.get(pos)
|
||||
.map(|arg| {
|
||||
if pos == 0 {
|
||||
arg.span
|
||||
} else {
|
||||
arg.span.with_lo(external_impl_sig.decl.inputs[0].span.lo())
|
||||
}
|
||||
})
|
||||
.unwrap_or_else(|| tcx.def_span(external_impl));
|
||||
|
||||
let mut err = struct_span_code_err!(
|
||||
tcx.dcx(),
|
||||
impl_span,
|
||||
E0806,
|
||||
"`{external_impl_name}` has {} but #[{eii_name}] requires it to have {}",
|
||||
potentially_plural_count(external_impl_number_args, "parameter"),
|
||||
declaration_number_args
|
||||
);
|
||||
|
||||
err.span_label(
|
||||
declaration_span,
|
||||
format!("requires {}", potentially_plural_count(declaration_number_args, "parameter")),
|
||||
);
|
||||
|
||||
err.span_label(
|
||||
impl_span,
|
||||
format!(
|
||||
"expected {}, found {}",
|
||||
potentially_plural_count(declaration_number_args, "parameter"),
|
||||
external_impl_number_args
|
||||
),
|
||||
);
|
||||
|
||||
err.span_label(eii_attr_span, format!("required because of this attribute"));
|
||||
|
||||
err.emit()
|
||||
}
|
||||
|
||||
fn report_eii_mismatch<'tcx>(
|
||||
infcx: &InferCtxt<'tcx>,
|
||||
mut cause: ObligationCause<'tcx>,
|
||||
param_env: ty::ParamEnv<'tcx>,
|
||||
terr: TypeError<'tcx>,
|
||||
(declaration_did, declaration_sig): (DefId, ty::FnSig<'tcx>),
|
||||
(external_impl_did, external_impl_sig): (LocalDefId, ty::FnSig<'tcx>),
|
||||
eii_attr_span: Span,
|
||||
eii_name: Symbol,
|
||||
) -> ErrorGuaranteed {
|
||||
let tcx = infcx.tcx;
|
||||
let (impl_err_span, trait_err_span, external_impl_name) =
|
||||
extract_spans_for_error_reporting(infcx, terr, &cause, declaration_did, external_impl_did);
|
||||
|
||||
let mut diag = struct_span_code_err!(
|
||||
tcx.dcx(),
|
||||
impl_err_span,
|
||||
E0806,
|
||||
"function `{}` has a type that is incompatible with the declaration of `#[{eii_name}]`",
|
||||
external_impl_name
|
||||
);
|
||||
|
||||
diag.span_note(eii_attr_span, "expected this because of this attribute");
|
||||
|
||||
match &terr {
|
||||
TypeError::ArgumentMutability(i) | TypeError::ArgumentSorts(_, i) => {
|
||||
if declaration_sig.inputs().len() == *i {
|
||||
// Suggestion to change output type. We do not suggest in `async` functions
|
||||
// to avoid complex logic or incorrect output.
|
||||
if let ItemKind::Fn { sig, .. } = &tcx.hir_expect_item(external_impl_did).kind
|
||||
&& !sig.header.asyncness.is_async()
|
||||
{
|
||||
let msg = "change the output type to match the declaration";
|
||||
let ap = Applicability::MachineApplicable;
|
||||
match sig.decl.output {
|
||||
hir::FnRetTy::DefaultReturn(sp) => {
|
||||
let sugg = format!(" -> {}", declaration_sig.output());
|
||||
diag.span_suggestion_verbose(sp, msg, sugg, ap);
|
||||
}
|
||||
hir::FnRetTy::Return(hir_ty) => {
|
||||
let sugg = declaration_sig.output();
|
||||
diag.span_suggestion_verbose(hir_ty.span, msg, sugg, ap);
|
||||
}
|
||||
};
|
||||
};
|
||||
} else if let Some(trait_ty) = declaration_sig.inputs().get(*i) {
|
||||
diag.span_suggestion_verbose(
|
||||
impl_err_span,
|
||||
"change the parameter type to match the declaration",
|
||||
trait_ty,
|
||||
Applicability::MachineApplicable,
|
||||
);
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
|
||||
cause.span = impl_err_span;
|
||||
infcx.err_ctxt().note_type_err(
|
||||
&mut diag,
|
||||
&cause,
|
||||
trait_err_span.map(|sp| (sp, Cow::from("type in declaration"), false)),
|
||||
Some(param_env.and(infer::ValuePairs::PolySigs(ExpectedFound {
|
||||
expected: ty::Binder::dummy(declaration_sig),
|
||||
found: ty::Binder::dummy(external_impl_sig),
|
||||
}))),
|
||||
terr,
|
||||
false,
|
||||
None,
|
||||
);
|
||||
|
||||
diag.emit()
|
||||
}
|
||||
|
||||
#[instrument(level = "debug", skip(infcx))]
|
||||
fn extract_spans_for_error_reporting<'tcx>(
|
||||
infcx: &infer::InferCtxt<'tcx>,
|
||||
terr: TypeError<'_>,
|
||||
cause: &ObligationCause<'tcx>,
|
||||
declaration: DefId,
|
||||
external_impl: LocalDefId,
|
||||
) -> (Span, Option<Span>, Ident) {
|
||||
let tcx = infcx.tcx;
|
||||
let (mut external_impl_args, external_impl_name) = {
|
||||
let item = tcx.hir_expect_item(external_impl);
|
||||
let (ident, sig, _, _) = item.expect_fn();
|
||||
(sig.decl.inputs.iter().map(|t| t.span).chain(iter::once(sig.decl.output.span())), ident)
|
||||
};
|
||||
|
||||
let declaration_args = declaration.as_local().map(|def_id| {
|
||||
if let Some(sig) = get_declaration_sig(tcx, def_id) {
|
||||
sig.decl.inputs.iter().map(|t| t.span).chain(iter::once(sig.decl.output.span()))
|
||||
} else {
|
||||
panic!("expected {def_id:?} to be a foreign function");
|
||||
}
|
||||
});
|
||||
|
||||
match terr {
|
||||
TypeError::ArgumentMutability(i) | TypeError::ArgumentSorts(ExpectedFound { .. }, i) => (
|
||||
external_impl_args.nth(i).unwrap(),
|
||||
declaration_args.and_then(|mut args| args.nth(i)),
|
||||
external_impl_name,
|
||||
),
|
||||
_ => (
|
||||
cause.span,
|
||||
tcx.hir_span_if_local(declaration).or_else(|| Some(tcx.def_span(declaration))),
|
||||
external_impl_name,
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
fn get_declaration_sig<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> Option<&'tcx FnSig<'tcx>> {
|
||||
let hir_id: HirId = tcx.local_def_id_to_hir_id(def_id);
|
||||
tcx.hir_fn_sig_by_hir_id(hir_id)
|
||||
}
|
||||
|
|
@ -14,8 +14,9 @@ use rustc_infer::infer::{self, BoundRegionConversionTime, InferCtxt, TyCtxtInfer
|
|||
use rustc_infer::traits::util;
|
||||
use rustc_middle::ty::error::{ExpectedFound, TypeError};
|
||||
use rustc_middle::ty::{
|
||||
self, BottomUpFolder, GenericArgs, GenericParamDefKind, Ty, TyCtxt, TypeFoldable, TypeFolder,
|
||||
TypeSuperFoldable, TypeVisitable, TypeVisitableExt, TypeVisitor, TypingMode, Upcast,
|
||||
self, BottomUpFolder, GenericArgs, GenericParamDefKind, Generics, Ty, TyCtxt, TypeFoldable,
|
||||
TypeFolder, TypeSuperFoldable, TypeVisitable, TypeVisitableExt, TypeVisitor, TypingMode,
|
||||
Upcast,
|
||||
};
|
||||
use rustc_middle::{bug, span_bug};
|
||||
use rustc_span::{DUMMY_SP, Span};
|
||||
|
|
@ -352,6 +353,7 @@ fn compare_method_predicate_entailment<'tcx>(
|
|||
// type would be more appropriate. In other places we have a `Vec<Span>`
|
||||
// corresponding to their `Vec<Predicate>`, but we don't have that here.
|
||||
// Fixing this would improve the output of test `issue-83765.rs`.
|
||||
// There's the same issue in compare_eii code.
|
||||
let result = ocx.sup(&cause, param_env, trait_sig, impl_sig);
|
||||
|
||||
if let Err(terr) = result {
|
||||
|
|
@ -1093,6 +1095,55 @@ fn check_region_bounds_on_impl_item<'tcx>(
|
|||
let trait_generics = tcx.generics_of(trait_m.def_id);
|
||||
let trait_params = trait_generics.own_counts().lifetimes;
|
||||
|
||||
let Err(CheckNumberOfEarlyBoundRegionsError { span, generics_span, bounds_span, where_span }) =
|
||||
check_number_of_early_bound_regions(
|
||||
tcx,
|
||||
impl_m.def_id.expect_local(),
|
||||
trait_m.def_id,
|
||||
impl_generics,
|
||||
impl_params,
|
||||
trait_generics,
|
||||
trait_params,
|
||||
)
|
||||
else {
|
||||
return Ok(());
|
||||
};
|
||||
|
||||
if !delay && let Some(guar) = check_region_late_boundedness(tcx, impl_m, trait_m) {
|
||||
return Err(guar);
|
||||
}
|
||||
|
||||
let reported = tcx
|
||||
.dcx()
|
||||
.create_err(LifetimesOrBoundsMismatchOnTrait {
|
||||
span,
|
||||
item_kind: impl_m.descr(),
|
||||
ident: impl_m.ident(tcx),
|
||||
generics_span,
|
||||
bounds_span,
|
||||
where_span,
|
||||
})
|
||||
.emit_unless_delay(delay);
|
||||
|
||||
Err(reported)
|
||||
}
|
||||
|
||||
pub(super) struct CheckNumberOfEarlyBoundRegionsError {
|
||||
pub(super) span: Span,
|
||||
pub(super) generics_span: Span,
|
||||
pub(super) bounds_span: Vec<Span>,
|
||||
pub(super) where_span: Option<Span>,
|
||||
}
|
||||
|
||||
pub(super) fn check_number_of_early_bound_regions<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
impl_def_id: LocalDefId,
|
||||
trait_def_id: DefId,
|
||||
impl_generics: &Generics,
|
||||
impl_params: usize,
|
||||
trait_generics: &Generics,
|
||||
trait_params: usize,
|
||||
) -> Result<(), CheckNumberOfEarlyBoundRegionsError> {
|
||||
debug!(?trait_generics, ?impl_generics);
|
||||
|
||||
// Must have same number of early-bound lifetime parameters.
|
||||
|
|
@ -1108,20 +1159,16 @@ fn check_region_bounds_on_impl_item<'tcx>(
|
|||
return Ok(());
|
||||
}
|
||||
|
||||
if !delay && let Some(guar) = check_region_late_boundedness(tcx, impl_m, trait_m) {
|
||||
return Err(guar);
|
||||
}
|
||||
|
||||
let span = tcx
|
||||
.hir_get_generics(impl_m.def_id.expect_local())
|
||||
.hir_get_generics(impl_def_id)
|
||||
.expect("expected impl item to have generics or else we can't compare them")
|
||||
.span;
|
||||
|
||||
let mut generics_span = tcx.def_span(trait_m.def_id);
|
||||
let mut generics_span = tcx.def_span(trait_def_id);
|
||||
let mut bounds_span = vec![];
|
||||
let mut where_span = None;
|
||||
|
||||
if let Some(trait_node) = tcx.hir_get_if_local(trait_m.def_id)
|
||||
if let Some(trait_node) = tcx.hir_get_if_local(trait_def_id)
|
||||
&& let Some(trait_generics) = trait_node.generics()
|
||||
{
|
||||
generics_span = trait_generics.span;
|
||||
|
|
@ -1146,7 +1193,7 @@ fn check_region_bounds_on_impl_item<'tcx>(
|
|||
_ => {}
|
||||
}
|
||||
}
|
||||
if let Some(impl_node) = tcx.hir_get_if_local(impl_m.def_id)
|
||||
if let Some(impl_node) = tcx.hir_get_if_local(impl_def_id.into())
|
||||
&& let Some(impl_generics) = impl_node.generics()
|
||||
{
|
||||
let mut impl_bounds = 0;
|
||||
|
|
@ -1177,19 +1224,7 @@ fn check_region_bounds_on_impl_item<'tcx>(
|
|||
}
|
||||
}
|
||||
|
||||
let reported = tcx
|
||||
.dcx()
|
||||
.create_err(LifetimesOrBoundsMismatchOnTrait {
|
||||
span,
|
||||
item_kind: impl_m.descr(),
|
||||
ident: impl_m.ident(tcx),
|
||||
generics_span,
|
||||
bounds_span,
|
||||
where_span,
|
||||
})
|
||||
.emit_unless_delay(delay);
|
||||
|
||||
Err(reported)
|
||||
Err(CheckNumberOfEarlyBoundRegionsError { span, generics_span, bounds_span, where_span })
|
||||
}
|
||||
|
||||
#[allow(unused)]
|
||||
|
|
|
|||
|
|
@ -64,6 +64,7 @@ a type parameter).
|
|||
|
||||
pub mod always_applicable;
|
||||
mod check;
|
||||
mod compare_eii;
|
||||
mod compare_impl_item;
|
||||
mod entry;
|
||||
pub mod intrinsic;
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ use rustc_abi::ExternAbi;
|
|||
use rustc_data_structures::fx::{FxHashSet, FxIndexMap, FxIndexSet};
|
||||
use rustc_errors::codes::*;
|
||||
use rustc_errors::{Applicability, ErrorGuaranteed, pluralize, struct_span_code_err};
|
||||
use rustc_hir::attrs::AttributeKind;
|
||||
use rustc_hir::attrs::{AttributeKind, EiiDecl, EiiImpl};
|
||||
use rustc_hir::def::{DefKind, Res};
|
||||
use rustc_hir::def_id::{DefId, LocalDefId};
|
||||
use rustc_hir::lang_items::LangItem;
|
||||
|
|
@ -39,6 +39,7 @@ use rustc_trait_selection::traits::{
|
|||
use tracing::{debug, instrument};
|
||||
use {rustc_ast as ast, rustc_hir as hir};
|
||||
|
||||
use super::compare_eii::compare_eii_function_types;
|
||||
use crate::autoderef::Autoderef;
|
||||
use crate::constrained_generic_params::{Parameter, identify_constrained_generic_params};
|
||||
use crate::errors::InvalidReceiverTyHint;
|
||||
|
|
@ -1170,12 +1171,41 @@ fn check_item_fn(
|
|||
decl: &hir::FnDecl<'_>,
|
||||
) -> Result<(), ErrorGuaranteed> {
|
||||
enter_wf_checking_ctxt(tcx, def_id, |wfcx| {
|
||||
check_eiis(tcx, def_id);
|
||||
|
||||
let sig = tcx.fn_sig(def_id).instantiate_identity();
|
||||
check_fn_or_method(wfcx, sig, decl, def_id);
|
||||
Ok(())
|
||||
})
|
||||
}
|
||||
|
||||
fn check_eiis(tcx: TyCtxt<'_>, def_id: LocalDefId) {
|
||||
// does the function have an EiiImpl attribute? that contains the defid of a *macro*
|
||||
// that was used to mark the implementation. This is a two step process.
|
||||
for EiiImpl { eii_macro, span, .. } in
|
||||
find_attr!(tcx.get_all_attrs(def_id), AttributeKind::EiiImpls(impls) => impls)
|
||||
.into_iter()
|
||||
.flatten()
|
||||
{
|
||||
// we expect this macro to have the `EiiMacroFor` attribute, that points to a function
|
||||
// signature that we'd like to compare the function we're currently checking with
|
||||
if let Some(eii_extern_target) = find_attr!(tcx.get_all_attrs(*eii_macro), AttributeKind::EiiExternTarget(EiiDecl {eii_extern_target, ..}) => *eii_extern_target)
|
||||
{
|
||||
let _ = compare_eii_function_types(
|
||||
tcx,
|
||||
def_id,
|
||||
eii_extern_target,
|
||||
tcx.item_name(*eii_macro),
|
||||
*span,
|
||||
);
|
||||
} else {
|
||||
panic!(
|
||||
"EII impl macro {eii_macro:?} did not have an eii extern target attribute pointing to a foreign function"
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[instrument(level = "debug", skip(tcx))]
|
||||
pub(crate) fn check_static_item<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
|
|
|
|||
|
|
@ -1697,3 +1697,28 @@ pub(crate) struct AsyncDropWithoutSyncDrop {
|
|||
#[primary_span]
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(hir_analysis_lifetimes_or_bounds_mismatch_on_eii)]
|
||||
pub(crate) struct LifetimesOrBoundsMismatchOnEii {
|
||||
#[primary_span]
|
||||
#[label]
|
||||
pub span: Span,
|
||||
#[label(hir_analysis_generics_label)]
|
||||
pub generics_span: Span,
|
||||
#[label(hir_analysis_where_label)]
|
||||
pub where_span: Option<Span>,
|
||||
#[label(hir_analysis_bounds_label)]
|
||||
pub bounds_span: Vec<Span>,
|
||||
pub ident: Symbol,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(hir_analysis_eii_with_generics)]
|
||||
pub(crate) struct EiiWithGenerics {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
#[label]
|
||||
pub attr: Span,
|
||||
pub eii_name: Symbol,
|
||||
}
|
||||
|
|
|
|||
|
|
@ -40,8 +40,7 @@ use rustc_session::output::{collect_crate_types, filename_for_input};
|
|||
use rustc_session::parse::feature_err;
|
||||
use rustc_session::search_paths::PathKind;
|
||||
use rustc_span::{
|
||||
DUMMY_SP, ErrorGuaranteed, ExpnKind, FileName, SourceFileHash, SourceFileHashAlgorithm, Span,
|
||||
Symbol, sym,
|
||||
DUMMY_SP, ErrorGuaranteed, ExpnKind, SourceFileHash, SourceFileHashAlgorithm, Span, Symbol, sym,
|
||||
};
|
||||
use rustc_trait_selection::{solve, traits};
|
||||
use tracing::{info, instrument};
|
||||
|
|
@ -595,7 +594,7 @@ fn write_out_deps(tcx: TyCtxt<'_>, outputs: &OutputFilenames, out_filenames: &[P
|
|||
.filter(|fmap| !fmap.is_imported())
|
||||
.map(|fmap| {
|
||||
(
|
||||
escape_dep_filename(&fmap.name.prefer_local().to_string()),
|
||||
escape_dep_filename(&fmap.name.prefer_local_unconditionally().to_string()),
|
||||
// This needs to be unnormalized,
|
||||
// as external tools wouldn't know how rustc normalizes them
|
||||
fmap.unnormalized_source_len as u64,
|
||||
|
|
@ -610,10 +609,7 @@ fn write_out_deps(tcx: TyCtxt<'_>, outputs: &OutputFilenames, out_filenames: &[P
|
|||
// (e.g. accessed in proc macros).
|
||||
let file_depinfo = sess.psess.file_depinfo.borrow();
|
||||
|
||||
let normalize_path = |path: PathBuf| {
|
||||
let file = FileName::from(path);
|
||||
escape_dep_filename(&file.prefer_local().to_string())
|
||||
};
|
||||
let normalize_path = |path: PathBuf| escape_dep_filename(&path.to_string_lossy());
|
||||
|
||||
// The entries will be used to declare dependencies between files in a
|
||||
// Makefile-like output, so the iteration order does not matter.
|
||||
|
|
@ -684,19 +680,19 @@ fn write_out_deps(tcx: TyCtxt<'_>, outputs: &OutputFilenames, out_filenames: &[P
|
|||
|
||||
for &cnum in tcx.crates(()) {
|
||||
let source = tcx.used_crate_source(cnum);
|
||||
if let Some((path, _)) = &source.dylib {
|
||||
if let Some(path) = &source.dylib {
|
||||
files.extend(hash_iter_files(
|
||||
iter::once(escape_dep_filename(&path.display().to_string())),
|
||||
checksum_hash_algo,
|
||||
));
|
||||
}
|
||||
if let Some((path, _)) = &source.rlib {
|
||||
if let Some(path) = &source.rlib {
|
||||
files.extend(hash_iter_files(
|
||||
iter::once(escape_dep_filename(&path.display().to_string())),
|
||||
checksum_hash_algo,
|
||||
));
|
||||
}
|
||||
if let Some((path, _)) = &source.rmeta {
|
||||
if let Some(path) = &source.rmeta {
|
||||
files.extend(hash_iter_files(
|
||||
iter::once(escape_dep_filename(&path.display().to_string())),
|
||||
checksum_hash_algo,
|
||||
|
|
@ -1061,6 +1057,9 @@ fn run_required_analyses(tcx: TyCtxt<'_>) {
|
|||
parallel!(
|
||||
{
|
||||
sess.time("looking_for_entry_point", || tcx.ensure_ok().entry_fn(()));
|
||||
sess.time("check_externally_implementable_items", || {
|
||||
tcx.ensure_ok().check_externally_implementable_items(())
|
||||
});
|
||||
|
||||
sess.time("looking_for_derive_registrar", || {
|
||||
tcx.ensure_ok().proc_macro_decls_static(())
|
||||
|
|
|
|||
|
|
@ -205,15 +205,17 @@ lint_dangling_pointers_from_locals = {$fn_kind} returns a dangling pointer to dr
|
|||
.ret_ty = return type is `{$ret_ty}`
|
||||
.local_var = local variable `{$local_var_name}` is dropped at the end of the {$fn_kind}
|
||||
.created_at = dangling pointer created here
|
||||
.note = a dangling pointer is safe, but dereferencing one is undefined behavior
|
||||
.note_safe = a dangling pointer is safe, but dereferencing one is undefined behavior
|
||||
.note_more_info = for more information, see <https://doc.rust-lang.org/reference/destructors.html>
|
||||
|
||||
lint_dangling_pointers_from_temporaries = this creates a dangling pointer because temporary `{$ty}` is dropped at end of statement
|
||||
.label_ptr = pointer created here
|
||||
.label_temporary = this `{$ty}` is dropped at end of statement
|
||||
.help_bind = bind the `{$ty}` to a variable such that it outlives the pointer returned by `{$callee}`
|
||||
.note_safe = a dangling pointer is safe, but dereferencing one is undefined behavior
|
||||
.note_return = returning a pointer to a local variable will always result in a dangling pointer
|
||||
.note_more_info = for more information, see <https://doc.rust-lang.org/reference/destructors.html>
|
||||
|
||||
lint_dangling_pointers_from_temporaries = a dangling pointer will be produced because the temporary `{$ty}` will be dropped
|
||||
.label_ptr = this pointer will immediately be invalid
|
||||
.label_temporary = this `{$ty}` is deallocated at the end of the statement, bind it to a variable to extend its lifetime
|
||||
.note = pointers do not have a lifetime; when calling `{$callee}` the `{$ty}` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned
|
||||
.help_bind = you must make sure that the variable you bind the `{$ty}` to lives at least as long as the pointer returned by the call to `{$callee}`
|
||||
.help_returned = in particular, if this pointer is returned from the current function, binding the `{$ty}` inside the function will not suffice
|
||||
.help_visit = for more information, see <https://doc.rust-lang.org/reference/destructors.html>
|
||||
|
||||
lint_default_hash_types = prefer `{$preferred}` over `{$used}`, it has better performance
|
||||
.note = a `use rustc_data_structures::fx::{$preferred}` may be necessary
|
||||
|
|
|
|||
|
|
@ -1138,10 +1138,10 @@ pub(crate) struct IgnoredUnlessCrateSpecified<'a> {
|
|||
// dangling.rs
|
||||
#[derive(LintDiagnostic)]
|
||||
#[diag(lint_dangling_pointers_from_temporaries)]
|
||||
#[note]
|
||||
#[help(lint_help_bind)]
|
||||
#[help(lint_help_returned)]
|
||||
#[help(lint_help_visit)]
|
||||
#[note(lint_note_safe)]
|
||||
#[note(lint_note_return)]
|
||||
#[note(lint_note_more_info)]
|
||||
// FIXME: put #[primary_span] on `ptr_span` once it does not cause conflicts
|
||||
pub(crate) struct DanglingPointersFromTemporaries<'tcx> {
|
||||
pub callee: Ident,
|
||||
|
|
@ -1154,7 +1154,8 @@ pub(crate) struct DanglingPointersFromTemporaries<'tcx> {
|
|||
|
||||
#[derive(LintDiagnostic)]
|
||||
#[diag(lint_dangling_pointers_from_locals)]
|
||||
#[note]
|
||||
#[note(lint_note_safe)]
|
||||
#[note(lint_note_more_info)]
|
||||
pub(crate) struct DanglingPointersFromLocals<'tcx> {
|
||||
pub ret_ty: Ty<'tcx>,
|
||||
#[label(lint_ret_ty)]
|
||||
|
|
|
|||
|
|
@ -135,16 +135,16 @@ impl<'a> std::fmt::Debug for CrateDump<'a> {
|
|||
writeln!(fmt, " priv: {:?}", data.is_private_dep())?;
|
||||
let CrateSource { dylib, rlib, rmeta, sdylib_interface } = data.source();
|
||||
if let Some(dylib) = dylib {
|
||||
writeln!(fmt, " dylib: {}", dylib.0.display())?;
|
||||
writeln!(fmt, " dylib: {}", dylib.display())?;
|
||||
}
|
||||
if let Some(rlib) = rlib {
|
||||
writeln!(fmt, " rlib: {}", rlib.0.display())?;
|
||||
writeln!(fmt, " rlib: {}", rlib.display())?;
|
||||
}
|
||||
if let Some(rmeta) = rmeta {
|
||||
writeln!(fmt, " rmeta: {}", rmeta.0.display())?;
|
||||
writeln!(fmt, " rmeta: {}", rmeta.display())?;
|
||||
}
|
||||
if let Some(sdylib_interface) = sdylib_interface {
|
||||
writeln!(fmt, " sdylib interface: {}", sdylib_interface.0.display())?;
|
||||
writeln!(fmt, " sdylib interface: {}", sdylib_interface.display())?;
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
|
|
@ -515,73 +515,19 @@ impl CStore {
|
|||
}
|
||||
}
|
||||
|
||||
fn existing_match(
|
||||
&self,
|
||||
externs: &Externs,
|
||||
name: Symbol,
|
||||
hash: Option<Svh>,
|
||||
kind: PathKind,
|
||||
) -> Option<CrateNum> {
|
||||
fn existing_match(&self, name: Symbol, hash: Option<Svh>) -> Option<CrateNum> {
|
||||
let hash = hash?;
|
||||
|
||||
for (cnum, data) in self.iter_crate_data() {
|
||||
if data.name() != name {
|
||||
trace!("{} did not match {}", data.name(), name);
|
||||
continue;
|
||||
}
|
||||
|
||||
match hash {
|
||||
Some(hash) if hash == data.hash() => return Some(cnum),
|
||||
Some(hash) => {
|
||||
debug!("actual hash {} did not match expected {}", hash, data.hash());
|
||||
continue;
|
||||
}
|
||||
None => {}
|
||||
}
|
||||
|
||||
// When the hash is None we're dealing with a top-level dependency
|
||||
// in which case we may have a specification on the command line for
|
||||
// this library. Even though an upstream library may have loaded
|
||||
// something of the same name, we have to make sure it was loaded
|
||||
// from the exact same location as well.
|
||||
//
|
||||
// We're also sure to compare *paths*, not actual byte slices. The
|
||||
// `source` stores paths which are normalized which may be different
|
||||
// from the strings on the command line.
|
||||
let source = data.source();
|
||||
if let Some(entry) = externs.get(name.as_str()) {
|
||||
// Only use `--extern crate_name=path` here, not `--extern crate_name`.
|
||||
if let Some(mut files) = entry.files() {
|
||||
if files.any(|l| {
|
||||
let l = l.canonicalized();
|
||||
source.dylib.as_ref().map(|(p, _)| p) == Some(l)
|
||||
|| source.rlib.as_ref().map(|(p, _)| p) == Some(l)
|
||||
|| source.rmeta.as_ref().map(|(p, _)| p) == Some(l)
|
||||
}) {
|
||||
return Some(cnum);
|
||||
}
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
// Alright, so we've gotten this far which means that `data` has the
|
||||
// right name, we don't have a hash, and we don't have a --extern
|
||||
// pointing for ourselves. We're still not quite yet done because we
|
||||
// have to make sure that this crate was found in the crate lookup
|
||||
// path (this is a top-level dependency) as we don't want to
|
||||
// implicitly load anything inside the dependency lookup path.
|
||||
let prev_kind = source
|
||||
.dylib
|
||||
.as_ref()
|
||||
.or(source.rlib.as_ref())
|
||||
.or(source.rmeta.as_ref())
|
||||
.expect("No sources for crate")
|
||||
.1;
|
||||
if kind.matches(prev_kind) {
|
||||
if hash == data.hash() {
|
||||
return Some(cnum);
|
||||
} else {
|
||||
debug!(
|
||||
"failed to load existing crate {}; kind {:?} did not match prev_kind {:?}",
|
||||
name, kind, prev_kind
|
||||
);
|
||||
debug!("actual hash {} did not match expected {}", hash, data.hash());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -678,7 +624,7 @@ impl CStore {
|
|||
None => (&source, &crate_root),
|
||||
};
|
||||
let dlsym_dylib = dlsym_source.dylib.as_ref().expect("no dylib for a proc-macro crate");
|
||||
Some(self.dlsym_proc_macros(tcx.sess, &dlsym_dylib.0, dlsym_root.stable_crate_id())?)
|
||||
Some(self.dlsym_proc_macros(tcx.sess, dlsym_dylib, dlsym_root.stable_crate_id())?)
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
|
@ -819,9 +765,7 @@ impl CStore {
|
|||
let path_kind = if dep.is_some() { PathKind::Dependency } else { PathKind::Crate };
|
||||
let private_dep = origin.private_dep();
|
||||
|
||||
let result = if let Some(cnum) =
|
||||
self.existing_match(&tcx.sess.opts.externs, name, hash, path_kind)
|
||||
{
|
||||
let result = if let Some(cnum) = self.existing_match(name, hash) {
|
||||
(LoadResult::Previous(cnum), None)
|
||||
} else {
|
||||
info!("falling back to a load");
|
||||
|
|
|
|||
47
compiler/rustc_metadata/src/eii.rs
Normal file
47
compiler/rustc_metadata/src/eii.rs
Normal file
|
|
@ -0,0 +1,47 @@
|
|||
use rustc_data_structures::fx::FxIndexMap;
|
||||
use rustc_hir::attrs::{AttributeKind, EiiDecl, EiiImpl};
|
||||
use rustc_hir::def_id::DefId;
|
||||
use rustc_hir::find_attr;
|
||||
use rustc_middle::query::LocalCrate;
|
||||
use rustc_middle::ty::TyCtxt;
|
||||
|
||||
// basically the map below but flattened out
|
||||
pub(crate) type EiiMapEncodedKeyValue = (DefId, (EiiDecl, Vec<(DefId, EiiImpl)>));
|
||||
|
||||
pub(crate) type EiiMap = FxIndexMap<
|
||||
DefId, // the defid of the macro that declared the eii
|
||||
(
|
||||
// the corresponding declaration
|
||||
EiiDecl,
|
||||
// all the given implementations, indexed by defid.
|
||||
// We expect there to be only one, but collect them all to give errors if there are more
|
||||
// (or if there are none) in the final crate we build.
|
||||
FxIndexMap<DefId, EiiImpl>,
|
||||
),
|
||||
>;
|
||||
|
||||
pub(crate) fn collect<'tcx>(tcx: TyCtxt<'tcx>, LocalCrate: LocalCrate) -> EiiMap {
|
||||
let mut eiis = EiiMap::default();
|
||||
|
||||
// iterate over all items in the current crate
|
||||
for id in tcx.hir_crate_items(()).eiis() {
|
||||
for i in
|
||||
find_attr!(tcx.get_all_attrs(id), AttributeKind::EiiImpls(e) => e).into_iter().flatten()
|
||||
{
|
||||
eiis.entry(i.eii_macro)
|
||||
.or_insert_with(|| {
|
||||
// find the decl for this one if it wasn't in yet (maybe it's from the local crate? not very useful but not illegal)
|
||||
(find_attr!(tcx.get_all_attrs(i.eii_macro), AttributeKind::EiiExternTarget(d) => *d).unwrap(), Default::default())
|
||||
}).1.insert(id.into(), *i);
|
||||
}
|
||||
|
||||
// if we find a new declaration, add it to the list without a known implementation
|
||||
if let Some(decl) =
|
||||
find_attr!(tcx.get_all_attrs(id), AttributeKind::EiiExternTarget(d) => *d)
|
||||
{
|
||||
eiis.entry(id.into()).or_insert((decl, Default::default()));
|
||||
}
|
||||
}
|
||||
|
||||
eiis
|
||||
}
|
||||
|
|
@ -16,6 +16,7 @@
|
|||
pub use rmeta::provide;
|
||||
|
||||
mod dependency_format;
|
||||
mod eii;
|
||||
mod foreign_modules;
|
||||
mod native_libs;
|
||||
mod rmeta;
|
||||
|
|
|
|||
|
|
@ -218,7 +218,7 @@ use std::ops::Deref;
|
|||
use std::path::{Path, PathBuf};
|
||||
use std::{cmp, fmt};
|
||||
|
||||
use rustc_data_structures::fx::{FxHashSet, FxIndexMap};
|
||||
use rustc_data_structures::fx::{FxHashSet, FxIndexMap, FxIndexSet};
|
||||
use rustc_data_structures::memmap::Mmap;
|
||||
use rustc_data_structures::owned_slice::{OwnedSlice, slice_owned};
|
||||
use rustc_data_structures::svh::Svh;
|
||||
|
|
@ -401,7 +401,7 @@ impl<'a> CrateLocator<'a> {
|
|||
|
||||
let mut candidates: FxIndexMap<
|
||||
_,
|
||||
(FxIndexMap<_, _>, FxIndexMap<_, _>, FxIndexMap<_, _>, FxIndexMap<_, _>),
|
||||
(FxIndexSet<_>, FxIndexSet<_>, FxIndexSet<_>, FxIndexSet<_>),
|
||||
> = Default::default();
|
||||
|
||||
// First, find all possible candidate rlibs and dylibs purely based on
|
||||
|
|
@ -460,10 +460,10 @@ impl<'a> CrateLocator<'a> {
|
|||
// filesystem code should not care, but this is nicer for diagnostics.
|
||||
let path = spf.path.to_path_buf();
|
||||
match kind {
|
||||
CrateFlavor::Rlib => rlibs.insert(path, search_path.kind),
|
||||
CrateFlavor::Rmeta => rmetas.insert(path, search_path.kind),
|
||||
CrateFlavor::Dylib => dylibs.insert(path, search_path.kind),
|
||||
CrateFlavor::SDylib => interfaces.insert(path, search_path.kind),
|
||||
CrateFlavor::Rlib => rlibs.insert(path),
|
||||
CrateFlavor::Rmeta => rmetas.insert(path),
|
||||
CrateFlavor::Dylib => dylibs.insert(path),
|
||||
CrateFlavor::SDylib => interfaces.insert(path),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
@ -524,10 +524,10 @@ impl<'a> CrateLocator<'a> {
|
|||
fn extract_lib(
|
||||
&self,
|
||||
crate_rejections: &mut CrateRejections,
|
||||
rlibs: FxIndexMap<PathBuf, PathKind>,
|
||||
rmetas: FxIndexMap<PathBuf, PathKind>,
|
||||
dylibs: FxIndexMap<PathBuf, PathKind>,
|
||||
interfaces: FxIndexMap<PathBuf, PathKind>,
|
||||
rlibs: FxIndexSet<PathBuf>,
|
||||
rmetas: FxIndexSet<PathBuf>,
|
||||
dylibs: FxIndexSet<PathBuf>,
|
||||
interfaces: FxIndexSet<PathBuf>,
|
||||
) -> Result<Option<(Svh, Library)>, CrateError> {
|
||||
let mut slot = None;
|
||||
// Order here matters, rmeta should come first.
|
||||
|
|
@ -575,10 +575,10 @@ impl<'a> CrateLocator<'a> {
|
|||
fn extract_one(
|
||||
&self,
|
||||
crate_rejections: &mut CrateRejections,
|
||||
m: FxIndexMap<PathBuf, PathKind>,
|
||||
m: FxIndexSet<PathBuf>,
|
||||
flavor: CrateFlavor,
|
||||
slot: &mut Option<(Svh, MetadataBlob, PathBuf, CrateFlavor)>,
|
||||
) -> Result<Option<(PathBuf, PathKind)>, CrateError> {
|
||||
) -> Result<Option<PathBuf>, CrateError> {
|
||||
// If we are producing an rlib, and we've already loaded metadata, then
|
||||
// we should not attempt to discover further crate sources (unless we're
|
||||
// locating a proc macro; exact logic is in needs_crate_flavor). This means
|
||||
|
|
@ -594,9 +594,9 @@ impl<'a> CrateLocator<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
let mut ret: Option<(PathBuf, PathKind)> = None;
|
||||
let mut ret: Option<PathBuf> = None;
|
||||
let mut err_data: Option<Vec<PathBuf>> = None;
|
||||
for (lib, kind) in m {
|
||||
for lib in m {
|
||||
info!("{} reading metadata from: {}", flavor, lib.display());
|
||||
if flavor == CrateFlavor::Rmeta && lib.metadata().is_ok_and(|m| m.len() == 0) {
|
||||
// Empty files will cause get_metadata_section to fail. Rmeta
|
||||
|
|
@ -640,7 +640,7 @@ impl<'a> CrateLocator<'a> {
|
|||
info!("no metadata found: {}", err);
|
||||
// Metadata was loaded from interface file earlier.
|
||||
if let Some((.., CrateFlavor::SDylib)) = slot {
|
||||
ret = Some((lib, kind));
|
||||
ret = Some(lib);
|
||||
continue;
|
||||
}
|
||||
// The file was present and created by the same compiler version, but we
|
||||
|
|
@ -689,7 +689,7 @@ impl<'a> CrateLocator<'a> {
|
|||
// As a result, we favor the sysroot crate here. Note that the
|
||||
// candidates are all canonicalized, so we canonicalize the sysroot
|
||||
// as well.
|
||||
if let Some((prev, _)) = &ret {
|
||||
if let Some(prev) = &ret {
|
||||
let sysroot = self.sysroot;
|
||||
let sysroot = try_canonicalize(sysroot).unwrap_or_else(|_| sysroot.to_path_buf());
|
||||
if prev.starts_with(&sysroot) {
|
||||
|
|
@ -714,7 +714,7 @@ impl<'a> CrateLocator<'a> {
|
|||
} else {
|
||||
*slot = Some((hash, metadata, lib.clone(), flavor));
|
||||
}
|
||||
ret = Some((lib, kind));
|
||||
ret = Some(lib);
|
||||
}
|
||||
|
||||
if let Some(candidates) = err_data {
|
||||
|
|
@ -774,10 +774,10 @@ impl<'a> CrateLocator<'a> {
|
|||
// First, filter out all libraries that look suspicious. We only accept
|
||||
// files which actually exist that have the correct naming scheme for
|
||||
// rlibs/dylibs.
|
||||
let mut rlibs = FxIndexMap::default();
|
||||
let mut rmetas = FxIndexMap::default();
|
||||
let mut dylibs = FxIndexMap::default();
|
||||
let mut sdylib_interfaces = FxIndexMap::default();
|
||||
let mut rlibs = FxIndexSet::default();
|
||||
let mut rmetas = FxIndexSet::default();
|
||||
let mut dylibs = FxIndexSet::default();
|
||||
let mut sdylib_interfaces = FxIndexSet::default();
|
||||
for loc in &self.exact_paths {
|
||||
let loc_canon = loc.canonicalized();
|
||||
let loc_orig = loc.original();
|
||||
|
|
@ -798,21 +798,21 @@ impl<'a> CrateLocator<'a> {
|
|||
};
|
||||
if file.starts_with("lib") {
|
||||
if file.ends_with(".rlib") {
|
||||
rlibs.insert(loc_canon.clone(), PathKind::ExternFlag);
|
||||
rlibs.insert(loc_canon.clone());
|
||||
continue;
|
||||
}
|
||||
if file.ends_with(".rmeta") {
|
||||
rmetas.insert(loc_canon.clone(), PathKind::ExternFlag);
|
||||
rmetas.insert(loc_canon.clone());
|
||||
continue;
|
||||
}
|
||||
if file.ends_with(".rs") {
|
||||
sdylib_interfaces.insert(loc_canon.clone(), PathKind::ExternFlag);
|
||||
sdylib_interfaces.insert(loc_canon.clone());
|
||||
}
|
||||
}
|
||||
let dll_prefix = self.target.dll_prefix.as_ref();
|
||||
let dll_suffix = self.target.dll_suffix.as_ref();
|
||||
if file.starts_with(dll_prefix) && file.ends_with(dll_suffix) {
|
||||
dylibs.insert(loc_canon.clone(), PathKind::ExternFlag);
|
||||
dylibs.insert(loc_canon.clone());
|
||||
continue;
|
||||
}
|
||||
crate_rejections
|
||||
|
|
|
|||
|
|
@ -33,12 +33,13 @@ use rustc_session::config::TargetModifier;
|
|||
use rustc_session::cstore::{CrateSource, ExternCrate};
|
||||
use rustc_span::hygiene::HygieneDecodeContext;
|
||||
use rustc_span::{
|
||||
BlobDecoder, BytePos, ByteSymbol, DUMMY_SP, Pos, SpanData, SpanDecoder, Symbol, SyntaxContext,
|
||||
kw,
|
||||
BlobDecoder, BytePos, ByteSymbol, DUMMY_SP, Pos, RemapPathScopeComponents, SpanData,
|
||||
SpanDecoder, Symbol, SyntaxContext, kw,
|
||||
};
|
||||
use tracing::debug;
|
||||
|
||||
use crate::creader::CStore;
|
||||
use crate::eii::EiiMapEncodedKeyValue;
|
||||
use crate::rmeta::table::IsDefault;
|
||||
use crate::rmeta::*;
|
||||
|
||||
|
|
@ -1487,6 +1488,13 @@ impl<'a> CrateMetadataRef<'a> {
|
|||
)
|
||||
}
|
||||
|
||||
fn get_externally_implementable_items(
|
||||
self,
|
||||
tcx: TyCtxt<'_>,
|
||||
) -> impl Iterator<Item = EiiMapEncodedKeyValue> {
|
||||
self.root.externally_implementable_items.decode((self, tcx))
|
||||
}
|
||||
|
||||
fn get_missing_lang_items<'tcx>(self, tcx: TyCtxt<'tcx>) -> &'tcx [LangItem] {
|
||||
tcx.arena.alloc_from_iter(self.root.lang_items_missing.decode((self, tcx)))
|
||||
}
|
||||
|
|
@ -1530,7 +1538,7 @@ impl<'a> CrateMetadataRef<'a> {
|
|||
.get((self, tcx), id)
|
||||
.unwrap()
|
||||
.decode((self, tcx));
|
||||
ast::MacroDef { macro_rules, body: Box::new(body) }
|
||||
ast::MacroDef { macro_rules, body: Box::new(body), eii_extern_target: None }
|
||||
}
|
||||
_ => bug!(),
|
||||
}
|
||||
|
|
@ -1669,15 +1677,15 @@ impl<'a> CrateMetadataRef<'a> {
|
|||
for virtual_dir in virtual_source_base_dir.iter().flatten() {
|
||||
if let Some(real_dir) = &real_source_base_dir
|
||||
&& let rustc_span::FileName::Real(old_name) = name
|
||||
&& let rustc_span::RealFileName::Remapped { local_path: _, virtual_name } =
|
||||
old_name
|
||||
&& let Ok(rest) = virtual_name.strip_prefix(virtual_dir)
|
||||
&& let (_working_dir, embeddable_name) =
|
||||
old_name.embeddable_name(RemapPathScopeComponents::MACRO)
|
||||
&& let Ok(rest) = embeddable_name.strip_prefix(virtual_dir)
|
||||
{
|
||||
let new_path = real_dir.join(rest);
|
||||
|
||||
debug!(
|
||||
"try_to_translate_virtual_to_real: `{}` -> `{}`",
|
||||
virtual_name.display(),
|
||||
embeddable_name.display(),
|
||||
new_path.display(),
|
||||
);
|
||||
|
||||
|
|
@ -1686,17 +1694,12 @@ impl<'a> CrateMetadataRef<'a> {
|
|||
// Note that this is a special case for imported rust-src paths specified by
|
||||
// https://rust-lang.github.io/rfcs/3127-trim-paths.html#handling-sysroot-paths.
|
||||
// Other imported paths are not currently remapped (see #66251).
|
||||
let (user_remapped, applied) =
|
||||
tcx.sess.source_map().path_mapping().map_prefix(&new_path);
|
||||
let new_name = if applied {
|
||||
rustc_span::RealFileName::Remapped {
|
||||
local_path: Some(new_path.clone()),
|
||||
virtual_name: user_remapped.to_path_buf(),
|
||||
}
|
||||
} else {
|
||||
rustc_span::RealFileName::LocalPath(new_path)
|
||||
};
|
||||
*old_name = new_name;
|
||||
*name = rustc_span::FileName::Real(
|
||||
tcx.sess
|
||||
.source_map()
|
||||
.path_mapping()
|
||||
.to_real_filename(&rustc_span::RealFileName::empty(), new_path),
|
||||
);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
|
@ -1711,15 +1714,12 @@ impl<'a> CrateMetadataRef<'a> {
|
|||
&& let Some(real_dir) = real_source_base_dir
|
||||
&& let rustc_span::FileName::Real(old_name) = name
|
||||
{
|
||||
let relative_path = match old_name {
|
||||
rustc_span::RealFileName::LocalPath(local) => {
|
||||
local.strip_prefix(real_dir).ok()
|
||||
}
|
||||
rustc_span::RealFileName::Remapped { virtual_name, .. } => {
|
||||
virtual_source_base_dir
|
||||
.and_then(|virtual_dir| virtual_name.strip_prefix(virtual_dir).ok())
|
||||
}
|
||||
};
|
||||
let (_working_dir, embeddable_path) =
|
||||
old_name.embeddable_name(RemapPathScopeComponents::MACRO);
|
||||
let relative_path = embeddable_path.strip_prefix(real_dir).ok().or_else(|| {
|
||||
virtual_source_base_dir
|
||||
.and_then(|virtual_dir| embeddable_path.strip_prefix(virtual_dir).ok())
|
||||
});
|
||||
debug!(
|
||||
?relative_path,
|
||||
?virtual_dir,
|
||||
|
|
@ -1727,10 +1727,10 @@ impl<'a> CrateMetadataRef<'a> {
|
|||
"simulate_remapped_rust_src_base"
|
||||
);
|
||||
if let Some(rest) = relative_path.and_then(|p| p.strip_prefix(subdir).ok()) {
|
||||
*old_name = rustc_span::RealFileName::Remapped {
|
||||
local_path: None,
|
||||
virtual_name: virtual_dir.join(subdir).join(rest),
|
||||
};
|
||||
*name =
|
||||
rustc_span::FileName::Real(rustc_span::RealFileName::from_virtual_path(
|
||||
&virtual_dir.join(subdir).join(rest),
|
||||
))
|
||||
}
|
||||
}
|
||||
};
|
||||
|
|
|
|||
|
|
@ -25,7 +25,7 @@ use super::{Decodable, DecodeIterator};
|
|||
use crate::creader::{CStore, LoadedMacro};
|
||||
use crate::rmeta::AttrFlags;
|
||||
use crate::rmeta::table::IsDefault;
|
||||
use crate::{foreign_modules, native_libs};
|
||||
use crate::{eii, foreign_modules, native_libs};
|
||||
|
||||
trait ProcessQueryValue<'tcx, T> {
|
||||
fn process_decoded(self, _tcx: TyCtxt<'tcx>, _err: impl Fn() -> !) -> T;
|
||||
|
|
@ -330,9 +330,22 @@ provide! { tcx, def_id, other, cdata,
|
|||
is_private_dep => { cdata.private_dep }
|
||||
is_panic_runtime => { cdata.root.panic_runtime }
|
||||
is_compiler_builtins => { cdata.root.compiler_builtins }
|
||||
|
||||
// FIXME: to be replaced with externally_implementable_items below
|
||||
has_global_allocator => { cdata.root.has_global_allocator }
|
||||
// FIXME: to be replaced with externally_implementable_items below
|
||||
has_alloc_error_handler => { cdata.root.has_alloc_error_handler }
|
||||
// FIXME: to be replaced with externally_implementable_items below
|
||||
has_panic_handler => { cdata.root.has_panic_handler }
|
||||
|
||||
externally_implementable_items => {
|
||||
cdata.get_externally_implementable_items(tcx)
|
||||
.map(|(decl_did, (decl, impls))| (
|
||||
decl_did,
|
||||
(decl, impls.into_iter().collect())
|
||||
)).collect()
|
||||
}
|
||||
|
||||
is_profiler_runtime => { cdata.root.profiler_runtime }
|
||||
required_panic_strategy => { cdata.root.required_panic_strategy }
|
||||
panic_in_drop_strategy => { cdata.root.panic_in_drop_strategy }
|
||||
|
|
@ -430,6 +443,7 @@ pub(in crate::rmeta) fn provide(providers: &mut Providers) {
|
|||
},
|
||||
native_libraries: native_libs::collect,
|
||||
foreign_modules: foreign_modules::collect,
|
||||
externally_implementable_items: eii::collect,
|
||||
|
||||
// Returns a map from a sufficiently visible external item (i.e., an
|
||||
// external item that is visible from at least one local module) to a
|
||||
|
|
|
|||
|
|
@ -35,6 +35,7 @@ use rustc_span::{
|
|||
};
|
||||
use tracing::{debug, instrument, trace};
|
||||
|
||||
use crate::eii::EiiMapEncodedKeyValue;
|
||||
use crate::errors::{FailCreateFileEncoder, FailWriteFile};
|
||||
use crate::rmeta::*;
|
||||
|
||||
|
|
@ -541,8 +542,6 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
|
|||
// is done.
|
||||
let required_source_files = self.required_source_files.take().unwrap();
|
||||
|
||||
let working_directory = &self.tcx.sess.opts.working_dir;
|
||||
|
||||
let mut adapted = TableBuilder::default();
|
||||
|
||||
let local_crate_stable_id = self.tcx.stable_crate_id(LOCAL_CRATE);
|
||||
|
|
@ -567,10 +566,8 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
|
|||
|
||||
match source_file.name {
|
||||
FileName::Real(ref original_file_name) => {
|
||||
let adapted_file_name = source_map
|
||||
.path_mapping()
|
||||
.to_embeddable_absolute_path(original_file_name.clone(), working_directory);
|
||||
|
||||
let mut adapted_file_name = original_file_name.clone();
|
||||
adapted_file_name.update_for_crate_metadata();
|
||||
adapted_source_file.name = FileName::Real(adapted_file_name);
|
||||
}
|
||||
_ => {
|
||||
|
|
@ -620,6 +617,9 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
|
|||
// We have already encoded some things. Get their combined size from the current position.
|
||||
stats.push(("preamble", self.position()));
|
||||
|
||||
let externally_implementable_items = stat!("externally-implementable-items", || self
|
||||
.encode_externally_implementable_items());
|
||||
|
||||
let (crate_deps, dylib_dependency_formats) =
|
||||
stat!("dep", || (self.encode_crate_deps(), self.encode_dylib_dependency_formats()));
|
||||
|
||||
|
|
@ -738,6 +738,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
|
|||
attrs,
|
||||
sym::default_lib_allocator,
|
||||
),
|
||||
externally_implementable_items,
|
||||
proc_macro_data,
|
||||
debugger_visualizers,
|
||||
compiler_builtins: ast::attr::contains_name(attrs, sym::compiler_builtins),
|
||||
|
|
@ -1649,6 +1650,15 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
fn encode_externally_implementable_items(&mut self) -> LazyArray<EiiMapEncodedKeyValue> {
|
||||
empty_proc_macro!(self);
|
||||
let externally_implementable_items = self.tcx.externally_implementable_items(LOCAL_CRATE);
|
||||
|
||||
self.lazy_array(externally_implementable_items.iter().map(|(decl_did, (decl, impls))| {
|
||||
(*decl_did, (decl.clone(), impls.iter().map(|(impl_did, i)| (*impl_did, *i)).collect()))
|
||||
}))
|
||||
}
|
||||
|
||||
#[instrument(level = "trace", skip(self))]
|
||||
fn encode_info_for_adt(&mut self, local_def_id: LocalDefId) {
|
||||
let def_id = local_def_id.to_def_id();
|
||||
|
|
|
|||
|
|
@ -44,6 +44,7 @@ use table::TableBuilder;
|
|||
use {rustc_ast as ast, rustc_hir as hir};
|
||||
|
||||
use crate::creader::CrateMetadataRef;
|
||||
use crate::eii::EiiMapEncodedKeyValue;
|
||||
|
||||
mod decoder;
|
||||
mod def_path_hash_map;
|
||||
|
|
@ -250,6 +251,7 @@ pub(crate) struct CrateRoot {
|
|||
has_alloc_error_handler: bool,
|
||||
has_panic_handler: bool,
|
||||
has_default_lib_allocator: bool,
|
||||
externally_implementable_items: LazyArray<EiiMapEncodedKeyValue>,
|
||||
|
||||
crate_deps: LazyArray<CrateDep>,
|
||||
dylib_dependency_formats: LazyArray<Option<LinkagePreference>>,
|
||||
|
|
|
|||
|
|
@ -87,6 +87,8 @@ trivially_parameterized_over_tcx! {
|
|||
rustc_hir::Safety,
|
||||
rustc_hir::Stability,
|
||||
rustc_hir::attrs::Deprecation,
|
||||
rustc_hir::attrs::EiiDecl,
|
||||
rustc_hir::attrs::EiiImpl,
|
||||
rustc_hir::attrs::StrippedCfgItem<rustc_hir::def_id::DefIndex>,
|
||||
rustc_hir::def::DefKind,
|
||||
rustc_hir::def::DocLinkResMap,
|
||||
|
|
|
|||
|
|
@ -1224,6 +1224,7 @@ pub(super) fn hir_module_items(tcx: TyCtxt<'_>, module_id: LocalModDefId) -> Mod
|
|||
body_owners,
|
||||
opaques,
|
||||
nested_bodies,
|
||||
eiis,
|
||||
..
|
||||
} = collector;
|
||||
ModuleItems {
|
||||
|
|
@ -1237,6 +1238,7 @@ pub(super) fn hir_module_items(tcx: TyCtxt<'_>, module_id: LocalModDefId) -> Mod
|
|||
opaques: opaques.into_boxed_slice(),
|
||||
nested_bodies: nested_bodies.into_boxed_slice(),
|
||||
delayed_lint_items: Box::new([]),
|
||||
eiis: eiis.into_boxed_slice(),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1259,6 +1261,7 @@ pub(crate) fn hir_crate_items(tcx: TyCtxt<'_>, _: ()) -> ModuleItems {
|
|||
opaques,
|
||||
nested_bodies,
|
||||
mut delayed_lint_items,
|
||||
eiis,
|
||||
..
|
||||
} = collector;
|
||||
|
||||
|
|
@ -1281,6 +1284,7 @@ pub(crate) fn hir_crate_items(tcx: TyCtxt<'_>, _: ()) -> ModuleItems {
|
|||
opaques: opaques.into_boxed_slice(),
|
||||
nested_bodies: nested_bodies.into_boxed_slice(),
|
||||
delayed_lint_items: delayed_lint_items.into_boxed_slice(),
|
||||
eiis: eiis.into_boxed_slice(),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1298,6 +1302,7 @@ struct ItemCollector<'tcx> {
|
|||
opaques: Vec<LocalDefId>,
|
||||
nested_bodies: Vec<LocalDefId>,
|
||||
delayed_lint_items: Vec<OwnerId>,
|
||||
eiis: Vec<LocalDefId>,
|
||||
}
|
||||
|
||||
impl<'tcx> ItemCollector<'tcx> {
|
||||
|
|
@ -1314,6 +1319,7 @@ impl<'tcx> ItemCollector<'tcx> {
|
|||
opaques: Vec::default(),
|
||||
nested_bodies: Vec::default(),
|
||||
delayed_lint_items: Vec::default(),
|
||||
eiis: Vec::default(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1335,6 +1341,12 @@ impl<'hir> Visitor<'hir> for ItemCollector<'hir> {
|
|||
self.delayed_lint_items.push(item.item_id().owner_id);
|
||||
}
|
||||
|
||||
if let ItemKind::Static(..) | ItemKind::Fn { .. } | ItemKind::Macro(..) = &item.kind
|
||||
&& item.eii
|
||||
{
|
||||
self.eiis.push(item.owner_id.def_id)
|
||||
}
|
||||
|
||||
// Items that are modules are handled here instead of in visit_mod.
|
||||
if let ItemKind::Mod(_, module) = &item.kind {
|
||||
self.submodules.push(item.owner_id);
|
||||
|
|
|
|||
|
|
@ -37,6 +37,9 @@ pub struct ModuleItems {
|
|||
nested_bodies: Box<[LocalDefId]>,
|
||||
// only filled with hir_crate_items, not with hir_module_items
|
||||
delayed_lint_items: Box<[OwnerId]>,
|
||||
|
||||
/// Statics and functions with an `EiiImpls` or `EiiExternTarget` attribute
|
||||
eiis: Box<[LocalDefId]>,
|
||||
}
|
||||
|
||||
impl ModuleItems {
|
||||
|
|
@ -58,6 +61,10 @@ impl ModuleItems {
|
|||
self.delayed_lint_items.iter().copied()
|
||||
}
|
||||
|
||||
pub fn eiis(&self) -> impl Iterator<Item = LocalDefId> {
|
||||
self.eiis.iter().copied()
|
||||
}
|
||||
|
||||
/// Returns all items that are associated with some `impl` block (both inherent and trait impl
|
||||
/// blocks).
|
||||
pub fn impl_items(&self) -> impl Iterator<Item = ImplItemId> {
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ use rustc_macros::{HashStable, TyDecodable, TyEncodable};
|
|||
use rustc_span::Symbol;
|
||||
use rustc_target::spec::SanitizerSet;
|
||||
|
||||
use crate::mir::mono::Visibility;
|
||||
use crate::ty::{InstanceKind, TyCtxt};
|
||||
|
||||
impl<'tcx> TyCtxt<'tcx> {
|
||||
|
|
@ -42,6 +43,10 @@ impl<'tcx> TyCtxt<'tcx> {
|
|||
attrs.to_mut().flags.remove(CodegenFnAttrFlags::RUSTC_STD_INTERNAL_SYMBOL);
|
||||
}
|
||||
|
||||
if attrs.flags.contains(CodegenFnAttrFlags::EXTERNALLY_IMPLEMENTABLE_ITEM) {
|
||||
attrs.to_mut().flags.remove(CodegenFnAttrFlags::EXTERNALLY_IMPLEMENTABLE_ITEM);
|
||||
}
|
||||
|
||||
if attrs.symbol_name.is_some() {
|
||||
attrs.to_mut().symbol_name = None;
|
||||
}
|
||||
|
|
@ -62,6 +67,12 @@ pub struct CodegenFnAttrs {
|
|||
/// using the `#[export_name = "..."]` or `#[link_name = "..."]` attribute
|
||||
/// depending on if this is a function definition or foreign function.
|
||||
pub symbol_name: Option<Symbol>,
|
||||
/// Defids of foreign items somewhere that this function should "satisfy".
|
||||
/// i.e., if a foreign function has some symbol foo,
|
||||
/// generate this function under its real name,
|
||||
/// but *also* under the same name as this foreign function so that the foreign function has an implementation.
|
||||
// FIXME: make "SymbolName<'tcx>"
|
||||
pub foreign_item_symbol_aliases: Vec<(Symbol, Linkage, Visibility)>,
|
||||
/// The `#[link_ordinal = "..."]` attribute, indicating an ordinal an
|
||||
/// imported function has in the dynamic library. Note that this must not
|
||||
/// be set when `link_name` is set. This is for foreign items with the
|
||||
|
|
@ -192,6 +203,12 @@ bitflags::bitflags! {
|
|||
const FOREIGN_ITEM = 1 << 16;
|
||||
/// `#[rustc_offload_kernel]`: indicates that this is an offload kernel, an extra ptr arg will be added.
|
||||
const OFFLOAD_KERNEL = 1 << 17;
|
||||
/// Externally implementable item symbols act a little like `RUSTC_STD_INTERNAL_SYMBOL`.
|
||||
/// When a crate declares an EII and dependencies expect the symbol to exist,
|
||||
/// they will refer to this symbol name before a definition is given.
|
||||
/// As such, we must make sure these symbols really do exist in the final binary/library.
|
||||
/// This flag is put on both the implementations of EIIs and the foreign item they implement.
|
||||
const EXTERNALLY_IMPLEMENTABLE_ITEM = 1 << 18;
|
||||
}
|
||||
}
|
||||
rustc_data_structures::external_bitflags_debug! { CodegenFnAttrFlags }
|
||||
|
|
@ -207,6 +224,7 @@ impl CodegenFnAttrs {
|
|||
symbol_name: None,
|
||||
link_ordinal: None,
|
||||
target_features: vec![],
|
||||
foreign_item_symbol_aliases: vec![],
|
||||
safe_target_features: false,
|
||||
linkage: None,
|
||||
import_linkage: None,
|
||||
|
|
@ -234,6 +252,9 @@ impl CodegenFnAttrs {
|
|||
|
||||
self.flags.contains(CodegenFnAttrFlags::NO_MANGLE)
|
||||
|| self.flags.contains(CodegenFnAttrFlags::RUSTC_STD_INTERNAL_SYMBOL)
|
||||
// note: for these we do also set a symbol name so technically also handled by the
|
||||
// condition below. However, I think that regardless these should be treated as extern.
|
||||
|| self.flags.contains(CodegenFnAttrFlags::EXTERNALLY_IMPLEMENTABLE_ITEM)
|
||||
|| self.symbol_name.is_some()
|
||||
|| match self.linkage {
|
||||
// These are private, so make sure we don't try to consider
|
||||
|
|
|
|||
|
|
@ -41,6 +41,7 @@ pub struct SymbolExportInfo {
|
|||
/// Was the symbol marked as `#[used(compiler)]` or `#[used(linker)]`?
|
||||
pub used: bool,
|
||||
/// Was the symbol marked as `#[rustc_std_internal_symbol]`?
|
||||
/// We also use this for externally implementable items.
|
||||
pub rustc_std_internal_symbol: bool,
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -3,9 +3,7 @@ use std::fmt::{self, Debug, Display, Formatter};
|
|||
use rustc_abi::{HasDataLayout, Size};
|
||||
use rustc_hir::def_id::DefId;
|
||||
use rustc_macros::{HashStable, Lift, TyDecodable, TyEncodable, TypeFoldable, TypeVisitable};
|
||||
use rustc_session::RemapFileNameExt;
|
||||
use rustc_session::config::RemapPathScopeComponents;
|
||||
use rustc_span::{DUMMY_SP, Span, Symbol};
|
||||
use rustc_span::{DUMMY_SP, RemapPathScopeComponents, Span, Symbol};
|
||||
use rustc_type_ir::TypeVisitableExt;
|
||||
|
||||
use super::interpret::ReportedErrorInfo;
|
||||
|
|
@ -587,11 +585,7 @@ impl<'tcx> TyCtxt<'tcx> {
|
|||
let caller = self.sess.source_map().lookup_char_pos(topmost.lo());
|
||||
self.const_caller_location(
|
||||
Symbol::intern(
|
||||
&caller
|
||||
.file
|
||||
.name
|
||||
.for_scope(self.sess, RemapPathScopeComponents::MACRO)
|
||||
.to_string_lossy(),
|
||||
&caller.file.name.display(RemapPathScopeComponents::MACRO).to_string_lossy(),
|
||||
),
|
||||
caller.line as u32,
|
||||
caller.col_display as u32 + 1,
|
||||
|
|
|
|||
|
|
@ -374,7 +374,7 @@ pub struct MonoItemData {
|
|||
/// Visibility doesn't have any effect when linkage is internal.
|
||||
///
|
||||
/// DSO means dynamic shared object, that is a dynamically linked executable or dylib.
|
||||
#[derive(Copy, Clone, PartialEq, Debug, HashStable)]
|
||||
#[derive(Copy, Clone, PartialEq, Debug, HashStable, TyEncodable, TyDecodable)]
|
||||
pub enum Visibility {
|
||||
/// Export the symbol from the DSO and apply overrides of the symbol by outside DSOs to within
|
||||
/// the DSO if the object file format supports this.
|
||||
|
|
|
|||
|
|
@ -504,7 +504,7 @@ fn write_scope_tree(
|
|||
"{0:1$} // at {2}",
|
||||
indented_header,
|
||||
ALIGN,
|
||||
tcx.sess.source_map().span_to_embeddable_string(span),
|
||||
tcx.sess.source_map().span_to_diagnostic_string(span),
|
||||
)?;
|
||||
} else {
|
||||
writeln!(w, "{indented_header}")?;
|
||||
|
|
@ -688,7 +688,7 @@ fn write_user_type_annotations(
|
|||
"| {:?}: user_ty: {}, span: {}, inferred_ty: {}",
|
||||
index.index(),
|
||||
annotation.user_ty,
|
||||
tcx.sess.source_map().span_to_embeddable_string(annotation.span),
|
||||
tcx.sess.source_map().span_to_diagnostic_string(annotation.span),
|
||||
with_no_trimmed_paths!(format!("{}", annotation.inferred_ty)),
|
||||
)?;
|
||||
}
|
||||
|
|
@ -1420,7 +1420,7 @@ impl<'tcx> Visitor<'tcx> for ExtraComments<'tcx> {
|
|||
self.push("mir::ConstOperand");
|
||||
self.push(&format!(
|
||||
"+ span: {}",
|
||||
self.tcx.sess.source_map().span_to_embeddable_string(*span)
|
||||
self.tcx.sess.source_map().span_to_diagnostic_string(*span)
|
||||
));
|
||||
if let Some(user_ty) = user_ty {
|
||||
self.push(&format!("+ user_ty: {user_ty:?}"));
|
||||
|
|
@ -1503,7 +1503,7 @@ impl<'tcx> Visitor<'tcx> for ExtraComments<'tcx> {
|
|||
}
|
||||
|
||||
fn comment(tcx: TyCtxt<'_>, SourceInfo { span, scope }: SourceInfo) -> String {
|
||||
let location = tcx.sess.source_map().span_to_embeddable_string(span);
|
||||
let location = tcx.sess.source_map().span_to_diagnostic_string(span);
|
||||
format!("scope {} at {}", scope.index(), location,)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -296,6 +296,8 @@ trivial! {
|
|||
rustc_ast::expand::allocator::AllocatorKind,
|
||||
rustc_hir::DefaultBodyStability,
|
||||
rustc_hir::attrs::Deprecation,
|
||||
rustc_hir::attrs::EiiDecl,
|
||||
rustc_hir::attrs::EiiImpl,
|
||||
rustc_data_structures::svh::Svh,
|
||||
rustc_errors::ErrorGuaranteed,
|
||||
rustc_hir::Constness,
|
||||
|
|
|
|||
|
|
@ -76,7 +76,7 @@ use rustc_data_structures::steal::Steal;
|
|||
use rustc_data_structures::svh::Svh;
|
||||
use rustc_data_structures::unord::{UnordMap, UnordSet};
|
||||
use rustc_errors::ErrorGuaranteed;
|
||||
use rustc_hir::attrs::StrippedCfgItem;
|
||||
use rustc_hir::attrs::{EiiDecl, EiiImpl, StrippedCfgItem};
|
||||
use rustc_hir::def::{DefKind, DocLinkResMap};
|
||||
use rustc_hir::def_id::{
|
||||
CrateNum, DefId, DefIdMap, LocalDefId, LocalDefIdMap, LocalDefIdSet, LocalModDefId,
|
||||
|
|
@ -2753,6 +2753,18 @@ rustc_queries! {
|
|||
desc { |tcx| "checking what set of sanitizers are enabled on `{}`", tcx.def_path_str(key) }
|
||||
feedable
|
||||
}
|
||||
|
||||
query check_externally_implementable_items(_: ()) {
|
||||
desc { "check externally implementable items" }
|
||||
}
|
||||
|
||||
/// Returns a list of all `externally implementable items` crate.
|
||||
query externally_implementable_items(cnum: CrateNum) -> &'tcx FxIndexMap<DefId, (EiiDecl, FxIndexMap<DefId, EiiImpl>)> {
|
||||
arena_cache
|
||||
desc { "looking up the externally implementable items of a crate" }
|
||||
cache_on_disk_if { *cnum == LOCAL_CRATE }
|
||||
separate_provide_extern
|
||||
}
|
||||
}
|
||||
|
||||
rustc_with_all_queries! { define_callbacks! }
|
||||
|
|
|
|||
|
|
@ -420,6 +420,13 @@ pub enum ObligationCauseCode<'tcx> {
|
|||
/// Only reachable if the `unsized_fn_params` feature is used. Unsized function arguments must
|
||||
/// be place expressions because we can't store them in MIR locals as temporaries.
|
||||
UnsizedNonPlaceExpr(Span),
|
||||
|
||||
/// Error derived when checking an impl item is compatible with
|
||||
/// its corresponding trait item's definition
|
||||
CompareEii {
|
||||
external_impl: LocalDefId,
|
||||
declaration: DefId,
|
||||
},
|
||||
}
|
||||
|
||||
/// Whether a value can be extracted into a const.
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@ use rustc_hir::definitions::{DefKey, DefPathDataName};
|
|||
use rustc_hir::limit::Limit;
|
||||
use rustc_macros::{Lift, extension};
|
||||
use rustc_session::cstore::{ExternCrate, ExternCrateSource};
|
||||
use rustc_span::{FileNameDisplayPreference, Ident, Symbol, kw, sym};
|
||||
use rustc_span::{Ident, RemapPathScopeComponents, Symbol, kw, sym};
|
||||
use rustc_type_ir::{Upcast as _, elaborate};
|
||||
use smallvec::SmallVec;
|
||||
|
||||
|
|
@ -890,7 +890,7 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write {
|
|||
"@{}",
|
||||
// This may end up in stderr diagnostics but it may also be emitted
|
||||
// into MIR. Hence we use the remapped path if available
|
||||
self.tcx().sess.source_map().span_to_embeddable_string(span)
|
||||
self.tcx().sess.source_map().span_to_diagnostic_string(span)
|
||||
)?;
|
||||
} else {
|
||||
write!(self, "@")?;
|
||||
|
|
@ -921,7 +921,7 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write {
|
|||
"@{}",
|
||||
// This may end up in stderr diagnostics but it may also be emitted
|
||||
// into MIR. Hence we use the remapped path if available
|
||||
self.tcx().sess.source_map().span_to_embeddable_string(span)
|
||||
self.tcx().sess.source_map().span_to_diagnostic_string(span)
|
||||
)?;
|
||||
} else {
|
||||
write!(self, "@")?;
|
||||
|
|
@ -947,10 +947,13 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write {
|
|||
self.print_def_path(did.to_def_id(), args)?;
|
||||
} else {
|
||||
let span = self.tcx().def_span(did);
|
||||
let preference = if with_forced_trimmed_paths() {
|
||||
FileNameDisplayPreference::Short
|
||||
let loc = if with_forced_trimmed_paths() {
|
||||
self.tcx().sess.source_map().span_to_short_string(
|
||||
span,
|
||||
RemapPathScopeComponents::DIAGNOSTICS,
|
||||
)
|
||||
} else {
|
||||
FileNameDisplayPreference::Remapped
|
||||
self.tcx().sess.source_map().span_to_diagnostic_string(span)
|
||||
};
|
||||
write!(
|
||||
self,
|
||||
|
|
@ -958,7 +961,7 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write {
|
|||
// This may end up in stderr diagnostics but it may also be
|
||||
// emitted into MIR. Hence we use the remapped path if
|
||||
// available
|
||||
self.tcx().sess.source_map().span_to_string(span, preference)
|
||||
loc
|
||||
)?;
|
||||
}
|
||||
} else {
|
||||
|
|
@ -1004,18 +1007,17 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write {
|
|||
self.print_def_path(did.to_def_id(), args)?;
|
||||
} else {
|
||||
let span = self.tcx().def_span(did);
|
||||
let preference = if with_forced_trimmed_paths() {
|
||||
FileNameDisplayPreference::Short
|
||||
// This may end up in stderr diagnostics but it may also be emitted
|
||||
// into MIR. Hence we use the remapped path if available
|
||||
let loc = if with_forced_trimmed_paths() {
|
||||
self.tcx().sess.source_map().span_to_short_string(
|
||||
span,
|
||||
RemapPathScopeComponents::DIAGNOSTICS,
|
||||
)
|
||||
} else {
|
||||
FileNameDisplayPreference::Remapped
|
||||
self.tcx().sess.source_map().span_to_diagnostic_string(span)
|
||||
};
|
||||
write!(
|
||||
self,
|
||||
"@{}",
|
||||
// This may end up in stderr diagnostics but it may also be emitted
|
||||
// into MIR. Hence we use the remapped path if available
|
||||
self.tcx().sess.source_map().span_to_string(span, preference)
|
||||
)?;
|
||||
write!(self, "@{loc}")?;
|
||||
}
|
||||
} else {
|
||||
write!(self, "@")?;
|
||||
|
|
@ -2258,7 +2260,7 @@ impl<'tcx> Printer<'tcx> for FmtPrinter<'_, 'tcx> {
|
|||
"<impl at {}>",
|
||||
// This may end up in stderr diagnostics but it may also be emitted
|
||||
// into MIR. Hence we use the remapped path if available
|
||||
self.tcx.sess.source_map().span_to_embeddable_string(span)
|
||||
self.tcx.sess.source_map().span_to_diagnostic_string(span)
|
||||
)?;
|
||||
self.empty_path = false;
|
||||
|
||||
|
|
|
|||
|
|
@ -1643,11 +1643,13 @@ impl<'v> RootCollector<'_, 'v> {
|
|||
MonoItemCollectionStrategy::Lazy => {
|
||||
self.entry_fn.and_then(|(id, _)| id.as_local()) == Some(def_id)
|
||||
|| self.tcx.is_reachable_non_generic(def_id)
|
||||
|| self
|
||||
.tcx
|
||||
.codegen_fn_attrs(def_id)
|
||||
.flags
|
||||
.contains(CodegenFnAttrFlags::RUSTC_STD_INTERNAL_SYMBOL)
|
||||
|| {
|
||||
let flags = self.tcx.codegen_fn_attrs(def_id).flags;
|
||||
flags.intersects(
|
||||
CodegenFnAttrFlags::RUSTC_STD_INTERNAL_SYMBOL
|
||||
| CodegenFnAttrFlags::EXTERNALLY_IMPLEMENTABLE_ITEM,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
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