Port the #[link] attribute to the new parser

This commit is contained in:
Jonathan Brouwer 2025-07-16 13:46:08 +02:00
parent aab5e0bf1f
commit e8d08b5416
No known key found for this signature in database
GPG key ID: 13619B051B673C52
14 changed files with 639 additions and 623 deletions

View file

@ -195,3 +195,55 @@ attr_parsing_invalid_meta_item = expected a literal (`1u8`, `1.0f32`, `"string"`
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_as_needed_compatibility =
linking modifier `as-needed` is only compatible with `dylib` and `framework` linking kinds
attr_parsing_bundle_needs_static =
linking modifier `bundle` is only compatible with `static` linking kind
attr_parsing_empty_link_name =
link name must not be empty
.label = empty link name
attr_parsing_import_name_type_raw =
import name type can only be used with link kind `raw-dylib`
attr_parsing_import_name_type_x86 =
import name type is only supported on x86
attr_parsing_incompatible_wasm_link =
`wasm_import_module` is incompatible with other arguments in `#[link]` attributes
attr_parsing_invalid_link_modifier =
invalid linking modifier syntax, expected '+' or '-' prefix before one of: bundle, verbatim, whole-archive, as-needed
attr_parsing_link_arg_unstable =
link kind `link-arg` is unstable
attr_parsing_link_cfg_unstable =
link cfg is unstable
attr_parsing_link_framework_apple =
link kind `framework` is only supported on Apple targets
attr_parsing_link_requires_name =
`#[link]` attribute requires a `name = "string"` argument
.label = missing `name` argument
attr_parsing_multiple_modifiers =
multiple `{$modifier}` modifiers in a single `modifiers` argument
attr_parsing_multiple_renamings =
multiple renamings were specified for library `{$lib_name}`
attr_parsing_raw_dylib_no_nul =
link name must not contain NUL characters if link kind is `raw-dylib`
attr_parsing_raw_dylib_elf_unstable =
link kind `raw-dylib` is unstable on ELF platforms
attr_parsing_raw_dylib_only_windows =
link kind `raw-dylib` is only supported on Windows targets
attr_parsing_whole_archive_needs_static =
linking modifier `whole-archive` is only compatible with `static` linking kind

View file

@ -36,7 +36,7 @@ pub fn parse_cfg_attr<'c, S: Stage>(
parse_cfg_entry(cx, single)
}
fn parse_cfg_entry<S: Stage>(
pub(crate) fn parse_cfg_entry<S: Stage>(
cx: &mut AcceptContext<'_, '_, S>,
item: &MetaItemOrLitParser<'_>,
) -> Option<CfgEntry> {

View file

@ -1,9 +1,21 @@
use rustc_feature::Features;
use rustc_hir::attrs::AttributeKind::{LinkName, LinkOrdinal, LinkSection};
use rustc_hir::attrs::Linkage;
use rustc_hir::attrs::*;
use rustc_session::Session;
use rustc_session::parse::feature_err;
use rustc_span::kw;
use rustc_target::spec::BinaryFormat;
use super::prelude::*;
use super::util::parse_single_integer;
use crate::session_diagnostics::{LinkOrdinalOutOfRange, NullOnLinkSection};
use crate::attributes::cfg::parse_cfg_entry;
use crate::fluent_generated;
use crate::session_diagnostics::{
AsNeededCompatibility, BundleNeedsStatic, EmptyLinkName, ImportNameTypeRaw, ImportNameTypeX86,
IncompatibleWasmLink, InvalidLinkModifier, LinkFrameworkApple, LinkOrdinalOutOfRange,
LinkRequiresName, MultipleModifiers, NullOnLinkSection, RawDylibNoNul, RawDylibOnlyWindows,
WholeArchiveNeedsStatic,
};
pub(crate) struct LinkNameParser;
@ -34,6 +46,409 @@ impl<S: Stage> SingleAttributeParser<S> for LinkNameParser {
}
}
pub(crate) struct LinkParser;
impl<S: Stage> CombineAttributeParser<S> for LinkParser {
type Item = LinkEntry;
const PATH: &[Symbol] = &[sym::link];
const CONVERT: ConvertFn<Self::Item> = AttributeKind::Link;
const TEMPLATE: AttributeTemplate = template!(List: &[
r#"name = "...""#,
r#"name = "...", kind = "dylib|static|...""#,
r#"name = "...", wasm_import_module = "...""#,
r#"name = "...", import_name_type = "decorated|noprefix|undecorated""#,
r#"name = "...", kind = "dylib|static|...", wasm_import_module = "...", import_name_type = "decorated|noprefix|undecorated""#,
], "https://doc.rust-lang.org/reference/items/external-blocks.html#the-link-attribute");
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(ALL_TARGETS); //FIXME Still checked fully in `check_attr.rs`
fn extend<'c>(
cx: &'c mut AcceptContext<'_, '_, S>,
args: &'c ArgParser<'_>,
) -> impl IntoIterator<Item = Self::Item> + 'c {
let mut result = None;
let Some(items) = args.list() else {
cx.expected_list(cx.attr_span);
return result;
};
let sess = cx.sess();
let features = cx.features();
let mut name = None;
let mut kind = None;
let mut modifiers = None;
let mut cfg = None;
let mut wasm_import_module = None;
let mut import_name_type = None;
for item in items.mixed() {
let Some(item) = item.meta_item() else {
cx.unexpected_literal(item.span());
continue;
};
let cont = match item.path().word().map(|ident| ident.name) {
Some(sym::name) => Self::parse_link_name(item, &mut name, cx),
Some(sym::kind) => Self::parse_link_kind(item, &mut kind, cx, sess, features),
Some(sym::modifiers) => Self::parse_link_modifiers(item, &mut modifiers, cx),
Some(sym::cfg) => Self::parse_link_cfg(item, &mut cfg, cx, sess, features),
Some(sym::wasm_import_module) => {
Self::parse_link_wasm_import_module(item, &mut wasm_import_module, cx)
}
Some(sym::import_name_type) => {
Self::parse_link_import_name_type(item, &mut import_name_type, cx)
}
_ => {
cx.expected_specific_argument_strings(
item.span(),
&[
sym::name,
sym::kind,
sym::modifiers,
sym::cfg,
sym::wasm_import_module,
sym::import_name_type,
],
);
true
}
};
if !cont {
return result;
}
}
// Do this outside the above loop so we don't depend on modifiers coming after kinds
let mut verbatim = None;
if let Some((modifiers, span)) = modifiers {
for modifier in modifiers.as_str().split(',') {
let (modifier, value): (Symbol, bool) = match modifier.strip_prefix(&['+', '-']) {
Some(m) => (Symbol::intern(m), modifier.starts_with('+')),
None => {
cx.emit_err(InvalidLinkModifier { span });
continue;
}
};
macro report_unstable_modifier($feature: ident) {
if !features.$feature() {
// FIXME: make this translatable
#[expect(rustc::untranslatable_diagnostic)]
feature_err(
sess,
sym::$feature,
span,
format!("linking modifier `{modifier}` is unstable"),
)
.emit();
}
}
let assign_modifier = |dst: &mut Option<bool>| {
if dst.is_some() {
cx.emit_err(MultipleModifiers { span, modifier });
} else {
*dst = Some(value);
}
};
match (modifier, &mut kind) {
(sym::bundle, Some(NativeLibKind::Static { bundle, .. })) => {
assign_modifier(bundle)
}
(sym::bundle, _) => {
cx.emit_err(BundleNeedsStatic { span });
}
(sym::verbatim, _) => assign_modifier(&mut verbatim),
(
sym::whole_dash_archive,
Some(NativeLibKind::Static { whole_archive, .. }),
) => assign_modifier(whole_archive),
(sym::whole_dash_archive, _) => {
cx.emit_err(WholeArchiveNeedsStatic { span });
}
(sym::as_dash_needed, Some(NativeLibKind::Dylib { as_needed }))
| (sym::as_dash_needed, Some(NativeLibKind::Framework { as_needed })) => {
report_unstable_modifier!(native_link_modifiers_as_needed);
assign_modifier(as_needed)
}
(sym::as_dash_needed, _) => {
cx.emit_err(AsNeededCompatibility { span });
}
_ => {
cx.expected_specific_argument_strings(
span,
&[
sym::bundle,
sym::verbatim,
sym::whole_dash_archive,
sym::as_dash_needed,
],
);
}
}
}
}
if let Some((_, span)) = wasm_import_module {
if name.is_some() || kind.is_some() || modifiers.is_some() || cfg.is_some() {
cx.emit_err(IncompatibleWasmLink { span });
}
}
if wasm_import_module.is_some() {
(name, kind) = (wasm_import_module, Some(NativeLibKind::WasmImportModule));
}
let Some((name, name_span)) = name else {
cx.emit_err(LinkRequiresName { span: cx.attr_span });
return result;
};
// Do this outside of the loop so that `import_name_type` can be specified before `kind`.
if let Some((_, span)) = import_name_type {
if kind != Some(NativeLibKind::RawDylib) {
cx.emit_err(ImportNameTypeRaw { span });
}
}
if let Some(NativeLibKind::RawDylib) = kind
&& name.as_str().contains('\0')
{
cx.emit_err(RawDylibNoNul { span: name_span });
}
result = Some(LinkEntry {
span: cx.attr_span,
kind: kind.unwrap_or(NativeLibKind::Unspecified),
name,
cfg,
verbatim,
import_name_type,
});
result
}
}
impl LinkParser {
fn parse_link_name<S: Stage>(
item: &MetaItemParser<'_>,
name: &mut Option<(Symbol, Span)>,
cx: &mut AcceptContext<'_, '_, S>,
) -> bool {
if name.is_some() {
cx.duplicate_key(item.span(), sym::name);
return true;
}
let Some(nv) = item.args().name_value() else {
cx.expected_name_value(item.span(), Some(sym::name));
return false;
};
let Some(link_name) = nv.value_as_str() else {
cx.expected_name_value(item.span(), Some(sym::name));
return false;
};
if link_name.is_empty() {
cx.emit_err(EmptyLinkName { span: nv.value_span });
}
*name = Some((link_name, nv.value_span));
true
}
fn parse_link_kind<S: Stage>(
item: &MetaItemParser<'_>,
kind: &mut Option<NativeLibKind>,
cx: &mut AcceptContext<'_, '_, S>,
sess: &Session,
features: &Features,
) -> bool {
if kind.is_some() {
cx.duplicate_key(item.span(), sym::kind);
return true;
}
let Some(nv) = item.args().name_value() else {
cx.expected_name_value(item.span(), Some(sym::kind));
return true;
};
let Some(link_kind) = nv.value_as_str() else {
cx.expected_name_value(item.span(), Some(sym::kind));
return true;
};
let link_kind = match link_kind {
kw::Static => NativeLibKind::Static { bundle: None, whole_archive: None },
sym::dylib => NativeLibKind::Dylib { as_needed: None },
sym::framework => {
if !sess.target.is_like_darwin {
cx.emit_err(LinkFrameworkApple { span: nv.value_span });
}
NativeLibKind::Framework { as_needed: None }
}
sym::raw_dash_dylib => {
if sess.target.is_like_windows {
// raw-dylib is stable and working on Windows
} else if sess.target.binary_format == BinaryFormat::Elf && features.raw_dylib_elf()
{
// raw-dylib is unstable on ELF, but the user opted in
} else if sess.target.binary_format == BinaryFormat::Elf && sess.is_nightly_build()
{
feature_err(
sess,
sym::raw_dylib_elf,
nv.value_span,
fluent_generated::attr_parsing_raw_dylib_elf_unstable,
)
.emit();
} else {
cx.emit_err(RawDylibOnlyWindows { span: nv.value_span });
}
NativeLibKind::RawDylib
}
sym::link_dash_arg => {
if !features.link_arg_attribute() {
feature_err(
sess,
sym::link_arg_attribute,
nv.value_span,
fluent_generated::attr_parsing_link_arg_unstable,
)
.emit();
}
NativeLibKind::LinkArg
}
_kind => {
cx.expected_specific_argument_strings(
nv.value_span,
&[
kw::Static,
sym::dylib,
sym::framework,
sym::raw_dash_dylib,
sym::link_dash_arg,
],
);
return true;
}
};
*kind = Some(link_kind);
true
}
fn parse_link_modifiers<S: Stage>(
item: &MetaItemParser<'_>,
modifiers: &mut Option<(Symbol, Span)>,
cx: &mut AcceptContext<'_, '_, S>,
) -> bool {
if modifiers.is_some() {
cx.duplicate_key(item.span(), sym::modifiers);
return true;
}
let Some(nv) = item.args().name_value() else {
cx.expected_name_value(item.span(), Some(sym::modifiers));
return true;
};
let Some(link_modifiers) = nv.value_as_str() else {
cx.expected_name_value(item.span(), Some(sym::modifiers));
return true;
};
*modifiers = Some((link_modifiers, nv.value_span));
true
}
fn parse_link_cfg<S: Stage>(
item: &MetaItemParser<'_>,
cfg: &mut Option<CfgEntry>,
cx: &mut AcceptContext<'_, '_, S>,
sess: &Session,
features: &Features,
) -> bool {
if cfg.is_some() {
cx.duplicate_key(item.span(), sym::cfg);
return true;
}
let Some(link_cfg) = item.args().list() else {
cx.expected_list(item.span());
return true;
};
let Some(link_cfg) = link_cfg.single() else {
cx.expected_single_argument(item.span());
return true;
};
if !features.link_cfg() {
feature_err(
sess,
sym::link_cfg,
item.span(),
fluent_generated::attr_parsing_link_cfg_unstable,
)
.emit();
}
*cfg = parse_cfg_entry(cx, link_cfg);
true
}
fn parse_link_wasm_import_module<S: Stage>(
item: &MetaItemParser<'_>,
wasm_import_module: &mut Option<(Symbol, Span)>,
cx: &mut AcceptContext<'_, '_, S>,
) -> bool {
if wasm_import_module.is_some() {
cx.duplicate_key(item.span(), sym::wasm_import_module);
return true;
}
let Some(nv) = item.args().name_value() else {
cx.expected_name_value(item.span(), Some(sym::wasm_import_module));
return true;
};
let Some(link_wasm_import_module) = nv.value_as_str() else {
cx.expected_name_value(item.span(), Some(sym::wasm_import_module));
return true;
};
*wasm_import_module = Some((link_wasm_import_module, item.span()));
true
}
fn parse_link_import_name_type<S: Stage>(
item: &MetaItemParser<'_>,
import_name_type: &mut Option<(PeImportNameType, Span)>,
cx: &mut AcceptContext<'_, '_, S>,
) -> bool {
if import_name_type.is_some() {
cx.duplicate_key(item.span(), sym::import_name_type);
return true;
}
let Some(nv) = item.args().name_value() else {
cx.expected_name_value(item.span(), Some(sym::import_name_type));
return true;
};
let Some(link_import_name_type) = nv.value_as_str() else {
cx.expected_name_value(item.span(), Some(sym::import_name_type));
return true;
};
if cx.sess().target.arch != "x86" {
cx.emit_err(ImportNameTypeX86 { span: item.span() });
return true;
}
let link_import_name_type = match link_import_name_type {
sym::decorated => PeImportNameType::Decorated,
sym::noprefix => PeImportNameType::NoPrefix,
sym::undecorated => PeImportNameType::Undecorated,
_ => {
cx.expected_specific_argument_strings(
item.span(),
&[sym::decorated, sym::noprefix, sym::undecorated],
);
return true;
}
};
*import_name_type = Some((link_import_name_type, item.span()));
true
}
}
pub(crate) struct LinkSectionParser;
impl<S: Stage> SingleAttributeParser<S> for LinkSectionParser {

View file

@ -30,7 +30,7 @@ use crate::attributes::dummy::DummyParser;
use crate::attributes::inline::{InlineParser, RustcForceInlineParser};
use crate::attributes::link_attrs::{
ExportStableParser, FfiConstParser, FfiPureParser, LinkNameParser, LinkOrdinalParser,
LinkSectionParser, LinkageParser, StdInternalSymbolParser,
LinkParser, LinkSectionParser, LinkageParser, StdInternalSymbolParser,
};
use crate::attributes::lint_helpers::{
AsPtrParser, AutomaticallyDerivedParser, PassByValueParser, PubTransparentParser,
@ -162,6 +162,7 @@ attribute_parsers!(
Combine<AllowConstFnUnstableParser>,
Combine<AllowInternalUnstableParser>,
Combine<ForceTargetFeatureParser>,
Combine<LinkParser>,
Combine<ReprParser>,
Combine<TargetFeatureParser>,
Combine<UnstableFeatureBoundParser>,

View file

@ -836,3 +836,97 @@ pub(crate) struct InvalidAttrStyle {
pub target_span: Option<Span>,
pub target: Target,
}
#[derive(Diagnostic)]
#[diag(attr_parsing_empty_link_name, code = E0454)]
pub(crate) struct EmptyLinkName {
#[primary_span]
#[label]
pub span: Span,
}
#[derive(Diagnostic)]
#[diag(attr_parsing_link_framework_apple, code = E0455)]
pub(crate) struct LinkFrameworkApple {
#[primary_span]
pub span: Span,
}
#[derive(Diagnostic)]
#[diag(attr_parsing_incompatible_wasm_link)]
pub(crate) struct IncompatibleWasmLink {
#[primary_span]
pub span: Span,
}
#[derive(Diagnostic)]
#[diag(attr_parsing_link_requires_name, code = E0459)]
pub(crate) struct LinkRequiresName {
#[primary_span]
#[label]
pub span: Span,
}
#[derive(Diagnostic)]
#[diag(attr_parsing_raw_dylib_no_nul)]
pub(crate) struct RawDylibNoNul {
#[primary_span]
pub span: Span,
}
#[derive(Diagnostic)]
#[diag(attr_parsing_raw_dylib_only_windows, code = E0455)]
pub(crate) struct RawDylibOnlyWindows {
#[primary_span]
pub span: Span,
}
#[derive(Diagnostic)]
#[diag(attr_parsing_invalid_link_modifier)]
pub(crate) struct InvalidLinkModifier {
#[primary_span]
pub span: Span,
}
#[derive(Diagnostic)]
#[diag(attr_parsing_multiple_modifiers)]
pub(crate) struct MultipleModifiers {
#[primary_span]
pub span: Span,
pub modifier: Symbol,
}
#[derive(Diagnostic)]
#[diag(attr_parsing_import_name_type_x86)]
pub(crate) struct ImportNameTypeX86 {
#[primary_span]
pub span: Span,
}
#[derive(Diagnostic)]
#[diag(attr_parsing_bundle_needs_static)]
pub(crate) struct BundleNeedsStatic {
#[primary_span]
pub span: Span,
}
#[derive(Diagnostic)]
#[diag(attr_parsing_whole_archive_needs_static)]
pub(crate) struct WholeArchiveNeedsStatic {
#[primary_span]
pub span: Span,
}
#[derive(Diagnostic)]
#[diag(attr_parsing_as_needed_compatibility)]
pub(crate) struct AsNeededCompatibility {
#[primary_span]
pub span: Span,
}
#[derive(Diagnostic)]
#[diag(attr_parsing_import_name_type_raw)]
pub(crate) struct ImportNameTypeRaw {
#[primary_span]
pub span: Span,
}

View file

@ -14,11 +14,13 @@ use itertools::Itertools;
use regex::Regex;
use rustc_arena::TypedArena;
use rustc_ast::CRATE_NODE_ID;
use rustc_attr_parsing::{ShouldEmit, eval_config_entry};
use rustc_data_structures::fx::FxIndexSet;
use rustc_data_structures::memmap::Mmap;
use rustc_data_structures::temp_dir::MaybeTempDir;
use rustc_errors::{DiagCtxtHandle, LintDiagnostic};
use rustc_fs_util::{TempDirBuilder, fix_windows_verbatim_for_gcc, try_canonicalize};
use rustc_hir::attrs::NativeLibKind;
use rustc_hir::def_id::{CrateNum, LOCAL_CRATE};
use rustc_macros::LintDiagnostic;
use rustc_metadata::fs::{METADATA_FILENAME, copy_to_stdout, emit_wrapper_file};
@ -38,7 +40,6 @@ use rustc_session::config::{
use rustc_session::lint::builtin::LINKER_MESSAGES;
use rustc_session::output::{check_file_is_writeable, invalid_output_for_target, out_filename};
use rustc_session::search_paths::PathKind;
use rustc_session::utils::NativeLibKind;
/// For all the linkers we support, and information they might
/// need out of the shared crate context before we get rid of it.
use rustc_session::{Session, filesearch};
@ -3019,7 +3020,9 @@ fn add_dynamic_crate(cmd: &mut dyn Linker, sess: &Session, cratepath: &Path) {
fn relevant_lib(sess: &Session, lib: &NativeLib) -> bool {
match lib.cfg {
Some(ref cfg) => rustc_attr_parsing::cfg_matches(cfg, sess, CRATE_NODE_ID, None),
Some(ref cfg) => {
eval_config_entry(sess, cfg, CRATE_NODE_ID, None, ShouldEmit::ErrorsAndLints).as_bool()
}
None => true,
}
}

View file

@ -25,10 +25,10 @@ use std::io;
use std::path::{Path, PathBuf};
use std::sync::Arc;
use rustc_ast as ast;
use rustc_data_structures::fx::{FxHashSet, FxIndexMap};
use rustc_data_structures::unord::UnordMap;
use rustc_hir::CRATE_HIR_ID;
use rustc_hir::attrs::{CfgEntry, NativeLibKind};
use rustc_hir::def_id::CrateNum;
use rustc_macros::{Decodable, Encodable, HashStable};
use rustc_metadata::EncodedMetadata;
@ -45,7 +45,6 @@ use rustc_session::Session;
use rustc_session::config::{CrateType, OutputFilenames, OutputType, RUST_CGU_EXT};
use rustc_session::cstore::{self, CrateSource};
use rustc_session::lint::builtin::LINKER_MESSAGES;
use rustc_session::utils::NativeLibKind;
use rustc_span::Symbol;
pub mod assert_module_sources;
@ -187,7 +186,7 @@ pub struct NativeLib {
pub kind: NativeLibKind,
pub name: Symbol,
pub filename: Option<Symbol>,
pub cfg: Option<ast::MetaItemInner>,
pub cfg: Option<CfgEntry>,
pub verbatim: bool,
pub dll_imports: Vec<cstore::DllImport>,
}

View file

@ -351,6 +351,17 @@ impl NativeLibKind {
)
}
}
#[derive(Debug, Encodable, Decodable, Clone, HashStable_Generic, PrintAttribute)]
pub struct LinkEntry {
pub span: Span,
pub kind: NativeLibKind,
pub name: Symbol,
pub cfg: Option<CfgEntry>,
pub verbatim: Option<bool>,
pub import_name_type: Option<(PeImportNameType, Span)>,
}
/// Represents parsed *built-in* inert attributes.
///
/// ## Overview
@ -521,6 +532,9 @@ pub enum AttributeKind {
/// Represents `#[inline]` and `#[rustc_force_inline]`.
Inline(InlineAttr, Span),
/// Represents `#[link]`.
Link(ThinVec<LinkEntry>, Span),
/// Represents `#[link_name]`.
LinkName { name: Symbol, span: Span },

View file

@ -50,6 +50,7 @@ impl AttributeKind {
Fundamental { .. } => Yes,
Ignore { .. } => No,
Inline(..) => No,
Link(..) => No,
LinkName { .. } => Yes, // Needed for rustdoc
LinkOrdinal { .. } => No,
LinkSection { .. } => Yes, // Needed for rustdoc

View file

@ -1,6 +1,3 @@
metadata_as_needed_compatibility =
linking modifier `as-needed` is only compatible with `dylib` and `framework` linking kinds
metadata_async_drop_types_in_dependency =
found async drop types in dependency `{$extern_crate}`, but async_drop feature is disabled for `{$local_crate}`
.help = if async drop type will be dropped in a crate without `feature(async_drop)`, sync Drop will be used
@ -11,9 +8,6 @@ metadata_bad_panic_strategy =
metadata_binary_output_to_tty =
option `-o` or `--emit` is used to write binary output type `metadata` to stdout, but stdout is a tty
metadata_bundle_needs_static =
linking modifier `bundle` is only compatible with `static` linking kind
metadata_cannot_find_crate =
can't find crate for `{$crate_name}`{$add_info}
@ -60,10 +54,6 @@ metadata_crate_not_panic_runtime =
metadata_dl_error =
{$path}{$err}
metadata_empty_link_name =
link name must not be empty
.label = empty link name
metadata_empty_renaming_target =
an empty renaming target was specified for library `{$lib_name}`
@ -108,15 +98,6 @@ metadata_full_metadata_not_found =
metadata_global_alloc_required =
no global memory allocator found but one is required; link to std or add `#[global_allocator]` to a static item that implements the GlobalAlloc trait
metadata_import_name_type_form =
import name type must be of the form `import_name_type = "string"`
metadata_import_name_type_raw =
import name type can only be used with link kind `raw-dylib`
metadata_import_name_type_x86 =
import name type is only supported on x86
metadata_incompatible_panic_in_drop_strategy =
the crate `{$crate_name}` is compiled with the panic-in-drop strategy `{$found_strategy}` which is incompatible with this crate's strategy of `{$desired_strategy}`
@ -143,15 +124,10 @@ metadata_incompatible_target_modifiers_r_missed =
mixing `{$flag_name_prefixed}` will cause an ABI mismatch in crate `{$local_crate}`
.note = `{$flag_name_prefixed}={$local_value}` in this crate is incompatible with unset `{$flag_name_prefixed}` in dependency `{$extern_crate}`
.help = the `{$flag_name_prefixed}` flag modifies the ABI so Rust crates compiled with different values of this flag cannot be used together safely
metadata_incompatible_wasm_link =
`wasm_import_module` is incompatible with other arguments in `#[link]` attributes
metadata_install_missing_components =
maybe you need to install the missing components with: `rustup component add rust-src rustc-dev llvm-tools-preview`
metadata_invalid_link_modifier =
invalid linking modifier syntax, expected '+' or '-' prefix before one of: bundle, verbatim, whole-archive, as-needed
metadata_invalid_meta_files =
found invalid metadata files for crate `{$crate_name}`{$add_info}
@ -164,67 +140,18 @@ metadata_lib_framework_apple =
metadata_lib_required =
crate `{$crate_name}` required to be available in {$kind} format, but was not found in this form
metadata_link_arg_unstable =
link kind `link-arg` is unstable
metadata_link_cfg_form =
link cfg must be of the form `cfg(/* predicate */)`
metadata_link_cfg_single_predicate =
link cfg must have a single predicate argument
metadata_link_cfg_unstable =
link cfg is unstable
metadata_link_framework_apple =
link kind `framework` is only supported on Apple targets
metadata_link_kind_form =
link kind must be of the form `kind = "string"`
metadata_link_modifiers_form =
link modifiers must be of the form `modifiers = "string"`
metadata_link_name_form =
link name must be of the form `name = "string"`
metadata_link_ordinal_raw_dylib =
`#[link_ordinal]` is only supported if link kind is `raw-dylib`
metadata_link_requires_name =
`#[link]` attribute requires a `name = "string"` argument
.label = missing `name` argument
metadata_missing_native_library =
could not find native static library `{$libname}`, perhaps an -L flag is missing?
metadata_multiple_candidates =
multiple candidates for `{$flavor}` dependency `{$crate_name}` found
metadata_multiple_cfgs =
multiple `cfg` arguments in a single `#[link]` attribute
metadata_multiple_import_name_type =
multiple `import_name_type` arguments in a single `#[link]` attribute
metadata_multiple_kinds_in_link =
multiple `kind` arguments in a single `#[link]` attribute
metadata_multiple_link_modifiers =
multiple `modifiers` arguments in a single `#[link]` attribute
metadata_multiple_modifiers =
multiple `{$modifier}` modifiers in a single `modifiers` argument
metadata_multiple_names_in_link =
multiple `name` arguments in a single `#[link]` attribute
metadata_multiple_renamings =
multiple renamings were specified for library `{$lib_name}`
metadata_multiple_wasm_import =
multiple `wasm_import_module` arguments in a single `#[link]` attribute
metadata_newer_crate_version =
found possibly newer version of crate `{$crate_name}`{$add_info}
.note = perhaps that crate needs to be recompiled?
@ -263,15 +190,6 @@ metadata_prev_alloc_error_handler =
metadata_prev_global_alloc =
previous global allocator defined here
metadata_raw_dylib_elf_unstable =
link kind `raw-dylib` is unstable on ELF platforms
metadata_raw_dylib_no_nul =
link name must not contain NUL characters if link kind is `raw-dylib`
metadata_raw_dylib_only_windows =
link kind `raw-dylib` is only supported on Windows targets
metadata_raw_dylib_unsupported_abi =
ABI not supported by `#[link(kind = "raw-dylib")]` on this architecture
@ -307,19 +225,6 @@ metadata_target_not_installed =
metadata_two_panic_runtimes =
cannot link together two panic runtimes: {$prev_name} and {$cur_name}
metadata_unexpected_link_arg =
unexpected `#[link]` argument, expected one of: name, kind, modifiers, cfg, wasm_import_module, import_name_type
metadata_unknown_import_name_type =
unknown import name type `{$import_name_type}`, expected one of: decorated, noprefix, undecorated
metadata_unknown_link_kind =
unknown link kind `{$kind}`, expected one of: static, dylib, framework, raw-dylib, link-arg
.label = unknown link kind
metadata_unknown_link_modifier =
unknown linking modifier `{$modifier}`, expected one of: bundle, verbatim, whole-archive, as-needed
metadata_unknown_target_modifier_unsafe_allowed = unknown target modifier `{$flag_name}`, requested by `-Cunsafe-allow-abi-mismatch={$flag_name}`
metadata_wasm_c_abi =

View file

@ -83,187 +83,6 @@ pub struct IncompatiblePanicInDropStrategy {
pub desired_strategy: PanicStrategy,
}
#[derive(Diagnostic)]
#[diag(metadata_multiple_names_in_link)]
pub struct MultipleNamesInLink {
#[primary_span]
pub span: Span,
}
#[derive(Diagnostic)]
#[diag(metadata_multiple_kinds_in_link)]
pub struct MultipleKindsInLink {
#[primary_span]
pub span: Span,
}
#[derive(Diagnostic)]
#[diag(metadata_link_name_form)]
pub struct LinkNameForm {
#[primary_span]
pub span: Span,
}
#[derive(Diagnostic)]
#[diag(metadata_link_kind_form)]
pub struct LinkKindForm {
#[primary_span]
pub span: Span,
}
#[derive(Diagnostic)]
#[diag(metadata_link_modifiers_form)]
pub struct LinkModifiersForm {
#[primary_span]
pub span: Span,
}
#[derive(Diagnostic)]
#[diag(metadata_link_cfg_form)]
pub struct LinkCfgForm {
#[primary_span]
pub span: Span,
}
#[derive(Diagnostic)]
#[diag(metadata_wasm_import_form)]
pub struct WasmImportForm {
#[primary_span]
pub span: Span,
}
#[derive(Diagnostic)]
#[diag(metadata_empty_link_name, code = E0454)]
pub struct EmptyLinkName {
#[primary_span]
#[label]
pub span: Span,
}
#[derive(Diagnostic)]
#[diag(metadata_link_framework_apple, code = E0455)]
pub struct LinkFrameworkApple {
#[primary_span]
pub span: Span,
}
#[derive(Diagnostic)]
#[diag(metadata_raw_dylib_only_windows, code = E0455)]
pub struct RawDylibOnlyWindows {
#[primary_span]
pub span: Span,
}
#[derive(Diagnostic)]
#[diag(metadata_unknown_link_kind, code = E0458)]
pub struct UnknownLinkKind<'a> {
#[primary_span]
#[label]
pub span: Span,
pub kind: &'a str,
}
#[derive(Diagnostic)]
#[diag(metadata_multiple_link_modifiers)]
pub struct MultipleLinkModifiers {
#[primary_span]
pub span: Span,
}
#[derive(Diagnostic)]
#[diag(metadata_multiple_cfgs)]
pub struct MultipleCfgs {
#[primary_span]
pub span: Span,
}
#[derive(Diagnostic)]
#[diag(metadata_link_cfg_single_predicate)]
pub struct LinkCfgSinglePredicate {
#[primary_span]
pub span: Span,
}
#[derive(Diagnostic)]
#[diag(metadata_multiple_wasm_import)]
pub struct MultipleWasmImport {
#[primary_span]
pub span: Span,
}
#[derive(Diagnostic)]
#[diag(metadata_unexpected_link_arg)]
pub struct UnexpectedLinkArg {
#[primary_span]
pub span: Span,
}
#[derive(Diagnostic)]
#[diag(metadata_invalid_link_modifier)]
pub struct InvalidLinkModifier {
#[primary_span]
pub span: Span,
}
#[derive(Diagnostic)]
#[diag(metadata_multiple_modifiers)]
pub struct MultipleModifiers<'a> {
#[primary_span]
pub span: Span,
pub modifier: &'a str,
}
#[derive(Diagnostic)]
#[diag(metadata_bundle_needs_static)]
pub struct BundleNeedsStatic {
#[primary_span]
pub span: Span,
}
#[derive(Diagnostic)]
#[diag(metadata_whole_archive_needs_static)]
pub struct WholeArchiveNeedsStatic {
#[primary_span]
pub span: Span,
}
#[derive(Diagnostic)]
#[diag(metadata_as_needed_compatibility)]
pub struct AsNeededCompatibility {
#[primary_span]
pub span: Span,
}
#[derive(Diagnostic)]
#[diag(metadata_unknown_link_modifier)]
pub struct UnknownLinkModifier<'a> {
#[primary_span]
pub span: Span,
pub modifier: &'a str,
}
#[derive(Diagnostic)]
#[diag(metadata_incompatible_wasm_link)]
pub struct IncompatibleWasmLink {
#[primary_span]
pub span: Span,
}
#[derive(Diagnostic)]
#[diag(metadata_link_requires_name, code = E0459)]
pub struct LinkRequiresName {
#[primary_span]
#[label]
pub span: Span,
}
#[derive(Diagnostic)]
#[diag(metadata_raw_dylib_no_nul)]
pub struct RawDylibNoNul {
#[primary_span]
pub span: Span,
}
#[derive(Diagnostic)]
#[diag(metadata_link_ordinal_raw_dylib)]
pub struct LinkOrdinalRawDylib {
@ -706,42 +525,6 @@ pub struct LibFilenameForm<'a> {
pub dll_suffix: &'a str,
}
#[derive(Diagnostic)]
#[diag(metadata_multiple_import_name_type)]
pub struct MultipleImportNameType {
#[primary_span]
pub span: Span,
}
#[derive(Diagnostic)]
#[diag(metadata_import_name_type_form)]
pub struct ImportNameTypeForm {
#[primary_span]
pub span: Span,
}
#[derive(Diagnostic)]
#[diag(metadata_import_name_type_x86)]
pub struct ImportNameTypeX86 {
#[primary_span]
pub span: Span,
}
#[derive(Diagnostic)]
#[diag(metadata_unknown_import_name_type)]
pub struct UnknownImportNameType<'a> {
#[primary_span]
pub span: Span,
pub import_name_type: &'a str,
}
#[derive(Diagnostic)]
#[diag(metadata_import_name_type_raw)]
pub struct ImportNameTypeRaw {
#[primary_span]
pub span: Span,
}
#[derive(Diagnostic)]
#[diag(metadata_wasm_c_abi)]
pub(crate) struct WasmCAbi {

View file

@ -3,25 +3,21 @@ use std::path::{Path, PathBuf};
use rustc_abi::ExternAbi;
use rustc_ast::CRATE_NODE_ID;
use rustc_attr_parsing as attr;
use rustc_attr_parsing::{ShouldEmit, eval_config_entry};
use rustc_data_structures::fx::FxHashSet;
use rustc_hir::attrs::AttributeKind;
use rustc_hir::attrs::{AttributeKind, NativeLibKind, PeImportNameType};
use rustc_hir::find_attr;
use rustc_middle::query::LocalCrate;
use rustc_middle::ty::{self, List, Ty, TyCtxt};
use rustc_session::Session;
use rustc_session::config::CrateType;
use rustc_session::cstore::{
DllCallingConvention, DllImport, ForeignModule, NativeLib, PeImportNameType,
};
use rustc_session::parse::feature_err;
use rustc_session::cstore::{DllCallingConvention, DllImport, ForeignModule, NativeLib};
use rustc_session::search_paths::PathKind;
use rustc_session::utils::NativeLibKind;
use rustc_span::Symbol;
use rustc_span::def_id::{DefId, LOCAL_CRATE};
use rustc_span::{Symbol, sym};
use rustc_target::spec::{BinaryFormat, LinkSelfContainedComponents};
use crate::{errors, fluent_generated};
use crate::errors;
/// The fallback directories are passed to linker, but not used when rustc does the search,
/// because in the latter case the set of fallback directories cannot always be determined
@ -192,7 +188,9 @@ pub(crate) fn collect(tcx: TyCtxt<'_>, LocalCrate: LocalCrate) -> Vec<NativeLib>
pub(crate) fn relevant_lib(sess: &Session, lib: &NativeLib) -> bool {
match lib.cfg {
Some(ref cfg) => attr::cfg_matches(cfg, sess, CRATE_NODE_ID, None),
Some(ref cfg) => {
eval_config_entry(sess, cfg, CRATE_NODE_ID, None, ShouldEmit::ErrorsAndLints).as_bool()
}
None => true,
}
}
@ -213,289 +211,23 @@ impl<'tcx> Collector<'tcx> {
return;
}
// Process all of the #[link(..)]-style arguments
let features = self.tcx.features();
for m in self.tcx.get_attrs(def_id, sym::link) {
let Some(items) = m.meta_item_list() else {
continue;
};
let mut name = None;
let mut kind = None;
let mut modifiers = None;
let mut cfg = None;
let mut wasm_import_module = None;
let mut import_name_type = None;
for item in items.iter() {
match item.name() {
Some(sym::name) => {
if name.is_some() {
sess.dcx().emit_err(errors::MultipleNamesInLink { span: item.span() });
continue;
}
let Some(link_name) = item.value_str() else {
sess.dcx().emit_err(errors::LinkNameForm { span: item.span() });
continue;
};
let span = item.name_value_literal_span().unwrap();
if link_name.is_empty() {
sess.dcx().emit_err(errors::EmptyLinkName { span });
}
name = Some((link_name, span));
}
Some(sym::kind) => {
if kind.is_some() {
sess.dcx().emit_err(errors::MultipleKindsInLink { span: item.span() });
continue;
}
let Some(link_kind) = item.value_str() else {
sess.dcx().emit_err(errors::LinkKindForm { span: item.span() });
continue;
};
let span = item.name_value_literal_span().unwrap();
let link_kind = match link_kind.as_str() {
"static" => NativeLibKind::Static { bundle: None, whole_archive: None },
"dylib" => NativeLibKind::Dylib { as_needed: None },
"framework" => {
if !sess.target.is_like_darwin {
sess.dcx().emit_err(errors::LinkFrameworkApple { span });
}
NativeLibKind::Framework { as_needed: None }
}
"raw-dylib" => {
if sess.target.is_like_windows {
// raw-dylib is stable and working on Windows
} else if sess.target.binary_format == BinaryFormat::Elf
&& features.raw_dylib_elf()
{
// raw-dylib is unstable on ELF, but the user opted in
} else if sess.target.binary_format == BinaryFormat::Elf
&& sess.is_nightly_build()
{
feature_err(
sess,
sym::raw_dylib_elf,
span,
fluent_generated::metadata_raw_dylib_elf_unstable,
)
.emit();
} else {
sess.dcx().emit_err(errors::RawDylibOnlyWindows { span });
}
NativeLibKind::RawDylib
}
"link-arg" => {
if !features.link_arg_attribute() {
feature_err(
sess,
sym::link_arg_attribute,
span,
fluent_generated::metadata_link_arg_unstable,
)
.emit();
}
NativeLibKind::LinkArg
}
kind => {
sess.dcx().emit_err(errors::UnknownLinkKind { span, kind });
continue;
}
};
kind = Some(link_kind);
}
Some(sym::modifiers) => {
if modifiers.is_some() {
sess.dcx()
.emit_err(errors::MultipleLinkModifiers { span: item.span() });
continue;
}
let Some(link_modifiers) = item.value_str() else {
sess.dcx().emit_err(errors::LinkModifiersForm { span: item.span() });
continue;
};
modifiers = Some((link_modifiers, item.name_value_literal_span().unwrap()));
}
Some(sym::cfg) => {
if cfg.is_some() {
sess.dcx().emit_err(errors::MultipleCfgs { span: item.span() });
continue;
}
let Some(link_cfg) = item.meta_item_list() else {
sess.dcx().emit_err(errors::LinkCfgForm { span: item.span() });
continue;
};
let [link_cfg] = link_cfg else {
sess.dcx()
.emit_err(errors::LinkCfgSinglePredicate { span: item.span() });
continue;
};
let Some(link_cfg) = link_cfg.meta_item_or_bool() else {
sess.dcx()
.emit_err(errors::LinkCfgSinglePredicate { span: item.span() });
continue;
};
if !features.link_cfg() {
feature_err(
sess,
sym::link_cfg,
item.span(),
fluent_generated::metadata_link_cfg_unstable,
)
.emit();
}
cfg = Some(link_cfg.clone());
}
Some(sym::wasm_import_module) => {
if wasm_import_module.is_some() {
sess.dcx().emit_err(errors::MultipleWasmImport { span: item.span() });
continue;
}
let Some(link_wasm_import_module) = item.value_str() else {
sess.dcx().emit_err(errors::WasmImportForm { span: item.span() });
continue;
};
wasm_import_module = Some((link_wasm_import_module, item.span()));
}
Some(sym::import_name_type) => {
if import_name_type.is_some() {
sess.dcx()
.emit_err(errors::MultipleImportNameType { span: item.span() });
continue;
}
let Some(link_import_name_type) = item.value_str() else {
sess.dcx().emit_err(errors::ImportNameTypeForm { span: item.span() });
continue;
};
if self.tcx.sess.target.arch != "x86" {
sess.dcx().emit_err(errors::ImportNameTypeX86 { span: item.span() });
continue;
}
let link_import_name_type = match link_import_name_type.as_str() {
"decorated" => PeImportNameType::Decorated,
"noprefix" => PeImportNameType::NoPrefix,
"undecorated" => PeImportNameType::Undecorated,
import_name_type => {
sess.dcx().emit_err(errors::UnknownImportNameType {
span: item.span(),
import_name_type,
});
continue;
}
};
import_name_type = Some((link_import_name_type, item.span()));
}
_ => {
sess.dcx().emit_err(errors::UnexpectedLinkArg { span: item.span() });
}
}
}
// Do this outside the above loop so we don't depend on modifiers coming after kinds
let mut verbatim = None;
if let Some((modifiers, span)) = modifiers {
for modifier in modifiers.as_str().split(',') {
let (modifier, value) = match modifier.strip_prefix(&['+', '-']) {
Some(m) => (m, modifier.starts_with('+')),
None => {
sess.dcx().emit_err(errors::InvalidLinkModifier { span });
continue;
}
};
macro report_unstable_modifier($feature: ident) {
if !features.$feature() {
// FIXME: make this translatable
#[expect(rustc::untranslatable_diagnostic)]
feature_err(
sess,
sym::$feature,
span,
format!("linking modifier `{modifier}` is unstable"),
)
.emit();
}
}
let assign_modifier = |dst: &mut Option<bool>| {
if dst.is_some() {
sess.dcx().emit_err(errors::MultipleModifiers { span, modifier });
} else {
*dst = Some(value);
}
};
match (modifier, &mut kind) {
("bundle", Some(NativeLibKind::Static { bundle, .. })) => {
assign_modifier(bundle)
}
("bundle", _) => {
sess.dcx().emit_err(errors::BundleNeedsStatic { span });
}
("verbatim", _) => assign_modifier(&mut verbatim),
("whole-archive", Some(NativeLibKind::Static { whole_archive, .. })) => {
assign_modifier(whole_archive)
}
("whole-archive", _) => {
sess.dcx().emit_err(errors::WholeArchiveNeedsStatic { span });
}
("as-needed", Some(NativeLibKind::Dylib { as_needed }))
| ("as-needed", Some(NativeLibKind::Framework { as_needed })) => {
report_unstable_modifier!(native_link_modifiers_as_needed);
assign_modifier(as_needed)
}
("as-needed", _) => {
sess.dcx().emit_err(errors::AsNeededCompatibility { span });
}
_ => {
sess.dcx().emit_err(errors::UnknownLinkModifier { span, modifier });
}
}
}
}
if let Some((_, span)) = wasm_import_module {
if name.is_some() || kind.is_some() || modifiers.is_some() || cfg.is_some() {
sess.dcx().emit_err(errors::IncompatibleWasmLink { span });
}
}
if wasm_import_module.is_some() {
(name, kind) = (wasm_import_module, Some(NativeLibKind::WasmImportModule));
}
let Some((name, name_span)) = name else {
sess.dcx().emit_err(errors::LinkRequiresName { span: m.span() });
continue;
};
// Do this outside of the loop so that `import_name_type` can be specified before `kind`.
if let Some((_, span)) = import_name_type {
if kind != Some(NativeLibKind::RawDylib) {
sess.dcx().emit_err(errors::ImportNameTypeRaw { span });
}
}
let dll_imports = match kind {
Some(NativeLibKind::RawDylib) => {
if name.as_str().contains('\0') {
sess.dcx().emit_err(errors::RawDylibNoNul { span: name_span });
}
foreign_items
.iter()
.map(|&child_item| {
self.build_dll_import(
abi,
import_name_type.map(|(import_name_type, _)| import_name_type),
child_item,
)
})
.collect()
}
for attr in
find_attr!(self.tcx.get_all_attrs(def_id), AttributeKind::Link(links, _) => links)
.iter()
.map(|v| v.iter())
.flatten()
{
let dll_imports = match attr.kind {
NativeLibKind::RawDylib => foreign_items
.iter()
.map(|&child_item| {
self.build_dll_import(
abi,
attr.import_name_type.map(|(import_name_type, _)| import_name_type),
child_item,
)
})
.collect(),
_ => {
for &child_item in foreign_items {
if let Some(span) = find_attr!(self.tcx.get_all_attrs(child_item), AttributeKind::LinkOrdinal {span, ..} => *span)
@ -508,15 +240,20 @@ impl<'tcx> Collector<'tcx> {
}
};
let kind = kind.unwrap_or(NativeLibKind::Unspecified);
let filename = find_bundled_library(name, verbatim, kind, cfg.is_some(), self.tcx);
let filename = find_bundled_library(
attr.name,
attr.verbatim,
attr.kind,
attr.cfg.is_some(),
self.tcx,
);
self.libs.push(NativeLib {
name,
name: attr.name,
filename,
kind,
cfg,
kind: attr.kind,
cfg: attr.cfg.clone(),
foreign_module: Some(def_id.to_def_id()),
verbatim,
verbatim: attr.verbatim,
dll_imports,
});
}

View file

@ -200,6 +200,9 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
&Attribute::Parsed(AttributeKind::Sanitize { on_set, off_set, span: attr_span}) => {
self.check_sanitize(attr_span, on_set | off_set, span, target);
},
Attribute::Parsed(AttributeKind::Link(_, attr_span)) => {
self.check_link(hir_id, *attr_span, span, target)
}
Attribute::Parsed(
AttributeKind::BodyStability { .. }
| AttributeKind::ConstStabilityIndirect
@ -305,7 +308,6 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
[sym::rustc_has_incoherent_inherent_impls, ..] => {
self.check_has_incoherent_inherent_impls(attr, span, target)
}
[sym::link, ..] => self.check_link(hir_id, attr, span, target),
[sym::macro_export, ..] => self.check_macro_export(hir_id, attr, target),
[sym::autodiff_forward, ..] | [sym::autodiff_reverse, ..] => {
self.check_autodiff(hir_id, attr, span, target)
@ -1324,7 +1326,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
}
/// Checks if `#[link]` is applied to an item other than a foreign module.
fn check_link(&self, hir_id: HirId, attr: &Attribute, span: Span, target: Target) {
fn check_link(&self, hir_id: HirId, attr_span: Span, span: Span, target: Target) {
if target == Target::ForeignMod
&& let hir::Node::Item(item) = self.tcx.hir_node(hir_id)
&& let Item { kind: ItemKind::ForeignMod { abi, .. }, .. } = item
@ -1336,7 +1338,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
self.tcx.emit_node_span_lint(
UNUSED_ATTRIBUTES,
hir_id,
attr.span(),
attr_span,
errors::Link { span: (target != Target::ForeignMod).then_some(span) },
);
}

View file

@ -466,6 +466,7 @@ symbols! {
arm,
arm_target_feature,
array,
as_dash_needed: "as-needed",
as_ptr,
as_ref,
as_str,
@ -592,6 +593,7 @@ symbols! {
btreeset_iter,
built,
builtin_syntax,
bundle,
c,
c_dash_variadic,
c_str,
@ -817,6 +819,7 @@ symbols! {
decl_macro,
declare_lint_pass,
decode,
decorated,
default_alloc_error_handler,
default_field_values,
default_fn,
@ -1075,6 +1078,7 @@ symbols! {
format_macro,
format_placeholder,
format_unsafe_arg,
framework,
freeze,
freeze_impls,
freg,
@ -1295,6 +1299,7 @@ symbols! {
link_arg_attribute,
link_args,
link_cfg,
link_dash_arg: "link-arg",
link_llvm_intrinsics,
link_name,
link_ordinal,
@ -1528,6 +1533,7 @@ symbols! {
noop_method_borrow,
noop_method_clone,
noop_method_deref,
noprefix,
noreturn,
nostack,
not,
@ -1741,6 +1747,7 @@ symbols! {
quote,
range_inclusive_new,
range_step,
raw_dash_dylib: "raw-dylib",
raw_dylib,
raw_dylib_elf,
raw_eq,
@ -2277,6 +2284,7 @@ symbols! {
unchecked_shl,
unchecked_shr,
unchecked_sub,
undecorated,
underscore_const_names,
underscore_imports,
underscore_lifetimes,
@ -2365,6 +2373,7 @@ symbols! {
vecdeque_iter,
vecdeque_reserve,
vector,
verbatim,
version,
vfp2,
vis,
@ -2389,6 +2398,7 @@ symbols! {
weak_odr,
where_clause_attrs,
while_let,
whole_dash_archive: "whole-archive",
width,
windows,
windows_subsystem,