Skip to content

[CDRIVER-6043] Modify definitions in intutil to avoid compound-literals #2056

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Conversation

vector-of-bool
Copy link
Contributor

@vector-of-bool vector-of-bool commented Jul 9, 2025

The following changes are made:

  • We avoid compound literals expanded from macros. This is to avoid buggy compound-literal support in VS 2017 (See CDRIVER-6043).

    Instead, we pass the relevant argument to a function that initializes the new aggregate object.

    This has the downside that we cannot use the macros in constant expressions, but that was a minor feature that wasn't really used anywhere.

  • Add a new macro to define bit masks. This simplifies the expressions that build bit patterns used for two's complement arithmetic.

  • Rename the members of mlib_upsized_integer to give them meaningful names.

This doesn't fully fix CDRIVER-6043, but will avoid future subtle issues with VS 2017.

The followin changes are made:

- We avoid compound literals expanded from macros. This is to avoid
  buggy compound-literal support in VS 2017 (See CDRIVER-6043).

  Instead, we pass the relevant argument to a function that initializes
  the new aggregate object.

  This has the downside that we cannot use the macros in constant
  expressions, but that was a minor feature that wasn't really used
  anywhere.
- Add a new macro to define bit masks. This simplifies the expressions
  that build bit patterns used for two's complement arithmetic.
- Rename the members of `mlib_upsized_integer` to give them meaningful
  names.
@vector-of-bool vector-of-bool requested a review from eramongodb July 9, 2025 17:26
@vector-of-bool vector-of-bool requested a review from a team as a code owner July 9, 2025 17:26
Copy link
Contributor

@eramongodb eramongodb left a comment

Choose a reason for hiding this comment

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

Very welcome changes! Minor suggestions mostly concerning type/signedness consistency, but otherwise LGTM.

/**
* @brief Like `sizeof`, but returns the number of bits in the object representation
*/
#define mlib_bitsizeof(T) ((sizeof (T)) * CHAR_BIT)
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
#define mlib_bitsizeof(T) ((sizeof (T)) * CHAR_BIT)
#define mlib_bitsizeof(T) ((sizeof (T)) * ((size_t) CHAR_BIT))

Type consistency.

/**
* @brief Generate a mask of contiguous bits.
*
* @param NumOnes The number of contiguous 1 bits
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
* @param NumOnes The number of contiguous 1 bits
* @param NumOnes The positive number of contiguous 1 bits

To document the requirement that NumOnes > 0:

// warning: shift count >= width of type [-Wshift-count-overflow]
// runtime error: shift exponent 64 is too large for 64-bit type 'unsigned long'
mlib_bits(0, 0)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Tweaked the definition to support setting zero 1 bits to "do the right thing", also tests for this.

* @brief Generate a mask of contiguous bits.
*
* @param NumOnes The number of contiguous 1 bits
* @param NumZeros The number of contiguous 0 bits to set in the low position
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
* @param NumZeros The number of contiguous 0 bits to set in the low position
* @param NumZeros The non-negative number of contiguous 0 bits to set in the low position

To document the requirement that NumZeroes >= 0.

Comment on lines 65 to 73
#define mlib_bits(NumOnes, NumZeros) ( \
/* Create a set of N 1 bits */ \
(/* Create a mask of all 0b1111... */ \
~UINTMAX_C(0) \
/* Shift down the chop off to only the number of 1 bits we want */ \
>> (mlib_bitsizeof(uintmax_t) - (uintmax_t)(NumOnes))) \
/* Shift left to add the low zeros */\
<< ((uintmax_t)(NumZeros)) \
)
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
#define mlib_bits(NumOnes, NumZeros) ( \
/* Create a set of N 1 bits */ \
(/* Create a mask of all 0b1111... */ \
~UINTMAX_C(0) \
/* Shift down the chop off to only the number of 1 bits we want */ \
>> (mlib_bitsizeof(uintmax_t) - (uintmax_t)(NumOnes))) \
/* Shift left to add the low zeros */\
<< ((uintmax_t)(NumZeros)) \
)
#define mlib_bits(NumOnes, NumZeros) ( \
(~UINTMAX_C(0) >> (mlib_bitsizeof(uintmax_t) - (uintmax_t)(NumOnes))) \
<< ((uintmax_t)(NumZeros)))

