1 //! Parsing and validation of builtin attributes
4 use rustc_ast::{Attribute, Lit, LitKind, MetaItem, MetaItemKind, NestedMetaItem, NodeId};
5 use rustc_ast_pretty::pprust;
6 use rustc_feature::{find_gated_cfg, is_builtin_attr_name, Features, GatedCfg};
7 use rustc_macros::HashStable_Generic;
8 use rustc_session::lint::builtin::UNEXPECTED_CFGS;
9 use rustc_session::lint::BuiltinLintDiagnostics;
10 use rustc_session::parse::{feature_err, ParseSess};
11 use rustc_session::Session;
12 use rustc_span::hygiene::Transparency;
13 use rustc_span::{symbol::sym, symbol::Symbol, Span};
14 use std::num::NonZeroU32;
16 use crate::session_diagnostics::{self, IncorrectReprFormatGenericCause};
18 /// The version placeholder that recently stabilized features contain inside the
19 /// `since` field of the `#[stable]` attribute.
21 /// For more, see [this pull request](https://github.com/rust-lang/rust/pull/100591).
22 pub const VERSION_PLACEHOLDER: &str = "CURRENT_RUSTC_VERSION";
24 pub fn is_builtin_attr(attr: &Attribute) -> bool {
25 attr.is_doc_comment() || attr.ident().filter(|ident| is_builtin_attr_name(ident.name)).is_some()
30 UnknownMetaItem(String, &'static [&'static str]),
34 MultipleStabilityLevels,
35 UnsupportedLiteral(UnsupportedLiteralReason, /* is_bytestr */ bool),
38 pub(crate) enum UnsupportedLiteralReason {
45 fn handle_errors(sess: &ParseSess, span: Span, error: AttrError) {
47 AttrError::MultipleItem(item) => {
48 sess.emit_err(session_diagnostics::MultipleItem { span, item });
50 AttrError::UnknownMetaItem(item, expected) => {
51 sess.emit_err(session_diagnostics::UnknownMetaItem { span, item, expected });
53 AttrError::MissingSince => {
54 sess.emit_err(session_diagnostics::MissingSince { span });
56 AttrError::NonIdentFeature => {
57 sess.emit_err(session_diagnostics::NonIdentFeature { span });
59 AttrError::MissingFeature => {
60 sess.emit_err(session_diagnostics::MissingFeature { span });
62 AttrError::MultipleStabilityLevels => {
63 sess.emit_err(session_diagnostics::MultipleStabilityLevels { span });
65 AttrError::UnsupportedLiteral(reason, is_bytestr) => {
66 sess.emit_err(session_diagnostics::UnsupportedLiteral {
70 start_point_span: sess.source_map().start_point(span),
76 #[derive(Copy, Clone, PartialEq, Encodable, Decodable, Debug, HashStable_Generic)]
84 #[derive(Clone, Encodable, Decodable, Debug, PartialEq, Eq, HashStable_Generic)]
85 pub enum InstructionSetAttr {
90 #[derive(Clone, Encodable, Decodable, Debug, HashStable_Generic)]
91 pub enum OptimizeAttr {
97 /// Represents the following attributes:
101 #[derive(Encodable, Decodable, Copy, Clone, Debug, PartialEq, Eq, Hash)]
102 #[derive(HashStable_Generic)]
103 pub struct Stability {
104 pub level: StabilityLevel,
109 pub fn is_unstable(&self) -> bool {
110 self.level.is_unstable()
113 pub fn is_stable(&self) -> bool {
114 self.level.is_stable()
118 /// Represents the `#[rustc_const_unstable]` and `#[rustc_const_stable]` attributes.
119 #[derive(Encodable, Decodable, Copy, Clone, Debug, PartialEq, Eq, Hash)]
120 #[derive(HashStable_Generic)]
121 pub struct ConstStability {
122 pub level: StabilityLevel,
124 /// whether the function has a `#[rustc_promotable]` attribute
125 pub promotable: bool,
128 impl ConstStability {
129 pub fn is_const_unstable(&self) -> bool {
130 self.level.is_unstable()
133 pub fn is_const_stable(&self) -> bool {
134 self.level.is_stable()
138 /// Represents the `#[rustc_default_body_unstable]` attribute.
139 #[derive(Encodable, Decodable, Copy, Clone, Debug, PartialEq, Eq, Hash)]
140 #[derive(HashStable_Generic)]
141 pub struct DefaultBodyStability {
142 pub level: StabilityLevel,
146 /// The available stability levels.
147 #[derive(Encodable, Decodable, PartialEq, Copy, Clone, Debug, Eq, Hash)]
148 #[derive(HashStable_Generic)]
149 pub enum StabilityLevel {
152 /// Reason for the current stability level.
153 reason: UnstableReason,
154 /// Relevant `rust-lang/rust` issue.
155 issue: Option<NonZeroU32>,
157 /// If part of a feature is stabilized and a new feature is added for the remaining parts,
158 /// then the `implied_by` attribute is used to indicate which now-stable feature previously
159 /// contained a item.
162 /// #[unstable(feature = "foo", issue = "...")]
164 /// #[unstable(feature = "foo", issue = "...")]
171 /// #[stable(feature = "foo", since = "1.XX.X")]
173 /// #[unstable(feature = "foobar", issue = "...", implied_by = "foo")]
176 implied_by: Option<Symbol>,
180 /// Rust release which stabilized this feature.
182 /// Is this item allowed to be referred to on stable, despite being contained in unstable
184 allowed_through_unstable_modules: bool,
188 impl StabilityLevel {
189 pub fn is_unstable(&self) -> bool {
190 matches!(self, StabilityLevel::Unstable { .. })
192 pub fn is_stable(&self) -> bool {
193 matches!(self, StabilityLevel::Stable { .. })
197 #[derive(Encodable, Decodable, PartialEq, Copy, Clone, Debug, Eq, Hash)]
198 #[derive(HashStable_Generic)]
199 pub enum UnstableReason {
205 impl UnstableReason {
206 fn from_opt_reason(reason: Option<Symbol>) -> Self {
207 // UnstableReason::Default constructed manually
209 Some(r) => Self::Some(r),
214 pub fn to_opt_reason(&self) -> Option<Symbol> {
217 Self::Default => Some(sym::unstable_location_reason_default),
218 Self::Some(r) => Some(*r),
223 /// Collects stability info from all stability attributes in `attrs`.
224 /// Returns `None` if no stability attributes are found.
225 pub fn find_stability(
229 ) -> (Option<(Stability, Span)>, Option<(ConstStability, Span)>, Option<(DefaultBodyStability, Span)>)
231 find_stability_generic(sess, attrs.iter(), item_sp)
234 fn find_stability_generic<'a, I>(
238 ) -> (Option<(Stability, Span)>, Option<(ConstStability, Span)>, Option<(DefaultBodyStability, Span)>)
240 I: Iterator<Item = &'a Attribute>,
242 use StabilityLevel::*;
244 let mut stab: Option<(Stability, Span)> = None;
245 let mut const_stab: Option<(ConstStability, Span)> = None;
246 let mut body_stab: Option<(DefaultBodyStability, Span)> = None;
247 let mut promotable = false;
248 let mut allowed_through_unstable_modules = false;
250 'outer: for attr in attrs_iter {
252 sym::rustc_const_unstable,
253 sym::rustc_const_stable,
256 sym::rustc_promotable,
257 sym::rustc_allowed_through_unstable_modules,
258 sym::rustc_default_body_unstable,
261 .any(|&s| attr.has_name(s))
263 continue; // not a stability level
266 let meta = attr.meta();
268 if attr.has_name(sym::rustc_promotable) {
270 } else if attr.has_name(sym::rustc_allowed_through_unstable_modules) {
271 allowed_through_unstable_modules = true;
273 // attributes with data
274 else if let Some(MetaItem { kind: MetaItemKind::List(ref metas), .. }) = meta {
275 let meta = meta.as_ref().unwrap();
276 let get = |meta: &MetaItem, item: &mut Option<Symbol>| {
281 AttrError::MultipleItem(pprust::path_to_string(&meta.path)),
285 if let Some(v) = meta.value_str() {
289 sess.emit_err(session_diagnostics::IncorrectMetaItem { span: meta.span });
294 let meta_name = meta.name_or_empty();
296 sym::rustc_const_unstable | sym::rustc_default_body_unstable | sym::unstable => {
297 if meta_name == sym::unstable && stab.is_some() {
301 AttrError::MultipleStabilityLevels,
304 } else if meta_name == sym::rustc_const_unstable && const_stab.is_some() {
308 AttrError::MultipleStabilityLevels,
311 } else if meta_name == sym::rustc_default_body_unstable && body_stab.is_some() {
315 AttrError::MultipleStabilityLevels,
320 let mut feature = None;
321 let mut reason = None;
322 let mut issue = None;
323 let mut issue_num = None;
324 let mut is_soft = false;
325 let mut implied_by = None;
327 let Some(mi) = meta.meta_item() else {
331 AttrError::UnsupportedLiteral(UnsupportedLiteralReason::Generic, false),
335 match mi.name_or_empty() {
337 if !get(mi, &mut feature) {
342 if !get(mi, &mut reason) {
347 if !get(mi, &mut issue) {
351 // These unwraps are safe because `get` ensures the meta item
352 // is a name/value pair string literal.
353 issue_num = match issue.unwrap().as_str() {
355 issue => match issue.parse::<NonZeroU32>() {
356 Ok(num) => Some(num),
359 session_diagnostics::InvalidIssueString {
361 cause: session_diagnostics::InvalidIssueStringCause::from_int_error_kind(
362 mi.name_value_literal_span().unwrap(),
374 sess.emit_err(session_diagnostics::SoftNoArgs {
381 if !get(mi, &mut implied_by) {
389 AttrError::UnknownMetaItem(
390 pprust::path_to_string(&mi.path),
391 &["feature", "reason", "issue", "soft"],
399 match (feature, reason, issue) {
400 (Some(feature), reason, Some(_)) => {
401 if !rustc_lexer::is_ident(feature.as_str()) {
405 AttrError::NonIdentFeature,
409 let level = Unstable {
410 reason: UnstableReason::from_opt_reason(reason),
415 if sym::unstable == meta_name {
416 stab = Some((Stability { level, feature }, attr.span));
417 } else if sym::rustc_const_unstable == meta_name {
419 ConstStability { level, feature, promotable: false },
422 } else if sym::rustc_default_body_unstable == meta_name {
424 Some((DefaultBodyStability { level, feature }, attr.span));
426 unreachable!("Unknown stability attribute {meta_name}");
430 handle_errors(&sess.parse_sess, attr.span, AttrError::MissingFeature);
434 sess.emit_err(session_diagnostics::MissingIssue { span: attr.span });
439 sym::rustc_const_stable | sym::stable => {
440 if meta_name == sym::stable && stab.is_some() {
444 AttrError::MultipleStabilityLevels,
447 } else if meta_name == sym::rustc_const_stable && const_stab.is_some() {
451 AttrError::MultipleStabilityLevels,
456 let mut feature = None;
457 let mut since = None;
460 NestedMetaItem::MetaItem(mi) => match mi.name_or_empty() {
462 if !get(mi, &mut feature) {
467 if !get(mi, &mut since) {
475 AttrError::UnknownMetaItem(
476 pprust::path_to_string(&mi.path),
477 &["feature", "since"],
483 NestedMetaItem::Literal(lit) => {
487 AttrError::UnsupportedLiteral(
488 UnsupportedLiteralReason::Generic,
497 if let Some(s) = since && s.as_str() == VERSION_PLACEHOLDER {
498 let version = option_env!("CFG_VERSION").unwrap_or("<current>");
499 let version = version.split(' ').next().unwrap();
500 since = Some(Symbol::intern(&version));
503 match (feature, since) {
504 (Some(feature), Some(since)) => {
505 let level = Stable { since, allowed_through_unstable_modules: false };
506 if sym::stable == meta_name {
507 stab = Some((Stability { level, feature }, attr.span));
510 ConstStability { level, feature, promotable: false },
516 handle_errors(&sess.parse_sess, attr.span, AttrError::MissingFeature);
520 handle_errors(&sess.parse_sess, attr.span, AttrError::MissingSince);
530 // Merge the const-unstable info into the stability info
532 if let Some((ref mut stab, _)) = const_stab {
533 stab.promotable = promotable;
535 sess.emit_err(session_diagnostics::RustcPromotablePairing { span: item_sp });
539 if allowed_through_unstable_modules {
542 level: StabilityLevel::Stable { ref mut allowed_through_unstable_modules, .. },
548 *allowed_through_unstable_modules = true;
550 sess.emit_err(session_diagnostics::RustcAllowedUnstablePairing { span: item_sp });
554 (stab, const_stab, body_stab)
557 pub fn find_crate_name(sess: &Session, attrs: &[Attribute]) -> Option<Symbol> {
558 sess.first_attr_value_str_by_name(attrs, sym::crate_name)
561 #[derive(Clone, Debug)]
562 pub struct Condition {
565 pub value: Option<Symbol>,
566 pub value_span: Option<Span>,
570 /// Tests if a cfg-pattern matches the cfg set
574 lint_node_id: NodeId,
575 features: Option<&Features>,
577 eval_condition(cfg, sess, features, &mut |cfg| {
578 try_gate_cfg(cfg.name, cfg.span, sess, features);
579 if let Some(names_valid) = &sess.check_config.names_valid {
580 if !names_valid.contains(&cfg.name) {
581 sess.buffer_lint_with_diagnostic(
585 "unexpected `cfg` condition name",
586 BuiltinLintDiagnostics::UnexpectedCfg((cfg.name, cfg.name_span), None),
590 if let Some(value) = cfg.value {
591 if let Some(values) = &sess.check_config.values_valid.get(&cfg.name) {
592 if !values.contains(&value) {
593 sess.buffer_lint_with_diagnostic(
597 "unexpected `cfg` condition value",
598 BuiltinLintDiagnostics::UnexpectedCfg(
599 (cfg.name, cfg.name_span),
600 cfg.value_span.map(|vs| (value, vs)),
606 sess.config.contains(&(cfg.name, cfg.value))
610 fn try_gate_cfg(name: Symbol, span: Span, sess: &ParseSess, features: Option<&Features>) {
611 let gate = find_gated_cfg(|sym| sym == name);
612 if let (Some(feats), Some(gated_cfg)) = (features, gate) {
613 gate_cfg(&gated_cfg, span, sess, feats);
617 fn gate_cfg(gated_cfg: &GatedCfg, cfg_span: Span, sess: &ParseSess, features: &Features) {
618 let (cfg, feature, has_feature) = gated_cfg;
619 if !has_feature(features) && !cfg_span.allows_unstable(*feature) {
620 let explain = format!("`cfg({})` is experimental and subject to change", cfg);
621 feature_err(sess, *feature, cfg_span, &explain).emit();
625 #[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
632 fn parse_version(s: &str, allow_appendix: bool) -> Option<Version> {
633 let mut components = s.split('-');
634 let d = components.next()?;
635 if !allow_appendix && components.next().is_some() {
638 let mut digits = d.splitn(3, '.');
639 let major = digits.next()?.parse().ok()?;
640 let minor = digits.next()?.parse().ok()?;
641 let patch = digits.next().unwrap_or("0").parse().ok()?;
642 Some(Version { major, minor, patch })
645 /// Evaluate a cfg-like condition (with `any` and `all`), using `eval` to
646 /// evaluate individual items.
647 pub fn eval_condition(
650 features: Option<&Features>,
651 eval: &mut impl FnMut(Condition) -> bool,
654 ast::MetaItemKind::List(ref mis) if cfg.name_or_empty() == sym::version => {
655 try_gate_cfg(sym::version, cfg.span, sess, features);
656 let (min_version, span) = match &mis[..] {
657 [NestedMetaItem::Literal(Lit { kind: LitKind::Str(sym, ..), span, .. })] => {
661 NestedMetaItem::Literal(Lit { span, .. })
662 | NestedMetaItem::MetaItem(MetaItem { span, .. }),
664 sess.emit_err(session_diagnostics::ExpectedVersionLiteral { span: *span });
668 sess.emit_err(session_diagnostics::ExpectedSingleVersionLiteral {
674 let Some(min_version) = parse_version(min_version.as_str(), false) else {
675 sess.emit_warning(session_diagnostics::UnknownVersionLiteral { span: *span });
678 let rustc_version = parse_version(env!("CFG_RELEASE"), true).unwrap();
680 // See https://github.com/rust-lang/rust/issues/64796#issuecomment-640851454 for details
681 if sess.assume_incomplete_release {
682 rustc_version > min_version
684 rustc_version >= min_version
687 ast::MetaItemKind::List(ref mis) => {
688 for mi in mis.iter() {
689 if !mi.is_meta_item() {
693 AttrError::UnsupportedLiteral(UnsupportedLiteralReason::Generic, false),
699 // The unwraps below may look dangerous, but we've already asserted
700 // that they won't fail with the loop above.
701 match cfg.name_or_empty() {
704 // We don't use any() here, because we want to evaluate all cfg condition
705 // as eval_condition can (and does) extra checks
706 .fold(false, |res, mi| {
707 res | eval_condition(mi.meta_item().unwrap(), sess, features, eval)
711 // We don't use all() here, because we want to evaluate all cfg condition
712 // as eval_condition can (and does) extra checks
713 .fold(true, |res, mi| {
714 res & eval_condition(mi.meta_item().unwrap(), sess, features, eval)
718 sess.emit_err(session_diagnostics::ExpectedOneCfgPattern {
724 !eval_condition(mis[0].meta_item().unwrap(), sess, features, eval)
727 if let Some(features) = features && !features.cfg_target_compact {
730 sym::cfg_target_compact,
732 &"compact `cfg(target(..))` is experimental and subject to change"
736 mis.iter().fold(true, |res, mi| {
737 let mut mi = mi.meta_item().unwrap().clone();
738 if let [seg, ..] = &mut mi.path.segments[..] {
739 seg.ident.name = Symbol::intern(&format!("target_{}", seg.ident.name));
742 res & eval_condition(&mi, sess, features, eval)
746 sess.emit_err(session_diagnostics::InvalidPredicate {
748 predicate: pprust::path_to_string(&cfg.path),
754 ast::MetaItemKind::Word | MetaItemKind::NameValue(..) if cfg.path.segments.len() != 1 => {
755 sess.emit_err(session_diagnostics::CfgPredicateIdentifier { span: cfg.path.span });
758 MetaItemKind::NameValue(ref lit) if !lit.kind.is_str() => {
762 AttrError::UnsupportedLiteral(
763 UnsupportedLiteralReason::CfgString,
764 lit.kind.is_bytestr(),
769 ast::MetaItemKind::Word | ast::MetaItemKind::NameValue(..) => {
770 let ident = cfg.ident().expect("multi-segment cfg predicate");
773 name_span: ident.span,
774 value: cfg.value_str(),
775 value_span: cfg.name_value_literal_span(),
782 #[derive(Copy, Debug, Encodable, Decodable, Clone, HashStable_Generic)]
783 pub struct Deprecation {
784 pub since: Option<Symbol>,
785 /// The note to issue a reason.
786 pub note: Option<Symbol>,
787 /// A text snippet used to completely replace any use of the deprecated item in an expression.
789 /// This is currently unstable.
790 pub suggestion: Option<Symbol>,
792 /// Whether to treat the since attribute as being a Rust version identifier
793 /// (rather than an opaque string).
794 pub is_since_rustc_version: bool,
797 /// Finds the deprecation attribute. `None` if none exists.
798 pub fn find_deprecation(sess: &Session, attrs: &[Attribute]) -> Option<(Deprecation, Span)> {
799 find_deprecation_generic(sess, attrs.iter())
802 fn find_deprecation_generic<'a, I>(sess: &Session, attrs_iter: I) -> Option<(Deprecation, Span)>
804 I: Iterator<Item = &'a Attribute>,
806 let mut depr: Option<(Deprecation, Span)> = None;
807 let is_rustc = sess.features_untracked().staged_api;
809 'outer: for attr in attrs_iter {
810 if !attr.has_name(sym::deprecated) {
814 let Some(meta) = attr.meta() else {
817 let mut since = None;
819 let mut suggestion = None;
821 MetaItemKind::Word => {}
822 MetaItemKind::NameValue(..) => note = meta.value_str(),
823 MetaItemKind::List(list) => {
824 let get = |meta: &MetaItem, item: &mut Option<Symbol>| {
829 AttrError::MultipleItem(pprust::path_to_string(&meta.path)),
833 if let Some(v) = meta.value_str() {
837 if let Some(lit) = meta.name_value_literal() {
841 AttrError::UnsupportedLiteral(
842 UnsupportedLiteralReason::DeprecatedString,
843 lit.kind.is_bytestr(),
847 sess.emit_err(session_diagnostics::IncorrectMetaItem2 {
858 NestedMetaItem::MetaItem(mi) => match mi.name_or_empty() {
860 if !get(mi, &mut since) {
865 if !get(mi, &mut note) {
870 if !sess.features_untracked().deprecated_suggestion {
871 sess.emit_err(session_diagnostics::DeprecatedItemSuggestion {
873 is_nightly: sess.is_nightly_build().then_some(()),
878 if !get(mi, &mut suggestion) {
886 AttrError::UnknownMetaItem(
887 pprust::path_to_string(&mi.path),
888 if sess.features_untracked().deprecated_suggestion {
889 &["since", "note", "suggestion"]
898 NestedMetaItem::Literal(lit) => {
902 AttrError::UnsupportedLiteral(
903 UnsupportedLiteralReason::DeprecatedKvPair,
916 handle_errors(&sess.parse_sess, attr.span, AttrError::MissingSince);
921 sess.emit_err(session_diagnostics::MissingNote { span: attr.span });
927 Deprecation { since, note, suggestion, is_since_rustc_version: is_rustc },
935 #[derive(PartialEq, Debug, Encodable, Decodable, Copy, Clone)]
945 #[derive(Eq, PartialEq, Debug, Copy, Clone)]
946 #[derive(Encodable, Decodable, HashStable_Generic)]
948 SignedInt(ast::IntTy),
949 UnsignedInt(ast::UintTy),
954 pub fn is_signed(self) -> bool {
958 SignedInt(..) => true,
959 UnsignedInt(..) => false,
964 /// Parse #[repr(...)] forms.
966 /// Valid repr contents: any of the primitive integral type names (see
967 /// `int_type_of_word`, below) to specify enum discriminant type; `C`, to use
968 /// the same discriminant size that the corresponding C enum would or C
969 /// structure layout, `packed` to remove padding, and `transparent` to delegate representation
970 /// concerns to the only non-ZST field.
971 pub fn find_repr_attrs(sess: &Session, attr: &Attribute) -> Vec<ReprAttr> {
972 if attr.has_name(sym::repr) { parse_repr_attr(sess, attr) } else { Vec::new() }
975 pub fn parse_repr_attr(sess: &Session, attr: &Attribute) -> Vec<ReprAttr> {
976 assert!(attr.has_name(sym::repr), "expected `#[repr(..)]`, found: {:?}", attr);
978 let mut acc = Vec::new();
979 let diagnostic = &sess.parse_sess.span_diagnostic;
981 if let Some(items) = attr.meta_item_list() {
983 let mut recognised = false;
985 let hint = match item.name_or_empty() {
986 sym::C => Some(ReprC),
987 sym::packed => Some(ReprPacked(1)),
988 sym::simd => Some(ReprSimd),
989 sym::transparent => Some(ReprTransparent),
991 sess.emit_err(session_diagnostics::InvalidReprAlignNeedArg {
997 name => int_type_of_word(name).map(ReprInt),
1000 if let Some(h) = hint {
1004 } else if let Some((name, value)) = item.name_value_literal() {
1005 let mut literal_error = None;
1006 if name == sym::align {
1008 match parse_alignment(&value.kind) {
1009 Ok(literal) => acc.push(ReprAlign(literal)),
1010 Err(message) => literal_error = Some(message),
1012 } else if name == sym::packed {
1014 match parse_alignment(&value.kind) {
1015 Ok(literal) => acc.push(ReprPacked(literal)),
1016 Err(message) => literal_error = Some(message),
1018 } else if matches!(name, sym::C | sym::simd | sym::transparent)
1019 || int_type_of_word(name).is_some()
1022 sess.emit_err(session_diagnostics::InvalidReprHintNoParen {
1024 name: name.to_ident_string(),
1027 if let Some(literal_error) = literal_error {
1028 sess.emit_err(session_diagnostics::InvalidReprGeneric {
1030 repr_arg: name.to_ident_string(),
1031 error_part: literal_error,
1034 } else if let Some(meta_item) = item.meta_item() {
1035 if let MetaItemKind::NameValue(ref value) = meta_item.kind {
1036 if meta_item.has_name(sym::align) || meta_item.has_name(sym::packed) {
1037 let name = meta_item.name_or_empty().to_ident_string();
1039 sess.emit_err(session_diagnostics::IncorrectReprFormatGeneric {
1042 cause: IncorrectReprFormatGenericCause::from_lit_kind(
1050 meta_item.name_or_empty(),
1051 sym::C | sym::simd | sym::transparent
1052 ) || int_type_of_word(meta_item.name_or_empty()).is_some()
1055 sess.emit_err(session_diagnostics::InvalidReprHintNoValue {
1056 span: meta_item.span,
1057 name: meta_item.name_or_empty().to_ident_string(),
1061 } else if let MetaItemKind::List(_) = meta_item.kind {
1062 if meta_item.has_name(sym::align) {
1064 sess.emit_err(session_diagnostics::IncorrectReprFormatAlignOneArg {
1065 span: meta_item.span,
1067 } else if meta_item.has_name(sym::packed) {
1069 sess.emit_err(session_diagnostics::IncorrectReprFormatPackedOneOrZeroArg {
1070 span: meta_item.span,
1073 meta_item.name_or_empty(),
1074 sym::C | sym::simd | sym::transparent
1075 ) || int_type_of_word(meta_item.name_or_empty()).is_some()
1078 sess.emit_err(session_diagnostics::InvalidReprHintNoParen {
1079 span: meta_item.span,
1080 name: meta_item.name_or_empty().to_ident_string(),
1086 // Not a word we recognize. This will be caught and reported by
1087 // the `check_mod_attrs` pass, but this pass doesn't always run
1088 // (e.g. if we only pretty-print the source), so we have to gate
1089 // the `delay_span_bug` call as follows:
1090 if sess.opts.pretty.map_or(true, |pp| pp.needs_analysis()) {
1091 diagnostic.delay_span_bug(item.span(), "unrecognized representation hint");
1099 fn int_type_of_word(s: Symbol) -> Option<IntType> {
1103 sym::i8 => Some(SignedInt(ast::IntTy::I8)),
1104 sym::u8 => Some(UnsignedInt(ast::UintTy::U8)),
1105 sym::i16 => Some(SignedInt(ast::IntTy::I16)),
1106 sym::u16 => Some(UnsignedInt(ast::UintTy::U16)),
1107 sym::i32 => Some(SignedInt(ast::IntTy::I32)),
1108 sym::u32 => Some(UnsignedInt(ast::UintTy::U32)),
1109 sym::i64 => Some(SignedInt(ast::IntTy::I64)),
1110 sym::u64 => Some(UnsignedInt(ast::UintTy::U64)),
1111 sym::i128 => Some(SignedInt(ast::IntTy::I128)),
1112 sym::u128 => Some(UnsignedInt(ast::UintTy::U128)),
1113 sym::isize => Some(SignedInt(ast::IntTy::Isize)),
1114 sym::usize => Some(UnsignedInt(ast::UintTy::Usize)),
1119 pub enum TransparencyError {
1120 UnknownTransparency(Symbol, Span),
1121 MultipleTransparencyAttrs(Span, Span),
1124 pub fn find_transparency(
1125 attrs: &[Attribute],
1127 ) -> (Transparency, Option<TransparencyError>) {
1128 let mut transparency = None;
1129 let mut error = None;
1131 if attr.has_name(sym::rustc_macro_transparency) {
1132 if let Some((_, old_span)) = transparency {
1133 error = Some(TransparencyError::MultipleTransparencyAttrs(old_span, attr.span));
1135 } else if let Some(value) = attr.value_str() {
1136 transparency = Some((
1138 sym::transparent => Transparency::Transparent,
1139 sym::semitransparent => Transparency::SemiTransparent,
1140 sym::opaque => Transparency::Opaque,
1142 error = Some(TransparencyError::UnknownTransparency(value, attr.span));
1151 let fallback = if macro_rules { Transparency::SemiTransparent } else { Transparency::Opaque };
1152 (transparency.map_or(fallback, |t| t.0), error)
1155 pub fn allow_internal_unstable<'a>(
1157 attrs: &'a [Attribute],
1158 ) -> impl Iterator<Item = Symbol> + 'a {
1159 allow_unstable(sess, attrs, sym::allow_internal_unstable)
1162 pub fn rustc_allow_const_fn_unstable<'a>(
1164 attrs: &'a [Attribute],
1165 ) -> impl Iterator<Item = Symbol> + 'a {
1166 allow_unstable(sess, attrs, sym::rustc_allow_const_fn_unstable)
1169 fn allow_unstable<'a>(
1171 attrs: &'a [Attribute],
1173 ) -> impl Iterator<Item = Symbol> + 'a {
1174 let attrs = sess.filter_by_name(attrs, symbol);
1176 .filter_map(move |attr| {
1177 attr.meta_item_list().or_else(|| {
1178 sess.emit_err(session_diagnostics::ExpectsFeatureList {
1180 name: symbol.to_ident_string(),
1187 list.into_iter().filter_map(move |it| {
1188 let name = it.ident().map(|ident| ident.name);
1190 sess.emit_err(session_diagnostics::ExpectsFeatures {
1192 name: symbol.to_ident_string(),
1199 pub fn parse_alignment(node: &ast::LitKind) -> Result<u32, &'static str> {
1200 if let ast::LitKind::Int(literal, ast::LitIntType::Unsuffixed) = node {
1201 if literal.is_power_of_two() {
1202 // rustc_middle::ty::layout::Align restricts align to <= 2^29
1203 if *literal <= 1 << 29 { Ok(*literal as u32) } else { Err("larger than 2^29") }
1205 Err("not a power of two")
1208 Err("not an unsuffixed integer")