mirror of
https://gitee.com/openharmony/third_party_rust_cxx
synced 2025-02-13 10:47:43 +00:00
Properly handle enum discriminant overflows.
This both checks for enum values that are illegal due to overflow and ensures we do not overflow on valid enums.
This commit is contained in:
parent
b3fcf7b724
commit
04fa0967e2
@ -127,14 +127,19 @@ fn expand_struct(strct: &Struct) -> TokenStream {
|
||||
fn expand_enum(enm: &Enum) -> TokenStream {
|
||||
let ident = &enm.ident;
|
||||
let doc = &enm.doc;
|
||||
let variants = enm.variants.iter().scan(0, |next_discriminant, variant| {
|
||||
let variant_ident = &variant.ident;
|
||||
let discriminant = variant.discriminant.unwrap_or(*next_discriminant);
|
||||
*next_discriminant = discriminant + 1;
|
||||
Some(quote! {
|
||||
pub const #variant_ident: Self = #ident(#discriminant);
|
||||
})
|
||||
});
|
||||
let variants = enm
|
||||
.variants
|
||||
.iter()
|
||||
.scan(None, |prev_discriminant, variant| {
|
||||
let variant_ident = &variant.ident;
|
||||
let discriminant = variant
|
||||
.discriminant
|
||||
.unwrap_or_else(|| prev_discriminant.map_or(0, |n| n + 1));
|
||||
*prev_discriminant = Some(discriminant);
|
||||
Some(quote! {
|
||||
pub const #variant_ident: Self = #ident(#discriminant);
|
||||
})
|
||||
});
|
||||
quote! {
|
||||
#doc
|
||||
#[derive(Copy, Clone, PartialEq, Eq)]
|
||||
|
@ -204,14 +204,23 @@ fn check_api_enum(cx: &mut Check, enm: &Enum) {
|
||||
}
|
||||
|
||||
let mut discriminants = HashSet::new();
|
||||
enm.variants.iter().fold(0, |next_discriminant, variant| {
|
||||
let discriminant = variant.discriminant.unwrap_or(next_discriminant);
|
||||
if !discriminants.insert(discriminant) {
|
||||
let msg = format!("discriminant value `{}` already exists", discriminant);
|
||||
cx.error(span_for_enum_error(enm), msg);
|
||||
}
|
||||
discriminant + 1
|
||||
});
|
||||
enm.variants
|
||||
.iter()
|
||||
.fold(None, |prev_discriminant, variant| {
|
||||
if variant.discriminant.is_none() && prev_discriminant.unwrap_or(0) == u32::MAX {
|
||||
let msg = format!("overflowed on value after {}", prev_discriminant.unwrap());
|
||||
cx.error(span_for_enum_error(enm), msg);
|
||||
return None;
|
||||
}
|
||||
let discriminant = variant
|
||||
.discriminant
|
||||
.unwrap_or_else(|| prev_discriminant.map_or(0, |n| n + 1));
|
||||
if !discriminants.insert(discriminant) {
|
||||
let msg = format!("discriminant value `{}` already exists", discriminant);
|
||||
cx.error(span_for_enum_error(enm), msg);
|
||||
}
|
||||
Some(discriminant)
|
||||
});
|
||||
}
|
||||
|
||||
fn check_api_type(cx: &mut Check, ty: &ExternType) {
|
||||
|
17
tests/ui/enum_overflows.rs
Normal file
17
tests/ui/enum_overflows.rs
Normal file
@ -0,0 +1,17 @@
|
||||
#[cxx::bridge]
|
||||
mod ffi {
|
||||
enum Good1 {
|
||||
A = 0xffffffff,
|
||||
}
|
||||
enum Good2 {
|
||||
B = 0xffffffff,
|
||||
C = 2020,
|
||||
}
|
||||
enum Bad {
|
||||
D = 0xfffffffe,
|
||||
E,
|
||||
F,
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {}
|
9
tests/ui/enum_overflows.stderr
Normal file
9
tests/ui/enum_overflows.stderr
Normal file
@ -0,0 +1,9 @@
|
||||
error: overflowed on value after 4294967295
|
||||
--> $DIR/enum_overflows.rs:10:5
|
||||
|
|
||||
10 | / enum Bad {
|
||||
11 | | D = 0xfffffffe,
|
||||
12 | | E,
|
||||
13 | | F,
|
||||
14 | | }
|
||||
| |_____^
|
Loading…
x
Reference in New Issue
Block a user