I think the thorough inline comments may be hurting readability more than helping. Suggest deferring the explanation to the doc comment above, which imo is sufficient.

Comment on lines 81 to 82
? ((T) mlib_bits(mlib_bitsizeof(T) - 1, 0)) \
: ((T) mlib_bits(mlib_bitsizeof(T), 0))))
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
? ((T) mlib_bits(mlib_bitsizeof(T) - 1, 0)) \
: ((T) mlib_bits(mlib_bitsizeof(T), 0))))
? ((T) mlib_bits(mlib_bitsizeof(T) - 1u, 0)) \
: ((T) mlib_bits(mlib_bitsizeof(T), 0))))

Signedness consistency.

@@ -460,7 +458,7 @@ static inline bool (mlib_mul) (uintmax_t *dst, bool dst_signed, bool a_signed, u
mlib_noexcept
{
// Multiplication is a lot more subtle
const uintmax_t signbit = (UINTMAX_C (1) << ((sizeof (intmax_t) * CHAR_BIT) - 1));
const uintmax_t signbit = mlib_bits (1, mlib_bitsizeof (uintmax_t) - 1);
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
const uintmax_t signbit = mlib_bits (1, mlib_bitsizeof (uintmax_t) - 1);
const uintmax_t signbit = mlib_bits (1, mlib_bitsizeof (uintmax_t) - 1u);

@@ -359,7 +357,7 @@ static inline bool (mlib_sub) (uintmax_t *dst, bool dst_signed, bool a_signed, u
{
// Perform the subtraction using regular wrapping arithmetic
const uintmax_t diff = *dst = a - b;
const uintmax_t signbit = (UINTMAX_C (1) << ((sizeof (intmax_t) * CHAR_BIT) - 1));
const uintmax_t signbit = mlib_bits (1, mlib_bitsizeof (uintmax_t) - 1);
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
const uintmax_t signbit = mlib_bits (1, mlib_bitsizeof (uintmax_t) - 1);
const uintmax_t signbit = mlib_bits (1, mlib_bitsizeof (uintmax_t) - 1u);

@@ -265,7 +263,7 @@ static inline bool (mlib_add) (uintmax_t *dst, bool dst_signed, bool a_signed, u
// Perform regular wrapping arithmetic on the unsigned value. The bit pattern
// is equivalent if there is two's complement signed arithmetic.
const uintmax_t sum = *dst = a + b;
const uintmax_t signbit = (UINTMAX_C (1) << ((sizeof (intmax_t) * CHAR_BIT) - 1));
const uintmax_t signbit = mlib_bits (1, mlib_bitsizeof (uintmax_t) - 1);
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
const uintmax_t signbit = mlib_bits (1, mlib_bitsizeof (uintmax_t) - 1);
const uintmax_t signbit = mlib_bits (1, mlib_bitsizeof (uintmax_t) - 1u);

#define _mlibMinofSigned(V) ((0 & (V)) - (UINTMAX_C (1) << ((sizeof (V) * CHAR_BIT) - 1)))
#define _mlibMinofSigned(V) \
/* NOLINTNEXTLINE(bugprone-sizeof-expression) */ \
(0 - mlib_bits(1, mlib_bitsizeof(V) - 1))
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
(0 - mlib_bits(1, mlib_bitsizeof(V) - 1))
(0 - mlib_bits(1, mlib_bitsizeof(V) - 1u))

#define _mlibMaxofSigned(V) (_mlibMaxofUnsigned (V) >> 1ull)
#define _mlibMaxofSigned(V) \
/* NOLINTNEXTLINE(bugprone-sizeof-expression) */ \
mlib_bits(mlib_bitsizeof(V) - 1, 0)
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
mlib_bits(mlib_bitsizeof(V) - 1, 0)
mlib_bits(mlib_bitsizeof(V) - 1u, 0)

@vector-of-bool vector-of-bool merged commit afb406d into mongodb:master Jul 11, 2025
40 of 42 checks passed
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.

2 participants