@@ -155,7 +155,7 @@ impl StringCache {
155
155
156
156
// NOTE: Deriving Eq here implies that a given string must always
157
157
// be interned the same way.
158
- #[ unsafe_no_drop_flag]
158
+ #[ unsafe_no_drop_flag] // See tests::atom_drop_is_idempotent
159
159
#[ derive( Eq , Hash , PartialEq ) ]
160
160
pub struct Atom {
161
161
/// This field is public so that the `atom!()` macro can use it.
@@ -236,10 +236,7 @@ impl Drop for Atom {
236
236
237
237
unsafe {
238
238
match string_cache_shared:: from_packed_dynamic ( self . data ) {
239
- // We use #[unsafe_no_drop_flag] so that Atom will be only 64
240
- // bits. That means we need to ignore a NULL pointer here,
241
- // which represents a value that was moved out.
242
- Some ( entry) if !entry. is_null ( ) => {
239
+ Some ( entry) => {
243
240
let entry = entry as * mut StringCacheEntry ;
244
241
if ( * entry) . ref_count . fetch_sub ( 1 , SeqCst ) == 1 {
245
242
drop_slow ( self ) ;
@@ -251,6 +248,7 @@ impl Drop for Atom {
251
248
}
252
249
}
253
250
251
+
254
252
impl ops:: Deref for Atom {
255
253
type Target = str ;
256
254
@@ -548,4 +546,15 @@ mod tests {
548
546
let atom = Atom :: from_slice ( "foobar" ) ;
549
547
let _: & str = atom. as_ref ( ) ;
550
548
}
549
+
550
+ /// Atom uses #[unsafe_no_drop_flag] to stay small, so drop() may be called more than once.
551
+ /// In calls after the first one, the atom will be filled with a POST_DROP value.
552
+ /// drop() must be a no-op in this case.
553
+ #[ test]
554
+ fn atom_drop_is_idempotent ( ) {
555
+ unsafe {
556
+ assert_eq ! ( :: string_cache_shared:: from_packed_dynamic( :: std:: mem:: POST_DROP_U64 ) , None ) ;
557
+ }
558
+ }
559
+
551
560
}
0 commit comments