1 //! Parsing and validation of builtin attributes
3 use crate::ast
::{self, Attribute, MetaItem, NestedMetaItem}
;
4 use crate::early_buffered_lints
::BufferedEarlyLintId
;
5 use crate::ext
::base
::ExtCtxt
;
6 use crate::feature_gate
::{Features, GatedCfg}
;
7 use crate::parse
::ParseSess
;
9 use errors
::{Applicability, Handler}
;
10 use syntax_pos
::hygiene
::Transparency
;
11 use syntax_pos
::{symbol::Symbol, symbol::sym, Span}
;
13 use super::{mark_used, MetaItemKind}
;
17 UnknownMetaItem(String
, &'
static [&'
static str]),
20 MultipleStabilityLevels
,
21 UnsupportedLiteral(&'
static str, /* is_bytestr */ bool
),
24 /// A template that the attribute input must match.
25 /// Only top-level shape (`#[attr]` vs `#[attr(...)]` vs `#[attr = ...]`) is considered now.
26 #[derive(Clone, Copy)]
27 pub struct AttributeTemplate
{
29 crate list
: Option
<&'
static str>,
30 crate name_value_str
: Option
<&'
static str>,
33 impl AttributeTemplate
{
34 /// Checks that the given meta-item is compatible with this template.
35 fn compatible(&self, meta_item_kind
: &ast
::MetaItemKind
) -> bool
{
36 match meta_item_kind
{
37 ast
::MetaItemKind
::Word
=> self.word
,
38 ast
::MetaItemKind
::List(..) => self.list
.is_some(),
39 ast
::MetaItemKind
::NameValue(lit
) if lit
.node
.is_str() => self.name_value_str
.is_some(),
40 ast
::MetaItemKind
::NameValue(..) => false,
45 fn handle_errors(sess
: &ParseSess
, span
: Span
, error
: AttrError
) {
46 let diag
= &sess
.span_diagnostic
;
48 AttrError
::MultipleItem(item
) => span_err
!(diag
, span
, E0538
,
49 "multiple '{}' items", item
),
50 AttrError
::UnknownMetaItem(item
, expected
) => {
51 let expected
= expected
53 .map(|name
| format
!("`{}`", name
))
55 struct_span_err
!(diag
, span
, E0541
, "unknown meta item '{}'", item
)
56 .span_label(span
, format
!("expected one of {}", expected
.join(", ")))
59 AttrError
::MissingSince
=> span_err
!(diag
, span
, E0542
, "missing 'since'"),
60 AttrError
::MissingFeature
=> span_err
!(diag
, span
, E0546
, "missing 'feature'"),
61 AttrError
::MultipleStabilityLevels
=> span_err
!(diag
, span
, E0544
,
62 "multiple stability levels"),
63 AttrError
::UnsupportedLiteral(
67 let mut err
= struct_span_err
!(diag
, span
, E0565
, "{}", msg
);
69 if let Ok(lint_str
) = sess
.source_map().span_to_snippet(span
) {
72 "consider removing the prefix",
73 format
!("{}", &lint_str
[1..]),
74 Applicability
::MaybeIncorrect
,
83 #[derive(Copy, Clone, Hash, PartialEq, RustcEncodable, RustcDecodable)]
91 #[derive(Copy, Clone, Hash, PartialEq, RustcEncodable, RustcDecodable)]
92 pub enum OptimizeAttr
{
98 #[derive(Copy, Clone, PartialEq)]
104 /// Determine what `#[unwind]` attribute is present in `attrs`, if any.
105 pub fn find_unwind_attr(diagnostic
: Option
<&Handler
>, attrs
: &[Attribute
]) -> Option
<UnwindAttr
> {
106 attrs
.iter().fold(None
, |ia
, attr
| {
107 if attr
.check_name(sym
::unwind
) {
108 if let Some(meta
) = attr
.meta() {
109 if let MetaItemKind
::List(items
) = meta
.node
{
110 if items
.len() == 1 {
111 if items
[0].check_name(sym
::allowed
) {
112 return Some(UnwindAttr
::Allowed
);
113 } else if items
[0].check_name(sym
::aborts
) {
114 return Some(UnwindAttr
::Aborts
);
119 struct_span_err
!(d
, attr
.span
, E0633
, "malformed `unwind` attribute input")
120 .span_label(attr
.span
, "invalid argument")
123 "the allowed arguments are `allowed` and `aborts`",
124 (vec
!["allowed", "aborts"]).into_iter()
125 .map(|s
| format
!("#[unwind({})]", s
)),
126 Applicability
::MachineApplicable
,
137 /// Represents the #[stable], #[unstable], #[rustc_{deprecated,const_unstable}] attributes.
138 #[derive(RustcEncodable, RustcDecodable, Copy, Clone, Debug, PartialEq, Eq, Hash)]
139 pub struct Stability
{
140 pub level
: StabilityLevel
,
142 pub rustc_depr
: Option
<RustcDeprecation
>,
143 /// `None` means the function is stable but needs to be a stable const fn, too
144 /// `Some` contains the feature gate required to be able to use the function
146 pub const_stability
: Option
<Symbol
>,
147 /// whether the function has a `#[rustc_promotable]` attribute
148 pub promotable
: bool
,
149 /// whether the function has a `#[rustc_allow_const_fn_ptr]` attribute
150 pub allow_const_fn_ptr
: bool
,
153 /// The available stability levels.
154 #[derive(RustcEncodable, RustcDecodable, PartialEq, PartialOrd, Copy, Clone, Debug, Eq, Hash)]
155 pub enum StabilityLevel
{
156 // Reason for the current stability level and the relevant rust-lang issue
157 Unstable { reason: Option<Symbol>, issue: u32, is_soft: bool }
,
158 Stable { since: Symbol }
,
161 impl StabilityLevel
{
162 pub fn is_unstable(&self) -> bool
{
163 if let StabilityLevel
::Unstable {..}
= *self {
169 pub fn is_stable(&self) -> bool
{
170 if let StabilityLevel
::Stable {..}
= *self {
178 #[derive(RustcEncodable, RustcDecodable, PartialEq, PartialOrd, Copy, Clone, Debug, Eq, Hash)]
179 pub struct RustcDeprecation
{
182 /// A text snippet used to completely replace any use of the deprecated item in an expression.
183 pub suggestion
: Option
<Symbol
>,
186 /// Checks if `attrs` contains an attribute like `#![feature(feature_name)]`.
187 /// This will not perform any "sanity checks" on the form of the attributes.
188 pub fn contains_feature_attr(attrs
: &[Attribute
], feature_name
: Symbol
) -> bool
{
189 attrs
.iter().any(|item
| {
190 item
.check_name(sym
::feature
) &&
191 item
.meta_item_list().map(|list
| {
192 list
.iter().any(|mi
| mi
.is_word() && mi
.check_name(feature_name
))
197 /// Collects stability info from all stability attributes in `attrs`.
198 /// Returns `None` if no stability attributes are found.
199 pub fn find_stability(sess
: &ParseSess
, attrs
: &[Attribute
],
200 item_sp
: Span
) -> Option
<Stability
> {
201 find_stability_generic(sess
, attrs
.iter(), item_sp
)
204 fn find_stability_generic
<'a
, I
>(sess
: &ParseSess
,
208 where I
: Iterator
<Item
= &'a Attribute
>
210 use StabilityLevel
::*;
212 let mut stab
: Option
<Stability
> = None
;
213 let mut rustc_depr
: Option
<RustcDeprecation
> = None
;
214 let mut rustc_const_unstable
: Option
<Symbol
> = None
;
215 let mut promotable
= false;
216 let mut allow_const_fn_ptr
= false;
217 let diagnostic
= &sess
.span_diagnostic
;
219 'outer
: for attr
in attrs_iter
{
221 sym
::rustc_deprecated
,
222 sym
::rustc_const_unstable
,
225 sym
::rustc_promotable
,
226 sym
::rustc_allow_const_fn_ptr
,
227 ].iter().any(|&s
| attr
.path
== s
) {
228 continue // not a stability level
233 let meta
= attr
.meta();
235 if attr
.path
== sym
::rustc_promotable
{
238 if attr
.path
== sym
::rustc_allow_const_fn_ptr
{
239 allow_const_fn_ptr
= true;
241 // attributes with data
242 else if let Some(MetaItem { node: MetaItemKind::List(ref metas), .. }
) = meta
{
243 let meta
= meta
.as_ref().unwrap();
244 let get
= |meta
: &MetaItem
, item
: &mut Option
<Symbol
>| {
246 handle_errors(sess
, meta
.span
, AttrError
::MultipleItem(meta
.path
.to_string()));
249 if let Some(v
) = meta
.value_str() {
253 span_err
!(diagnostic
, meta
.span
, E0539
, "incorrect meta item");
258 macro_rules
! get_meta
{
259 ($
($name
:ident
),+) => {
261 let mut $name
= None
;
264 if let Some(mi
) = meta
.meta_item() {
265 match mi
.name_or_empty() {
267 sym
::$name
=> if !get(mi
, &mut $name
) { continue 'outer }
,
270 let expected
= &[ $
( stringify
!($name
) ),+ ];
274 AttrError
::UnknownMetaItem(mi
.path
.to_string(), expected
),
283 AttrError
::UnsupportedLiteral(
284 "unsupported literal",
294 match meta
.name_or_empty() {
295 sym
::rustc_deprecated
=> {
296 if rustc_depr
.is_some() {
297 span_err
!(diagnostic
, item_sp
, E0540
,
298 "multiple rustc_deprecated attributes");
302 get_meta
!(since
, reason
, suggestion
);
304 match (since
, reason
) {
305 (Some(since
), Some(reason
)) => {
306 rustc_depr
= Some(RustcDeprecation
{
313 handle_errors(sess
, attr
.span
, AttrError
::MissingSince
);
317 span_err
!(diagnostic
, attr
.span
, E0543
, "missing 'reason'");
322 sym
::rustc_const_unstable
=> {
323 if rustc_const_unstable
.is_some() {
324 span_err
!(diagnostic
, item_sp
, E0553
,
325 "multiple rustc_const_unstable attributes");
330 if let Some(feature
) = feature
{
331 rustc_const_unstable
= Some(feature
);
333 span_err
!(diagnostic
, attr
.span
, E0629
, "missing 'feature'");
339 handle_errors(sess
, attr
.span
, AttrError
::MultipleStabilityLevels
);
343 let mut feature
= None
;
344 let mut reason
= None
;
345 let mut issue
= None
;
346 let mut is_soft
= false;
348 if let Some(mi
) = meta
.meta_item() {
349 match mi
.name_or_empty() {
350 sym
::feature
=> if !get(mi
, &mut feature
) { continue 'outer }
,
351 sym
::reason
=> if !get(mi
, &mut reason
) { continue 'outer }
,
352 sym
::issue
=> if !get(mi
, &mut issue
) { continue 'outer }
,
355 let msg
= "`soft` should not have any arguments";
356 sess
.span_diagnostic
.span_err(mi
.span
, msg
);
364 AttrError
::UnknownMetaItem(
366 &["feature", "reason", "issue", "soft"]
376 AttrError
::UnsupportedLiteral(
377 "unsupported literal",
385 match (feature
, reason
, issue
) {
386 (Some(feature
), reason
, Some(issue
)) => {
387 stab
= Some(Stability
{
391 if let Ok(issue
) = issue
.as_str().parse() {
394 span_err
!(diagnostic
, attr
.span
, E0545
,
395 "incorrect 'issue'");
403 const_stability
: None
,
405 allow_const_fn_ptr
: false,
409 handle_errors(sess
, attr
.span
, AttrError
::MissingFeature
);
413 span_err
!(diagnostic
, attr
.span
, E0547
, "missing 'issue'");
420 handle_errors(sess
, attr
.span
, AttrError
::MultipleStabilityLevels
);
424 let mut feature
= None
;
425 let mut since
= None
;
428 NestedMetaItem
::MetaItem(mi
) => {
429 match mi
.name_or_empty() {
430 sym
::feature
=> if !get(mi
, &mut feature
) { continue 'outer }
,
431 sym
::since
=> if !get(mi
, &mut since
) { continue 'outer }
,
436 AttrError
::UnknownMetaItem(
437 mi
.path
.to_string(), &["since", "note"],
444 NestedMetaItem
::Literal(lit
) => {
448 AttrError
::UnsupportedLiteral(
449 "unsupported literal",
458 match (feature
, since
) {
459 (Some(feature
), Some(since
)) => {
460 stab
= Some(Stability
{
466 const_stability
: None
,
468 allow_const_fn_ptr
: false,
472 handle_errors(sess
, attr
.span
, AttrError
::MissingFeature
);
476 handle_errors(sess
, attr
.span
, AttrError
::MissingSince
);
486 // Merge the deprecation info into the stability info
487 if let Some(rustc_depr
) = rustc_depr
{
488 if let Some(ref mut stab
) = stab
{
489 stab
.rustc_depr
= Some(rustc_depr
);
491 span_err
!(diagnostic
, item_sp
, E0549
,
492 "rustc_deprecated attribute must be paired with \
493 either stable or unstable attribute");
497 // Merge the const-unstable info into the stability info
498 if let Some(feature
) = rustc_const_unstable
{
499 if let Some(ref mut stab
) = stab
{
500 stab
.const_stability
= Some(feature
);
502 span_err
!(diagnostic
, item_sp
, E0630
,
503 "rustc_const_unstable attribute must be paired with \
504 either stable or unstable attribute");
508 // Merge the const-unstable info into the stability info
509 if promotable
|| allow_const_fn_ptr
{
510 if let Some(ref mut stab
) = stab
{
511 stab
.promotable
= promotable
;
512 stab
.allow_const_fn_ptr
= allow_const_fn_ptr
;
514 span_err
!(diagnostic
, item_sp
, E0717
,
515 "rustc_promotable and rustc_allow_const_fn_ptr attributes \
516 must be paired with either stable or unstable attribute");
523 pub fn find_crate_name(attrs
: &[Attribute
]) -> Option
<Symbol
> {
524 super::first_attr_value_str_by_name(attrs
, sym
::crate_name
)
527 /// Tests if a cfg-pattern matches the cfg set
528 pub fn cfg_matches(cfg
: &ast
::MetaItem
, sess
: &ParseSess
, features
: Option
<&Features
>) -> bool
{
529 eval_condition(cfg
, sess
, &mut |cfg
| {
530 if let (Some(feats
), Some(gated_cfg
)) = (features
, GatedCfg
::gate(cfg
)) {
531 gated_cfg
.check_and_emit(sess
, feats
);
533 let error
= |span
, msg
| { sess.span_diagnostic.span_err(span, msg); true }
;
534 if cfg
.path
.segments
.len() != 1 {
535 return error(cfg
.path
.span
, "`cfg` predicate key must be an identifier");
538 MetaItemKind
::List(..) => {
539 error(cfg
.span
, "unexpected parentheses after `cfg` predicate key")
541 MetaItemKind
::NameValue(lit
) if !lit
.node
.is_str() => {
545 AttrError
::UnsupportedLiteral(
546 "literal in `cfg` predicate value must be a string",
547 lit
.node
.is_bytestr()
552 MetaItemKind
::NameValue(..) | MetaItemKind
::Word
=> {
553 let ident
= cfg
.ident().expect("multi-segment cfg predicate");
554 sess
.config
.contains(&(ident
.name
, cfg
.value_str()))
560 /// Evaluate a cfg-like condition (with `any` and `all`), using `eval` to
561 /// evaluate individual items.
562 pub fn eval_condition
<F
>(cfg
: &ast
::MetaItem
, sess
: &ParseSess
, eval
: &mut F
)
564 where F
: FnMut(&ast
::MetaItem
) -> bool
567 ast
::MetaItemKind
::List(ref mis
) => {
568 for mi
in mis
.iter() {
569 if !mi
.is_meta_item() {
573 AttrError
::UnsupportedLiteral(
574 "unsupported literal",
582 // The unwraps below may look dangerous, but we've already asserted
583 // that they won't fail with the loop above.
584 match cfg
.name_or_empty() {
585 sym
::any
=> mis
.iter().any(|mi
| {
586 eval_condition(mi
.meta_item().unwrap(), sess
, eval
)
588 sym
::all
=> mis
.iter().all(|mi
| {
589 eval_condition(mi
.meta_item().unwrap(), sess
, eval
)
593 span_err
!(sess
.span_diagnostic
, cfg
.span
, E0536
, "expected 1 cfg-pattern");
597 !eval_condition(mis
[0].meta_item().unwrap(), sess
, eval
)
600 span_err
!(sess
.span_diagnostic
, cfg
.span
, E0537
,
601 "invalid predicate `{}`", cfg
.path
);
606 ast
::MetaItemKind
::Word
| ast
::MetaItemKind
::NameValue(..) => {
613 #[derive(RustcEncodable, RustcDecodable, PartialEq, PartialOrd, Clone, Debug, Eq, Hash)]
614 pub struct Deprecation
{
615 pub since
: Option
<Symbol
>,
616 pub note
: Option
<Symbol
>,
619 /// Finds the deprecation attribute. `None` if none exists.
620 pub fn find_deprecation(sess
: &ParseSess
, attrs
: &[Attribute
],
621 item_sp
: Span
) -> Option
<Deprecation
> {
622 find_deprecation_generic(sess
, attrs
.iter(), item_sp
)
625 fn find_deprecation_generic
<'a
, I
>(sess
: &ParseSess
,
628 -> Option
<Deprecation
>
629 where I
: Iterator
<Item
= &'a Attribute
>
631 let mut depr
: Option
<Deprecation
> = None
;
632 let diagnostic
= &sess
.span_diagnostic
;
634 'outer
: for attr
in attrs_iter
{
635 if !attr
.check_name(sym
::deprecated
) {
640 span_err
!(diagnostic
, item_sp
, E0550
, "multiple deprecated attributes");
644 let meta
= attr
.meta().unwrap();
645 depr
= match &meta
.node
{
646 MetaItemKind
::Word
=> Some(Deprecation { since: None, note: None }
),
647 MetaItemKind
::NameValue(..) => {
648 meta
.value_str().map(|note
| {
649 Deprecation { since: None, note: Some(note) }
652 MetaItemKind
::List(list
) => {
653 let get
= |meta
: &MetaItem
, item
: &mut Option
<Symbol
>| {
656 sess
, meta
.span
, AttrError
::MultipleItem(meta
.path
.to_string())
660 if let Some(v
) = meta
.value_str() {
664 if let Some(lit
) = meta
.name_value_literal() {
668 AttrError
::UnsupportedLiteral(
669 "literal in `deprecated` \
670 value must be a string",
671 lit
.node
.is_bytestr()
675 span_err
!(diagnostic
, meta
.span
, E0551
, "incorrect meta item");
682 let mut since
= None
;
686 NestedMetaItem
::MetaItem(mi
) => {
687 match mi
.name_or_empty() {
688 sym
::since
=> if !get(mi
, &mut since
) { continue 'outer }
,
689 sym
::note
=> if !get(mi
, &mut note
) { continue 'outer }
,
694 AttrError
::UnknownMetaItem(mi
.path
.to_string(),
701 NestedMetaItem
::Literal(lit
) => {
705 AttrError
::UnsupportedLiteral(
706 "item in `deprecated` must be a key/value pair",
715 Some(Deprecation { since, note }
)
723 #[derive(PartialEq, Debug, RustcEncodable, RustcDecodable, Copy, Clone)]
733 #[derive(Eq, Hash, PartialEq, Debug, RustcEncodable, RustcDecodable, Copy, Clone)]
735 SignedInt(ast
::IntTy
),
736 UnsignedInt(ast
::UintTy
)
741 pub fn is_signed(self) -> bool
{
745 SignedInt(..) => true,
746 UnsignedInt(..) => false
751 /// Parse #[repr(...)] forms.
753 /// Valid repr contents: any of the primitive integral type names (see
754 /// `int_type_of_word`, below) to specify enum discriminant type; `C`, to use
755 /// the same discriminant size that the corresponding C enum would or C
756 /// structure layout, `packed` to remove padding, and `transparent` to elegate representation
757 /// concerns to the only non-ZST field.
758 pub fn find_repr_attrs(sess
: &ParseSess
, attr
: &Attribute
) -> Vec
<ReprAttr
> {
761 let mut acc
= Vec
::new();
762 let diagnostic
= &sess
.span_diagnostic
;
763 if attr
.path
== sym
::repr
{
764 if let Some(items
) = attr
.meta_item_list() {
767 if !item
.is_meta_item() {
771 AttrError
::UnsupportedLiteral(
772 "meta item in `repr` must be an identifier",
779 let mut recognised
= false;
781 let hint
= match item
.name_or_empty() {
782 sym
::C
=> Some(ReprC
),
783 sym
::packed
=> Some(ReprPacked(1)),
784 sym
::simd
=> Some(ReprSimd
),
785 sym
::transparent
=> Some(ReprTransparent
),
786 name
=> int_type_of_word(name
).map(ReprInt
),
789 if let Some(h
) = hint
{
793 } else if let Some((name
, value
)) = item
.name_value_literal() {
794 let parse_alignment
= |node
: &ast
::LitKind
| -> Result
<u32, &'
static str> {
795 if let ast
::LitKind
::Int(literal
, ast
::LitIntType
::Unsuffixed
) = node
{
796 if literal
.is_power_of_two() {
797 // rustc::ty::layout::Align restricts align to <= 2^29
798 if *literal
<= 1 << 29 {
801 Err("larger than 2^29")
804 Err("not a power of two")
807 Err("not an unsuffixed integer")
811 let mut literal_error
= None
;
812 if name
== sym
::align
{
814 match parse_alignment(&value
.node
) {
815 Ok(literal
) => acc
.push(ReprAlign(literal
)),
816 Err(message
) => literal_error
= Some(message
)
819 else if name
== sym
::packed
{
821 match parse_alignment(&value
.node
) {
822 Ok(literal
) => acc
.push(ReprPacked(literal
)),
823 Err(message
) => literal_error
= Some(message
)
826 if let Some(literal_error
) = literal_error
{
827 span_err
!(diagnostic
, item
.span(), E0589
,
828 "invalid `repr(align)` attribute: {}", literal_error
);
831 if let Some(meta_item
) = item
.meta_item() {
832 if meta_item
.check_name(sym
::align
) {
833 if let MetaItemKind
::NameValue(ref value
) = meta_item
.node
{
835 let mut err
= struct_span_err
!(diagnostic
, item
.span(), E0693
,
836 "incorrect `repr(align)` attribute format");
838 ast
::LitKind
::Int(int
, ast
::LitIntType
::Unsuffixed
) => {
841 "use parentheses instead",
842 format
!("align({})", int
),
843 Applicability
::MachineApplicable
846 ast
::LitKind
::Str(s
, _
) => {
849 "use parentheses instead",
850 format
!("align({})", s
),
851 Applicability
::MachineApplicable
862 // Not a word we recognize
863 span_err
!(diagnostic
, item
.span(), E0552
,
864 "unrecognized representation hint");
872 fn int_type_of_word(s
: Symbol
) -> Option
<IntType
> {
876 sym
::i8 => Some(SignedInt(ast
::IntTy
::I8
)),
877 sym
::u8 => Some(UnsignedInt(ast
::UintTy
::U8
)),
878 sym
::i16 => Some(SignedInt(ast
::IntTy
::I16
)),
879 sym
::u16 => Some(UnsignedInt(ast
::UintTy
::U16
)),
880 sym
::i32 => Some(SignedInt(ast
::IntTy
::I32
)),
881 sym
::u32 => Some(UnsignedInt(ast
::UintTy
::U32
)),
882 sym
::i64 => Some(SignedInt(ast
::IntTy
::I64
)),
883 sym
::u64 => Some(UnsignedInt(ast
::UintTy
::U64
)),
884 sym
::i128
=> Some(SignedInt(ast
::IntTy
::I128
)),
885 sym
::u128
=> Some(UnsignedInt(ast
::UintTy
::U128
)),
886 sym
::isize => Some(SignedInt(ast
::IntTy
::Isize
)),
887 sym
::usize => Some(UnsignedInt(ast
::UintTy
::Usize
)),
892 pub enum TransparencyError
{
893 UnknownTransparency(Symbol
, Span
),
894 MultipleTransparencyAttrs(Span
, Span
),
897 pub fn find_transparency(
898 attrs
: &[Attribute
], is_legacy
: bool
899 ) -> (Transparency
, Option
<TransparencyError
>) {
900 let mut transparency
= None
;
901 let mut error
= None
;
903 if attr
.check_name(sym
::rustc_macro_transparency
) {
904 if let Some((_
, old_span
)) = transparency
{
905 error
= Some(TransparencyError
::MultipleTransparencyAttrs(old_span
, attr
.span
));
907 } else if let Some(value
) = attr
.value_str() {
908 transparency
= Some((match &*value
.as_str() {
909 "transparent" => Transparency
::Transparent
,
910 "semitransparent" => Transparency
::SemiTransparent
,
911 "opaque" => Transparency
::Opaque
,
913 error
= Some(TransparencyError
::UnknownTransparency(value
, attr
.span
));
920 let fallback
= if is_legacy { Transparency::SemiTransparent }
else { Transparency::Opaque }
;
921 (transparency
.map_or(fallback
, |t
| t
.0), error
)
924 pub fn check_builtin_macro_attribute(ecx
: &ExtCtxt
<'_
>, meta_item
: &MetaItem
, name
: Symbol
) {
925 // All the built-in macro attributes are "words" at the moment.
926 let template
= AttributeTemplate { word: true, list: None, name_value_str: None }
;
927 let attr
= ecx
.attribute(meta_item
.clone());
928 check_builtin_attribute(ecx
.parse_sess
, &attr
, name
, template
);
931 crate fn check_builtin_attribute(
932 sess
: &ParseSess
, attr
: &ast
::Attribute
, name
: Symbol
, template
: AttributeTemplate
934 // Some special attributes like `cfg` must be checked
935 // before the generic check, so we skip them here.
936 let should_skip
= |name
| name
== sym
::cfg
;
937 // Some of previously accepted forms were used in practice,
938 // report them as warnings for now.
939 let should_warn
= |name
| name
== sym
::doc
|| name
== sym
::ignore
||
940 name
== sym
::inline
|| name
== sym
::link
||
941 name
== sym
::test
|| name
== sym
::bench
;
943 match attr
.parse_meta(sess
) {
944 Ok(meta
) => if !should_skip(name
) && !template
.compatible(&meta
.node
) {
945 let error_msg
= format
!("malformed `{}` attribute input", name
);
946 let mut msg
= "attribute must be of the form ".to_owned();
947 let mut suggestions
= vec
![];
948 let mut first
= true;
951 let code
= format
!("#[{}]", name
);
952 msg
.push_str(&format
!("`{}`", &code
));
953 suggestions
.push(code
);
955 if let Some(descr
) = template
.list
{
957 msg
.push_str(" or ");
960 let code
= format
!("#[{}({})]", name
, descr
);
961 msg
.push_str(&format
!("`{}`", &code
));
962 suggestions
.push(code
);
964 if let Some(descr
) = template
.name_value_str
{
966 msg
.push_str(" or ");
968 let code
= format
!("#[{} = \"{}\"]", name
, descr
);
969 msg
.push_str(&format
!("`{}`", &code
));
970 suggestions
.push(code
);
972 if should_warn(name
) {
974 BufferedEarlyLintId
::IllFormedAttributeInput
,
980 sess
.span_diagnostic
.struct_span_err(meta
.span
, &error_msg
)
983 if suggestions
.len() == 1 {
984 "must be of the form"
986 "the following are the possible correct uses"
988 suggestions
.into_iter(),
989 Applicability
::HasPlaceholders
,
993 Err(mut err
) => err
.emit(),