Unnamed repository; edit this file 'description' to name the repository.
Diffstat (limited to 'crates/hir-def/src/attrs.rs')
| -rw-r--r-- | crates/hir-def/src/attrs.rs | 86 |
1 files changed, 78 insertions, 8 deletions
diff --git a/crates/hir-def/src/attrs.rs b/crates/hir-def/src/attrs.rs index b560d08492..5cf5a9b6be 100644 --- a/crates/hir-def/src/attrs.rs +++ b/crates/hir-def/src/attrs.rs @@ -159,7 +159,7 @@ fn match_attr_flags(attr_flags: &mut AttrFlags, attr: ast::Meta) -> ControlFlow< None => match &*first_segment { "deprecated" => attr_flags.insert(AttrFlags::IS_DEPRECATED), "doc" => extract_doc_tt_attr(attr_flags, tt), - "repr" => attr_flags.insert(AttrFlags::HAS_REPR), + "repr" | "rustc_scalable_vector" => attr_flags.insert(AttrFlags::HAS_REPR), "target_feature" => attr_flags.insert(AttrFlags::HAS_TARGET_FEATURE), "proc_macro_derive" | "rustc_builtin_macro" => { attr_flags.insert(AttrFlags::IS_DERIVE_OR_BUILTIN_MACRO) @@ -200,7 +200,7 @@ fn match_attr_flags(attr_flags: &mut AttrFlags, attr: ast::Meta) -> ControlFlow< let segment4 = segment4.and_then(|it| it.segment()?.name_ref()); segment1.text() == "test" && segment3.is_none_or(|it| it.text() == "prelude") - && segment4.is_none_or(|it| it.text() == "core") + && segment4.is_none_or(|it| matches!(&*it.text(), "core" | "std")) }); if is_test { attr_flags.insert(AttrFlags::IS_TEST); @@ -217,6 +217,7 @@ fn match_attr_flags(attr_flags: &mut AttrFlags, attr: ast::Meta) -> ControlFlow< "rustc_allow_incoherent_impl" => { attr_flags.insert(AttrFlags::RUSTC_ALLOW_INCOHERENT_IMPL) } + "rustc_scalable_vector" => attr_flags.insert(AttrFlags::HAS_REPR), "fundamental" => attr_flags.insert(AttrFlags::FUNDAMENTAL), "no_std" => attr_flags.insert(AttrFlags::IS_NO_STD), "may_dangle" => attr_flags.insert(AttrFlags::MAY_DANGLE), @@ -257,6 +258,9 @@ fn match_attr_flags(attr_flags: &mut AttrFlags, attr: ast::Meta) -> ControlFlow< Some(second_segment) => match &*first_segment { "rust_analyzer" => match &*second_segment { "skip" => attr_flags.insert(AttrFlags::RUST_ANALYZER_SKIP), + "prefer_underscore_import" => { + attr_flags.insert(AttrFlags::PREFER_UNDERSCORE_IMPORT) + } _ => {} }, _ => {} @@ -329,6 +333,8 @@ bitflags::bitflags! { const MACRO_STYLE_BRACES = 1 << 46; const MACRO_STYLE_BRACKETS = 1 << 47; const MACRO_STYLE_PARENTHESES = 1 << 48; + + const PREFER_UNDERSCORE_IMPORT = 1 << 49; } } @@ -724,14 +730,40 @@ impl AttrFlags { fn repr(db: &dyn DefDatabase, owner: AdtId) -> Option<ReprOptions> { let mut result = None; collect_attrs::<Infallible>(db, owner.into(), |attr| { - if let ast::Meta::TokenTreeMeta(attr) = attr - && attr.path().is1("repr") + let mut current = None; + if let ast::Meta::TokenTreeMeta(attr) = &attr + && let Some(path) = attr.path() && let Some(tt) = attr.token_tree() - && let Some(repr) = parse_repr_tt(&tt) { + if path.is1("repr") + && let Some(repr) = parse_repr_tt(&tt) + { + current = Some(repr); + } else if path.is1("rustc_scalable_vector") + && let mut tt = TokenTreeChildren::new(&tt) + && let Some(NodeOrToken::Token(scalable)) = tt.next() + && let Some(scalable) = ast::IntNumber::cast(scalable) + && let Ok(scalable) = scalable.value() + && let Ok(scalable) = scalable.try_into() + { + current = Some(ReprOptions { + scalable: Some(rustc_abi::ScalableElt::ElementCount(scalable)), + ..ReprOptions::default() + }); + } + } else if let ast::Meta::PathMeta(attr) = &attr + && attr.path().is1("rustc_scalable_vector") + { + current = Some(ReprOptions { + scalable: Some(rustc_abi::ScalableElt::Container), + ..ReprOptions::default() + }); + } + + if let Some(current) = current { match &mut result { - Some(existing) => merge_repr(existing, repr), - None => result = Some(repr), + Some(existing) => merge_repr(existing, current), + None => result = Some(current), } } ControlFlow::Continue(()) @@ -1076,10 +1108,45 @@ impl AttrFlags { }) } } + + pub fn unstable_feature(self, db: &dyn DefDatabase, owner: AttrDefId) -> Option<Symbol> { + if !self.contains(AttrFlags::IS_UNSTABLE) { + return None; + } + + return unstable_feature(db, owner); + + #[salsa::tracked] + fn unstable_feature(db: &dyn DefDatabase, owner: AttrDefId) -> Option<Symbol> { + collect_attrs(db, owner, |attr| { + if let ast::Meta::TokenTreeMeta(attr) = attr + && let path = attr.path() + && path.is1("unstable") + && let Some(tt) = attr.token_tree() + { + let mut tt = TokenTreeChildren::new(&tt); + // Technically the `feature = "..."` always comes first, but it's not a requirement. + while let Some(token) = tt.next() { + if let NodeOrToken::Token(token) = token + && token.text() == "feature" + && let Some(NodeOrToken::Token(eq)) = tt.next() + && eq.kind() == T![=] + && let Some(NodeOrToken::Token(feature)) = tt.next() + && let Some(feature) = ast::String::cast(feature) + && let Ok(feature) = feature.value() + { + return ControlFlow::Break(Symbol::intern(&feature)); + } + } + } + ControlFlow::Continue(()) + }) + } + } } fn merge_repr(this: &mut ReprOptions, other: ReprOptions) { - let ReprOptions { int, align, pack, flags, field_shuffle_seed: _ } = this; + let ReprOptions { int, align, pack, flags, scalable, field_shuffle_seed: _ } = this; flags.insert(other.flags); *align = (*align).max(other.align); *pack = match (*pack, other.pack) { @@ -1089,6 +1156,9 @@ fn merge_repr(this: &mut ReprOptions, other: ReprOptions) { if other.int.is_some() { *int = other.int; } + if other.scalable.is_some() { + *scalable = other.scalable; + } } fn parse_repr_tt(tt: &ast::TokenTree) -> Option<ReprOptions> { |