diff --git a/CHANGES b/CHANGES index 6fd28678..f34ae9ed 100644 --- a/CHANGES +++ b/CHANGES @@ -1,5 +1,8 @@ # unreleased + * Wrap conditional fields in `#if` blocks in generated C++ `operator==` and + `operator!=`, so headers still compile when a feature is disabled (#937). + * Emit `&str`, `&CStr`, and arrays thereof as C string literals, and byte-string (`b"..."`) constants as `uint8_t[]` arrays, instead of dropping them. diff --git a/src/bindgen/language_backend/clike.rs b/src/bindgen/language_backend/clike.rs index 4d927abe..c105bc54 100644 --- a/src/bindgen/language_backend/clike.rs +++ b/src/bindgen/language_backend/clike.rs @@ -287,19 +287,36 @@ impl<'a> CLikeLanguageBackend<'a> { other ); out.open_brace(); - out.write("return "); - let vec: Vec<_> = s - .fields - .iter() - .skip(skip_fields) - .map(|field| format!("{} {} {}.{}", field.name, $op, other, field.name)) - .collect(); - out.write_vertical_source_list( - self, - &vec[..], - ListType::Join(&format!(" {}", $conjuc)), - |_, out, s| write!(out, "{}", s), - ); + out.write("return"); + let fields = &s.fields[skip_fields..]; + if matches!($op, "==" | "!=") && fields.iter().any(|field| field.cfg.is_some()) { + out.new_line(); + for field in fields { + let condition = field.cfg.to_condition(self.config); + condition.write_before(self.config, out); + write!( + out, + "{} {} {}.{} {}", + field.name, $op, other, field.name, $conjuc + ); + condition.write_after(self.config, out); + out.new_line(); + } + // A neutral operand keeps the expression valid even if all fields are absent. + write!(out, "{}", $op == "=="); + } else { + out.write(" "); + let vec: Vec<_> = fields + .iter() + .map(|field| format!("{} {} {}.{}", field.name, $op, other, field.name)) + .collect(); + out.write_vertical_source_list( + self, + &vec[..], + ListType::Join(&format!(" {}", $conjuc)), + |_, out, s| write!(out, "{}", s), + ); + } out.write(";"); out.close_brace(false); }}; diff --git a/tests/expectations/cfg.cpp b/tests/expectations/cfg.cpp index 13063484..05287631 100644 --- a/tests/expectations/cfg.cpp +++ b/tests/expectations/cfg.cpp @@ -266,6 +266,21 @@ struct ConditionalField { int32_t field #endif ; + + bool operator==(const ConditionalField& other) const { + return +#if defined(X11) + field == other.field && +#endif + true; + } + bool operator!=(const ConditionalField& other) const { + return +#if defined(X11) + field != other.field || +#endif + false; + } }; constexpr static const ConditionalField ConditionalField_ZERO = ConditionalField{ #if defined(X11) diff --git a/tests/rust/cfg.rs b/tests/rust/cfg.rs index b42c1d1a..a002333d 100644 --- a/tests/rust/cfg.rs +++ b/tests/rust/cfg.rs @@ -60,9 +60,6 @@ struct BarHandle { y: f32, } -// FIXME(#634): Support deriving methods for structs with conditional fields. -/// cbindgen:derive-eq=false -/// cbindgen:derive-neq=false #[repr(C)] struct ConditionalField { #[cfg(x11)]