diff --git a/compiler/rustc_macros/src/serialize.rs b/compiler/rustc_macros/src/serialize.rs index 7bc669f2b00..66e6b571beb 100644 --- a/compiler/rustc_macros/src/serialize.rs +++ b/compiler/rustc_macros/src/serialize.rs @@ -247,13 +247,24 @@ fn encodable_body( }) .collect(); - let result = quote! { ::rustc_serialize::Encoder::emit_enum_variant( - __encoder, - #variant_name, - #variant_idx, - #field_idx, - |__encoder| { ::std::result::Result::Ok({ #encode_fields }) } - ) }; + let result = if field_idx != 0 { + quote! { + ::rustc_serialize::Encoder::emit_enum_variant( + __encoder, + #variant_name, + #variant_idx, + #field_idx, + |__encoder| { ::std::result::Result::Ok({ #encode_fields }) } + ) + } + } else { + quote! { + ::rustc_serialize::Encoder::emit_fieldless_enum_variant::<#variant_idx>( + __encoder, + #variant_name, + ) + } + }; variant_idx += 1; result }); diff --git a/compiler/rustc_serialize/src/json.rs b/compiler/rustc_serialize/src/json.rs index e5369b4bbfd..df78e1bcbf6 100644 --- a/compiler/rustc_serialize/src/json.rs +++ b/compiler/rustc_serialize/src/json.rs @@ -589,6 +589,13 @@ impl<'a> crate::Encoder for Encoder<'a> { } } + fn emit_fieldless_enum_variant( + &mut self, + name: &str, + ) -> Result<(), Self::Error> { + escape_str(self.writer, name) + } + fn emit_enum_variant_arg(&mut self, first: bool, f: F) -> EncodeResult where F: FnOnce(&mut Encoder<'a>) -> EncodeResult, @@ -885,6 +892,13 @@ impl<'a> crate::Encoder for PrettyEncoder<'a> { } } + fn emit_fieldless_enum_variant( + &mut self, + name: &str, + ) -> Result<(), Self::Error> { + escape_str(self.writer, name) + } + fn emit_enum_variant_arg(&mut self, first: bool, f: F) -> EncodeResult where F: FnOnce(&mut PrettyEncoder<'a>) -> EncodeResult, diff --git a/compiler/rustc_serialize/src/serialize.rs b/compiler/rustc_serialize/src/serialize.rs index e32e4493726..96a2231b590 100644 --- a/compiler/rustc_serialize/src/serialize.rs +++ b/compiler/rustc_serialize/src/serialize.rs @@ -58,6 +58,20 @@ pub trait Encoder { f(self) } + // We put the field index in a const generic to allow the emit_usize to be + // compiled into a more efficient form. In practice, the variant index is + // known at compile-time, and that knowledge allows much more efficient + // codegen than we'd otherwise get. LLVM isn't always able to make the + // optimization that would otherwise be necessary here, likely due to the + // multiple levels of inlining and const-prop that are needed. + #[inline] + fn emit_fieldless_enum_variant( + &mut self, + _v_name: &str, + ) -> Result<(), Self::Error> { + self.emit_usize(ID) + } + #[inline] fn emit_enum_variant_arg(&mut self, _first: bool, f: F) -> Result<(), Self::Error> where