Skip to content

Conversation

@eramongodb
Copy link
Contributor

Related to CXX-2745 and CXX-3320. This PR proposes defining a BSONCXX_PRIVATE_INLINE_CXX17 macro for use with inline variables to prevent their inclusion in the (stable) ABI. This also extends support for declaring constexpr variables as inline (or equivalent) while fixing distinct behaviors across compilers, improving C++17 forward compatibility.

Important

This changes in this PR remove v1::types::b_*::type_id and v1::oid::k_oid_length from the (experimental) stable ABI.

Note

The BSONCXX_PRIVATE_INLINE_CXX17 macro is for use with variables, not functions.

Initially motivated by this GCC warning when compiling with certain configurations such as with -fsanitize=address,undefined on RHEL:

error: 'bsoncxx::detail::strong_ordering::less' declared weak after being used
     static strong_ordering const less;
                                  ^~~~

This required moving the inverted() function after the out-of-line definitions containing the [[gnu::weak]] attribute. This prompted further investigation into the potential use of [[gnu::weak]] with constexpr static data members. However, this effort was halted by this Clang issue:

struct S { static constexpr int var = 0; }; // s.hpp
[[gnu::weak]] constexpr int S::var;         // s.hpp (namespace scope)
static constexpr int usage = S::var;        // constexpr usage

where Clang emits the following compilation error with C++ standards prior to C++17:

error: constexpr variable 'usage' must be initialized by a constant expression
      | static constexpr int usage = S::var; // constexpr usage
      |                      ^       ~~~~~~
note: initializer of weak variable 'var' is not considered constant because it may be different at runtime
      | static constexpr int usage = S::var; // constexpr usage
      |                              ^
note: declared here
      | struct S { static constexpr int var = 0; }; // s.hpp
      |                                 ^

Clang does not support the declaration of a constexpr variable as a "weak" symbol due to what Clang interprets as contradictory intent: constexpr is "a value computable at compile-time", whereas "weak" is "a value potentially overridden at runtime". This is not the case for GCC or MSVC which appear to interpret the "potentially-overwritten" behavior as an allowance rather than explicit intent.

To avoid including static data members in the stable ABI, this PR proposes making an initiative to move away from [[gnu::weak]] with Clang and instead use its __inline__ extension instead. As mentioned in the BSONCXX_PRIVATE_INLINE_CXX17 documentation comment, this extension is supported by all relevant Clang compilers.

Similarly, the macro definition is updated to use inline with supported MSVC compiler versions instead of unconditionally using __declspec(selectany)... when it is correctly supported: versions prior to 19.20, aka before "Visual Studio 2019", produce "multiple definition" errors for inline static data members, but not for regular namespace-scope variables which appear to work as intended.

Unfortunately, it seems the strong_ordering data members cannot be declared constexpr due to not being a literal type. However, given this is internal API, I believe the discrepancy from specification is acceptable so long as it is known to maintainers.

@eramongodb eramongodb self-assigned this Sep 26, 2025
@eramongodb eramongodb requested a review from a team as a code owner September 26, 2025 18:15
Copy link
Contributor

@vector-of-bool vector-of-bool left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

#define BSONCXX_PRIVATE_INLINE_CXX17 inline
#else
#define BSONCXX_PRIVATE_INLINE_CXX17 \
BSONCXX_PRIVATE_IF_GCC([[gnu::weak]]) \
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I expect this needs to be moved below where BSONCXX_PRIVATE_IF_GCC (and others) are defined below.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is not necessary due to BSONCXX_PRIVATE_IF_GCC(...) only being evaluated/substituted when BSONCXX_PRIVATE_INLINE_CXX17 is evaluated/substituted. So long as both macro definitions are visible at the point of substitution, the order does not matter. Nevertheless, moved them below as suggested to better match a typical declaration-dependent order.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Doh right. Thank you for the example.

@eramongodb eramongodb merged commit 10f7c5f into mongodb:master Sep 30, 2025
21 checks passed
@eramongodb eramongodb deleted the cxx-abi-v1-inline branch September 30, 2025 14:07
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants