diff options
Diffstat (limited to 'compiler/rustc_attr_parsing/src')
| -rw-r--r-- | compiler/rustc_attr_parsing/src/attributes/cfg.rs | 2 | ||||
| -rw-r--r-- | compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs | 1 | ||||
| -rw-r--r-- | compiler/rustc_attr_parsing/src/attributes/crate_level.rs | 172 | ||||
| -rw-r--r-- | compiler/rustc_attr_parsing/src/attributes/deprecation.rs | 2 | ||||
| -rw-r--r-- | compiler/rustc_attr_parsing/src/attributes/link_attrs.rs | 419 | ||||
| -rw-r--r-- | compiler/rustc_attr_parsing/src/attributes/prelude.rs | 15 | ||||
| -rw-r--r-- | compiler/rustc_attr_parsing/src/attributes/repr.rs | 27 | ||||
| -rw-r--r-- | compiler/rustc_attr_parsing/src/context.rs | 30 | ||||
| -rw-r--r-- | compiler/rustc_attr_parsing/src/interface.rs | 9 | ||||
| -rw-r--r-- | compiler/rustc_attr_parsing/src/lib.rs | 1 | ||||
| -rw-r--r-- | compiler/rustc_attr_parsing/src/parser.rs | 59 | ||||
| -rw-r--r-- | compiler/rustc_attr_parsing/src/session_diagnostics.rs | 104 | ||||
| -rw-r--r-- | compiler/rustc_attr_parsing/src/target_checking.rs | 37 |
13 files changed, 808 insertions, 70 deletions
diff --git a/compiler/rustc_attr_parsing/src/attributes/cfg.rs b/compiler/rustc_attr_parsing/src/attributes/cfg.rs index 695ee666476..70855611079 100644 --- a/compiler/rustc_attr_parsing/src/attributes/cfg.rs +++ b/compiler/rustc_attr_parsing/src/attributes/cfg.rs @@ -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> { diff --git a/compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs b/compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs index ffdacff7152..d5d51f2e79a 100644 --- a/compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs +++ b/compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs @@ -218,6 +218,7 @@ impl<S: Stage> AttributeParser<S> for NakedParser { sym::rustc_std_internal_symbol, // FIXME(#82232, #143834): temporarily renamed to mitigate `#[align]` nameres ambiguity sym::rustc_align, + sym::rustc_align_static, // obviously compatible with self sym::naked, // documentation diff --git a/compiler/rustc_attr_parsing/src/attributes/crate_level.rs b/compiler/rustc_attr_parsing/src/attributes/crate_level.rs index 2fed09b85e8..0b2c05482bf 100644 --- a/compiler/rustc_attr_parsing/src/attributes/crate_level.rs +++ b/compiler/rustc_attr_parsing/src/attributes/crate_level.rs @@ -1,6 +1,40 @@ -use rustc_feature::AttributeType; +use std::num::IntErrorKind; + +use rustc_hir::limit::Limit; use super::prelude::*; +use crate::session_diagnostics::LimitInvalid; + +impl<S: Stage> AcceptContext<'_, '_, S> { + fn parse_limit_int(&self, nv: &NameValueParser) -> Option<Limit> { + let Some(limit) = nv.value_as_str() else { + self.expected_string_literal(nv.value_span, Some(nv.value_as_lit())); + return None; + }; + + let error_str = match limit.as_str().parse() { + Ok(i) => return Some(Limit::new(i)), + Err(e) => match e.kind() { + IntErrorKind::PosOverflow => "`limit` is too large", + IntErrorKind::Empty => "`limit` must be a non-negative integer", + IntErrorKind::InvalidDigit => "not a valid integer", + IntErrorKind::NegOverflow => { + panic!( + "`limit` should never negatively overflow since we're parsing into a usize and we'd get Empty instead" + ) + } + IntErrorKind::Zero => { + panic!("zero is a valid `limit` so should have returned Ok() when parsing") + } + kind => panic!("unimplemented IntErrorKind variant: {:?}", kind), + }, + }; + + self.emit_err(LimitInvalid { span: self.attr_span, value_span: nv.value_span, error_str }); + + None + } +} pub(crate) struct CrateNameParser; @@ -11,8 +45,8 @@ impl<S: Stage> SingleAttributeParser<S> for CrateNameParser { const TEMPLATE: AttributeTemplate = template!(NameValueStr: "name"); const TYPE: AttributeType = AttributeType::CrateLevel; - // FIXME: crate name is allowed on all targets and ignored, - // even though it should only be valid on crates of course + // because it's a crate-level attribute, we already warn about it. + // Putting target limitations here would give duplicate warnings const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(ALL_TARGETS); fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option<AttributeKind> { @@ -34,3 +68,135 @@ impl<S: Stage> SingleAttributeParser<S> for CrateNameParser { }) } } + +pub(crate) struct RecursionLimitParser; + +impl<S: Stage> SingleAttributeParser<S> for RecursionLimitParser { + const PATH: &[Symbol] = &[sym::recursion_limit]; + const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepOutermost; + const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::WarnButFutureError; + const TEMPLATE: AttributeTemplate = template!(NameValueStr: "N", "https://doc.rust-lang.org/reference/attributes/limits.html#the-recursion_limit-attribute"); + const TYPE: AttributeType = AttributeType::CrateLevel; + + // because it's a crate-level attribute, we already warn about it. + // Putting target limitations here would give duplicate warnings + const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(ALL_TARGETS); + + fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option<AttributeKind> { + let ArgParser::NameValue(nv) = args else { + cx.expected_name_value(cx.attr_span, None); + return None; + }; + + Some(AttributeKind::RecursionLimit { + limit: cx.parse_limit_int(nv)?, + attr_span: cx.attr_span, + limit_span: nv.value_span, + }) + } +} + +pub(crate) struct MoveSizeLimitParser; + +impl<S: Stage> SingleAttributeParser<S> for MoveSizeLimitParser { + const PATH: &[Symbol] = &[sym::move_size_limit]; + const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepOutermost; + const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error; + const TEMPLATE: AttributeTemplate = template!(NameValueStr: "N"); + const TYPE: AttributeType = AttributeType::CrateLevel; + + // because it's a crate-level attribute, we already warn about it. + // Putting target limitations here would give duplicate warnings + const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(ALL_TARGETS); + + fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option<AttributeKind> { + let ArgParser::NameValue(nv) = args else { + cx.expected_name_value(cx.attr_span, None); + return None; + }; + + Some(AttributeKind::MoveSizeLimit { + limit: cx.parse_limit_int(nv)?, + attr_span: cx.attr_span, + limit_span: nv.value_span, + }) + } +} + +pub(crate) struct TypeLengthLimitParser; + +impl<S: Stage> SingleAttributeParser<S> for TypeLengthLimitParser { + const PATH: &[Symbol] = &[sym::type_length_limit]; + const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepOutermost; + const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::WarnButFutureError; + const TEMPLATE: AttributeTemplate = template!(NameValueStr: "N"); + const TYPE: AttributeType = AttributeType::CrateLevel; + + // because it's a crate-level attribute, we already warn about it. + // Putting target limitations here would give duplicate warnings + const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(ALL_TARGETS); + + fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option<AttributeKind> { + let ArgParser::NameValue(nv) = args else { + cx.expected_name_value(cx.attr_span, None); + return None; + }; + + Some(AttributeKind::TypeLengthLimit { + limit: cx.parse_limit_int(nv)?, + attr_span: cx.attr_span, + limit_span: nv.value_span, + }) + } +} + +pub(crate) struct PatternComplexityLimitParser; + +impl<S: Stage> SingleAttributeParser<S> for PatternComplexityLimitParser { + const PATH: &[Symbol] = &[sym::pattern_complexity_limit]; + const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepOutermost; + const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error; + const TEMPLATE: AttributeTemplate = template!(NameValueStr: "N"); + const TYPE: AttributeType = AttributeType::CrateLevel; + + // because it's a crate-level attribute, we already warn about it. + // Putting target limitations here would give duplicate warnings + const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(ALL_TARGETS); + + fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option<AttributeKind> { + let ArgParser::NameValue(nv) = args else { + cx.expected_name_value(cx.attr_span, None); + return None; + }; + + Some(AttributeKind::PatternComplexityLimit { + limit: cx.parse_limit_int(nv)?, + attr_span: cx.attr_span, + limit_span: nv.value_span, + }) + } +} + +pub(crate) struct NoCoreParser; + +impl<S: Stage> NoArgsAttributeParser<S> for NoCoreParser { + const PATH: &[Symbol] = &[sym::no_core]; + const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Warn; + // because it's a crate-level attribute, we already warn about it. + // Putting target limitations here would give duplicate warnings + const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(ALL_TARGETS); + const CREATE: fn(Span) -> AttributeKind = AttributeKind::NoCore; + const TYPE: AttributeType = AttributeType::CrateLevel; +} + +pub(crate) struct NoStdParser; + +impl<S: Stage> NoArgsAttributeParser<S> for NoStdParser { + const PATH: &[Symbol] = &[sym::no_std]; + const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Warn; + // because it's a crate-level attribute, we already warn about it. + // Putting target limitations here would give duplicate warnings + const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(ALL_TARGETS); + const CREATE: fn(Span) -> AttributeKind = AttributeKind::NoStd; + const TYPE: AttributeType = AttributeType::CrateLevel; +} diff --git a/compiler/rustc_attr_parsing/src/attributes/deprecation.rs b/compiler/rustc_attr_parsing/src/attributes/deprecation.rs index 31c698228ef..f96477e28cd 100644 --- a/compiler/rustc_attr_parsing/src/attributes/deprecation.rs +++ b/compiler/rustc_attr_parsing/src/attributes/deprecation.rs @@ -58,7 +58,7 @@ impl<S: Stage> SingleAttributeParser<S> for DeprecationParser { Allow(Target::AssocTy), Allow(Target::AssocConst), Allow(Target::Variant), - Allow(Target::Impl { of_trait: false }), //FIXME This does not make sense + Allow(Target::Impl { of_trait: false }), Allow(Target::Crate), Error(Target::WherePredicate), ]); diff --git a/compiler/rustc_attr_parsing/src/attributes/link_attrs.rs b/compiler/rustc_attr_parsing/src/attributes/link_attrs.rs index 5e4551ccd79..d4942e56f42 100644 --- a/compiler/rustc_attr_parsing/src/attributes/link_attrs.rs +++ b/compiler/rustc_attr_parsing/src/attributes/link_attrs.rs @@ -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 { diff --git a/compiler/rustc_attr_parsing/src/attributes/prelude.rs b/compiler/rustc_attr_parsing/src/attributes/prelude.rs index 2bcdee55c75..8f040ffb9d4 100644 --- a/compiler/rustc_attr_parsing/src/attributes/prelude.rs +++ b/compiler/rustc_attr_parsing/src/attributes/prelude.rs @@ -1,20 +1,29 @@ -// parsing -// templates -pub(super) use rustc_feature::{AttributeTemplate, template}; // data structures +#[doc(hidden)] +pub(super) use rustc_feature::{AttributeTemplate, AttributeType, template}; +#[doc(hidden)] pub(super) use rustc_hir::attrs::AttributeKind; +#[doc(hidden)] pub(super) use rustc_hir::lints::AttributeLintKind; +#[doc(hidden)] pub(super) use rustc_hir::{MethodKind, Target}; +#[doc(hidden)] pub(super) use rustc_span::{DUMMY_SP, Ident, Span, Symbol, sym}; +#[doc(hidden)] pub(super) use thin_vec::ThinVec; +#[doc(hidden)] pub(super) use crate::attributes::{ AcceptMapping, AttributeOrder, AttributeParser, CombineAttributeParser, ConvertFn, NoArgsAttributeParser, OnDuplicate, SingleAttributeParser, }; // contexts +#[doc(hidden)] pub(super) use crate::context::{AcceptContext, FinalizeContext, Stage}; +#[doc(hidden)] pub(super) use crate::parser::*; // target checking +#[doc(hidden)] pub(super) use crate::target_checking::Policy::{Allow, Error, Warn}; +#[doc(hidden)] pub(super) use crate::target_checking::{ALL_TARGETS, AllowedTargets}; diff --git a/compiler/rustc_attr_parsing/src/attributes/repr.rs b/compiler/rustc_attr_parsing/src/attributes/repr.rs index 23aabd15597..0330e2515c7 100644 --- a/compiler/rustc_attr_parsing/src/attributes/repr.rs +++ b/compiler/rustc_attr_parsing/src/attributes/repr.rs @@ -331,3 +331,30 @@ impl<S: Stage> AttributeParser<S> for AlignParser { Some(AttributeKind::Align { align, span }) } } + +#[derive(Default)] +pub(crate) struct AlignStaticParser(AlignParser); + +impl AlignStaticParser { + const PATH: &'static [Symbol] = &[sym::rustc_align_static]; + const TEMPLATE: AttributeTemplate = AlignParser::TEMPLATE; + + fn parse<'c, S: Stage>( + &mut self, + cx: &'c mut AcceptContext<'_, '_, S>, + args: &'c ArgParser<'_>, + ) { + self.0.parse(cx, args) + } +} + +impl<S: Stage> AttributeParser<S> for AlignStaticParser { + const ATTRIBUTES: AcceptMapping<Self, S> = &[(Self::PATH, Self::TEMPLATE, Self::parse)]; + const ALLOWED_TARGETS: AllowedTargets = + AllowedTargets::AllowList(&[Allow(Target::Static), Allow(Target::ForeignStatic)]); + + fn finalize(self, _cx: &FinalizeContext<'_, '_, S>) -> Option<AttributeKind> { + let (align, span) = self.0.0?; + Some(AttributeKind::Align { align, span }) + } +} diff --git a/compiler/rustc_attr_parsing/src/context.rs b/compiler/rustc_attr_parsing/src/context.rs index b16ef7edd64..b3ab1d3edd6 100644 --- a/compiler/rustc_attr_parsing/src/context.rs +++ b/compiler/rustc_attr_parsing/src/context.rs @@ -24,13 +24,16 @@ use crate::attributes::codegen_attrs::{ UsedParser, }; use crate::attributes::confusables::ConfusablesParser; -use crate::attributes::crate_level::CrateNameParser; +use crate::attributes::crate_level::{ + CrateNameParser, MoveSizeLimitParser, NoCoreParser, NoStdParser, PatternComplexityLimitParser, + RecursionLimitParser, TypeLengthLimitParser, +}; use crate::attributes::deprecation::DeprecationParser; 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, @@ -47,7 +50,7 @@ use crate::attributes::proc_macro_attrs::{ ProcMacroAttributeParser, ProcMacroDeriveParser, ProcMacroParser, RustcBuiltinMacroParser, }; use crate::attributes::prototype::CustomMirParser; -use crate::attributes::repr::{AlignParser, ReprParser}; +use crate::attributes::repr::{AlignParser, AlignStaticParser, ReprParser}; use crate::attributes::rustc_internal::{ RustcLayoutScalarValidRangeEnd, RustcLayoutScalarValidRangeStart, RustcObjectLifetimeDefaultParser, @@ -149,6 +152,7 @@ attribute_parsers!( pub(crate) static ATTRIBUTE_PARSERS = [ // tidy-alphabetical-start AlignParser, + AlignStaticParser, BodyStabilityParser, ConfusablesParser, ConstStabilityParser, @@ -162,6 +166,7 @@ attribute_parsers!( Combine<AllowConstFnUnstableParser>, Combine<AllowInternalUnstableParser>, Combine<ForceTargetFeatureParser>, + Combine<LinkParser>, Combine<ReprParser>, Combine<TargetFeatureParser>, Combine<UnstableFeatureBoundParser>, @@ -180,10 +185,13 @@ attribute_parsers!( Single<LinkOrdinalParser>, Single<LinkSectionParser>, Single<LinkageParser>, + Single<MoveSizeLimitParser>, Single<MustUseParser>, Single<OptimizeParser>, Single<PathAttributeParser>, + Single<PatternComplexityLimitParser>, Single<ProcMacroDeriveParser>, + Single<RecursionLimitParser>, Single<RustcBuiltinMacroParser>, Single<RustcForceInlineParser>, Single<RustcLayoutScalarValidRangeEnd>, @@ -193,6 +201,7 @@ attribute_parsers!( Single<ShouldPanicParser>, Single<SkipDuringMethodDispatchParser>, Single<TransparencyParser>, + Single<TypeLengthLimitParser>, Single<WithoutArgs<AllowIncoherentImplParser>>, Single<WithoutArgs<AllowInternalUnsafeParser>>, Single<WithoutArgs<AsPtrParser>>, @@ -214,8 +223,10 @@ attribute_parsers!( Single<WithoutArgs<MacroEscapeParser>>, Single<WithoutArgs<MarkerParser>>, Single<WithoutArgs<MayDangleParser>>, + Single<WithoutArgs<NoCoreParser>>, Single<WithoutArgs<NoImplicitPreludeParser>>, Single<WithoutArgs<NoMangleParser>>, + Single<WithoutArgs<NoStdParser>>, Single<WithoutArgs<NonExhaustiveParser>>, Single<WithoutArgs<ParenSugarParser>>, Single<WithoutArgs<PassByValueParser>>, @@ -345,7 +356,10 @@ impl<'f, 'sess: 'f, S: Stage> SharedContext<'f, 'sess, S> { /// must be delayed until after HIR is built. This method will take care of the details of /// that. pub(crate) fn emit_lint(&mut self, lint: AttributeLintKind, span: Span) { - if matches!(self.stage.should_emit(), ShouldEmit::Nothing) { + if !matches!( + self.stage.should_emit(), + ShouldEmit::ErrorsAndLints | ShouldEmit::EarlyFatal { also_emit_lints: true } + ) { return; } let id = self.target_id; @@ -669,20 +683,20 @@ pub enum ShouldEmit { /// /// Only relevant when early parsing, in late parsing equivalent to `ErrorsAndLints`. /// Late parsing is never fatal, and instead tries to emit as many diagnostics as possible. - EarlyFatal, + EarlyFatal { also_emit_lints: bool }, /// The operation will emit errors and lints. /// This is usually what you need. ErrorsAndLints, /// The operation will emit *not* errors and lints. - /// Use this if you are *sure* that this operation will be called at a different time with `ShouldEmit::Emit`. + /// Use this if you are *sure* that this operation will be called at a different time with `ShouldEmit::ErrorsAndLints`. Nothing, } impl ShouldEmit { pub(crate) fn emit_err(&self, diag: Diag<'_>) -> ErrorGuaranteed { match self { - ShouldEmit::EarlyFatal if diag.level() == Level::DelayedBug => diag.emit(), - ShouldEmit::EarlyFatal => diag.upgrade_to_fatal().emit(), + ShouldEmit::EarlyFatal { .. } if diag.level() == Level::DelayedBug => diag.emit(), + ShouldEmit::EarlyFatal { .. } => diag.upgrade_to_fatal().emit(), ShouldEmit::ErrorsAndLints => diag.emit(), ShouldEmit::Nothing => diag.delay_as_bug(), } diff --git a/compiler/rustc_attr_parsing/src/interface.rs b/compiler/rustc_attr_parsing/src/interface.rs index a3558850ef3..0fe3c209421 100644 --- a/compiler/rustc_attr_parsing/src/interface.rs +++ b/compiler/rustc_attr_parsing/src/interface.rs @@ -273,14 +273,7 @@ impl<'sess, S: Stage> AttributeParser<'sess, S> { (accept.accept_fn)(&mut cx, args); if !matches!(cx.stage.should_emit(), ShouldEmit::Nothing) { Self::check_type(accept.attribute_type, target, &mut cx); - self.check_target( - path.get_attribute_path(), - attr.span, - &accept.allowed_targets, - target, - target_id, - &mut emit_lint, - ); + Self::check_target(&accept.allowed_targets, target, &mut cx); } } } else { diff --git a/compiler/rustc_attr_parsing/src/lib.rs b/compiler/rustc_attr_parsing/src/lib.rs index 4dd908cdc40..f51cc8c4e8b 100644 --- a/compiler/rustc_attr_parsing/src/lib.rs +++ b/compiler/rustc_attr_parsing/src/lib.rs @@ -79,6 +79,7 @@ // tidy-alphabetical-start #![allow(internal_features)] #![doc(rust_logo)] +#![feature(decl_macro)] #![feature(rustdoc_internals)] #![recursion_limit = "256"] // tidy-alphabetical-end diff --git a/compiler/rustc_attr_parsing/src/parser.rs b/compiler/rustc_attr_parsing/src/parser.rs index 6d3cf684296..4f903594225 100644 --- a/compiler/rustc_attr_parsing/src/parser.rs +++ b/compiler/rustc_attr_parsing/src/parser.rs @@ -10,11 +10,11 @@ use rustc_ast::token::{self, Delimiter, MetaVarKind}; use rustc_ast::tokenstream::TokenStream; use rustc_ast::{AttrArgs, DelimArgs, Expr, ExprKind, LitKind, MetaItemLit, NormalAttr, Path}; use rustc_ast_pretty::pprust; -use rustc_errors::PResult; +use rustc_errors::{Diag, PResult}; use rustc_hir::{self as hir, AttrPath}; use rustc_parse::exp; use rustc_parse::parser::{Parser, PathStyle, token_descr}; -use rustc_session::errors::report_lit_error; +use rustc_session::errors::{create_lit_error, report_lit_error}; use rustc_session::parse::ParseSess; use rustc_span::{ErrorGuaranteed, Ident, Span, Symbol, sym}; use thin_vec::ThinVec; @@ -379,22 +379,23 @@ struct MetaItemListParserContext<'a, 'sess> { impl<'a, 'sess> MetaItemListParserContext<'a, 'sess> { fn parse_unsuffixed_meta_item_lit(&mut self) -> PResult<'sess, MetaItemLit> { - let uninterpolated_span = self.parser.token_uninterpolated_span(); - let Some(token_lit) = self.parser.eat_token_lit() else { - return self.parser.handle_missing_lit(Parser::mk_meta_item_lit_char); - }; + let Some(token_lit) = self.parser.eat_token_lit() else { return Err(self.expected_lit()) }; + self.unsuffixed_meta_item_from_lit(token_lit) + } + fn unsuffixed_meta_item_from_lit( + &mut self, + token_lit: token::Lit, + ) -> PResult<'sess, MetaItemLit> { let lit = match MetaItemLit::from_token_lit(token_lit, self.parser.prev_token.span) { Ok(lit) => lit, Err(err) => { - let guar = - report_lit_error(&self.parser.psess, err, token_lit, uninterpolated_span); - // Pack possible quotes and prefixes from the original literal into - // the error literal's symbol so they can be pretty-printed faithfully. - let suffixless_lit = token::Lit::new(token_lit.kind, token_lit.symbol, None); - let symbol = Symbol::intern(&suffixless_lit.to_string()); - let token_lit = token::Lit::new(token::Err(guar), symbol, token_lit.suffix); - MetaItemLit::from_token_lit(token_lit, uninterpolated_span).unwrap() + return Err(create_lit_error( + &self.parser.psess, + err, + token_lit, + self.parser.prev_token_uninterpolated_span(), + )); } }; @@ -448,16 +449,28 @@ impl<'a, 'sess> MetaItemListParserContext<'a, 'sess> { } fn parse_meta_item_inner(&mut self) -> PResult<'sess, MetaItemOrLitParser<'static>> { - match self.parse_unsuffixed_meta_item_lit() { - Ok(lit) => return Ok(MetaItemOrLitParser::Lit(lit)), - Err(err) => err.cancel(), // we provide a better error below - } - - match self.parse_attr_item() { - Ok(mi) => return Ok(MetaItemOrLitParser::MetaItemParser(mi)), - Err(err) => err.cancel(), // we provide a better error below + if let Some(token_lit) = self.parser.eat_token_lit() { + // If a literal token is parsed, we commit to parsing a MetaItemLit for better errors + Ok(MetaItemOrLitParser::Lit(self.unsuffixed_meta_item_from_lit(token_lit)?)) + } else { + let prev_pros = self.parser.approx_token_stream_pos(); + match self.parse_attr_item() { + Ok(item) => Ok(MetaItemOrLitParser::MetaItemParser(item)), + Err(err) => { + // If `parse_attr_item` made any progress, it likely has a more precise error we should prefer + // If it didn't make progress we use the `expected_lit` from below + if self.parser.approx_token_stream_pos() != prev_pros { + Err(err) + } else { + err.cancel(); + Err(self.expected_lit()) + } + } + } } + } + fn expected_lit(&mut self) -> Diag<'sess> { let mut err = InvalidMetaItem { span: self.parser.token.span, descr: token_descr(&self.parser.token), @@ -492,7 +505,7 @@ impl<'a, 'sess> MetaItemListParserContext<'a, 'sess> { self.parser.bump(); } - Err(self.parser.dcx().create_err(err)) + self.parser.dcx().create_err(err) } fn parse( diff --git a/compiler/rustc_attr_parsing/src/session_diagnostics.rs b/compiler/rustc_attr_parsing/src/session_diagnostics.rs index a639b55e81f..32ea9005a97 100644 --- a/compiler/rustc_attr_parsing/src/session_diagnostics.rs +++ b/compiler/rustc_attr_parsing/src/session_diagnostics.rs @@ -836,3 +836,107 @@ 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, +} + +#[derive(Diagnostic)] +#[diag(attr_parsing_limit_invalid)] +pub(crate) struct LimitInvalid<'a> { + #[primary_span] + pub span: Span, + #[label] + pub value_span: Span, + pub error_str: &'a str, +} diff --git a/compiler/rustc_attr_parsing/src/target_checking.rs b/compiler/rustc_attr_parsing/src/target_checking.rs index 6f4dd76fa81..edc496b460c 100644 --- a/compiler/rustc_attr_parsing/src/target_checking.rs +++ b/compiler/rustc_attr_parsing/src/target_checking.rs @@ -3,9 +3,8 @@ use std::borrow::Cow; use rustc_ast::AttrStyle; use rustc_errors::DiagArgValue; use rustc_feature::{AttributeType, Features}; -use rustc_hir::lints::{AttributeLint, AttributeLintKind}; -use rustc_hir::{AttrPath, MethodKind, Target}; -use rustc_span::Span; +use rustc_hir::lints::AttributeLintKind; +use rustc_hir::{MethodKind, Target}; use crate::AttributeParser; use crate::context::{AcceptContext, Stage}; @@ -71,38 +70,34 @@ pub(crate) enum Policy { impl<'sess, S: Stage> AttributeParser<'sess, S> { pub(crate) fn check_target( - &self, - attr_name: AttrPath, - attr_span: Span, allowed_targets: &AllowedTargets, target: Target, - target_id: S::Id, - mut emit_lint: impl FnMut(AttributeLint<S::Id>), + cx: &mut AcceptContext<'_, 'sess, S>, ) { match allowed_targets.is_allowed(target) { AllowedResult::Allowed => {} AllowedResult::Warn => { let allowed_targets = allowed_targets.allowed_targets(); - let (applied, only) = - allowed_targets_applied(allowed_targets, target, self.features); - emit_lint(AttributeLint { - id: target_id, - span: attr_span, - kind: AttributeLintKind::InvalidTarget { - name: attr_name, + let (applied, only) = allowed_targets_applied(allowed_targets, target, cx.features); + let name = cx.attr_path.clone(); + let attr_span = cx.attr_span; + cx.emit_lint( + AttributeLintKind::InvalidTarget { + name, target, only: if only { "only " } else { "" }, applied, }, - }); + attr_span, + ); } AllowedResult::Error => { let allowed_targets = allowed_targets.allowed_targets(); - let (applied, only) = - allowed_targets_applied(allowed_targets, target, self.features); - self.dcx().emit_err(InvalidTarget { - span: attr_span, - name: attr_name, + let (applied, only) = allowed_targets_applied(allowed_targets, target, cx.features); + let name = cx.attr_path.clone(); + cx.dcx().emit_err(InvalidTarget { + span: cx.attr_span.clone(), + name, target: target.plural_name(), only: if only { "only " } else { "" }, applied: DiagArgValue::StrListSepByAnd( |
