Indicate if a message is a DynamicMessage in the class data and improve the

error message from Dynamic/DownCastMessage when trying to downcast a
DynamicMessage to a generated type.
Previously the error message would say "can't down cast Foo to Foo", which is
confusing.

PiperOrigin-RevId: 647363909
pull/17252/head
Protobuf Team Bot 5 months ago committed by Copybara-Service
parent 237332ef92
commit dfe3300c2f
  1. 1
      src/google/protobuf/dynamic_message.cc
  2. 11
      src/google/protobuf/message_lite.cc
  3. 14
      src/google/protobuf/message_lite.h

@ -666,6 +666,7 @@ const Message* DynamicMessageFactory::GetPrototypeNoLock(
*target = type_info; *target = type_info;
type_info->class_data.descriptor = type; type_info->class_data.descriptor = type;
type_info->class_data.is_dynamic = true;
type_info->pool = (pool_ == nullptr) ? type->file()->pool() : pool_; type_info->pool = (pool_ == nullptr) ? type->file()->pool() : pool_;
type_info->factory = this; type_info->factory = this;

@ -195,6 +195,17 @@ void MessageLite::LogInitializationErrorMessage() const {
namespace internal { namespace internal {
void FailDynamicCast(const MessageLite& from, const MessageLite& to) {
const auto to_name = to.GetTypeName();
if (internal::GetClassData(from)->is_dynamic) {
ABSL_LOG(FATAL)
<< "Cannot downcast from a DynamicMessage to generated type "
<< to_name;
}
const auto from_name = from.GetTypeName();
ABSL_LOG(FATAL) << "Cannot downcast " << from_name << " to " << to_name;
}
template <bool aliasing> template <bool aliasing>
bool MergeFromImpl(absl::string_view input, MessageLite* msg, bool MergeFromImpl(absl::string_view input, MessageLite* msg,
const internal::TcParseTableBase* tc_table, const internal::TcParseTableBase* tc_table,

@ -649,6 +649,7 @@ class PROTOBUF_EXPORT MessageLite {
// LITE objects (ie !descriptor_methods) collocate their name as a // LITE objects (ie !descriptor_methods) collocate their name as a
// char[] just beyond the ClassData. // char[] just beyond the ClassData.
bool is_lite; bool is_lite;
bool is_dynamic = false;
// In normal mode we have the small constructor to avoid the cost in // In normal mode we have the small constructor to avoid the cost in
// codegen. // codegen.
@ -1087,12 +1088,19 @@ T* DynamicCastMessage(MessageLite* from) {
DynamicCastMessage<T>(static_cast<const MessageLite*>(from))); DynamicCastMessage<T>(static_cast<const MessageLite*>(from)));
} }
namespace internal {
[[noreturn]] PROTOBUF_EXPORT void FailDynamicCast(const MessageLite& from,
const MessageLite& to);
} // namespace internal
template <typename T> template <typename T>
const T& DynamicCastMessage(const MessageLite& from) { const T& DynamicCastMessage(const MessageLite& from) {
const T* destination_message = DynamicCastMessage<T>(&from); const T* destination_message = DynamicCastMessage<T>(&from);
ABSL_CHECK(destination_message != nullptr) if (ABSL_PREDICT_FALSE(destination_message == nullptr)) {
<< "Cannot downcast " << from.GetTypeName() << " to " // Move the logging into an out-of-line function to reduce bloat in the
<< T::default_instance().GetTypeName(); // caller.
internal::FailDynamicCast(from, T::default_instance());
}
return *destination_message; return *destination_message;
} }

Loading…
Cancel
Save