Skip to content
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

constexpr redefinition errors when compiling Protocol Buffers generated code with Visual Studio 2022 and Protocol Buffers v29.3 #20100

Open
Matgo01 opened this issue Jan 24, 2025 · 11 comments

Comments

@Matgo01
Copy link

Matgo01 commented Jan 24, 2025

I encountered multiple errors while compiling the code generated by Protocol Buffers v29.3 using Visual Studio 2022. The errors point to constexpr redefinition issues and other problems with functions being marked as constexpr. Below is the exact error message:

RiskUnitProtocol.pb.cc
1>C:\Users\mgorla\Documents\alicanto\QPosition_Risk\QPosition_Risk\RiskUnitProtocol.pb.cc(10553,15): error C2475: 'RiskUnitProtocol::Drivers::InternalNewImpl_': redefinition; different 'constexpr' specifiers
1> C:\Users\mgorla\Documents\alicanto\QPosition_Risk\QPosition_Risk\RiskUnitProtocol.pb.h(10937,25):
1> see declaration of 'RiskUnitProtocol::Drivers::InternalNewImpl_'
1>C:\Users\mgorla\Documents\alicanto\QPosition_Risk\QPosition_Risk\RiskUnitProtocol.pb.cc(10553,15): error C3615: constexpr function 'RiskUnitProtocol::Drivers::InternalNewImpl_' cannot return a constant expression
1> C:\Users\mgorla\Documents\alicanto\QPosition_Risk\QPosition_Risk\RiskUnitProtocol.pb.cc(10553,15):
1> failure was caused by reaching the end of a constexpr function
1>C:\Users\mgorla\Documents\alicanto\QPosition_Risk\QPosition_Risk\RiskUnitProtocol.pb.cc(16780,41): error C2475: 'RiskUnitProtocol::VistaturaSecondoLivello::InternalNewImpl_': redefinition; different 'constexpr' specifiers
1> C:\Users\mgorla\Documents\alicanto\QPosition_Risk\QPosition_Risk\RiskUnitProtocol.pb.h(512,15):
1> see declaration of 'RiskUnitProtocol::VistaturaSecondoLivello::InternalNewImpl_'
1>C:\Users\mgorla\Documents\alicanto\QPosition_Risk\QPosition_Risk\RiskUnitProtocol.pb.cc(19031,19): error C2475: 'RiskUnitProtocol::Simulazioni::InternalNewImpl_': redefinition; different 'constexpr' specifiers
1> C:\Users\mgorla\Documents\alicanto\QPosition_Risk\QPosition_Risk\RiskUnitProtocol.pb.h(7997,25):
1> see declaration of 'RiskUnitProtocol::Simulazioni::InternalNewImpl_'
1>C:\Users\mgorla\Documents\alicanto\QPosition_Risk\QPosition_Risk\RiskUnitProtocol.pb.cc(19031,19): error C3615: constexpr function 'RiskUnitProtocol::Simulazioni::InternalNewImpl_' cannot return a constant expression
1> C:\Users\mgorla\Documents\alicanto\QPosition_Risk\QPosition_Risk\RiskUnitProtocol.pb.cc(19031,19):
1> failure was caused by reaching the end of a constexpr function
Environment:

Protocol Buffers version: v29.2
Compiler: Visual Studio 2022
Operating System: Windows 1\

@Matgo01 Matgo01 added the untriaged auto added to all issues by default when created. label Jan 24, 2025
@mkruskal-google mkruskal-google added c++ and removed untriaged auto added to all issues by default when created. labels Jan 25, 2025
@sbenzaquen
Copy link
Contributor

Would you mind posting (you can omit/replace field names if you want):

  • the definition of RiskUnitProtocol::Drivers.
  • the definition of RiskUnitProtocol::Drivers::InternalNewImpl_.
  • C++ language version used.

@Matgo01
Copy link
Author

Matgo01 commented Jan 27, 2025

