Skip to content

Commit 78e9f18

Browse files
wip
Signed-off-by: Jonathan Brouwer <[email protected]>
1 parent 63fb71a commit 78e9f18

File tree

13 files changed

+317
-490
lines changed

13 files changed

+317
-490
lines changed

compiler/rustc_attr_parsing/src/context.rs

Lines changed: 8 additions & 205 deletions
Original file line numberDiff line numberDiff line change
@@ -4,15 +4,12 @@ use std::ops::{Deref, DerefMut};
44
use std::sync::LazyLock;
55

66
use private::Sealed;
7-
use rustc_ast::{self as ast, LitKind, MetaItemLit, NodeId, Safety};
7+
use rustc_ast::{self as ast, LitKind, MetaItemLit, NodeId};
88
use rustc_attr_data_structures::AttributeKind;
99
use rustc_attr_data_structures::lints::{AttributeLint, AttributeLintKind};
10-
use rustc_errors::{Applicability, DiagCtxtHandle, Diagnostic};
11-
use rustc_feature::{
12-
AttributeSafety, AttributeTemplate, BUILTIN_ATTRIBUTE_MAP, BuiltinAttribute, Features,
13-
};
10+
use rustc_errors::{DiagCtxtHandle, Diagnostic};
11+
use rustc_feature::{AttributeTemplate, Features};
1412
use rustc_hir::{AttrArgs, AttrItem, AttrPath, Attribute, HashIgnoredAttrId, HirId};
15-
use rustc_parse::validate_attr::{is_attr_template_compatible, parse_meta};
1613
use rustc_session::Session;
1714
use rustc_span::{DUMMY_SP, ErrorGuaranteed, Span, Symbol, sym};
1815

