Skip to content

Commit 2805cc3

Browse files
committed
Validate repr attribute
1 parent b6d2d98 commit 2805cc3

File tree

3 files changed

+67
-1
lines changed

3 files changed

+67
-1
lines changed

enumflags_derive/src/lib.rs

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -106,7 +106,7 @@ fn collect_flags<'a>(variants: impl Iterator<Item=&'a syn::Variant>)
106106
/// Given a list of attributes, find the `repr`, if any, and return the integer
107107
/// type specified.
108108
fn extract_repr(attrs: &[syn::Attribute])
109-
-> Result<Option<syn::Ident>, syn::Error>
109+
-> Result<Option<Ident>, syn::Error>
110110
{
111111
use syn::{Meta, NestedMeta};
112112
attrs.iter()
@@ -132,6 +132,29 @@ fn extract_repr(attrs: &[syn::Attribute])
132132
.transpose()
133133
}
134134

135+
/// Check the repr and return the number of bits available
136+
fn type_bits(ty: &Ident) -> Result<u8, syn::Error> {
137+
// This would be so much easier if we could just match on an Ident...
138+
if ty == "usize" {
139+
Err(syn::Error::new_spanned(ty,
140+
"#[repr(usize)] is not supported. Use u32 or u64 instead."))
141+
}
142+
else if ty == "i8" || ty == "i16" || ty == "i32"
143+
|| ty == "i64" || ty == "i128" || ty == "isize" {
144+
Err(syn::Error::new_spanned(ty,
145+
"Signed types in a repr are not supported."))
146+
}
147+
else if ty == "u8" { Ok(8) }
148+
else if ty == "u16" { Ok(16) }
149+
else if ty == "u32" { Ok(32) }
150+
else if ty == "u64" { Ok(64) }
151+
else if ty == "u128" { Ok(128) }
152+
else {
153+
Err(syn::Error::new_spanned(ty,
154+
"repr must be an integer type for #[bitflags]."))
155+
}
156+
}
157+
135158
/// Returns deferred checks
136159
fn check_flag(
137160
type_name: &Ident,
@@ -193,6 +216,7 @@ fn gen_enumflags(ident: &Ident, item: &DeriveInput, data: &DataEnum)
193216
let ty = extract_repr(&item.attrs)?
194217
.ok_or_else(|| syn::Error::new_spanned(&ident,
195218
"repr attribute missing. Add #[repr(u64)] or a similar attribute to specify the size of the bitfield."))?;
219+
type_bits(&ty)?;
196220
let std_path = quote_spanned!(span => ::enumflags2::_internal::core);
197221

198222
Ok(quote_spanned! {

test_suite/ui/invalid_repr.rs

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
#[enumflags2::bitflags]
2+
#[repr(C)]
3+
#[derive(Clone, Copy)]
4+
enum NotAType {
5+
Bar = 1,
6+
Baz = 2,
7+
}
8+
9+
#[enumflags2::bitflags]
10+
#[repr(i32)]
11+
#[derive(Clone, Copy)]
12+
enum SignedType {
13+
Bar = 1,
14+
Baz = 2,
15+
}
16+
17+
#[enumflags2::bitflags]
18+
#[repr(usize)]
19+
#[derive(Clone, Copy)]
20+
enum Usize {
21+
Bar = 1,
22+
Baz = 2,
23+
}
24+
25+
fn main() {}

test_suite/ui/invalid_repr.stderr

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
error: repr must be an integer type for #[bitflags].
2+
--> $DIR/invalid_repr.rs:2:8
3+
|
4+
2 | #[repr(C)]
5+
| ^
6+
7+
error: Signed types in a repr are not supported.
8+
--> $DIR/invalid_repr.rs:10:8
9+
|
10+
10 | #[repr(i32)]
11+
| ^^^
12+
13+
error: #[repr(usize)] is not supported. Use u32 or u64 instead.
14+
--> $DIR/invalid_repr.rs:18:8
15+
|
16+
18 | #[repr(usize)]
17+
| ^^^^^

0 commit comments

Comments
 (0)