Skip to content

Commit 4d38c0b

Browse files
committed
rewrite the repr parser
1 parent eda04d0 commit 4d38c0b

File tree

2 files changed

+135
-203
lines changed

2 files changed

+135
-203
lines changed

compiler/rustc_attr_parsing/src/attributes/repr.rs

+127-203
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,11 @@
11
use rustc_abi::Align;
2-
use rustc_ast::{IntTy, LitIntType, LitKind, MetaItemLit, UintTy};
2+
use rustc_ast::{IntTy, LitIntType, LitKind, UintTy};
33
use rustc_attr_data_structures::{AttributeKind, IntType, ReprAttr};
4-
use rustc_span::symbol::Ident;
54
use rustc_span::{Span, Symbol, sym};
65

76
use super::{CombineAttributeParser, ConvertFn};
87
use crate::context::AcceptContext;
9-
use crate::parser::{ArgParser, MetaItemListParser, MetaItemOrLitParser, MetaItemParser};
8+
use crate::parser::{ArgParser, MetaItemListParser, MetaItemParser};
109
use crate::session_diagnostics;
1110
use crate::session_diagnostics::IncorrectReprFormatGenericCause;
1211

@@ -42,253 +41,178 @@ impl CombineAttributeParser for ReprParser {
4241
reprs
4342
}
4443
}
44+
macro_rules! int_pat {
45+
() => {
46+
sym::i8
47+
| sym::u8
48+
| sym::i16
49+
| sym::u16
50+
| sym::i32
51+
| sym::u32
52+
| sym::i64
53+
| sym::u64
54+
| sym::i128
55+
| sym::u128
56+
| sym::isize
57+
| sym::usize
58+
};
59+
}
4560

