mirror of
https://github.com/rust-lang/rust-analyzer.git
synced 2025-10-29 10:58:02 +00:00
Merge pull request #19416 from ShoyuVanilla/issue-15037
fix: Handle multiple `#[repr(..)]` attrs correctly
This commit is contained in:
commit
2e5e5113df
3 changed files with 91 additions and 71 deletions
|
|
@ -233,7 +233,12 @@ impl Attrs {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn repr(&self) -> Option<ReprOptions> {
|
pub fn repr(&self) -> Option<ReprOptions> {
|
||||||
self.by_key(&sym::repr).tt_values().find_map(parse_repr_tt)
|
self.by_key(&sym::repr).tt_values().filter_map(parse_repr_tt).fold(None, |acc, repr| {
|
||||||
|
acc.map_or(Some(repr), |mut acc| {
|
||||||
|
merge_repr(&mut acc, repr);
|
||||||
|
Some(acc)
|
||||||
|
})
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -260,6 +265,19 @@ fn parse_rustc_legacy_const_generics(tt: &crate::tt::TopSubtree) -> Box<[u32]> {
|
||||||
indices.into_boxed_slice()
|
indices.into_boxed_slice()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn merge_repr(this: &mut ReprOptions, other: ReprOptions) {
|
||||||
|
let ReprOptions { int, align, pack, flags, field_shuffle_seed: _ } = this;
|
||||||
|
flags.insert(other.flags);
|
||||||
|
*align = (*align).max(other.align);
|
||||||
|
*pack = match (*pack, other.pack) {
|
||||||
|
(Some(pack), None) | (None, Some(pack)) => Some(pack),
|
||||||
|
_ => (*pack).min(other.pack),
|
||||||
|
};
|
||||||
|
if other.int.is_some() {
|
||||||
|
*int = other.int;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn parse_repr_tt(tt: &crate::tt::TopSubtree) -> Option<ReprOptions> {
|
fn parse_repr_tt(tt: &crate::tt::TopSubtree) -> Option<ReprOptions> {
|
||||||
use crate::builtin_type::{BuiltinInt, BuiltinUint};
|
use crate::builtin_type::{BuiltinInt, BuiltinUint};
|
||||||
use rustc_abi::{Align, Integer, IntegerType, ReprFlags, ReprOptions};
|
use rustc_abi::{Align, Integer, IntegerType, ReprFlags, ReprOptions};
|
||||||
|
|
@ -269,15 +287,13 @@ fn parse_repr_tt(tt: &crate::tt::TopSubtree) -> Option<ReprOptions> {
|
||||||
_ => return None,
|
_ => return None,
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut flags = ReprFlags::empty();
|
let mut acc = ReprOptions::default();
|
||||||
let mut int = None;
|
|
||||||
let mut max_align: Option<Align> = None;
|
|
||||||
let mut min_pack: Option<Align> = None;
|
|
||||||
|
|
||||||
let mut tts = tt.iter();
|
let mut tts = tt.iter();
|
||||||
while let Some(tt) = tts.next() {
|
while let Some(tt) = tts.next() {
|
||||||
if let TtElement::Leaf(tt::Leaf::Ident(ident)) = tt {
|
let TtElement::Leaf(tt::Leaf::Ident(ident)) = tt else {
|
||||||
flags.insert(match &ident.sym {
|
continue;
|
||||||
|
};
|
||||||
|
let repr = match &ident.sym {
|
||||||
s if *s == sym::packed => {
|
s if *s == sym::packed => {
|
||||||
let pack = if let Some(TtElement::Subtree(_, mut tt_iter)) = tts.peek() {
|
let pack = if let Some(TtElement::Subtree(_, mut tt_iter)) = tts.peek() {
|
||||||
tts.next();
|
tts.next();
|
||||||
|
|
@ -289,27 +305,28 @@ fn parse_repr_tt(tt: &crate::tt::TopSubtree) -> Option<ReprOptions> {
|
||||||
} else {
|
} else {
|
||||||
0
|
0
|
||||||
};
|
};
|
||||||
let pack = Align::from_bytes(pack).unwrap_or(Align::ONE);
|
let pack = Some(Align::from_bytes(pack).unwrap_or(Align::ONE));
|
||||||
min_pack =
|
ReprOptions { pack, ..Default::default() }
|
||||||
Some(if let Some(min_pack) = min_pack { min_pack.min(pack) } else { pack });
|
|
||||||
ReprFlags::empty()
|
|
||||||
}
|
}
|
||||||
s if *s == sym::align => {
|
s if *s == sym::align => {
|
||||||
|
let mut align = None;
|
||||||
if let Some(TtElement::Subtree(_, mut tt_iter)) = tts.peek() {
|
if let Some(TtElement::Subtree(_, mut tt_iter)) = tts.peek() {
|
||||||
tts.next();
|
tts.next();
|
||||||
if let Some(TtElement::Leaf(tt::Leaf::Literal(lit))) = tt_iter.next() {
|
if let Some(TtElement::Leaf(tt::Leaf::Literal(lit))) = tt_iter.next() {
|
||||||
if let Ok(align) = lit.symbol.as_str().parse() {
|
if let Ok(a) = lit.symbol.as_str().parse() {
|
||||||
let align = Align::from_bytes(align).ok();
|
align = Align::from_bytes(a).ok();
|
||||||
max_align = max_align.max(align);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ReprFlags::empty()
|
ReprOptions { align, ..Default::default() }
|
||||||
}
|
}
|
||||||
s if *s == sym::C => ReprFlags::IS_C,
|
s if *s == sym::C => ReprOptions { flags: ReprFlags::IS_C, ..Default::default() },
|
||||||
s if *s == sym::transparent => ReprFlags::IS_TRANSPARENT,
|
s if *s == sym::transparent => {
|
||||||
s if *s == sym::simd => ReprFlags::IS_SIMD,
|
ReprOptions { flags: ReprFlags::IS_TRANSPARENT, ..Default::default() }
|
||||||
|
}
|
||||||
|
s if *s == sym::simd => ReprOptions { flags: ReprFlags::IS_SIMD, ..Default::default() },
|
||||||
repr => {
|
repr => {
|
||||||
|
let mut int = None;
|
||||||
if let Some(builtin) = BuiltinInt::from_suffix_sym(repr)
|
if let Some(builtin) = BuiltinInt::from_suffix_sym(repr)
|
||||||
.map(Either::Left)
|
.map(Either::Left)
|
||||||
.or_else(|| BuiltinUint::from_suffix_sym(repr).map(Either::Right))
|
.or_else(|| BuiltinUint::from_suffix_sym(repr).map(Either::Right))
|
||||||
|
|
@ -333,19 +350,13 @@ fn parse_repr_tt(tt: &crate::tt::TopSubtree) -> Option<ReprOptions> {
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
ReprFlags::empty()
|
ReprOptions { int, ..Default::default() }
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
};
|
||||||
|
merge_repr(&mut acc, repr);
|
||||||
}
|
}
|
||||||
|
|
||||||
Some(ReprOptions {
|
Some(acc)
|
||||||
int,
|
|
||||||
align: max_align,
|
|
||||||
pack: min_pack,
|
|
||||||
flags,
|
|
||||||
field_shuffle_seed: rustc_hashes::Hash64::ZERO,
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
||||||
|
|
|
||||||
|
|
@ -24,9 +24,6 @@ extern crate rustc_hashes;
|
||||||
#[cfg(not(feature = "in-rust-tree"))]
|
#[cfg(not(feature = "in-rust-tree"))]
|
||||||
extern crate ra_ap_rustc_abi as rustc_abi;
|
extern crate ra_ap_rustc_abi as rustc_abi;
|
||||||
|
|
||||||
#[cfg(not(feature = "in-rust-tree"))]
|
|
||||||
extern crate ra_ap_rustc_hashes as rustc_hashes;
|
|
||||||
|
|
||||||
pub mod db;
|
pub mod db;
|
||||||
|
|
||||||
pub mod attr;
|
pub mod attr;
|
||||||
|
|
|
||||||
|
|
@ -284,6 +284,18 @@ fn repr_packed() {
|
||||||
check_size_and_align("#[repr(Rust, packed(5))] struct Goal(i32);", "", 4, 1);
|
check_size_and_align("#[repr(Rust, packed(5))] struct Goal(i32);", "", 4, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn multiple_repr_attrs() {
|
||||||
|
size_and_align!(
|
||||||
|
#[repr(C)]
|
||||||
|
#[repr(packed)]
|
||||||
|
struct Goal {
|
||||||
|
id: i32,
|
||||||
|
u: u8,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn generic() {
|
fn generic() {
|
||||||
size_and_align! {
|
size_and_align! {
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue