Skip to content

Commit b166f19

Browse files
Rework illformed attribute check for unparsed attributes
Signed-off-by: Jonathan Brouwer <jonathantbrouwer@gmail.com>
1 parent 81af9d4 commit b166f19

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

+830
-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: 39 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -203,10 +203,12 @@ mod private {
203203
#[allow(private_interfaces)]
204204
pub trait Stage: Sized + 'static + Sealed {
205205
type Id: Copy;
206-
const SHOULD_EMIT_LINTS: bool;
206+
const IS_LATE: bool;
207207

208208
fn parsers() -> &'static group_type!(Self);
209209

210+
fn should_emit_errors(&self) -> bool;
211+
210212
fn emit_err<'sess>(
211213
&self,
212214
sess: &'sess Session,
@@ -218,11 +220,16 @@ pub trait Stage: Sized + 'static + Sealed {
218220
#[allow(private_interfaces)]
219221
impl Stage for Early {
220222
type Id = NodeId;
221-
const SHOULD_EMIT_LINTS: bool = false;
223+
const IS_LATE: bool = false;
222224

223225
fn parsers() -> &'static group_type!(Self) {
224226
&early::ATTRIBUTE_PARSERS
225227
}
228+
229+
fn should_emit_errors(&self) -> bool {
230+
self.emit_errors.should_emit()
231+
}
232+
226233
fn emit_err<'sess>(
227234
&self,
228235
sess: &'sess Session,
@@ -240,11 +247,16 @@ impl Stage for Early {
240247
#[allow(private_interfaces)]
241248
impl Stage for Late {
242249
type Id = HirId;
243-
const SHOULD_EMIT_LINTS: bool = true;
250+
const IS_LATE: bool = true;
244251

245252
fn parsers() -> &'static group_type!(Self) {
246253
&late::ATTRIBUTE_PARSERS
247254
}
255+
256+
fn should_emit_errors(&self) -> bool {
257+
true
258+
}
259+
248260
fn emit_err<'sess>(
249261
&self,
250262
tcx: &'sess Session,
@@ -290,7 +302,7 @@ impl<'f, 'sess: 'f, S: Stage> SharedContext<'f, 'sess, S> {
290302
/// must be delayed until after HIR is built. This method will take care of the details of
291303
/// that.
292304
pub(crate) fn emit_lint(&mut self, lint: AttributeLintKind, span: Span) {
293-
if !S::SHOULD_EMIT_LINTS {
305+
if !S::IS_LATE {
294306
return;
295307
}
296308
let id = self.target_id;
@@ -696,6 +708,22 @@ impl<'sess> AttributeParser<'sess, Early> {
696708
};
697709
parse_fn(&mut cx, args)
698710
}
711+
712+
/// Returns whether the attribute is valid
713+
pub fn validate_attribute_early(
714+
sess: &'sess Session,
715+
attr: &ast::Attribute,
716+
target_node_id: NodeId,
717+
) -> bool {
718+
let parser = Self {
719+
features: None,
720+
tools: Vec::new(),
721+
parse_only: None,
722+
sess,
723+
stage: Early { emit_errors: ShouldEmit::ErrorsAndLints },
724+
};
725+
parser.validate_attribute(attr, target_node_id, &mut |_| {}, true)
726+
}
699727
}
700728

701729
impl<'sess, S: Stage> AttributeParser<'sess, S> {
@@ -712,6 +740,10 @@ impl<'sess, S: Stage> AttributeParser<'sess, S> {
712740
&self.sess
713741
}
714742

743+
pub(crate) fn stage(&self) -> &S {
744+
&self.stage
745+
}
746+
715747
pub(crate) fn features(&self) -> &'sess Features {
716748
self.features.expect("features not available at this point in the compiler")
717749
}
@@ -785,12 +817,14 @@ impl<'sess, S: Stage> AttributeParser<'sess, S> {
785817
ast::AttrKind::Normal(n) => {
786818
attr_paths.push(PathParser::Ast(&n.item.path));
787819

820+
// Parse attribute using new infra
788821
let parser = MetaItemParser::from_attr(n, self.dcx());
789822
let path = parser.path();
790823
let args = parser.args();
791824
let parts = path.segments().map(|i| i.name).collect::<Vec<_>>();
792825

793826
if let Some(accepts) = S::parsers().0.get(parts.as_slice()) {
827+
self.validate_attribute(attr, target_id, &mut emit_lint, true);
794828
for (template, accept) in accepts {
795829
let mut cx: AcceptContext<'_, 'sess, S> = AcceptContext {
796830
shared: SharedContext {
@@ -821,7 +855,7 @@ impl<'sess, S: Stage> AttributeParser<'sess, S> {
821855
// // || FIXME_TEMPORARY_ATTR_ALLOWLIST.contains(&parts[0]),
822856
// "attribute {path} wasn't parsed and isn't a know tool attribute",
823857
// );
824-
858+
self.validate_attribute(attr, target_id, &mut emit_lint, false);
825859
attributes.push(Attribute::Unparsed(Box::new(AttrItem {
826860
path: AttrPath::from_ast(&n.item.path),
827861
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)