46-
fn parse_repr(cx: &AcceptContext<'_>, param: &MetaItemParser<'_>) -> Option<ReprAttr> {
47-
// FIXME(jdonszelmann): invert the parsing here to match on the word first and then the
48-
// structure.
49-
let (ident, args) = param.word_or_empty();
61+
// TODO: inline
62+
fn int_type_of_word(s: Symbol) -> Option<IntType> {
63+
use IntType::*;
5064

51-
if args.no_args() {
52-
parse_simple_repr(cx, ident, param.span())
53-
} else if let Some(list) = args.list() {
54-
parse_list_repr(cx, ident, list, param.span())
55-
} else if let Some(name_value) = args.name_value() {
56-
reject_name_value_repr(cx, ident, name_value.value_as_lit(), param.span());
57-
None
58-
} else {
59-
completely_unknown(cx, param.span());
60-
None
65+
match s {
66+
sym::i8 => Some(SignedInt(IntTy::I8)),
67+
sym::u8 => Some(UnsignedInt(UintTy::U8)),
68+
sym::i16 => Some(SignedInt(IntTy::I16)),
69+
sym::u16 => Some(UnsignedInt(UintTy::U16)),
70+
sym::i32 => Some(SignedInt(IntTy::I32)),
71+
sym::u32 => Some(UnsignedInt(UintTy::U32)),
72+
sym::i64 => Some(SignedInt(IntTy::I64)),
73+
sym::u64 => Some(UnsignedInt(UintTy::U64)),
74+
sym::i128 => Some(SignedInt(IntTy::I128)),
75+
sym::u128 => Some(UnsignedInt(UintTy::U128)),
76+
sym::isize => Some(SignedInt(IntTy::Isize)),
77+
sym::usize => Some(UnsignedInt(UintTy::Usize)),
78+
_ => None,
6179
}
6280
}
6381

64-
fn parse_list_repr(
82+
fn parse_repr(
6583
cx: &AcceptContext<'_>,
66-
ident: Ident,
67-
list: &MetaItemListParser<'_>,
68-
param_span: Span,
84+
param: &MetaItemParser<'_>,
6985
) -> Option<ReprAttr> {
70-
if let Some(single) = list.single() {
71-
match single {
72-
MetaItemOrLitParser::MetaItemParser(meta) => {
73-
reject_not_literal_list(cx, ident, meta.span(), param_span);
74-
None
75-
}
76-
MetaItemOrLitParser::Lit(lit) => parse_singleton_list_repr(cx, ident, lit, param_span),
77-
_ => unreachable!(),
78-
}
79-
} else {
80-
reject_not_one_element_list(cx, ident, param_span);
81-
None
82-
}
83-
}
86+
use ReprAttr::*;
8487

85-
fn reject_not_one_element_list(cx: &AcceptContext<'_>, ident: Ident, param_span: Span) {
86-
match ident.name {
87-
sym::align => {
88-
cx.dcx()
89-
.emit_err(session_diagnostics::IncorrectReprFormatAlignOneArg { span: param_span });
90-
}
91-
sym::packed => {
92-
cx.dcx().emit_err(session_diagnostics::IncorrectReprFormatPackedOneOrZeroArg {
93-
span: param_span,
94-
});
95-
}
96-
sym::Rust | sym::C | sym::simd | sym::transparent => {
97-
cx.dcx().emit_err(session_diagnostics::InvalidReprHintNoParen {
98-
span: param_span,
99-
name: ident.to_string(),
100-
});
101-
}
102-
other if int_type_of_word(other).is_some() => {
103-
cx.dcx().emit_err(session_diagnostics::InvalidReprHintNoParen {
104-
span: param_span,
105-
name: ident.to_string(),
106-
});
107-
}
108-
_ => {
109-
completely_unknown(cx, param_span);
110-
}
111-
}
112-
}
88+
// FIXME(jdonszelmann): invert the parsing here to match on the word first and then the
89+
// structure.
90+
let (ident, args) = param.word_or_empty();
11391

114-
fn reject_not_literal_list(
115-
cx: &AcceptContext<'_>,
116-
ident: Ident,
117-
meta_span: Span,
118-
param_span: Span,
119-
) {
120-
match ident.name {
121-
sym::align => {
122-
cx.dcx().emit_err(session_diagnostics::IncorrectReprFormatExpectInteger {
123-
span: meta_span,
124-
});
92+
match (ident.name, args) {
93+
(sym::align, ArgParser::NoArgs) => {
94+
cx.dcx().emit_err(session_diagnostics::InvalidReprAlignNeedArg { span: ident.span });
95+
None
12596
}
97+
(sym::align, ArgParser::List(l)) => parse_repr_align(cx, l, param.span(), AlignKind::Align),
12698

127-
sym::packed => {
128-
cx.dcx().emit_err(session_diagnostics::IncorrectReprFormatPackedExpectInteger {
129-
span: meta_span,
130-
});
131-
}
132-
sym::Rust | sym::C | sym::simd | sym::transparent => {
133-
cx.dcx().emit_err(session_diagnostics::InvalidReprHintNoParen {
134-
span: param_span,
135-
name: ident.to_string(),
136-
});
137-
}
138-
other if int_type_of_word(other).is_some() => {
139-
cx.dcx().emit_err(session_diagnostics::InvalidReprHintNoParen {
140-
span: param_span,
141-
name: ident.to_string(),
142-
});
143-
}
144-
_ => {
145-
completely_unknown(cx, param_span);
146-
}
147-
}
148-
}
99+
(sym::packed, ArgParser::NoArgs) => Some(ReprPacked(Align::ONE)),
100+
(sym::packed, ArgParser::List(l)) => parse_repr_align(cx, l, param.span(), AlignKind::Packed),
149101

150-
fn reject_name_value_repr(
151-
cx: &AcceptContext<'_>,
152-
ident: Ident,
153-
value: &MetaItemLit,
154-
param_span: Span,
155-
) {
156-
match ident.name {
157-
sym::align | sym::packed => {
102+
(sym::align | sym::packed, ArgParser::NameValue(l)) => {
158103
cx.dcx().emit_err(session_diagnostics::IncorrectReprFormatGeneric {
159-
span: param_span,
104+
span: param.span(),
160105
// FIXME(jdonszelmann) can just be a string in the diag type
161106
repr_arg: &ident.to_string(),
162107
cause: IncorrectReprFormatGenericCause::from_lit_kind(
163-
param_span,
164-
&value.kind,
108+
param.span(),
109+
&l.value_as_lit().kind,
165110
ident.name.as_str(),
166111
),
167112
});
113+
None
168114
}
169-
sym::Rust | sym::C | sym::simd | sym::transparent => {
170-
cx.dcx().emit_err(session_diagnostics::InvalidReprHintNoValue {
171-
span: param_span,
172-
name: ident.to_string(),
173-
});
115+
116+
(sym::Rust, ArgParser::NoArgs) => {
117+
Some(ReprRust)
174118
}
175-
other if int_type_of_word(other).is_some() => {
176-
cx.dcx().emit_err(session_diagnostics::InvalidReprHintNoValue {
177-
span: param_span,
178-
name: ident.to_string(),
179-
});
119+
(sym::C, ArgParser::NoArgs) => {
120+
Some(ReprC)
180121
}
181-
_ => {
182-
completely_unknown(cx, param_span);
122+
(sym::simd, ArgParser::NoArgs) => {
123+
Some(ReprSimd)
124+
}
125+
(sym::transparent, ArgParser::NoArgs) => {
126+
Some(ReprTransparent)
127+
}
128+
(i@int_pat!(), ArgParser::NoArgs) => {
129+
// int_pat!() should make sure it always parses
130+
Some(ReprInt(int_type_of_word(i).unwrap()))
183131
}
184-
}
185-
}
186132

187-
fn parse_singleton_list_repr(
188-
cx: &AcceptContext<'_>,
189-
ident: Ident,
190-
lit: &MetaItemLit,
191-
param_span: Span,
192-
) -> Option<ReprAttr> {
193-
match ident.name {
194-
sym::align => match parse_alignment(&lit.kind) {
195-
Ok(literal) => Some(ReprAttr::ReprAlign(literal)),
196-
Err(message) => {
197-
cx.dcx().emit_err(session_diagnostics::InvalidReprGeneric {
198-
span: lit.span,
199-
repr_arg: ident.to_string(),
200-
error_part: message,
201-
});
202-
None
203-
}
204-
},
205-
sym::packed => match parse_alignment(&lit.kind) {
206-
Ok(literal) => Some(ReprAttr::ReprPacked(literal)),
207-
Err(message) => {
208-
cx.dcx().emit_err(session_diagnostics::InvalidReprGeneric {
209-
span: lit.span,
210-
repr_arg: ident.to_string(),
211-
error_part: message,
212-
});
213-
None
214-
}
215-
},
216-
sym::Rust | sym::C | sym::simd | sym::transparent => {
217-
cx.dcx().emit_err(session_diagnostics::InvalidReprHintNoParen {
218-
span: param_span,
133+
(sym::Rust | sym::C | sym::simd | sym::transparent | int_pat!(), ArgParser::NameValue(_)) => {
134+
cx.dcx().emit_err(session_diagnostics::InvalidReprHintNoValue {
135+
span: param.span(),
219136
name: ident.to_string(),
220137
});
221138
None
222139
}
223-
other if int_type_of_word(other).is_some() => {
140+
(sym::Rust | sym::C | sym::simd | sym::transparent | int_pat!(), ArgParser::List(_)) => {
224141
cx.dcx().emit_err(session_diagnostics::InvalidReprHintNoParen {
225-
span: param_span,
142+
span: param.span(),
226143
name: ident.to_string(),
227144
});
228145
None
229146
}
147+
230148
_ => {
231-
completely_unknown(cx, param_span);
149+
cx.dcx().emit_err(session_diagnostics::UnrecognizedReprHint { span: param.span() });
232150
None
233151
}
234152
}
235153
}
236154

237-
fn parse_simple_repr(cx: &AcceptContext<'_>, ident: Ident, param_span: Span) -> Option<ReprAttr> {
238-
use ReprAttr::*;
239-
match ident.name {
240-
sym::Rust => Some(ReprRust),
241-
sym::C => Some(ReprC),
242-
sym::packed => Some(ReprPacked(Align::ONE)),
243-
sym::simd => Some(ReprSimd),
244-
sym::transparent => Some(ReprTransparent),
245-
sym::align => {
246-
cx.dcx().emit_err(session_diagnostics::InvalidReprAlignNeedArg { span: ident.span });
247-
None
248-
}
249-
other => {
250-
if let Some(int) = int_type_of_word(other) {
251-
Some(ReprInt(int))
252-
} else {
253-
completely_unknown(cx, param_span);
254-
None
155+
enum AlignKind {
156+
Packed,
157+
Align
158+
}
159+
160+
fn parse_repr_align(cx: &AcceptContext<'_>, list: &MetaItemListParser<'_>, param_span: Span, align_kind: AlignKind) -> Option<ReprAttr> {
161+
use AlignKind::*;
162+
163+
let Some(align) = list.single() else {
164+
match align_kind {
165+
Packed => {
166+
cx.dcx().emit_err(session_diagnostics::IncorrectReprFormatPackedOneOrZeroArg {
167+
span: param_span,
168+
});
169+
},
170+
Align => {
171+
cx.dcx()
172+
.emit_err(session_diagnostics::IncorrectReprFormatAlignOneArg { span: param_span });
255173
}
256174
}
257-
}
258-
}
259175

260-
// Not a word we recognize. This will be caught and reported by
261-
// the `check_mod_attrs` pass, but this pass doesn't always run
262-
// (e.g. if we only pretty-print the source), so we have to gate
263-
// the `span_delayed_bug` call as follows:
264-
// TODO: remove this in favor of just reporting the error here if we can...
265-
fn completely_unknown(cx: &AcceptContext<'_>, param_span: Span) {
266-
if cx.sess().opts.pretty.map_or(true, |pp| pp.needs_analysis()) {
267-
cx.dcx().span_delayed_bug(param_span, "unrecognized representation hint");
268-
}
269-
}
176+
return None
177+
};
270178

271-
fn int_type_of_word(s: Symbol) -> Option<IntType> {
272-
use IntType::*;
179+
let Some(lit) = align.lit() else {
180+
match align_kind {
181+
Packed => {
182+
cx.dcx().emit_err(session_diagnostics::IncorrectReprFormatPackedExpectInteger {
183+
span: align.span(),
184+
});
185+
},
186+
Align => {
187+
cx.dcx().emit_err(session_diagnostics::IncorrectReprFormatExpectInteger {
188+
span: align.span(),
189+
});
190+
}
191+
}
273192

274-
match s {
275-
sym::i8 => Some(SignedInt(IntTy::I8)),
276-
sym::u8 => Some(UnsignedInt(UintTy::U8)),
277-
sym::i16 => Some(SignedInt(IntTy::I16)),
278-
sym::u16 => Some(UnsignedInt(UintTy::U16)),
279-
sym::i32 => Some(SignedInt(IntTy::I32)),
280-
sym::u32 => Some(UnsignedInt(UintTy::U32)),
281-
sym::i64 => Some(SignedInt(IntTy::I64)),
282-
sym::u64 => Some(UnsignedInt(UintTy::U64)),
283-
sym::i128 => Some(SignedInt(IntTy::I128)),
284-
sym::u128 => Some(UnsignedInt(UintTy::U128)),
285-
sym::isize => Some(SignedInt(IntTy::Isize)),
286-
sym::usize => Some(UnsignedInt(UintTy::Usize)),
287-
_ => None,
193+
return None
194+
};
195+
196+
match parse_alignment(&lit.kind) {
197+
Ok(literal) => Some(match align_kind {
198+
AlignKind::Packed => ReprAttr::ReprPacked(literal),
199+
AlignKind::Align => ReprAttr::ReprAlign(literal),
200+
}),
201+
Err(message) => {
202+
cx.dcx().emit_err(session_diagnostics::InvalidReprGeneric {
203+
span: lit.span,
204+
repr_arg: match align_kind {
205+
Packed => "packed".to_string(),
206+
Align => "align".to_string(),
207+
},
208+
error_part: message,
209+
});
210+
None
211+
}
288212
}
289213
}
290214

291-
pub(crate) fn parse_alignment(node: &LitKind) -> Result<Align, &'static str> {
215+
fn parse_alignment(node: &LitKind) -> Result<Align, &'static str> {
292216
if let LitKind::Int(literal, LitIntType::Unsuffixed) = node {
293217
// `Align::from_bytes` accepts 0 as an input, check is_power_of_two() first
294218
if literal.get().is_power_of_two() {

0 commit comments

Comments
 (0)