@@ -59,10 +56,7 @@ use crate::attributes::traits::{
5956
use crate::attributes::transparency::TransparencyParser;
6057
use crate::attributes::{AttributeParser as _, Combine, Single, WithoutArgs};
6158
use crate::parser::{ArgParser, MetaItemParser, PathParser};
62-
use crate::session_diagnostics::{
63-
AttributeParseError, AttributeParseErrorReason, InvalidAttrUnsafe, UnknownMetaItem,
64-
UnsafeAttrOutsideUnsafe, UnsafeAttrOutsideUnsafeSuggestion,
65-
};
59+
use crate::session_diagnostics::{AttributeParseError, AttributeParseErrorReason, UnknownMetaItem};
6660

6761
macro_rules! group_type {
6862
($stage: ty) => {
@@ -753,6 +747,10 @@ impl<'sess, S: Stage> AttributeParser<'sess, S> {
753747
&self.sess
754748
}
755749

750+
pub(crate) fn stage(&self) -> &S {
751+
&self.stage
752+
}
753+
756754
pub(crate) fn features(&self) -> &'sess Features {
757755
self.features.expect("features not available at this point in the compiler")
758756
}
@@ -897,201 +895,6 @@ impl<'sess, S: Stage> AttributeParser<'sess, S> {
897895
attributes
898896
}
899897

900-
fn validate_attribute(
901-
&self,
902-
attr: &ast::Attribute,
903-
target_id: S::Id,
904-
emit_lint: &mut impl FnMut(AttributeLint<S::Id>),
905-
check_attr_template: bool,
906-
) -> bool {
907-
if !self.stage.should_emit_errors() {
908-
return true;
909-
}
910-
let ast::AttrKind::Normal(normal) = &attr.kind else { return true };
911-
if attr.has_name(sym::cfg_trace) || attr.has_name(sym::cfg_attr_trace) {
912-
return true;
913-
}
914-
self.check_attribute_safety(attr, target_id, emit_lint);
915-
916-
let builtin_attr_info =
917-
attr.ident().and_then(|ident| BUILTIN_ATTRIBUTE_MAP.get(&ident.name));
918-
if (builtin_attr_info.is_none() || attr.has_name(sym::rustc_dummy))
919-
&& !matches!(normal.item.args, rustc_ast::AttrArgs::Eq { .. })
920-
{
921-
return true;
922-
}
923-
924-
// FIXME
925-
let meta = match parse_meta(&self.sess.psess, attr) {
926-
Ok(meta) => meta,
927-
Err(err) => {
928-
err.emit();
929-
return false;
930-
}
931-
};
932-
if check_attr_template {
933-
return true;
934-
}
935-
936-
if let Some(BuiltinAttribute { name, template, .. }) = builtin_attr_info {
937-
// FIXME when all attributes are parsed, this check can be removed
938-
if !is_attr_template_compatible(&template, &meta.kind) {
939-
self.emit_malformed_unparsed_attribute(
940-
attr.style, meta.span, *name, *template, target_id, emit_lint,
941-
);
942-
return false
943-
}
944-
}
945-
946-
true
947-
}
948-
949-
fn check_attribute_safety(
950-
&self,
951-
attr: &ast::Attribute,
952-
id: S::Id,
953-
emit_lint: &mut impl FnMut(AttributeLint<S::Id>),
954-
) {
955-
let builtin_attr_info =
956-
attr.ident().and_then(|ident| BUILTIN_ATTRIBUTE_MAP.get(&ident.name));
957-
958-
let builtin_attr_safety = builtin_attr_info.map(|x| x.safety);
959-
960-
let attr_item = attr.get_normal_item();
961-
match (builtin_attr_safety, attr_item.unsafety) {
962-
// - Unsafe builtin attribute
963-
// - User wrote `#[unsafe(..)]`, which is permitted on any edition
964-
(Some(AttributeSafety::Unsafe { .. }), Safety::Unsafe(..)) => {
965-
// OK
966-
}
967-
968-
// - Unsafe builtin attribute
969-
// - User did not write `#[unsafe(..)]`
970-
(Some(AttributeSafety::Unsafe { unsafe_since }), Safety::Default) => {
971-
let path_span = attr_item.path.span;
972-
973-
// If the `attr_item`'s span is not from a macro, then just suggest
974-
// wrapping it in `unsafe(...)`. Otherwise, we suggest putting the
975-
// `unsafe(`, `)` right after and right before the opening and closing
976-
// square bracket respectively.
977-
let diag_span = attr_item.span();
978-
979-
// Attributes can be safe in earlier editions, and become unsafe in later ones.
980-
//
981-
// Use the span of the attribute's name to determine the edition: the span of the
982-
// attribute as a whole may be inaccurate if it was emitted by a macro.
983-
//
984-
// See https://github.com/rust-lang/rust/issues/142182.
985-
let emit_error = match unsafe_since {
986-
None => true,
987-
Some(unsafe_since) => path_span.edition() >= unsafe_since,
988-
};
989-
990-
if emit_error {
991-
self.dcx().emit_err(UnsafeAttrOutsideUnsafe {
992-
span: path_span,
993-
suggestion: UnsafeAttrOutsideUnsafeSuggestion {
994-
left: diag_span.shrink_to_lo(),
995-
right: diag_span.shrink_to_hi(),
996-
},
997-
});
998-
} else {
999-
emit_lint(AttributeLint {
1000-
id,
1001-
span: path_span,
1002-
kind: AttributeLintKind::UnsafeAttrOutsideUnsafe {
1003-
attribute_name_span: path_span,
1004-
sugg_spans: (diag_span.shrink_to_lo(), diag_span.shrink_to_hi()),
1005-
},
1006-
});
1007-
}
1008-
}
1009-
1010-
// - Normal builtin attribute, or any non-builtin attribute
1011-
// - All non-builtin attributes are currently considered safe; writing `#[unsafe(..)]` is
1012-
// not permitted on non-builtin attributes or normal builtin attributes
1013-
(Some(AttributeSafety::Normal) | None, Safety::Unsafe(unsafe_span)) => {
1014-
self.dcx().emit_err(InvalidAttrUnsafe {
1015-
span: unsafe_span,
1016-
name: attr_item.path.clone(),
1017-
});
1018-
}
1019-
1020-
// - Normal builtin attribute
1021-
// - No explicit `#[unsafe(..)]` written.
1022-
(Some(AttributeSafety::Normal), Safety::Default) => {
1023-
// OK
1024-
}
1025-
1026-
// - Non-builtin attribute
1027-
// - No explicit `#[unsafe(..)]` written.
1028-
(None, Safety::Default) => {
1029-
// OK
1030-
}
1031-
1032-
(
1033-
Some(AttributeSafety::Unsafe { .. } | AttributeSafety::Normal) | None,
1034-
Safety::Safe(..),
1035-
) => {
1036-
self.sess.psess.dcx().span_delayed_bug(
1037-
attr_item.span(),
1038-
"`check_attribute_safety` does not expect `Safety::Safe` on attributes",
1039-
);
1040-
}
1041-
}
1042-
}
1043-
1044-
fn emit_malformed_unparsed_attribute(
1045-
&self,
1046-
style: ast::AttrStyle,
1047-
span: Span,
1048-
name: Symbol,
1049-
template: AttributeTemplate,
1050-
target_id: S::Id,
1051-
emit_lint: &mut impl FnMut(AttributeLint<S::Id>),
1052-
) {
1053-
// Some of previously accepted forms were used in practice,
1054-
// report them as warnings for now.
1055-
let should_warn = |name| matches!(name, sym::doc | sym::link | sym::test | sym::bench);
1056-
1057-
let error_msg = format!("malformed `{name}` attribute input");
1058-
let mut suggestions = vec![];
1059-
let inner = if style == ast::AttrStyle::Inner { "!" } else { "" };
1060-
if template.word {
1061-
suggestions.push(format!("#{inner}[{name}]"));
1062-
}
1063-
if let Some(descr) = template.list {
1064-
suggestions.push(format!("#{inner}[{name}({descr})]"));
1065-
}
1066-
suggestions.extend(template.one_of.iter().map(|&word| format!("#{inner}[{name}({word})]")));
1067-
if let Some(descr) = template.name_value_str {
1068-
suggestions.push(format!("#{inner}[{name} = \"{descr}\"]"));
1069-
}
1070-
if should_warn(name) {
1071-
emit_lint(AttributeLint {
1072-
id: target_id,
1073-
span,
1074-
kind: AttributeLintKind::IllFormedAttributeInput { suggestions },
1075-
});
1076-
} else {
1077-
suggestions.sort();
1078-
self.sess
1079-
.dcx()
1080-
.struct_span_err(span, error_msg)
1081-
.with_span_suggestions(
1082-
span,
1083-
if suggestions.len() == 1 {
1084-
"must be of the form"
1085-
} else {
1086-
"the following are the possible correct uses"
1087-
},
1088-
suggestions,
1089-
Applicability::HasPlaceholders,
1090-
)
1091-
.emit();
1092-
}
1093-
}
1094-
1095898
/// Returns whether there is a parser for an attribute with this name
1096899
pub fn is_parsed_attribute(path: &[Symbol]) -> bool {
1097900
Late::parsers().0.contains_key(path)

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" }

0 commit comments

Comments
 (0)