Skip to content

Commit 737cb2d

Browse files
Rollup merge of rust-lang#157125 - JonathanBrouwer:repr-target-checking2, r=mejrs
Rewrite the `#[repr]` attribute parser The `#[repr]` attribute parser was one of the first attribute parsers we made, and didn't use a lot of the awesome infra we have nowadays yet, so in preparation for a new approach I'm trying for rust-lang#156569 I decided to clean it up. This PR should have no observable effect other than improved diagnostic messages. r? @mejrs
2 parents 377d5ba + 7aef596 commit 737cb2d

41 files changed

Lines changed: 394 additions & 551 deletions

Some content is hidden

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

compiler/rustc_attr_parsing/src/attributes/prelude.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ pub(super) use rustc_hir::attrs::AttributeKind;
66
#[doc(hidden)]
77
pub(super) use rustc_hir::{MethodKind, Target};
88
#[doc(hidden)]
9-
pub(super) use rustc_span::{DUMMY_SP, Ident, Span, Symbol, sym};
9+
pub(super) use rustc_span::{Ident, Span, Symbol, sym};
1010
#[doc(hidden)]
1111
pub(super) use thin_vec::ThinVec;
1212

compiler/rustc_attr_parsing/src/attributes/repr.rs

Lines changed: 80 additions & 171 deletions
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,27 @@
11
use rustc_abi::{Align, Size};
22
use rustc_ast::{IntTy, LitIntType, LitKind, UintTy};
3-
use rustc_hir::attrs::{IntType, ReprAttr};
3+
use rustc_hir::attrs::IntType::{SignedInt, UnsignedInt};
4+
use rustc_hir::attrs::ReprAttr;
45

56
use super::prelude::*;
6-
use crate::session_diagnostics::{self, IncorrectReprFormatGenericCause};
7+
use crate::session_diagnostics;
78

89
/// Parse #[repr(...)] forms.
910
///
10-
/// Valid repr contents: any of the primitive integral type names (see
11-
/// `int_type_of_word`, below) to specify enum discriminant type; `C`, to use
12-
/// the same discriminant size that the corresponding C enum would or C
13-
/// structure layout, `packed` to remove padding, and `transparent` to delegate representation
14-
/// concerns to the only non-ZST field.
15-
// FIXME(jdonszelmann): is a vec the right representation here even? isn't it just a struct?
11+
/// Valid repr contents:
12+
/// * any of the primitive integral type names to specify enum discriminant type
13+
/// * `Rust`, to use the default `Rust` layout of the type
14+
/// * `C`, to use the same layout for the type that C would use
15+
/// * `align(...)`, to change the alignment requirements of the type
16+
/// * `packed`, to remove padding
17+
/// * `transparent`, to delegate representation concerns to the only non-ZST field.
1618
pub(crate) struct ReprParser;
1719

