Skip to content

Commit 52b9195

Browse files
Auto merge of #143963 - JonathanBrouwer:rework-illformed-attr, r=<try>
Move attribute validation from `rustc_parse` to `rustc_attr_parsing` This moves the old attribute validation from `rustc_parse` to `rustc_attr_parsing`. This PR is easiest to review commit-by-commit. This is part 1 of 2, of a fix for #143940, the perfomance regression caused by #143460. This PR does not yet fix the performance regression but does the refactoring work to prepare for fixing it. After all these changes there should be no functional change to the compiler, other than some re-ordering of the errors.
2 parents 0864097 + cff21c0 commit 52b9195

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

46 files changed

+842
-825
lines changed

Cargo.lock

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3275,7 +3275,6 @@ dependencies = [
32753275
"rustc_feature",
32763276
"rustc_fluent_macro",
32773277
"rustc_macros",
3278-
"rustc_parse",
32793278
"rustc_session",
32803279
"rustc_span",
32813280
"rustc_target",
@@ -3321,6 +3320,7 @@ dependencies = [
33213320
"rustc_hir",
33223321
"rustc_lexer",
33233322
"rustc_macros",
3323+
"rustc_parse",
33243324
"rustc_session",
33253325
"rustc_span",
33263326
"thin-vec",

compiler/rustc_ast_passes/Cargo.toml

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,6 @@ rustc_errors = { path = "../rustc_errors" }
1515
rustc_feature = { path = "../rustc_feature" }
1616
rustc_fluent_macro = { path = "../rustc_fluent_macro" }
1717
rustc_macros = { path = "../rustc_macros" }
18-
rustc_parse = { path = "../rustc_parse" }
1918
rustc_session = { path = "../rustc_session" }
2019
rustc_span = { path = "../rustc_span" }
2120
rustc_target = { path = "../rustc_target" }

compiler/rustc_ast_passes/src/ast_validation.rs

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,6 @@ use rustc_ast_pretty::pprust::{self, State};
2929
use rustc_data_structures::fx::FxIndexMap;
3030
use rustc_errors::DiagCtxtHandle;
3131
use rustc_feature::Features;
32-
use rustc_parse::validate_attr;
3332
use rustc_session::Session;
3433
use rustc_session::lint::builtin::{
3534
DEPRECATED_WHERE_CLAUSE_LOCATION, MISSING_ABI, MISSING_UNSAFE_ON_EXTERN,
@@ -928,10 +927,6 @@ fn validate_generic_param_order(dcx: DiagCtxtHandle<'_>, generics: &[GenericPara
928927
}
929928

930929
impl<'a> Visitor<'a> for AstValidator<'a> {
931-
fn visit_attribute(&mut self, attr: &Attribute) {
932-
validate_attr::check_attr(&self.sess.psess, attr, self.lint_node_id);
933-
}
934-
935930
fn visit_ty(&mut self, ty: &'a Ty) {
936931
self.visit_ty_common(ty);
937932
self.walk_ty(ty)

compiler/rustc_attr_data_structures/src/lints.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,4 +13,5 @@ pub enum AttributeLintKind {
1313
UnusedDuplicate { this: Span, other: Span, warning: bool },
1414
IllFormedAttributeInput { suggestions: Vec<String> },
1515
EmptyAttribute { first_span: Span },
16+
UnsafeAttrOutsideUnsafe { attribute_name_span: Span, sugg_spans: (Span, Span) },
1617
}

compiler/rustc_attr_parsing/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ rustc_fluent_macro = { path = "../rustc_fluent_macro" }
1515
rustc_hir = { path = "../rustc_hir" }
1616
rustc_lexer = { path = "../rustc_lexer" }
1717
rustc_macros = { path = "../rustc_macros" }
18+
rustc_parse = { path = "../rustc_parse" }
1819
rustc_session = { path = "../rustc_session" }
1920
rustc_span = { path = "../rustc_span" }
2021
thin-vec = "0.2.12"

compiler/rustc_attr_parsing/messages.ftl

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -161,3 +161,12 @@ attr_parsing_unused_multiple =
161161
162162
-attr_parsing_previously_accepted =
163163
this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
164+
165+
attr_parsing_unsafe_attr_outside_unsafe = unsafe attribute used without unsafe
166+
.label = usage of unsafe attribute
167+
attr_parsing_unsafe_attr_outside_unsafe_suggestion = wrap the attribute in `unsafe(...)`
168+
169+
attr_parsing_invalid_attr_unsafe = `{$name}` is not an unsafe attribute
170+
.label = this is not an unsafe attribute
171+
.suggestion = remove the `unsafe(...)`
172+
.note = extraneous unsafe is not allowed in attributes

compiler/rustc_attr_parsing/src/attributes/stability.rs

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -247,7 +247,12 @@ pub(crate) fn parse_stability<S: Stage>(
247247
let mut feature = None;
248248
let mut since = None;
249249

250-
for param in args.list()?.mixed() {
250+
let ArgParser::List(list) = args else {
251+
cx.expected_list(cx.attr_span);
252+
return None;
253+
};
254+
255+
for param in list.mixed() {
251256
let param_span = param.span();
252257
let Some(param) = param.meta_item() else {
253258
cx.emit_err(session_diagnostics::UnsupportedLiteral {
@@ -322,7 +327,13 @@ pub(crate) fn parse_unstability<S: Stage>(
322327
let mut is_soft = false;
323328
let mut implied_by = None;
324329
let mut old_name = None;
325-
for param in args.list()?.mixed() {
330+
331+
let ArgParser::List(list) = args else {
332+
cx.expected_list(cx.attr_span);
333+
return None;
334+
};
335+
336+
for param in list.mixed() {
326337
let Some(param) = param.meta_item() else {
327338
cx.emit_err(session_diagnostics::UnsupportedLiteral {
328339
span: param.span(),

compiler/rustc_attr_parsing/src/context.rs

Lines changed: 36 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -203,10 +203,11 @@ mod private {
203203
#[allow(private_interfaces)]
204204
pub trait Stage: Sized + 'static + Sealed {
205205
type Id: Copy;
206-
const SHOULD_EMIT_LINTS: bool;
207206

208207
fn parsers() -> &'static group_type!(Self);
209208

209+
fn should_emit_errors_and_lints(&self) -> bool;
210+
210211
fn emit_err<'sess>(
211212
&self,
212213
sess: &'sess Session,
@@ -218,11 +219,15 @@ pub trait Stage: Sized + 'static + Sealed {
218219
#[allow(private_interfaces)]
219220
impl Stage for Early {
220221
type Id = NodeId;
221-
const SHOULD_EMIT_LINTS: bool = false;
222222

223223
fn parsers() -> &'static group_type!(Self) {
224224
&early::ATTRIBUTE_PARSERS
225225
}
226+
227+
fn should_emit_errors_and_lints(&self) -> bool {
228+
self.emit_errors.should_emit()
229+
}
230+
226231
fn emit_err<'sess>(
227232
&self,
228233
sess: &'sess Session,
@@ -240,11 +245,15 @@ impl Stage for Early {
240245
#[allow(private_interfaces)]
241246
impl Stage for Late {
242247
type Id = HirId;
243-
const SHOULD_EMIT_LINTS: bool = true;
244248

245249
fn parsers() -> &'static group_type!(Self) {
246250
&late::ATTRIBUTE_PARSERS
247251
}
252+
253+
fn should_emit_errors_and_lints(&self) -> bool {
254+
true
255+
}
256+
248257
fn emit_err<'sess>(
249258
&self,
250259
tcx: &'sess Session,
@@ -290,7 +299,7 @@ impl<'f, 'sess: 'f, S: Stage> SharedContext<'f, 'sess, S> {
290299
/// must be delayed until after HIR is built. This method will take care of the details of
291300
/// that.
292301
pub(crate) fn emit_lint(&mut self, lint: AttributeLintKind, span: Span) {
293-
if !S::SHOULD_EMIT_LINTS {
302+
if !self.stage.should_emit_errors_and_lints() {
294303
return;
295304
}
296305
let id = self.target_id;
@@ -696,6 +705,22 @@ impl<'sess> AttributeParser<'sess, Early> {
696705
};
697706
parse_fn(&mut cx, args)
698707
}
708+
709+
/// Returns whether the attribute is valid
710+
pub fn validate_attribute_early(
711+
sess: &'sess Session,
712+
attr: &ast::Attribute,
713+
target_node_id: NodeId,
714+
) -> bool {
715+
let parser = Self {
716+
features: None,
717+
tools: Vec::new(),
718+
parse_only: None,
719+
sess,
720+
stage: Early { emit_errors: ShouldEmit::ErrorsAndLints },
721+
};
722+
parser.validate_attribute(attr, target_node_id, &mut |_| {}, true)
723+
}
699724
}
700725

701726
impl<'sess, S: Stage> AttributeParser<'sess, S> {
@@ -712,6 +737,10 @@ impl<'sess, S: Stage> AttributeParser<'sess, S> {
712737
&self.sess
713738
}
714739

740+
pub(crate) fn stage(&self) -> &S {
741+
&self.stage
742+
}
743+
715744
pub(crate) fn features(&self) -> &'sess Features {
716745
self.features.expect("features not available at this point in the compiler")
717746
}
@@ -785,12 +814,14 @@ impl<'sess, S: Stage> AttributeParser<'sess, S> {
785814
ast::AttrKind::Normal(n) => {
786815
attr_paths.push(PathParser::Ast(&n.item.path));
787816

817+
// Parse attribute using new infra
788818
let parser = MetaItemParser::from_attr(n, self.dcx());
789819
let path = parser.path();
790820
let args = parser.args();
791821
let parts = path.segments().map(|i| i.name).collect::<Vec<_>>();
792822

793823
if let Some(accepts) = S::parsers().0.get(parts.as_slice()) {
824+
self.validate_attribute(attr, target_id, &mut emit_lint, true);
794825
for (template, accept) in accepts {
795826
let mut cx: AcceptContext<'_, 'sess, S> = AcceptContext {
796827
shared: SharedContext {
@@ -821,7 +852,7 @@ impl<'sess, S: Stage> AttributeParser<'sess, S> {
821852
// // || FIXME_TEMPORARY_ATTR_ALLOWLIST.contains(&parts[0]),
822853
// "attribute {path} wasn't parsed and isn't a know tool attribute",
823854
// );
824-
855+
self.validate_attribute(attr, target_id, &mut emit_lint, false);
825856
attributes.push(Attribute::Unparsed(Box::new(AttrItem {
826857
path: AttrPath::from_ast(&n.item.path),
827858
args: self.lower_attr_args(&n.item.args, lower_span),

compiler/rustc_attr_parsing/src/lib.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,7 @@ pub(crate) mod context;
8989
mod lints;
9090
pub mod parser;
9191
mod session_diagnostics;
92+
mod validate_attr;
9293

9394
pub use attributes::cfg::{CFG_TEMPLATE, EvalConfigResult, eval_config_entry, parse_cfg_attr};
9495
pub use attributes::cfg_old::*;
@@ -97,5 +98,8 @@ pub use attributes::util::{
9798
};
9899
pub use context::{AttributeParser, Early, Late, OmitDoc, ShouldEmit};
99100
pub use lints::emit_attribute_lint;
101+
pub use validate_attr::{
102+
check_attribute_safety, check_builtin_meta_item, emit_fatal_malformed_builtin_attribute,
103+
};
100104

101105
rustc_fluent_macro::fluent_messages! { "../messages.ftl" }

compiler/rustc_attr_parsing/src/lints.rs

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ use rustc_errors::{DiagArgValue, LintEmitter};
33
use rustc_hir::HirId;
44

55
use crate::session_diagnostics;
6+
use crate::session_diagnostics::{UnsafeAttrOutsideUnsafeLint, UnsafeAttrOutsideUnsafeSuggestion};
67

78
pub fn emit_attribute_lint<L: LintEmitter>(lint: &AttributeLint<HirId>, lint_emitter: L) {
89
let AttributeLint { id, span, kind } = lint;
@@ -34,5 +35,19 @@ pub fn emit_attribute_lint<L: LintEmitter>(lint: &AttributeLint<HirId>, lint_emi
3435
*first_span,
3536
session_diagnostics::EmptyAttributeList { attr_span: *first_span },
3637
),
38+
&AttributeLintKind::UnsafeAttrOutsideUnsafe { attribute_name_span, sugg_spans } => {
39+
lint_emitter.emit_node_span_lint(
40+
rustc_session::lint::builtin::UNSAFE_ATTR_OUTSIDE_UNSAFE,
41+
*id,
42+
*span,
43+
UnsafeAttrOutsideUnsafeLint {
44+
span: attribute_name_span,
45+
suggestion: UnsafeAttrOutsideUnsafeSuggestion {
46+
left: sugg_spans.0.shrink_to_lo(),
47+
right: sugg_spans.1.shrink_to_hi(),
48+
},
49+
},
50+
)
51+
}
3752
}
3853
}

0 commit comments

Comments
 (0)