Skip to content

Commit a3070a3

Browse files
committed
feat: allow multiple suggestions for malformed crate_type attribute
1 parent 9337f7a commit a3070a3

File tree

14 files changed

+214
-192
lines changed

14 files changed

+214
-192
lines changed

compiler/rustc_builtin_macros/src/cfg_accessible.rs

+3-4
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,7 @@ use rustc_ast as ast;
44
use rustc_expand::base::{Annotatable, ExpandResult, ExtCtxt, Indeterminate, MultiItemModifier};
55
use rustc_feature::AttributeTemplate;
66
use rustc_parse::validate_attr;
7-
use rustc_span::symbol::sym;
8-
use rustc_span::Span;
7+
use rustc_span::{Span, sym};
98

109
use crate::errors;
1110

@@ -45,9 +44,9 @@ impl MultiItemModifier for Expander {
4544
item: Annotatable,
4645
_is_derive_const: bool,
4746
) -> ExpandResult<Vec<Annotatable>, Annotatable> {
48-
let template = AttributeTemplate { list: Some("path"), ..Default::default() };
47+
let template = AttributeTemplate { list: Some(&["path"]), ..Default::default() };
48+
4949
validate_attr::check_builtin_meta_item(
50-
&ecx.ecfg.features,
5150
&ecx.sess.psess,
5251
meta_item,
5352
ast::AttrStyle::Outer,

compiler/rustc_builtin_macros/src/derive.rs

+9-9
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,12 @@
11
use rustc_ast as ast;
2-
use rustc_ast::{GenericParamKind, ItemKind, MetaItemKind, NestedMetaItem, StmtKind};
2+
use rustc_ast::{GenericParamKind, ItemKind, MetaItemInner, MetaItemKind, StmtKind};
33
use rustc_expand::base::{
44
Annotatable, DeriveResolution, ExpandResult, ExtCtxt, Indeterminate, MultiItemModifier,
55
};
66
use rustc_feature::AttributeTemplate;
77
use rustc_parse::validate_attr;
88
use rustc_session::Session;
9-
use rustc_span::symbol::{sym, Ident};
10-
use rustc_span::{ErrorGuaranteed, Span};
9+
use rustc_span::{ErrorGuaranteed, Ident, Span, sym};
1110

1211
use crate::cfg_eval::cfg_eval;
1312
use crate::errors;
@@ -35,10 +34,11 @@ impl MultiItemModifier for Expander {
3534
let (sess, features) = (ecx.sess, ecx.ecfg.features);
3635
let result =
3736
ecx.resolver.resolve_derives(ecx.current_expansion.id, ecx.force_mode, &|| {
38-
let template =
39-
AttributeTemplate { list: Some("Trait1, Trait2, ..."), ..Default::default() };
37+
let template = AttributeTemplate {
38+
list: Some(&["Trait1", "Trait2", "..."]),
39+
..Default::default()
40+
};
4041
validate_attr::check_builtin_meta_item(
41-
features,
4242
&sess.psess,
4343
meta_item,
4444
ast::AttrStyle::Outer,
@@ -50,9 +50,9 @@ impl MultiItemModifier for Expander {
5050
let mut resolutions = match &meta_item.kind {
5151
MetaItemKind::List(list) => {
5252
list.iter()
53-
.filter_map(|nested_meta| match nested_meta {
54-
NestedMetaItem::MetaItem(meta) => Some(meta),
55-
NestedMetaItem::Lit(lit) => {
53+
.filter_map(|meta_item_inner| match meta_item_inner {
54+
MetaItemInner::MetaItem(meta) => Some(meta),
55+
MetaItemInner::Lit(lit) => {
5656
// Reject `#[derive("Debug")]`.
5757
report_unexpected_meta_item_lit(sess, lit);
5858
None

compiler/rustc_feature/src/builtin_attrs.rs

+149-120
Large diffs are not rendered by default.

compiler/rustc_parse/src/validate_attr.rs

+27-48
Original file line numberDiff line numberDiff line change
@@ -3,22 +3,19 @@
33
use rustc_ast::token::Delimiter;
44
use rustc_ast::tokenstream::DelimSpan;
55
use rustc_ast::{
6-
self as ast, AttrArgs, AttrArgsEq, Attribute, DelimArgs, MetaItem, MetaItemKind,
7-
NestedMetaItem, Safety,
6+
self as ast, AttrArgs, Attribute, DelimArgs, MetaItem, MetaItemInner, MetaItemKind, Safety,
87
};
98
use rustc_errors::{Applicability, FatalError, PResult};
10-
use rustc_feature::{
11-
AttributeSafety, AttributeTemplate, BuiltinAttribute, Features, BUILTIN_ATTRIBUTE_MAP,
12-
};
9+
use rustc_feature::{AttributeSafety, AttributeTemplate, BUILTIN_ATTRIBUTE_MAP, BuiltinAttribute};
1310
use rustc_session::errors::report_lit_error;
14-
use rustc_session::lint::builtin::{ILL_FORMED_ATTRIBUTE_INPUT, UNSAFE_ATTR_OUTSIDE_UNSAFE};
1511
use rustc_session::lint::BuiltinLintDiag;
12+
use rustc_session::lint::builtin::{ILL_FORMED_ATTRIBUTE_INPUT, UNSAFE_ATTR_OUTSIDE_UNSAFE};
1613
use rustc_session::parse::ParseSess;
17-
use rustc_span::{sym, BytePos, Span, Symbol};
14+
use rustc_span::{Span, Symbol, sym};
1815

1916
use crate::{errors, parse_in};
2017

21-
pub fn check_attr(features: &Features, psess: &ParseSess, attr: &Attribute) {
18+
pub fn check_attr(psess: &ParseSess, attr: &Attribute) {
2219
if attr.is_doc_comment() {
2320
return;
2421
}
@@ -28,24 +25,24 @@ pub fn check_attr(features: &Features, psess: &ParseSess, attr: &Attribute) {
2825

2926
// All non-builtin attributes are considered safe
3027
let safety = attr_info.map(|x| x.safety).unwrap_or(AttributeSafety::Normal);
31-
check_attribute_safety(features, psess, safety, attr);
28+
check_attribute_safety(psess, safety, attr);
3229

3330
// Check input tokens for built-in and key-value attributes.
3431
match attr_info {
3532
// `rustc_dummy` doesn't have any restrictions specific to built-in attributes.
3633
Some(BuiltinAttribute { name, template, .. }) if *name != sym::rustc_dummy => {
3734
match parse_meta(psess, attr) {
3835
// Don't check safety again, we just did that
39-
Ok(meta) => check_builtin_meta_item(
40-
features, psess, &meta, attr.style, *name, *template, false,
41-
),
36+
Ok(meta) => {
37+
check_builtin_meta_item(psess, &meta, attr.style, *name, *template, false)
38+
}
4239
Err(err) => {
4340
err.emit();
4441
}
4542
}
4643
}
4744
_ => {
48-
if let AttrArgs::Eq(..) = attr_item.args {
45+
if let AttrArgs::Eq { .. } = attr_item.args {
4946
// All key-value attributes are restricted to meta-item syntax.
5047
match parse_meta(psess, attr) {
5148
Ok(_) => {}
@@ -72,7 +69,7 @@ pub fn parse_meta<'a>(psess: &'a ParseSess, attr: &Attribute) -> PResult<'a, Met
7269
parse_in(psess, tokens.clone(), "meta list", |p| p.parse_meta_seq_top())?;
7370
MetaItemKind::List(nmis)
7471
}
75-
AttrArgs::Eq(_, AttrArgsEq::Ast(expr)) => {
72+
AttrArgs::Eq { expr, .. } => {
7673
if let ast::ExprKind::Lit(token_lit) = expr.kind {
7774
let res = ast::MetaItemLit::from_token_lit(token_lit, expr.span);
7875
let res = match res {
@@ -118,7 +115,6 @@ pub fn parse_meta<'a>(psess: &'a ParseSess, attr: &Attribute) -> PResult<'a, Met
118115
return Err(err);
119116
}
120117
}
121-
AttrArgs::Eq(_, AttrArgsEq::Hir(lit)) => MetaItemKind::NameValue(lit.clone()),
122118
},
123119
})
124120
}
@@ -145,7 +141,7 @@ pub(super) fn check_cfg_attr_bad_delim(psess: &ParseSess, span: DelimSpan, delim
145141

146142
/// Checks that the given meta-item is compatible with this `AttributeTemplate`.
147143
fn is_attr_template_compatible(template: &AttributeTemplate, meta: &ast::MetaItemKind) -> bool {
148-
let is_one_allowed_subword = |items: &[NestedMetaItem]| match items {
144+
let is_one_allowed_subword = |items: &[MetaItemInner]| match items {
149145
[item] => item.is_word() && template.one_of.iter().any(|&word| item.has_name(word)),
150146
_ => false,
151147
};
@@ -157,16 +153,7 @@ fn is_attr_template_compatible(template: &AttributeTemplate, meta: &ast::MetaIte
157153
}
158154
}
159155

160-
pub fn check_attribute_safety(
161-
features: &Features,
162-
psess: &ParseSess,
163-
safety: AttributeSafety,
164-
attr: &Attribute,
165-
) {
166-
if !features.unsafe_attributes {
167-
return;
168-
}
169-
156+
pub fn check_attribute_safety(psess: &ParseSess, safety: AttributeSafety, attr: &Attribute) {
170157
let attr_item = attr.get_normal_item();
171158

172159
if safety == AttributeSafety::Unsafe {
@@ -177,11 +164,7 @@ pub fn check_attribute_safety(
177164
// wrapping it in `unsafe(...)`. Otherwise, we suggest putting the
178165
// `unsafe(`, `)` right after and right before the opening and closing
179166
// square bracket respectively.
180-
let diag_span = if attr_item.span().can_be_used_for_suggestions() {
181-
attr_item.span()
182-
} else {
183-
attr.span.with_lo(attr.span.lo() + BytePos(2)).with_hi(attr.span.hi() - BytePos(1))
184-
};
167+
let diag_span = attr_item.span();
185168

186169
if attr.span.at_least_rust_2024() {
187170
psess.dcx().emit_err(errors::UnsafeAttrOutsideUnsafe {
@@ -203,33 +186,28 @@ pub fn check_attribute_safety(
203186
);
204187
}
205188
}
206-
} else {
207-
if let Safety::Unsafe(unsafe_span) = attr_item.unsafety {
208-
psess.dcx().emit_err(errors::InvalidAttrUnsafe {
209-
span: unsafe_span,
210-
name: attr_item.path.clone(),
211-
});
212-
}
189+
} else if let Safety::Unsafe(unsafe_span) = attr_item.unsafety {
190+
psess.dcx().emit_err(errors::InvalidAttrUnsafe {
191+
span: unsafe_span,
192+
name: attr_item.path.clone(),
193+
});
213194
}
214195
}
215196

216197
// Called by `check_builtin_meta_item` and code that manually denies
217198
// `unsafe(...)` in `cfg`
218-
pub fn deny_builtin_meta_unsafety(features: &Features, psess: &ParseSess, meta: &MetaItem) {
199+
pub fn deny_builtin_meta_unsafety(psess: &ParseSess, meta: &MetaItem) {
219200
// This only supports denying unsafety right now - making builtin attributes
220201
// support unsafety will requite us to thread the actual `Attribute` through
221202
// for the nice diagnostics.
222-
if features.unsafe_attributes {
223-
if let Safety::Unsafe(unsafe_span) = meta.unsafety {
224-
psess
225-
.dcx()
226-
.emit_err(errors::InvalidAttrUnsafe { span: unsafe_span, name: meta.path.clone() });
227-
}
203+
if let Safety::Unsafe(unsafe_span) = meta.unsafety {
204+
psess
205+
.dcx()
206+
.emit_err(errors::InvalidAttrUnsafe { span: unsafe_span, name: meta.path.clone() });
228207
}
229208
}
230209

231210
pub fn check_builtin_meta_item(
232-
features: &Features,
233211
psess: &ParseSess,
234212
meta: &MetaItem,
235213
style: ast::AttrStyle,
@@ -246,7 +224,7 @@ pub fn check_builtin_meta_item(
246224
}
247225

248226
if deny_unsafety {
249-
deny_builtin_meta_unsafety(features, psess, meta);
227+
deny_builtin_meta_unsafety(psess, meta);
250228
}
251229
}
252230

@@ -270,7 +248,8 @@ fn emit_malformed_attribute(
270248
suggestions.push(format!("#{inner}[{name}]"));
271249
}
272250
if let Some(descr) = template.list {
273-
suggestions.push(format!("#{inner}[{name}({descr})]"));
251+
let descr_formatted = descr.join(", ");
252+
suggestions.push(format!("#{inner}[{name}({descr_formatted})]"));
274253
}
275254
suggestions.extend(template.one_of.iter().map(|&word| format!("#{inner}[{name}({word})]")));
276255
if let Some(descr) = template.name_value_str {

library/backtrace

library/stdarch

Submodule stdarch updated 115 files

src/doc/book

Submodule book updated 1009 files

src/doc/edition-guide

Submodule edition-guide updated 43 files

src/doc/reference

Submodule reference updated 108 files

src/doc/rust-by-example

Submodule rust-by-example updated 103 files

src/tools/cargo

Submodule cargo updated 1063 files

src/tools/rust-analyzer/crates/hir-expand/src/inert_attr_macro.rs

+17-2
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ pub struct BuiltinAttribute {
2323
#[derive(Clone, Copy)]
2424
pub struct AttributeTemplate {
2525
pub word: bool,
26-
pub list: Option<&'static str>,
26+
pub list: Option<&'static [&'static str]>,
2727
pub name_value_str: Option<&'static str>,
2828
}
2929

@@ -464,6 +464,9 @@ pub const INERT_ATTRIBUTES: &[BuiltinAttribute] = &[
464464
// Used by the `rustc::potential_query_instability` lint to warn methods which
465465
// might not be stable during incremental compilation.
466466
rustc_attr!(rustc_lint_query_instability, Normal, template!(Word), WarnFollowing, INTERNAL_UNSTABLE),
467+
// Used by the `rustc::untracked_query_information` lint to warn methods which
468+
// might break incremental compilation.
469+
rustc_attr!(rustc_lint_untracked_query_information, Normal, template!(Word), WarnFollowing, INTERNAL_UNSTABLE),
467470
// Used by the `rustc::untranslatable_diagnostic` and `rustc::diagnostic_outside_of_impl` lints
468471
// to assist in changes to diagnostic APIs.
469472
rustc_attr!(rustc_lint_diagnostics, Normal, template!(Word), WarnFollowing, INTERNAL_UNSTABLE),
@@ -629,6 +632,19 @@ pub const INERT_ATTRIBUTES: &[BuiltinAttribute] = &[
629632
rustc_safe_intrinsic, Normal, template!(Word), WarnFollowing,
630633
"the `#[rustc_safe_intrinsic]` attribute is used internally to mark intrinsics as safe"
631634
),
635+
rustc_attr!(
636+
rustc_intrinsic, Normal, template!(Word), ErrorFollowing,
637+
"the `#[rustc_intrinsic]` attribute is used to declare intrinsics with function bodies",
638+
),
639+
rustc_attr!(
640+
rustc_no_mir_inline, Normal, template!(Word), WarnFollowing,
641+
"#[rustc_no_mir_inline] prevents the MIR inliner from inlining a function while not affecting codegen"
642+
),
643+
rustc_attr!(
644+
rustc_intrinsic_must_be_overridden, Normal, template!(Word), ErrorFollowing,
645+
"the `#[rustc_intrinsic_must_be_overridden]` attribute is used to declare intrinsics without real bodies",
646+
),
647+
632648
rustc_attr!(
633649
rustc_deprecated_safe_2024, Normal, template!(Word), WarnFollowing,
634650
"the `#[rustc_safe_intrinsic]` marks functions as unsafe in Rust 2024",
@@ -679,7 +695,6 @@ pub const INERT_ATTRIBUTES: &[BuiltinAttribute] = &[
679695
template!(List: r#"cfg = "...", module = "...", kind = "...""#), DuplicatesOk,
680696
),
681697
rustc_attr!(TEST, rustc_symbol_name, Normal, template!(Word), WarnFollowing),
682-
rustc_attr!(TEST, rustc_polymorphize_error, Normal, template!(Word), WarnFollowing),
683698
rustc_attr!(TEST, rustc_def_path, Normal, template!(Word), WarnFollowing),
684699
rustc_attr!(TEST, rustc_mir, Normal, template!(List: "arg1, arg2, ..."), DuplicatesOk),
685700
gated!(

0 commit comments

Comments
 (0)