Skip to content

Commit 6b0c356

Browse files
Rework illformed attribute check for unparsed attributes
Signed-off-by: Jonathan Brouwer <[email protected]>
1 parent 81af9d4 commit 6b0c356

Some content is hidden

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

42 files changed

+836
-819
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)