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