Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 37 additions & 1 deletion compiler/rustc_attr_parsing/src/attributes/rustc_internal.rs
Original file line number Diff line number Diff line change
@@ -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,
Expand All @@ -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;
Expand Down Expand Up @@ -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 {
Expand All @@ -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 {
Expand Down
2 changes: 2 additions & 0 deletions compiler/rustc_attr_parsing/src/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -181,6 +181,7 @@ attribute_parsers!(
Single<IgnoreParser>,
Single<InlineParser>,
Single<InstructionSetParser>,
Single<LangParser>,
Single<LinkNameParser>,
Single<LinkOrdinalParser>,
Single<LinkSectionParser>,
Expand Down Expand Up @@ -253,6 +254,7 @@ attribute_parsers!(
Single<WithoutArgs<NoMangleParser>>,
Single<WithoutArgs<NoStdParser>>,
Single<WithoutArgs<NonExhaustiveParser>>,
Single<WithoutArgs<PanicHandlerParser>>,
Single<WithoutArgs<PanicRuntimeParser>>,
Single<WithoutArgs<ParenSugarParser>>,
Single<WithoutArgs<PassByValueParser>>,
Expand Down
9 changes: 9 additions & 0 deletions compiler/rustc_attr_parsing/src/session_diagnostics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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> {
Expand Down
4 changes: 2 additions & 2 deletions compiler/rustc_codegen_ssa/src/codegen_attrs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
};
Expand Down Expand Up @@ -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
Expand Down
4 changes: 2 additions & 2 deletions compiler/rustc_error_codes/src/error_codes/E0264.md
Original file line number Diff line number Diff line change
Expand Up @@ -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();
}
```

Expand Down
4 changes: 4 additions & 0 deletions compiler/rustc_hir/src/attrs/data_structures.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -953,6 +954,9 @@ pub enum AttributeKind {
/// Represents `#[instruction_set]`
InstructionSet(InstructionSetAttr),

/// Represents `#[lang]`
Lang(LangItem, Span),

/// Represents `#[link]`.
Link(ThinVec<LinkEntry>, Span),

Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_hir/src/attrs/encode_cross_crate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ impl AttributeKind {
Ignore { .. } => No,
Inline(..) => No,
InstructionSet(..) => No,
Lang(..) => Yes,
Link(..) => No,
LinkName { .. } => Yes, // Needed for rustdoc
LinkOrdinal { .. } => No,
Expand Down
20 changes: 4 additions & 16 deletions compiler/rustc_hir/src/lang_items.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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};

Expand Down Expand Up @@ -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.")]
Expand Down Expand Up @@ -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);
Expand Down
12 changes: 5 additions & 7 deletions compiler/rustc_passes/src/check_attr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -256,6 +256,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
| AttributeKind::Fundamental
| AttributeKind::Ignore { .. }
| AttributeKind::InstructionSet(..)
| AttributeKind::Lang(..)
| AttributeKind::LinkName { .. }
| AttributeKind::LinkOrdinal { .. }
| AttributeKind::LinkSection { .. }
Expand Down Expand Up @@ -395,8 +396,6 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
// need to be fixed
| sym::deprecated_safe // FIXME(deprecated_safe)
// internal
| sym::panic_handler
| sym::lang
| sym::default_lib_allocator
| sym::rustc_diagnostic_item
| sym::rustc_nonnull_optimization_guaranteed
Expand Down Expand Up @@ -786,15 +785,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,
});
}
Expand Down Expand Up @@ -858,7 +856,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
Expand All @@ -868,7 +866,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> {

self.dcx().emit_err(errors::LangItemWithTargetFeature {
attr_span,
name: lang_item,
name: lang_item.name(),
sig_span: sig.span,
});
}
Expand Down
12 changes: 4 additions & 8 deletions compiler/rustc_passes/src/dead.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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;
Expand All @@ -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
Expand Down
9 changes: 0 additions & 9 deletions compiler/rustc_passes/src/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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>,
Expand Down
23 changes: 18 additions & 5 deletions compiler/rustc_passes/src/lang_items.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down Expand Up @@ -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() => {
Expand All @@ -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");
}
}
}
Expand Down Expand Up @@ -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()),
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Kept the old parsers here, because changing it is bad for perf :c
I'll take a further look at this in the future

_ 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;
}
3 changes: 2 additions & 1 deletion compiler/rustc_passes/src/weak_lang_items.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -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()
{
Expand Down
4 changes: 2 additions & 2 deletions tests/ui/error-codes/E0264.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
#![feature(lang_items)]

extern "C" {
#[lang = "cake"]
fn cake(); //~ ERROR E0264
#[lang = "copy"]
fn copy(); //~ ERROR E0264
}

fn main() {}
4 changes: 2 additions & 2 deletions tests/ui/error-codes/E0264.stderr
Original file line number Diff line number Diff line change
@@ -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
Expand Down
Loading
Loading