1820
impl CombineAttributeParser for ReprParser {
1921
type Item = (ReprAttr, Span);
2022
const PATH: &[Symbol] = &[sym::repr];
2123
const CONVERT: ConvertFn<Self::Item> =
2224
|items, first_span| AttributeKind::Repr { reprs: items, first_span };
23-
// FIXME(jdonszelmann): never used
2425
const TEMPLATE: AttributeTemplate = template!(
2526
List: &["C", "Rust", "transparent", "align(...)", "packed(...)", "<integer type>"],
2627
"https://doc.rust-lang.org/reference/type-layout.html#representations"
@@ -30,29 +31,24 @@ impl CombineAttributeParser for ReprParser {
3031
cx: &mut AcceptContext<'_, '_>,
3132
args: &ArgParser,
3233
) -> impl IntoIterator<Item = Self::Item> {
33-
let mut reprs = Vec::new();
34-
3534
let Some(list) = cx.expect_list(args, cx.attr_span) else {
36-
return reprs;
35+
return vec![];
3736
};
3837

3938
if list.is_empty() {
4039
let attr_span = cx.attr_span;
4140
cx.adcx().warn_empty_attribute(attr_span);
42-
return reprs;
41+
return vec![];
4342
}
4443

44+
let mut reprs = Vec::new();
4545
for param in list.mixed() {
46-
if let Some(_) = param.as_lit() {
47-
cx.emit_err(session_diagnostics::ReprIdent { span: cx.attr_span });
46+
let Some(item) = param.meta_item() else {
47+
cx.adcx().expected_identifier(param.span());
4848
continue;
49-
}
50-
51-
reprs.extend(
52-
param.meta_item().and_then(|mi| parse_repr(cx, &mi)).map(|r| (r, param.span())),
53-
);
49+
};
50+
reprs.extend(parse_repr(cx, &item).map(|r| (r, param.span())));
5451
}
55-
5652
reprs
5753
}
5854

@@ -61,122 +57,69 @@ impl CombineAttributeParser for ReprParser {
6157
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(ALL_TARGETS);
6258
}
6359

64-
macro_rules! int_pat {
65-
() => {
66-
sym::i8
67-
| sym::u8
68-
| sym::i16
69-
| sym::u16
70-
| sym::i32
71-
| sym::u32
72-
| sym::i64
73-
| sym::u64
74-
| sym::i128
75-
| sym::u128
76-
| sym::isize
77-
| sym::usize
78-
};
79-
}
80-
81-
fn int_type_of_word(s: Symbol) -> Option<IntType> {
82-
use IntType::*;
83-
84-
match s {
85-
sym::i8 => Some(SignedInt(IntTy::I8)),
86-
sym::u8 => Some(UnsignedInt(UintTy::U8)),
87-
sym::i16 => Some(SignedInt(IntTy::I16)),
88-
sym::u16 => Some(UnsignedInt(UintTy::U16)),
89-
sym::i32 => Some(SignedInt(IntTy::I32)),
90-
sym::u32 => Some(UnsignedInt(UintTy::U32)),
91-
sym::i64 => Some(SignedInt(IntTy::I64)),
92-
sym::u64 => Some(UnsignedInt(UintTy::U64)),
93-
sym::i128 => Some(SignedInt(IntTy::I128)),
94-
sym::u128 => Some(UnsignedInt(UintTy::U128)),
95-
sym::isize => Some(SignedInt(IntTy::Isize)),
96-
sym::usize => Some(UnsignedInt(UintTy::Usize)),
97-
_ => None,
98-
}
99-
}
100-
101-
fn parse_repr(cx: &AcceptContext<'_, '_>, param: &MetaItemParser) -> Option<ReprAttr> {
60+
fn parse_repr(cx: &mut AcceptContext<'_, '_>, param: &MetaItemParser) -> Option<ReprAttr> {
10261
use ReprAttr::*;
10362

104-
// FIXME(jdonszelmann): invert the parsing here to match on the word first and then the
105-
// structure.
106-
let (name, ident_span) = if let Some(ident) = param.path().word() {
107-
(Some(ident.name), ident.span)
108-
} else {
109-
(None, DUMMY_SP)
110-
};
111-
112-
let args = param.args();
113-
114-
match (name, args) {
115-
(Some(sym::align), ArgParser::NoArgs) => {
116-
cx.emit_err(session_diagnostics::InvalidReprAlignNeedArg { span: ident_span });
117-
None
118-
}
119-
(Some(sym::align), ArgParser::List(l)) => {
120-
parse_repr_align(cx, l, param.span(), AlignKind::Align)
121-
}
122-
123-
(Some(sym::packed), ArgParser::NoArgs) => Some(ReprPacked(Align::ONE)),
124-
(Some(sym::packed), ArgParser::List(l)) => {
125-
parse_repr_align(cx, l, param.span(), AlignKind::Packed)
126-
}
127-
128-
(Some(name @ sym::align | name @ sym::packed), ArgParser::NameValue(l)) => {
129-
cx.emit_err(session_diagnostics::IncorrectReprFormatGeneric {
130-
span: param.span(),
131-
// FIXME(jdonszelmann) can just be a string in the diag type
132-
repr_arg: name,
133-
cause: IncorrectReprFormatGenericCause::from_lit_kind(
134-
param.span(),
135-
&l.value_as_lit().kind,
136-
name,
137-
),
138-
});
139-
None
140-
}
141-
142-
(Some(sym::Rust), ArgParser::NoArgs) => Some(ReprRust),
143-
(Some(sym::C), ArgParser::NoArgs) => Some(ReprC),
144-
(Some(sym::simd), ArgParser::NoArgs) => Some(ReprSimd),
145-
(Some(sym::transparent), ArgParser::NoArgs) => Some(ReprTransparent),
146-
(Some(name @ int_pat!()), ArgParser::NoArgs) => {
147-
// int_pat!() should make sure it always parses
148-
Some(ReprInt(int_type_of_word(name).unwrap()))
149-
}
63+
macro_rules! no_args {
64+
($constructor: expr) => {{
65+
cx.expect_no_args(param.args())?;
66+
Some($constructor)
67+
}};
68+
}
15069

151-
(
152-
Some(
153-
name @ sym::Rust
154-
| name @ sym::C
155-
| name @ sym::simd
156-
| name @ sym::transparent
157-
| name @ int_pat!(),
158-
),
159-
ArgParser::NameValue(_),
160-
) => {
161-
cx.emit_err(session_diagnostics::InvalidReprHintNoValue { span: param.span(), name });
162-
None
163-
}
164-
(
165-
Some(
166-
name @ sym::Rust
167-
| name @ sym::C
168-
| name @ sym::simd
169-
| name @ sym::transparent
170-
| name @ int_pat!(),
171-
),
172-
ArgParser::List(_),
173-
) => {
174-
cx.emit_err(session_diagnostics::InvalidReprHintNoParen { span: param.span(), name });
175-
None
70+
match param.path().word_sym() {
71+
Some(sym::align) => {
72+
let l = cx.expect_list(param.args(), param.span())?;
73+
parse_repr_align(cx, l, AlignKind::Align)
17674
}
177-
75+
Some(sym::packed) => match param.args() {
76+
ArgParser::NoArgs => Some(ReprPacked(Align::ONE)),
77+
ArgParser::List(l) => parse_repr_align(cx, l, AlignKind::Packed),
78+
ArgParser::NameValue(_) => {
79+
cx.adcx().expected_list_or_no_args(param.span());
80+
None
81+
}
82+
},
83+
Some(sym::Rust) => no_args!(ReprRust),
84+
Some(sym::C) => no_args!(ReprC),
85+
Some(sym::simd) => no_args!(ReprSimd),
86+
Some(sym::transparent) => no_args!(ReprTransparent),
87+
Some(sym::i8) => no_args!(ReprInt(SignedInt(IntTy::I8))),
88+
Some(sym::u8) => no_args!(ReprInt(UnsignedInt(UintTy::U8))),
89+
Some(sym::i16) => no_args!(ReprInt(SignedInt(IntTy::I16))),
90+
Some(sym::u16) => no_args!(ReprInt(UnsignedInt(UintTy::U16))),
91+
Some(sym::i32) => no_args!(ReprInt(SignedInt(IntTy::I32))),
92+
Some(sym::u32) => no_args!(ReprInt(UnsignedInt(UintTy::U32))),
93+
Some(sym::i64) => no_args!(ReprInt(SignedInt(IntTy::I64))),
94+
Some(sym::u64) => no_args!(ReprInt(UnsignedInt(UintTy::U64))),
95+
Some(sym::i128) => no_args!(ReprInt(SignedInt(IntTy::I128))),
96+
Some(sym::u128) => no_args!(ReprInt(UnsignedInt(UintTy::U128))),
97+
Some(sym::isize) => no_args!(ReprInt(SignedInt(IntTy::Isize))),
98+
Some(sym::usize) => no_args!(ReprInt(UnsignedInt(UintTy::Usize))),
17899
_ => {
179-
cx.emit_err(session_diagnostics::UnrecognizedReprHint { span: param.span() });
100+
cx.adcx().expected_specific_argument(
101+
param.span(),
102+
&[
103+
sym::align,
104+
sym::packed,
105+
sym::Rust,
106+
sym::C,
107+
sym::simd,
108+
sym::transparent,
109+
sym::i8,
110+
sym::u8,
111+
sym::i16,
112+
sym::u16,
113+
sym::i32,
114+
sym::u32,
115+
sym::i64,
116+
sym::u64,
117+
sym::i128,
118+
sym::u128,
119+
sym::isize,
120+
sym::usize,
121+
],
122+
);
180123
None
181124
}
182125
}
@@ -188,44 +131,17 @@ enum AlignKind {
188131
}
189132

190133
fn parse_repr_align(
191-
cx: &AcceptContext<'_, '_>,
134+
cx: &mut AcceptContext<'_, '_>,
192135
list: &MetaItemListParser,
193-
param_span: Span,
194136
align_kind: AlignKind,
195137
) -> Option<ReprAttr> {
196-
use AlignKind::*;
197-
198138
let Some(align) = list.as_single() else {
199-
match align_kind {
200-
Packed => {
201-
cx.emit_err(session_diagnostics::IncorrectReprFormatPackedOneOrZeroArg {
202-
span: param_span,
203-
});
204-
}
205-
Align => {
206-
cx.emit_err(session_diagnostics::IncorrectReprFormatAlignOneArg {
207-
span: param_span,
208-
});
209-
}
210-
}
211-
139+
cx.adcx().expected_single_argument(list.span, list.len());
212140
return None;
213141
};
214142

215143
let Some(lit) = align.as_lit() else {
216-
match align_kind {
217-
Packed => {
218-
cx.emit_err(session_diagnostics::IncorrectReprFormatPackedExpectInteger {
219-
span: align.span(),
220-
});
221-
}
222-
Align => {
223-
cx.emit_err(session_diagnostics::IncorrectReprFormatExpectInteger {
224-
span: align.span(),
225-
});
226-
}
227-
}
228-
144+
cx.adcx().expected_integer_literal(align.span());
229145
return None;
230146
};
231147

@@ -235,12 +151,8 @@ fn parse_repr_align(
235151
AlignKind::Align => ReprAttr::ReprAlign(literal),
236152
}),
237153
Err(message) => {
238-
cx.emit_err(session_diagnostics::InvalidReprGeneric {
154+
cx.emit_err(session_diagnostics::InvalidAlignmentValue {
239155
span: lit.span,
240-
repr_arg: match align_kind {
241-
Packed => "packed".to_string(),
242-
Align => "align".to_string(),
243-
},
244156
error_part: message,
245157
});
246158
None
@@ -294,10 +206,7 @@ impl RustcAlignParser {
294206
};
295207

296208
let Some(lit) = align.as_lit() else {
297-
cx.emit_err(session_diagnostics::IncorrectReprFormatExpectInteger {
298-
span: align.span(),
299-
});
300-
209+
cx.adcx().expected_integer_literal(align.span());
301210
return;
302211
};
303212

0 commit comments

Comments
 (0)