I have resolved the initial issue, but I am currently facing 500 linking errors related to the Abseil library. Specifically, I am encountering the following unresolved external symbol error:
externally referenced symbol "bool __cdecl absl::lts_20240116::CUnescape(class std::basic_string_view<char,struct std::char_traits >,class std::basic_string<char,struct std::char_traits,class std::allocator > *,class std::basic_string<char,struct std::char_traits,class std::allocator > *)" (?CUnescape@lts_20240116@absl@@YA_NV?$basic_string_view@DU?$char_traits@D@std@@@std@@pav?$basic_string@DU?$char_traits@D@std@@v?$allocator@D@2@@4@1@Z) in function "bool __cdecl absl::lts_20240116::CUnescape(class std::basic_string_view<char,struct std::char_traits >,class std::basic_string<char,struct std::char_traits,class std::allocator > *)" (?CUnescape@lts_20240116@absl@@YA_NV?$basic_string_view@DU?$char_traits@D@std@@@std@@pav?$basic_string@DU?$char_traits@D@std@@v?$allocator@D@2@@4@@z)
I am using Visual Studio 2022 and C++20 with an x86 architecture.
Currently, I am linking the following libraries: libprotobufd.lib, libprotobuf-lited.lib, and libprotocd.lib.
Thanks in advance for your help.

@mkruskal-google
Copy link
Member

What cmake flags are you using? We have a dependency on abseil, so you might need to link in that as well

@sbenzaquen
Copy link
Contributor

Would you mind sharing what was the issue and how you solved it?
Was there something wrong on our side?

@Matgo01
Copy link
Author

Matgo01 commented Jan 28, 2025

I followed the instructions to create a solution for Visual Studio and subsequently compiled the libraries. Currently, I am using only libprotobufd.lib, libprotobuf_lited.lib, and protocd.lib. I also tried linking the Abseil libraries, but I was wondering if that is the right approach or if I made any mistakes. If not, which Abseil libraries should I add to the linker

@Matgo01
Copy link
Author

Matgo01 commented Jan 28, 2025

The errors were related to constexpr functions in the file.pb.cc file, which contained expressions that could not be evaluated at compile time. I resolved the issue by modifying the file.pb.cc file to make the problematic expressions evaluable during compilation.
I modified the expressions in file.pb.cc to meet the requirements for constexpr evaluation.
I replaced runtime-dependent expressions with statically evaluable values

@sbenzaquen
Copy link
Contributor

I replaced runtime-dependent expressions with statically evaluable values

What part of the expression was wrong, and how did you fix it?
We should fix it in the generator, not directly in the generated files.

@Matgo01
Copy link
Author

Matgo01 commented Jan 28, 2025

I solved the linking error by linking this list of static libraries: absl_str_format_internal.lib
absl_strings_internal.lib
absl_string_view.lib
absl_log_initialize.lib
absl_log_entry.lib
absl_log_flags.lib
absl_log_severity.lib
absl_log_internal_conditions.lib
absl_log_internal_message.lib
absl_log_internal_nullguard.lib
absl_log_internal_proto.lib
absl_log_internal_format.lib
absl_log_internal_globals.lib
absl_log_internal_log_sink_set.lib
absl_log_sink.lib
absl_raw_logging_internal.lib
absl_log_globals.lib
absl_log_internal_check_op.lib
utf8_validity.lib
utf8_range.lib
absl_cord.lib
absl_cordz_info.lib
absl_cordz_handle.lib
absl_cordz_functions.lib
absl_cord_internal.lib
absl_crc_cord_state.lib
absl_crc32c.lib
absl_crc_internal.lib
absl_exponential_biased.lib
absl_kernel_timeout_internal.lib
absl_graphcycles_internal.lib
absl_synchronization.lib
absl_time.lib
absl_time_zone.lib
absl_int128.lib
absl_examine_stack.lib
absl_stacktrace.lib
absl_symbolize.lib
absl_demangle_internal.lib
absl_debugging_internal.lib
absl_malloc_internal.lib
absl_throw_delegate.lib
absl_strerror.lib
absl_raw_hash_set.lib
absl_hash.lib
absl_city.lib
absl_low_level_hash.lib
absl_base.lib
absl_spinlock_wait.lib
absl_status.lib
absl_statusor.lib
absl_strings.lib
libprotobufd.lib
libprotobuf-lited.lib
libprotocd.lib

@Matgo01
Copy link
Author

Matgo01 commented Jan 28, 2025

I resolved an error in C++20 related to the PROTOBUF_FIELD_OFFSET macro in the following code:

constexpr auto arena_bits = ::google::protobuf::internal::EncodePlacementArenaOffsets({
PROTOBUF_FIELD_OFFSET(Subscription, impl.ltype_) +
decltype(Subscription::impl.ltype_)::InternalGetArenaOffset(
::google::protobuf::Message::internal_visibility()),
});
The error message was: "the expression must have a constant value", which occurred because PROTOBUF_FIELD_OFFSET internally uses reinterpret_cast, which is not allowed in a constexpr context in C++20. This restriction comes from the stricter rules for compile-time evaluation introduced in C++20.

To fix the issue, I replaced the PROTOBUF_FIELD_OFFSET macro with the standard offsetof macro, which is allowed in constant expressions and evaluates to a constexpr value. After the change, the code looks like this:

constexpr auto arena_bits = ::google::protobuf::internal::EncodePlacementArenaOffsets({
offsetof(Subscription, impl.ltype_) +
decltype(Subscription::impl.ltype_)::InternalGetArenaOffset(
::google::protobuf::Message::internal_visibility()),
});
By making this modification, I ensured that the offset computation is valid in a constexpr context. Using offsetof solved the issue, as it is designed for compile-time evaluation, making the code fully compliant with C++20's constexpr requirements.

@Matgo01
Copy link
Author

Matgo01 commented Jan 28, 2025

I resolved an error in C++20 that occurred in the following code:

using HasBits = decltype(std::declval().impl.has_bits);
static constexpr ::int32_t kHasBitsOffset =
8 * PROTOBUF_FIELD_OFFSET(Message, impl.has_bits);
The error message was: "the expression must have a constant value", which happened because PROTOBUF_FIELD_OFFSET internally uses reinterpret_cast, which is not allowed in a constexpr context in C++20. This limitation is due to the stricter compile-time evaluation rules introduced in the C++20 standard.

To resolve the issue, I replaced static constexpr with inline const, which relaxes the requirement for compile-time evaluation while still allowing the constant to be defined with internal linkage and avoiding unnecessary memory usage. Here's the updated code:

using HasBits = decltype(std::declval().impl.has_bits);
inline const ::int32_t kHasBitsOffset =
8 * PROTOBUF_FIELD_OFFSET(Message, impl.has_bits);
By making this change, I avoided the need for constexpr evaluation, which is incompatible with reinterpret_cast. Using inline const achieves the same functionality but allows the code to compile without violating C++20's restrictions. This solution is effective because inline const provides a compile-time constant for all practical purposes without requiring strict constexpr compliance.

@Matgo01
Copy link
Author

Matgo01 commented Jan 28, 2025

I resolved an error in the following code that uses the ::google::protobuf::internal::memswap function:

::google::protobuf::internal::memswap<
PROTOBUF_FIELD_OFFSET(Message, impl.entype_)
+ sizeof(Message::impl.entype_)
- PROTOBUF_FIELD_OFFSET(Message, impl.heartbeat_)>(
reinterpret_cast<char*>(&impl.heartbeat_),
reinterpret_cast<char*>(&other->impl.heartbeat_));
The error message was: "no matching function template specialization for google::protobuf::internal::memswap that matches the argument list". The problem arose because the memswap function could not be instantiated with the specific arguments passed, likely due to its template constraints or missing implementation for the provided size.

To resolve this issue, I created my own memswap function, which manually swaps the contents of two memory regions using a temporary buffer. Here's the function I implemented:

inline void memswap(char* a, char* b, size_t size) {
// Create a temporary buffer to store the data
std::vector temp(size);

// Copy data from 'a' to the temporary buffer
std::memcpy(temp.data(), a, size);

// Copy data from 'b' to 'a'
std::memcpy(a, b, size);

// Copy data from the temporary buffer to 'b'
std::memcpy(b, temp.data(), size);

}
This function uses std::vector to allocate a temporary buffer of the required size and then performs the memory swapping in three steps:

Copy the content of a into the temporary buffer.
Copy the content of b into a.
Copy the content of the temporary buffer into b.
With this custom memswap function, I replaced the original ::google::protobuf::internal::memswap call, and the updated code now works as expected. This approach is straightforward, portable, and resolves the issue while preserving the intended functionality.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

3 participants