|
1 |
| -use rustc_attr_data_structures::{AttributeKind, OptimizeAttr}; |
| 1 | +use rustc_attr_data_structures::{AttributeKind, OptimizeAttr, UsedBy}; |
2 | 2 | use rustc_feature::{AttributeTemplate, template};
|
3 | 3 | use rustc_session::parse::feature_err;
|
4 | 4 | use rustc_span::{Span, Symbol, sym};
|
@@ -201,3 +201,84 @@ impl<S: Stage> SingleAttributeParser<S> for NoMangleParser {
|
201 | 201 | Some(AttributeKind::NoMangle(cx.attr_span))
|
202 | 202 | }
|
203 | 203 | }
|
| 204 | + |
| 205 | +#[derive(Default)] |
| 206 | +pub(crate) struct UsedParser { |
| 207 | + first_compiler: Option<Span>, |
| 208 | + first_linker: Option<Span>, |
| 209 | +} |
| 210 | + |
| 211 | +// A custom `AttributeParser` is used rather than a Simple attribute parser because |
| 212 | +// - Specifying two `#[used]` attributes is a warning (but will be an error in the future) |
| 213 | +// - But specifying two conflicting attributes: `#[used(compiler)]` and `#[used(linker)]` is already an error today |
| 214 | +// We can change this to a Simple parser once the warning becomes an error |
| 215 | +impl<S: Stage> AttributeParser<S> for UsedParser { |
| 216 | + const ATTRIBUTES: AcceptMapping<Self, S> = &[( |
| 217 | + &[sym::used], |
| 218 | + template!(Word, List: "compiler|linker"), |
| 219 | + |group: &mut Self, cx, args| { |
| 220 | + let used_by = match args { |
| 221 | + ArgParser::NoArgs => UsedBy::Linker, |
| 222 | + ArgParser::List(list) => { |
| 223 | + let Some(l) = list.single() else { |
| 224 | + cx.expected_single_argument(list.span); |
| 225 | + return; |
| 226 | + }; |
| 227 | + |
| 228 | + match l.meta_item().and_then(|i| i.path().word_sym()) { |
| 229 | + Some(sym::compiler) => { |
| 230 | + if !cx.features().used_with_arg() { |
| 231 | + feature_err( |
| 232 | + &cx.sess(), |
| 233 | + sym::used_with_arg, |
| 234 | + cx.attr_span, |
| 235 | + "`#[used(compiler)]` is currently unstable", |
| 236 | + ) |
| 237 | + .emit(); |
| 238 | + } |
| 239 | + UsedBy::Compiler |
| 240 | + } |
| 241 | + Some(sym::linker) => { |
| 242 | + if !cx.features().used_with_arg() { |
| 243 | + feature_err( |
| 244 | + &cx.sess(), |
| 245 | + sym::used_with_arg, |
| 246 | + cx.attr_span, |
| 247 | + "`#[used(linker)]` is currently unstable", |
| 248 | + ) |
| 249 | + .emit(); |
| 250 | + } |
| 251 | + UsedBy::Linker |
| 252 | + } |
| 253 | + _ => { |
| 254 | + cx.expected_specific_argument(l.span(), vec!["compiler", "linker"]); |
| 255 | + return; |
| 256 | + } |
| 257 | + } |
| 258 | + } |
| 259 | + ArgParser::NameValue(_) => return, |
| 260 | + }; |
| 261 | + |
| 262 | + let target = match used_by { |
| 263 | + UsedBy::Compiler => &mut group.first_compiler, |
| 264 | + UsedBy::Linker => &mut group.first_linker, |
| 265 | + }; |
| 266 | + |
| 267 | + let attr_span = cx.attr_span; |
| 268 | + if let Some(prev) = *target { |
| 269 | + cx.warn_unused_duplicate(prev, attr_span); |
| 270 | + } else { |
| 271 | + *target = Some(attr_span); |
| 272 | + } |
| 273 | + }, |
| 274 | + )]; |
| 275 | + |
| 276 | + fn finalize(self, _cx: &FinalizeContext<'_, '_, S>) -> Option<AttributeKind> { |
| 277 | + // Ratcheting behaviour, if both `linker` and `compiler` are specified, use `linker` |
| 278 | + Some(match (self.first_compiler, self.first_linker) { |
| 279 | + (_, Some(span)) => AttributeKind::Used { used_by: UsedBy::Linker, span }, |
| 280 | + (Some(span), _) => AttributeKind::Used { used_by: UsedBy::Compiler, span }, |
| 281 | + (None, None) => return None, |
| 282 | + }) |
| 283 | + } |
| 284 | +} |
0 commit comments