Rollup merge of #152568 - JonathanBrouwer:port_lang, r=jdonszelmann
Port `#[lang]` and `#[panic_handler]` to the new attribute parsers For https://github.com/rust-lang/rust/issues/131229#issuecomment-2971351163 r? @jdonszelmann
This commit is contained in:
commit
22f973db34
17 changed files with 105 additions and 56 deletions
|
|
@ -1,6 +1,7 @@
|
|||
use std::path::PathBuf;
|
||||
|
||||
use rustc_ast::{LitIntType, LitKind, MetaItemLit};
|
||||
use rustc_hir::LangItem;
|
||||
use rustc_hir::attrs::{
|
||||
BorrowckGraphvizFormatKind, CguFields, CguKind, DivergingBlockBehavior,
|
||||
DivergingFallbackBehavior, RustcCleanAttribute, RustcCleanQueries, RustcLayoutType,
|
||||
|
|
@ -12,7 +13,7 @@ use rustc_span::Symbol;
|
|||
use super::prelude::*;
|
||||
use super::util::parse_single_integer;
|
||||
use crate::session_diagnostics::{
|
||||
AttributeRequiresOpt, CguFieldsMissing, RustcScalableVectorCountOutOfRange,
|
||||
AttributeRequiresOpt, CguFieldsMissing, RustcScalableVectorCountOutOfRange, UnknownLangItem,
|
||||
};
|
||||
|
||||
pub(crate) struct RustcMainParser;
|
||||
|
|
@ -626,6 +627,32 @@ impl<S: Stage> SingleAttributeParser<S> for RustcScalableVectorParser {
|
|||
}
|
||||
}
|
||||
|
||||
pub(crate) struct LangParser;
|
||||
|
||||
impl<S: Stage> SingleAttributeParser<S> for LangParser {
|
||||
const PATH: &[Symbol] = &[sym::lang];
|
||||
const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepInnermost;
|
||||
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
|
||||
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(ALL_TARGETS); // Targets are checked per lang item in `rustc_passes`
|
||||
const TEMPLATE: AttributeTemplate = template!(NameValueStr: "name");
|
||||
|
||||
fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option<AttributeKind> {
|
||||
let Some(nv) = args.name_value() else {
|
||||
cx.expected_name_value(cx.attr_span, None);
|
||||
return None;
|
||||
};
|
||||
let Some(name) = nv.value_as_str() else {
|
||||
cx.expected_string_literal(nv.value_span, Some(nv.value_as_lit()));
|
||||
return None;
|
||||
};
|
||||
let Some(lang_item) = LangItem::from_name(name) else {
|
||||
cx.emit_err(UnknownLangItem { span: cx.attr_span, name });
|
||||
return None;
|
||||
};
|
||||
Some(AttributeKind::Lang(lang_item, cx.attr_span))
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) struct RustcHasIncoherentInherentImplsParser;
|
||||
|
||||
impl<S: Stage> NoArgsAttributeParser<S> for RustcHasIncoherentInherentImplsParser {
|
||||
|
|
@ -641,6 +668,15 @@ impl<S: Stage> NoArgsAttributeParser<S> for RustcHasIncoherentInherentImplsParse
|
|||
const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcHasIncoherentInherentImpls;
|
||||
}
|
||||
|
||||
pub(crate) struct PanicHandlerParser;
|
||||
|
||||
impl<S: Stage> NoArgsAttributeParser<S> for PanicHandlerParser {
|
||||
const PATH: &[Symbol] = &[sym::panic_handler];
|
||||
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
|
||||
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(ALL_TARGETS); // Targets are checked per lang item in `rustc_passes`
|
||||
const CREATE: fn(Span) -> AttributeKind = |span| AttributeKind::Lang(LangItem::PanicImpl, span);
|
||||
}
|
||||
|
||||
pub(crate) struct RustcHiddenTypeOfOpaquesParser;
|
||||
|
||||
impl<S: Stage> NoArgsAttributeParser<S> for RustcHiddenTypeOfOpaquesParser {
|
||||
|
|
|
|||
|
|
@ -181,6 +181,7 @@ attribute_parsers!(
|
|||
Single<IgnoreParser>,
|
||||
Single<InlineParser>,
|
||||
Single<InstructionSetParser>,
|
||||
Single<LangParser>,
|
||||
Single<LinkNameParser>,
|
||||
Single<LinkOrdinalParser>,
|
||||
Single<LinkSectionParser>,
|
||||
|
|
@ -254,6 +255,7 @@ attribute_parsers!(
|
|||
Single<WithoutArgs<NoMangleParser>>,
|
||||
Single<WithoutArgs<NoStdParser>>,
|
||||
Single<WithoutArgs<NonExhaustiveParser>>,
|
||||
Single<WithoutArgs<PanicHandlerParser>>,
|
||||
Single<WithoutArgs<PanicRuntimeParser>>,
|
||||
Single<WithoutArgs<ParenSugarParser>>,
|
||||
Single<WithoutArgs<PassByValueParser>>,
|
||||
|
|
|
|||
|
|
@ -1013,6 +1013,15 @@ pub(crate) struct DocAliasMalformed {
|
|||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag("definition of an unknown lang item: `{$name}`", code = E0522)]
|
||||
pub(crate) struct UnknownLangItem {
|
||||
#[primary_span]
|
||||
#[label("definition of unknown lang item `{$name}`")]
|
||||
pub span: Span,
|
||||
pub name: Symbol,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag("target `{$current_target}` does not support `#[instruction_set({$instruction_set}::*)]`")]
|
||||
pub(crate) struct UnsupportedInstructionSet<'a> {
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ use rustc_hir::attrs::{
|
|||
};
|
||||
use rustc_hir::def::DefKind;
|
||||
use rustc_hir::def_id::{DefId, LOCAL_CRATE, LocalDefId};
|
||||
use rustc_hir::{self as hir, Attribute, LangItem, find_attr, lang_items};
|
||||
use rustc_hir::{self as hir, Attribute, find_attr};
|
||||
use rustc_middle::middle::codegen_fn_attrs::{
|
||||
CodegenFnAttrFlags, CodegenFnAttrs, PatchableFunctionEntry, SanitizerFnAttrs,
|
||||
};
|
||||
|
|
@ -504,7 +504,7 @@ fn handle_lang_items(
|
|||
attrs: &[Attribute],
|
||||
codegen_fn_attrs: &mut CodegenFnAttrs,
|
||||
) {
|
||||
let lang_item = lang_items::extract(attrs).and_then(|(name, _)| LangItem::from_name(name));
|
||||
let lang_item = find_attr!(attrs, AttributeKind::Lang(lang, _) => lang);
|
||||
|
||||
// Weak lang items have the same semantics as "std internal" symbols in the
|
||||
// sense that they're preserved through all our LTO passes and only
|
||||
|
|
|
|||
|
|
@ -7,8 +7,8 @@ Erroneous code example:
|
|||
#![allow(internal_features)]
|
||||
|
||||
extern "C" {
|
||||
#[lang = "cake"] // error: unknown external lang item: `cake`
|
||||
fn cake();
|
||||
#[lang = "copy"] // error: unknown external lang item: `copy`
|
||||
fn copy();
|
||||
}
|
||||
```
|
||||
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ use rustc_ast::token::DocFragmentKind;
|
|||
use rustc_ast::{AttrStyle, Path, ast};
|
||||
use rustc_data_structures::fx::FxIndexMap;
|
||||
use rustc_error_messages::{DiagArgValue, IntoDiagArg};
|
||||
use rustc_hir::LangItem;
|
||||
use rustc_macros::{Decodable, Encodable, HashStable_Generic, PrintAttribute};
|
||||
use rustc_span::def_id::DefId;
|
||||
use rustc_span::hygiene::Transparency;
|
||||
|
|
@ -953,6 +954,9 @@ pub enum AttributeKind {
|
|||
/// Represents `#[instruction_set]`
|
||||
InstructionSet(InstructionSetAttr),
|
||||
|
||||
/// Represents `#[lang]`
|
||||
Lang(LangItem, Span),
|
||||
|
||||
/// Represents `#[link]`.
|
||||
Link(ThinVec<LinkEntry>, Span),
|
||||
|
||||
|
|
|
|||
|
|
@ -50,6 +50,7 @@ impl AttributeKind {
|
|||
Ignore { .. } => No,
|
||||
Inline(..) => No,
|
||||
InstructionSet(..) => No,
|
||||
Lang(..) => Yes,
|
||||
Link(..) => No,
|
||||
LinkName { .. } => Yes, // Needed for rustdoc
|
||||
LinkOrdinal { .. } => No,
|
||||
|
|
|
|||
|
|
@ -7,12 +7,12 @@
|
|||
//! * Traits that represent operators; e.g., `Add`, `Sub`, `Index`.
|
||||
//! * Functions called by the compiler itself.
|
||||
|
||||
use rustc_ast::attr::AttributeExt;
|
||||
use rustc_data_structures::fx::FxIndexMap;
|
||||
use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
|
||||
use rustc_macros::{BlobDecodable, Encodable, HashStable_Generic};
|
||||
use rustc_span::{Span, Symbol, kw, sym};
|
||||
use rustc_macros::{BlobDecodable, Encodable, HashStable_Generic, PrintAttribute};
|
||||
use rustc_span::{Symbol, kw, sym};
|
||||
|
||||
use crate::attrs::PrintAttribute;
|
||||
use crate::def_id::DefId;
|
||||
use crate::{MethodKind, Target};
|
||||
|
||||
|
|
@ -75,7 +75,7 @@ macro_rules! language_item_table {
|
|||
$( $(#[$attr:meta])* $variant:ident, $module:ident :: $name:ident, $method:ident, $target:expr, $generics:expr; )*
|
||||
) => {
|
||||
/// A representation of all the valid lang items in Rust.
|
||||
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, Encodable, BlobDecodable)]
|
||||
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, Encodable, BlobDecodable, PrintAttribute)]
|
||||
pub enum LangItem {
|
||||
$(
|
||||
#[doc = concat!("The `", stringify!($name), "` lang item.")]
|
||||
|
|
@ -150,18 +150,6 @@ impl<CTX> HashStable<CTX> for LangItem {
|
|||
}
|
||||
}
|
||||
|
||||
/// Extracts the first `lang = "$name"` out of a list of attributes.
|
||||
/// The `#[panic_handler]` attribute is also extracted out when found.
|
||||
pub fn extract(attrs: &[impl AttributeExt]) -> Option<(Symbol, Span)> {
|
||||
attrs.iter().find_map(|attr| {
|
||||
Some(match attr {
|
||||
_ if attr.has_name(sym::lang) => (attr.value_str()?, attr.span()),
|
||||
_ if attr.has_name(sym::panic_handler) => (sym::panic_impl, attr.span()),
|
||||
_ => return None,
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
language_item_table! {
|
||||
// Variant name, Name, Getter method name, Target Generic requirements;
|
||||
Sized, sym::sized, sized_trait, Target::Trait, GenericRequirement::Exact(0);
|
||||
|
|
|
|||
|
|
@ -256,6 +256,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
|
|||
| AttributeKind::Fundamental
|
||||
| AttributeKind::Ignore { .. }
|
||||
| AttributeKind::InstructionSet(..)
|
||||
| AttributeKind::Lang(..)
|
||||
| AttributeKind::LinkName { .. }
|
||||
| AttributeKind::LinkOrdinal { .. }
|
||||
| AttributeKind::LinkSection { .. }
|
||||
|
|
@ -394,8 +395,6 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
|
|||
| sym::deny
|
||||
| sym::forbid
|
||||
// internal
|
||||
| sym::panic_handler
|
||||
| sym::lang
|
||||
| sym::default_lib_allocator
|
||||
| sym::rustc_nonnull_optimization_guaranteed
|
||||
| sym::rustc_inherit_overflow_checks
|
||||
|
|
@ -784,15 +783,14 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
|
|||
Target::Fn => {
|
||||
// `#[track_caller]` is not valid on weak lang items because they are called via
|
||||
// `extern` declarations and `#[track_caller]` would alter their ABI.
|
||||
if let Some((lang_item, _)) = hir::lang_items::extract(attrs)
|
||||
&& let Some(item) = hir::LangItem::from_name(lang_item)
|
||||
if let Some(item) = find_attr!(attrs, AttributeKind::Lang(item, _) => item)
|
||||
&& item.is_weak()
|
||||
{
|
||||
let sig = self.tcx.hir_node(hir_id).fn_sig().unwrap();
|
||||
|
||||
self.dcx().emit_err(errors::LangItemWithTrackCaller {
|
||||
attr_span,
|
||||
name: lang_item,
|
||||
name: item.name(),
|
||||
sig_span: sig.span,
|
||||
});
|
||||
}
|
||||
|
|
@ -856,7 +854,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
|
|||
Target::Method(MethodKind::Trait { body: true } | MethodKind::Inherent)
|
||||
| Target::Fn => {
|
||||
// `#[target_feature]` is not allowed in lang items.
|
||||
if let Some((lang_item, _)) = hir::lang_items::extract(attrs)
|
||||
if let Some(lang_item) = find_attr!(attrs, AttributeKind::Lang(lang, _) => lang)
|
||||
// Calling functions with `#[target_feature]` is
|
||||
// not unsafe on WASM, see #84988
|
||||
&& !self.tcx.sess.target.is_like_wasm
|
||||
|
|
@ -866,7 +864,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
|
|||
|
||||
self.dcx().emit_err(errors::LangItemWithTargetFeature {
|
||||
attr_span,
|
||||
name: lang_item,
|
||||
name: lang_item.name(),
|
||||
sig_span: sig.span,
|
||||
});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -22,7 +22,7 @@ use rustc_middle::ty::{self, AssocTag, TyCtxt};
|
|||
use rustc_middle::{bug, span_bug};
|
||||
use rustc_session::lint::builtin::DEAD_CODE;
|
||||
use rustc_session::lint::{self, LintExpectationId};
|
||||
use rustc_span::{Symbol, kw, sym};
|
||||
use rustc_span::{Symbol, kw};
|
||||
|
||||
use crate::errors::{
|
||||
ChangeFields, IgnoredDerivedImpls, MultipleDeadCodes, ParentInfo, UselessAssignment,
|
||||
|
|
@ -706,12 +706,6 @@ fn has_allow_dead_code_or_lang_attr(
|
|||
tcx: TyCtxt<'_>,
|
||||
def_id: LocalDefId,
|
||||
) -> Option<ComesFromAllowExpect> {
|
||||
fn has_lang_attr(tcx: TyCtxt<'_>, def_id: LocalDefId) -> bool {
|
||||
tcx.has_attr(def_id, sym::lang)
|
||||
// Stable attribute for #[lang = "panic_impl"]
|
||||
|| tcx.has_attr(def_id, sym::panic_handler)
|
||||
}
|
||||
|
||||
fn has_allow_expect_dead_code(tcx: TyCtxt<'_>, def_id: LocalDefId) -> bool {
|
||||
let hir_id = tcx.local_def_id_to_hir_id(def_id);
|
||||
let lint_level = tcx.lint_level_at_node(lint::builtin::DEAD_CODE, hir_id).level;
|
||||
|
|
@ -732,7 +726,9 @@ fn has_allow_dead_code_or_lang_attr(
|
|||
|
||||
if has_allow_expect_dead_code(tcx, def_id) {
|
||||
Some(ComesFromAllowExpect::Yes)
|
||||
} else if has_used_like_attr(tcx, def_id) || has_lang_attr(tcx, def_id) {
|
||||
} else if has_used_like_attr(tcx, def_id)
|
||||
|| find_attr!(tcx.get_all_attrs(def_id), AttributeKind::Lang(..))
|
||||
{
|
||||
Some(ComesFromAllowExpect::No)
|
||||
} else {
|
||||
None
|
||||
|
|
|
|||
|
|
@ -465,15 +465,6 @@ pub(crate) struct LangItemOnIncorrectTarget {
|
|||
pub actual_target: Target,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag("definition of an unknown lang item: `{$name}`", code = E0522)]
|
||||
pub(crate) struct UnknownLangItem {
|
||||
#[primary_span]
|
||||
#[label("definition of unknown lang item `{$name}`")]
|
||||
pub span: Span,
|
||||
pub name: Symbol,
|
||||
}
|
||||
|
||||
pub(crate) struct InvalidAttrAtCrateLevel {
|
||||
pub span: Span,
|
||||
pub sugg_span: Option<Span>,
|
||||
|
|
|
|||
|
|
@ -11,16 +11,15 @@ use rustc_ast as ast;
|
|||
use rustc_ast::visit;
|
||||
use rustc_data_structures::fx::FxHashMap;
|
||||
use rustc_hir::def_id::{DefId, LocalDefId};
|
||||
use rustc_hir::lang_items::{GenericRequirement, extract};
|
||||
use rustc_hir::lang_items::GenericRequirement;
|
||||
use rustc_hir::{LangItem, LanguageItems, MethodKind, Target};
|
||||
use rustc_middle::query::Providers;
|
||||
use rustc_middle::ty::{ResolverAstLowering, TyCtxt};
|
||||
use rustc_session::cstore::ExternCrate;
|
||||
use rustc_span::Span;
|
||||
use rustc_span::{Span, Symbol, sym};
|
||||
|
||||
use crate::errors::{
|
||||
DuplicateLangItem, IncorrectCrateType, IncorrectTarget, LangItemOnIncorrectTarget,
|
||||
UnknownLangItem,
|
||||
};
|
||||
use crate::weak_lang_items;
|
||||
|
||||
|
|
@ -62,7 +61,7 @@ impl<'ast, 'tcx> LanguageItemCollector<'ast, 'tcx> {
|
|||
item_span: Span,
|
||||
generics: Option<&'ast ast::Generics>,
|
||||
) {
|
||||
if let Some((name, attr_span)) = extract(attrs) {
|
||||
if let Some((name, attr_span)) = extract_ast(attrs) {
|
||||
match LangItem::from_name(name) {
|
||||
// Known lang item with attribute on correct target.
|
||||
Some(lang_item) if actual_target == lang_item.target() => {
|
||||
|
|
@ -86,7 +85,7 @@ impl<'ast, 'tcx> LanguageItemCollector<'ast, 'tcx> {
|
|||
}
|
||||
// Unknown lang item.
|
||||
_ => {
|
||||
self.tcx.dcx().emit_err(UnknownLangItem { span: attr_span, name });
|
||||
self.tcx.dcx().delayed_bug("unknown lang item");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -359,6 +358,20 @@ impl<'ast, 'tcx> visit::Visitor<'ast> for LanguageItemCollector<'ast, 'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
/// Extracts the first `lang = "$name"` out of a list of attributes.
|
||||
/// The `#[panic_handler]` attribute is also extracted out when found.
|
||||
///
|
||||
/// This function is used for `ast::Attribute`, for `hir::Attribute` use the `find_attr!` macro with `AttributeKind::Lang`
|
||||
pub(crate) fn extract_ast(attrs: &[rustc_ast::ast::Attribute]) -> Option<(Symbol, Span)> {
|
||||
attrs.iter().find_map(|attr| {
|
||||
Some(match attr {
|
||||
_ if attr.has_name(sym::lang) => (attr.value_str()?, attr.span()),
|
||||
_ if attr.has_name(sym::panic_handler) => (sym::panic_impl, attr.span()),
|
||||
_ => return None,
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
pub(crate) fn provide(providers: &mut Providers) {
|
||||
providers.get_lang_items = get_lang_items;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@ use rustc_target::spec::Os;
|
|||
use crate::errors::{
|
||||
MissingLangItem, MissingPanicHandler, PanicUnwindWithoutStd, UnknownExternLangItem,
|
||||
};
|
||||
use crate::lang_items::extract_ast;
|
||||
|
||||
/// Checks the crate for usage of weak lang items, returning a vector of all the
|
||||
/// lang items required by this crate, but not defined yet.
|
||||
|
|
@ -46,7 +47,7 @@ struct WeakLangItemVisitor<'a, 'tcx> {
|
|||
|
||||
impl<'ast> visit::Visitor<'ast> for WeakLangItemVisitor<'_, '_> {
|
||||
fn visit_foreign_item(&mut self, i: &'ast ast::ForeignItem) {
|
||||
if let Some((lang_item, _)) = lang_items::extract(&i.attrs) {
|
||||
if let Some((lang_item, _)) = extract_ast(&i.attrs) {
|
||||
if let Some(item) = LangItem::from_name(lang_item)
|
||||
&& item.is_weak()
|
||||
{
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
#![feature(lang_items)]
|
||||
|
||||
extern "C" {
|
||||
#[lang = "cake"]
|
||||
fn cake(); //~ ERROR E0264
|
||||
#[lang = "copy"]
|
||||
fn copy(); //~ ERROR E0264
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
error[E0264]: unknown external lang item: `cake`
|
||||
error[E0264]: unknown external lang item: `copy`
|
||||
--> $DIR/E0264.rs:5:5
|
||||
|
|
||||
LL | fn cake();
|
||||
LL | fn copy();
|
||||
| ^^^^^^^^^^
|
||||
|
||||
error: aborting due to 1 previous error
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
//@ run-pass
|
||||
//@ check-fail
|
||||
|
||||
// Test that this doesn't abort during AST lowering. In #96847 it did abort
|
||||
// because the attribute was being lowered twice.
|
||||
|
|
@ -9,6 +9,7 @@
|
|||
fn main() {
|
||||
for _ in [1,2,3] {
|
||||
#![lang="foo"]
|
||||
//~^ ERROR definition of an unknown lang item: `foo` [E0522]
|
||||
println!("foo");
|
||||
}
|
||||
}
|
||||
|
|
|
|||
9
tests/ui/lowering/issue-96847.stderr
Normal file
9
tests/ui/lowering/issue-96847.stderr
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
error[E0522]: definition of an unknown lang item: `foo`
|
||||
--> $DIR/issue-96847.rs:11:9
|
||||
|
|
||||
LL | #![lang="foo"]
|
||||
| ^^^^^^^^^^^^^^ definition of unknown lang item `foo`
|
||||
|
||||
error: aborting due to 1 previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0522`.
|
||||
Loading…
Add table
Add a link
Reference in a new issue