From ebe0af335cfe291d1666c413825e38e751638de7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Emilio=20Cobos=20=C3=81lvarez?= Date: Mon, 16 Dec 2019 11:19:35 +0100 Subject: [PATCH] enum: Add an option to generate copy-assignments. And recommend its usage if copy-constructors are being generated, as otherwise C++ in its whole glory would do a bitwise copy, which is not really what you want if you have constructors / destructors around. --- docs.md | 7 ++++++ src/bindgen/config.rs | 11 +++++++++ src/bindgen/ir/enumeration.rs | 23 +++++++++++++++++++ .../expectations/destructor-and-copy-ctor.cpp | 21 +++++++++++++++++ tests/rust/destructor-and-copy-ctor.rs | 7 ++++++ tests/rust/destructor-and-copy-ctor.toml | 1 + 6 files changed, 70 insertions(+) diff --git a/docs.md b/docs.md index 8b85de391..ad18d4035 100644 --- a/docs.md +++ b/docs.md @@ -723,6 +723,13 @@ derive_tagged_enum_destructor = false # # default: false derive_tagged_enum_copy_constructor = false +# Whether enums with fields should generate copy-assignment operators. +# +# This depends on also deriving copy-constructors, and it is highly encouraged +# for this to be set to true. +# +# default: false +derive_tagged_enum_copy_assignment = false # Whether enums with fields should generate an empty, private destructor. # This allows the auto-generated constructor functions to compile, if there are diff --git a/src/bindgen/config.rs b/src/bindgen/config.rs index 70787bff5..19bae831c 100644 --- a/src/bindgen/config.rs +++ b/src/bindgen/config.rs @@ -420,6 +420,11 @@ pub struct EnumConfig { pub derive_tagged_enum_destructor: bool, /// Whether to generate copy-constructors of tagged enums. pub derive_tagged_enum_copy_constructor: bool, + /// Whether to generate copy-assignment operators of tagged enums. + /// + /// This is only generated if a copy constructor for the same tagged enum is + /// generated as well. + pub derive_tagged_enum_copy_assignment: bool, /// Whether to generate empty, private default-constructors for tagged /// enums. pub private_default_tagged_enum_constructor: bool, @@ -462,6 +467,12 @@ impl EnumConfig { } self.derive_tagged_enum_copy_constructor } + pub(crate) fn derive_tagged_enum_copy_assignment(&self, annotations: &AnnotationSet) -> bool { + if let Some(x) = annotations.bool("derive-tagged-enum-copy-assignment") { + return x; + } + self.derive_tagged_enum_copy_assignment + } pub(crate) fn private_default_tagged_enum_constructor( &self, annotations: &AnnotationSet, diff --git a/src/bindgen/ir/enumeration.rs b/src/bindgen/ir/enumeration.rs index 22fbbb56c..b0035c156 100644 --- a/src/bindgen/ir/enumeration.rs +++ b/src/bindgen/ir/enumeration.rs @@ -977,6 +977,29 @@ impl Source for Enum { write!(out, "default: break;"); out.close_brace(false); out.close_brace(false); + + if config.language == Language::Cxx + && config + .enumeration + .derive_tagged_enum_copy_assignment(&self.annotations) + { + out.new_line(); + write!( + out, + "{}& operator=(const {}& {})", + self.export_name, self.export_name, other + ); + out.open_brace(); + write!(out, "if (this != &{})", other); + out.open_brace(); + write!(out, "this->~{}();", self.export_name); + out.new_line(); + write!(out, "new (this) {}({});", self.export_name, other); + out.close_brace(false); + out.new_line(); + write!(out, "return *this;"); + out.close_brace(false); + } } if let Some(body) = config.export.extra_body(&self.path) { diff --git a/tests/expectations/destructor-and-copy-ctor.cpp b/tests/expectations/destructor-and-copy-ctor.cpp index 958710ce5..9c0bbedb0 100644 --- a/tests/expectations/destructor-and-copy-ctor.cpp +++ b/tests/expectations/destructor-and-copy-ctor.cpp @@ -163,6 +163,13 @@ struct Foo { default: break; } } + Foo& operator=(const Foo& other) { + if (this != &other) { + this->~Foo(); + new (this) Foo(other); + } + return *this; + } }; template @@ -310,6 +317,13 @@ union Baz { default: break; } } + Baz& operator=(const Baz& other) { + if (this != &other) { + this->~Baz(); + new (this) Baz(other); + } + return *this; + } }; union Taz { @@ -390,6 +404,13 @@ union Taz { default: break; } } + Taz& operator=(const Taz& other) { + if (this != &other) { + this->~Taz(); + new (this) Taz(other); + } + return *this; + } }; union Tazz { diff --git a/tests/rust/destructor-and-copy-ctor.rs b/tests/rust/destructor-and-copy-ctor.rs index 48ba6fa25..24ccf1879 100644 --- a/tests/rust/destructor-and-copy-ctor.rs +++ b/tests/rust/destructor-and-copy-ctor.rs @@ -64,5 +64,12 @@ pub enum Tazz { Taz2(i32), } +/// cbindgen:derive-tagged-enum-copy-assignment=false +#[repr(u8)] +pub enum Tazz { + Bar4, + Taz2(i32), +} + #[no_mangle] pub extern "C" fn root(a: &Foo, b: &Baz, c: &Taz, d: Tazz) {} diff --git a/tests/rust/destructor-and-copy-ctor.toml b/tests/rust/destructor-and-copy-ctor.toml index bb973b61b..55e2a6c28 100644 --- a/tests/rust/destructor-and-copy-ctor.toml +++ b/tests/rust/destructor-and-copy-ctor.toml @@ -1,6 +1,7 @@ [enum] derive_tagged_enum_destructor = true derive_tagged_enum_copy_constructor = true +derive_tagged_enum_copy_assignment = true derive_helper_methods = true private_default_tagged_enum_constructor = true