|
1 |
| -use rustc_attr_data_structures::{AttributeKind, OptimizeAttr}; |
| 1 | +use rustc_attr_data_structures::lints::AttributeLintKind; |
| 2 | +use rustc_attr_data_structures::{AttributeKind, OptimizeAttr, UsedBy}; |
2 | 3 | use rustc_feature::{AttributeTemplate, template};
|
3 |
| -use rustc_span::sym; |
| 4 | +use rustc_session::parse::feature_err; |
| 5 | +use rustc_span::{Span, sym}; |
4 | 6 |
|
5 |
| -use super::{AttributeOrder, OnDuplicate, SingleAttributeParser}; |
6 |
| -use crate::context::{AcceptContext, Stage}; |
| 7 | +use super::{AcceptMapping, AttributeOrder, AttributeParser, OnDuplicate, SingleAttributeParser}; |
| 8 | +use crate::context::{AcceptContext, FinalizeContext, Stage}; |
7 | 9 | use crate::parser::ArgParser;
|
8 | 10 |
|
9 | 11 | pub(crate) struct OptimizeParser;
|
@@ -56,3 +58,90 @@ impl<S: Stage> SingleAttributeParser<S> for ColdParser {
|
56 | 58 | Some(AttributeKind::Cold(cx.attr_span))
|
57 | 59 | }
|
58 | 60 | }
|
| 61 | + |
| 62 | +#[derive(Default)] |
| 63 | +pub(crate) struct UsedParser { |
| 64 | + first_compiler: Option<Span>, |
| 65 | + first_linker: Option<Span>, |
| 66 | +} |
| 67 | + |
| 68 | +// A custom `AttributeParser` is used rather than a Simple attribute parser because |
| 69 | +// - Specifying two `#[used]` attributes is a warning (but will be an error in the future) |
| 70 | +// - But specifying two conflicting attributes: `#[used(compiler)]` and `#[used(linker)]` is already an error today |
| 71 | +// We can change this to a Simple parser once the warning becomes an error |
| 72 | +impl<S: Stage> AttributeParser<S> for UsedParser { |
| 73 | + const ATTRIBUTES: AcceptMapping<Self, S> = &[( |
| 74 | + &[sym::used], |
| 75 | + template!(Word, List: "compiler|linker"), |
| 76 | + |group: &mut Self, cx, args| { |
| 77 | + let used_by = match args { |
| 78 | + ArgParser::NoArgs => UsedBy::Linker, |
| 79 | + ArgParser::List(list) => { |
| 80 | + let Some(l) = list.single() else { |
| 81 | + cx.expected_single_argument(list.span); |
| 82 | + return; |
| 83 | + }; |
| 84 | + |
| 85 | + match l.meta_item().and_then(|i| i.path().word_sym()) { |
| 86 | + Some(sym::compiler) => { |
| 87 | + if !cx.features().used_with_arg() { |
| 88 | + feature_err( |
| 89 | + &cx.sess(), |
| 90 | + sym::used_with_arg, |
| 91 | + cx.attr_span, |
| 92 | + "`#[used(compiler)]` is currently unstable", |
| 93 | + ) |
| 94 | + .emit(); |
| 95 | + } |
| 96 | + UsedBy::Compiler |
| 97 | + } |
| 98 | + Some(sym::linker) => { |
| 99 | + if !cx.features().used_with_arg() { |
| 100 | + feature_err( |
| 101 | + &cx.sess(), |
| 102 | + sym::used_with_arg, |
| 103 | + cx.attr_span, |
| 104 | + "`#[used(linker)]` is currently unstable", |
| 105 | + ) |
| 106 | + .emit(); |
| 107 | + } |
| 108 | + UsedBy::Linker |
| 109 | + } |
| 110 | + _ => { |
| 111 | + cx.expected_specific_argument(l.span(), vec!["compiler", "linker"]); |
| 112 | + return; |
| 113 | + } |
| 114 | + } |
| 115 | + } |
| 116 | + ArgParser::NameValue(_) => return, |
| 117 | + }; |
| 118 | + |
| 119 | + let target = match used_by { |
| 120 | + UsedBy::Compiler => &mut group.first_compiler, |
| 121 | + UsedBy::Linker => &mut group.first_linker, |
| 122 | + }; |
| 123 | + |
| 124 | + if let Some(prev) = *target { |
| 125 | + cx.emit_lint( |
| 126 | + AttributeLintKind::UnusedDuplicate { |
| 127 | + this: cx.attr_span, |
| 128 | + other: prev, |
| 129 | + warning: false, |
| 130 | + }, |
| 131 | + cx.attr_span, |
| 132 | + ); |
| 133 | + } else { |
| 134 | + *target = Some(cx.attr_span); |
| 135 | + } |
| 136 | + }, |
| 137 | + )]; |
| 138 | + |
| 139 | + fn finalize(self, _cx: &FinalizeContext<'_, '_, S>) -> Option<AttributeKind> { |
| 140 | + // Ratcheting behaviour, if both `linker` and `compiler` are specified, use `linker` |
| 141 | + Some(match (self.first_compiler, self.first_linker) { |
| 142 | + (_, Some(span)) => AttributeKind::Used { used_by: UsedBy::Linker, span }, |
| 143 | + (Some(span), _) => AttributeKind::Used { used_by: UsedBy::Compiler, span }, |
| 144 | + (None, None) => return None, |
| 145 | + }) |
| 146 | + } |
| 147 | +} |
0 commit comments