Sync from Piper @461045587 PROTOBUF_SYNC_PIPER
diff --git a/src/google/protobuf/arena.cc b/src/google/protobuf/arena.cc index 9200cb2..0c1bcf9 100644 --- a/src/google/protobuf/arena.cc +++ b/src/google/protobuf/arena.cc
@@ -382,7 +382,7 @@ void ThreadSafeArena::SetInitialBlock(void* mem, size_t size) { SerialArena* serial = SerialArena::New({mem, size}, &thread_cache(), arena_stats_.MutableStats()); - serial->set_next(NULL); + serial->set_next(nullptr); threads_.store(serial, std::memory_order_relaxed); CacheSerialArena(serial); }
diff --git a/src/google/protobuf/arena.h b/src/google/protobuf/arena.h index b629780..59e02e0 100644 --- a/src/google/protobuf/arena.h +++ b/src/google/protobuf/arena.h
@@ -120,7 +120,7 @@ // here. size_t max_block_size; - // An initial block of memory for the arena to use, or NULL for none. If + // An initial block of memory for the arena to use, or nullptr for none. If // provided, the block must live at least as long as the arena itself. The // creator of the Arena retains ownership of the block after the Arena is // destroyed. @@ -143,7 +143,7 @@ ArenaOptions() : start_block_size(internal::AllocationPolicy::kDefaultStartBlockSize), max_block_size(internal::AllocationPolicy::kDefaultMaxBlockSize), - initial_block(NULL), + initial_block(nullptr), initial_block_size(0), block_alloc(nullptr), block_dealloc(nullptr), @@ -180,7 +180,7 @@ #if PROTOBUF_RTTI #define RTTI_TYPE_ID(type) (&typeid(type)) #else -#define RTTI_TYPE_ID(type) (NULL) +#define RTTI_TYPE_ID(type) (nullptr) #endif // Arena allocator. Arena allocation replaces ordinary (heap-based) allocation @@ -210,7 +210,7 @@ // with `args` (without `arena`), called when a T is allocated on the heap; // and a constructor callable with `Arena* arena, Args&&... args`, called when // a T is allocated on an arena. If the second constructor is called with a -// NULL arena pointer, it must be equivalent to invoking the first +// null arena pointer, it must be equivalent to invoking the first // (`args`-only) constructor. // // - The type T must have a particular type trait: a nested type @@ -220,7 +220,7 @@ // // - The type T *may* have the type trait |DestructorSkippable_|. If this type // trait is present in the type, then its destructor will not be called if and -// only if it was passed a non-NULL arena pointer. If this type trait is not +// only if it was passed a non-null arena pointer. If this type trait is not // present on the type, then its destructor is always called when the // containing arena is destroyed. // @@ -263,9 +263,9 @@ void Init(const ArenaOptions&) {} // API to create proto2 message objects on the arena. If the arena passed in - // is NULL, then a heap allocated object is returned. Type T must be a message - // defined in a .proto file with cc_enable_arenas set to true, otherwise a - // compilation error will occur. + // is nullptr, then a heap allocated object is returned. Type T must be a + // message defined in a .proto file with cc_enable_arenas set to true, + // otherwise a compilation error will occur. // // RepeatedField and RepeatedPtrField may also be instantiated directly on an // arena with this method. @@ -342,7 +342,7 @@ "CreateArray requires a trivially destructible type"); GOOGLE_CHECK_LE(num_elements, std::numeric_limits<size_t>::max() / sizeof(T)) << "Requested size is too large to fit into size_t."; - if (arena == NULL) { + if (arena == nullptr) { return static_cast<T*>(::operator new[](num_elements * sizeof(T))); } else { return arena->CreateInternalRawArray<T>(num_elements); @@ -386,7 +386,7 @@ // arena-allocated memory. template <typename T> PROTOBUF_ALWAYS_INLINE void OwnDestructor(T* object) { - if (object != NULL) { + if (object != nullptr) { impl_.AddCleanup(object, &internal::cleanup::arena_destruct_object<T>); } } @@ -401,9 +401,9 @@ } // Retrieves the arena associated with |value| if |value| is an arena-capable - // message, or NULL otherwise. If possible, the call resolves at compile time. - // Note that we can often devirtualize calls to `value->GetArena()` so usually - // calling this method is unnecessary. + // message, or nullptr otherwise. If possible, the call resolves at compile + // time. Note that we can often devirtualize calls to `value->GetArena()` so + // usually calling this method is unnecessary. template <typename T> PROTOBUF_ALWAYS_INLINE static Arena* GetArena(const T* value) { return GetArenaInternal(value); @@ -568,7 +568,7 @@ static_assert( InternalHelper<T>::is_arena_constructable::value, "CreateMessage can only construct types that are ArenaConstructable"); - if (arena == NULL) { + if (arena == nullptr) { return new T(nullptr, static_cast<Args&&>(args)...); } else { return arena->DoCreateMessage<T>(static_cast<Args&&>(args)...); @@ -583,7 +583,7 @@ static_assert( InternalHelper<T>::is_arena_constructable::value, "CreateMessage can only construct types that are ArenaConstructable"); - if (arena == NULL) { + if (arena == nullptr) { // Generated arena constructor T(Arena*) is protected. Call via // InternalHelper. return InternalHelper<T>::New(); @@ -730,13 +730,13 @@ // using the virtual destructor instead. template <typename T> PROTOBUF_ALWAYS_INLINE void OwnInternal(T* object, std::true_type) { - if (object != NULL) { + if (object != nullptr) { impl_.AddCleanup(object, &internal::arena_delete_object<MessageLite>); } } template <typename T> PROTOBUF_ALWAYS_INLINE void OwnInternal(T* object, std::false_type) { - if (object != NULL) { + if (object != nullptr) { impl_.AddCleanup(object, &internal::arena_delete_object<T>); } }
diff --git a/src/google/protobuf/arena_unittest.cc b/src/google/protobuf/arena_unittest.cc index 6c88505..0987c99 100644 --- a/src/google/protobuf/arena_unittest.cc +++ b/src/google/protobuf/arena_unittest.cc
@@ -84,10 +84,10 @@ class SimpleDataType { public: - SimpleDataType() : notifier_(NULL) {} + SimpleDataType() : notifier_(nullptr) {} void SetNotifier(Notifier* notifier) { notifier_ = notifier; } virtual ~SimpleDataType() { - if (notifier_ != NULL) { + if (notifier_ != nullptr) { notifier_->Notify(); } }; @@ -171,17 +171,17 @@ TEST(ArenaTest, BasicCreate) { Arena arena; - EXPECT_TRUE(Arena::Create<int32_t>(&arena) != NULL); - EXPECT_TRUE(Arena::Create<int64_t>(&arena) != NULL); - EXPECT_TRUE(Arena::Create<float>(&arena) != NULL); - EXPECT_TRUE(Arena::Create<double>(&arena) != NULL); - EXPECT_TRUE(Arena::Create<std::string>(&arena) != NULL); + EXPECT_TRUE(Arena::Create<int32_t>(&arena) != nullptr); + EXPECT_TRUE(Arena::Create<int64_t>(&arena) != nullptr); + EXPECT_TRUE(Arena::Create<float>(&arena) != nullptr); + EXPECT_TRUE(Arena::Create<double>(&arena) != nullptr); + EXPECT_TRUE(Arena::Create<std::string>(&arena) != nullptr); arena.Own(new int32_t); arena.Own(new int64_t); arena.Own(new float); arena.Own(new double); arena.Own(new std::string); - arena.Own<int>(NULL); + arena.Own<int>(nullptr); Notifier notifier; SimpleDataType* data = Arena::Create<SimpleDataType>(&arena); data->SetNotifier(¬ifier); @@ -196,7 +196,7 @@ Arena arena; const std::string s("foo"); const std::string* s_copy = Arena::Create<std::string>(&arena, s); - EXPECT_TRUE(s_copy != NULL); + EXPECT_TRUE(s_copy != nullptr); EXPECT_EQ("foo", s); EXPECT_EQ("foo", *s_copy); } @@ -205,7 +205,7 @@ Arena arena; std::string s("foo"); const std::string* s_copy = Arena::Create<std::string>(&arena, s); - EXPECT_TRUE(s_copy != NULL); + EXPECT_TRUE(s_copy != nullptr); EXPECT_EQ("foo", s); EXPECT_EQ("foo", *s_copy); } @@ -214,7 +214,7 @@ Arena arena; std::string s("foo"); const std::string* s_move = Arena::Create<std::string>(&arena, std::move(s)); - EXPECT_TRUE(s_move != NULL); + EXPECT_TRUE(s_move != nullptr); EXPECT_TRUE(s.empty()); // NOLINT EXPECT_EQ("foo", *s_move); } @@ -226,7 +226,7 @@ const MustBeConstructedWithOneThroughFour* new_object = Arena::Create<MustBeConstructedWithOneThroughFour>(&arena, 1, "2", three, &four); - EXPECT_TRUE(new_object != NULL); + EXPECT_TRUE(new_object != nullptr); ASSERT_EQ(1, new_object->one_); ASSERT_STREQ("2", new_object->two_); ASSERT_EQ("3", new_object->three_); @@ -242,7 +242,7 @@ const MustBeConstructedWithOneThroughEight* new_object = Arena::Create<MustBeConstructedWithOneThroughEight>( &arena, 1, "2", three, &four, 5, "6", seven, eight); - EXPECT_TRUE(new_object != NULL); + EXPECT_TRUE(new_object != nullptr); ASSERT_EQ(1, new_object->one_); ASSERT_STREQ("2", new_object->two_); ASSERT_EQ("3", new_object->three_); @@ -504,7 +504,7 @@ TestAllTypes::NestedMessage* released_null = arena_message->release_optional_nested_message(); - EXPECT_EQ(NULL, released_null); + EXPECT_EQ(nullptr, released_null); } TEST(ArenaTest, SetAllocatedString) { @@ -605,8 +605,8 @@ } TEST(ArenaTest, ReleaseFromArenaMessageMakesCopy) { - TestAllTypes::NestedMessage* nested_msg = NULL; - std::string* nested_string = NULL; + TestAllTypes::NestedMessage* nested_msg = nullptr; + std::string* nested_string = nullptr; { Arena arena; TestAllTypes* arena_message = Arena::CreateMessage<TestAllTypes>(&arena); @@ -623,7 +623,7 @@ #if PROTOBUF_RTTI TEST(ArenaTest, ReleaseFromArenaMessageUsingReflectionMakesCopy) { - TestAllTypes::NestedMessage* nested_msg = NULL; + TestAllTypes::NestedMessage* nested_msg = nullptr; // Note: no string: reflection API only supports releasing submessages. { Arena arena; @@ -1098,7 +1098,7 @@ EXPECT_TRUE(refl->HasOneof(*message, oneof)); submsg = refl->ReleaseMessage(message, msg_field); EXPECT_FALSE(refl->HasOneof(*message, oneof)); - EXPECT_TRUE(submsg->GetArena() == NULL); + EXPECT_TRUE(submsg->GetArena() == nullptr); delete submsg; } @@ -1111,7 +1111,7 @@ TestAllTypes* t = Arena::CreateMessage<TestAllTypes>(arena1); t->set_optional_string("field1"); t->set_optional_int32(i); - if (arena1 != NULL) { + if (arena1 != nullptr) { field1.UnsafeArenaAddAllocated(t); } else { field1.AddAllocated(t); @@ -1121,7 +1121,7 @@ TestAllTypes* t = Arena::CreateMessage<TestAllTypes>(arena2); t->set_optional_string("field2"); t->set_optional_int32(i); - if (arena2 != NULL) { + if (arena2 != nullptr) { field2.UnsafeArenaAddAllocated(t); } else { field2.AddAllocated(t); @@ -1154,12 +1154,12 @@ TEST(ArenaTest, SwapRepeatedFieldWithNoArenaOnRightHandSide) { Arena arena; - TestSwapRepeatedField(&arena, NULL); + TestSwapRepeatedField(&arena, nullptr); } TEST(ArenaTest, SwapRepeatedFieldWithNoArenaOnLeftHandSide) { Arena arena; - TestSwapRepeatedField(NULL, &arena); + TestSwapRepeatedField(nullptr, &arena); } TEST(ArenaTest, ExtensionsOnArena) { @@ -1218,11 +1218,11 @@ TestAllTypes* extracted_messages[5]; // ExtractSubrange should copy to the heap. repeated_message.ExtractSubrange(0, 5, extracted_messages); - EXPECT_EQ(NULL, extracted_messages[0]->GetArena()); + EXPECT_EQ(nullptr, extracted_messages[0]->GetArena()); // We need to free the heap-allocated messages to prevent a leak. for (int i = 0; i < 5; i++) { delete extracted_messages[i]; - extracted_messages[i] = NULL; + extracted_messages[i] = nullptr; } } @@ -1342,7 +1342,7 @@ { MessageLite* generic_message = prototype->New(&arena); - EXPECT_TRUE(generic_message != NULL); + EXPECT_TRUE(generic_message != nullptr); EXPECT_EQ(&arena, generic_message->GetArena()); EXPECT_TRUE(generic_message->ParseFromString(serialized)); TestAllTypes* deserialized = static_cast<TestAllTypes*>(generic_message); @@ -1463,8 +1463,8 @@ TEST(ArenaTest, GetArenaShouldReturnNullForNonArenaAllocatedMessages) { ArenaMessage message; const ArenaMessage* const_pointer_to_message = &message; - EXPECT_EQ(NULL, Arena::GetArena(&message)); - EXPECT_EQ(NULL, Arena::GetArena(const_pointer_to_message)); + EXPECT_EQ(nullptr, Arena::GetArena(&message)); + EXPECT_EQ(nullptr, Arena::GetArena(const_pointer_to_message)); } TEST(ArenaTest, GetArenaShouldReturnNullForNonArenaCompatibleTypes) {
diff --git a/src/google/protobuf/compiler/command_line_interface.cc b/src/google/protobuf/compiler/command_line_interface.cc index a688bcf..0a0c7e3 100644 --- a/src/google/protobuf/compiler/command_line_interface.cc +++ b/src/google/protobuf/compiler/command_line_interface.cc
@@ -1680,8 +1680,7 @@ })) { case google::protobuf::io::win32::ExpandWildcardsResult::kSuccess: break; - case google::protobuf::io::win32::ExpandWildcardsResult:: - kErrorNoMatchingFile: + case google::protobuf::io::win32::ExpandWildcardsResult::kErrorNoMatchingFile: // Path does not exist, is not a file, or it's longer than MAX_PATH and // long path handling is disabled. std::cerr << "Invalid file name pattern or missing input file \""
diff --git a/src/google/protobuf/compiler/cpp/helpers.cc b/src/google/protobuf/compiler/cpp/helpers.cc index a8c5899..4939aa5 100644 --- a/src/google/protobuf/compiler/cpp/helpers.cc +++ b/src/google/protobuf/compiler/cpp/helpers.cc
@@ -925,6 +925,13 @@ bool ShouldSplit(const Descriptor*, const Options&) { return false; } bool ShouldSplit(const FieldDescriptor*, const Options&) { return false; } +bool ShouldForceAllocationOnConstruction(const Descriptor* desc, + const Options& options) { + (void)desc; + (void)options; + return false; +} + static bool HasRepeatedFields(const Descriptor* descriptor) { for (int i = 0; i < descriptor->field_count(); ++i) { if (descriptor->field(i)->label() == FieldDescriptor::LABEL_REPEATED) {
diff --git a/src/google/protobuf/compiler/cpp/helpers.h b/src/google/protobuf/compiler/cpp/helpers.h index 6befbaa..21a488e 100644 --- a/src/google/protobuf/compiler/cpp/helpers.h +++ b/src/google/protobuf/compiler/cpp/helpers.h
@@ -379,6 +379,11 @@ // Is the given field being split out? bool ShouldSplit(const FieldDescriptor* field, const Options& options); +// Should we generate code that force creating an allocation in the constructor +// of the given message? +bool ShouldForceAllocationOnConstruction(const Descriptor* desc, + const Options& options); + inline bool IsFieldUsed(const FieldDescriptor* /* field */, const Options& /* options */) { return true;
diff --git a/src/google/protobuf/compiler/cpp/message.cc b/src/google/protobuf/compiler/cpp/message.cc index 04bb5d1..3ca5315 100644 --- a/src/google/protobuf/compiler/cpp/message.cc +++ b/src/google/protobuf/compiler/cpp/message.cc
@@ -1269,9 +1269,9 @@ GenerateSingularFieldHasBits(field, format); } - if (!IsCrossFileMaybeMap(field)) { - GenerateFieldClear(field, true, format); - } + if (!IsCrossFileMaybeMap(field)) { + GenerateFieldClear(field, true, format); + } // Generate type-specific accessors. if (!IsFieldStripped(field, options_)) { @@ -2483,6 +2483,13 @@ field_generators_.get(field).GenerateConstructorCode(printer); } + if (ShouldForceAllocationOnConstruction(descriptor_, options_)) { + format( + "#ifdef PROTOBUF_FORCE_ALLOCATION_ON_CONSTRUCTION\n" + "$mutable_unknown_fields$;\n" + "#endif // PROTOBUF_FORCE_ALLOCATION_ON_CONSTRUCTION\n"); + } + for (auto oneof : OneOfRange(descriptor_)) { format("clear_has_$1$();\n", oneof->name()); } @@ -2722,6 +2729,13 @@ " static_cast<size_t>(reinterpret_cast<char*>(&$last$) -\n" " reinterpret_cast<char*>(&$first$)) + sizeof($last$));\n"; + if (ShouldForceAllocationOnConstruction(descriptor_, options_)) { + format( + "#ifdef PROTOBUF_FORCE_ALLOCATION_ON_CONSTRUCTION\n" + "$mutable_unknown_fields$;\n" + "#endif // PROTOBUF_FORCE_ALLOCATION_ON_CONSTRUCTION\n"); + } + for (size_t i = 0; i < optimized_order_.size(); ++i) { const FieldDescriptor* field = optimized_order_[i]; if (ShouldSplit(field, options_)) {
diff --git a/src/google/protobuf/compiler/subprocess.cc b/src/google/protobuf/compiler/subprocess.cc index 764f9ab..6faab05 100644 --- a/src/google/protobuf/compiler/subprocess.cc +++ b/src/google/protobuf/compiler/subprocess.cc
@@ -46,6 +46,7 @@ #include <google/protobuf/stubs/logging.h> #include <google/protobuf/stubs/common.h> #include <google/protobuf/stubs/substitute.h> +#include <google/protobuf/io/io_win32.h> #include <google/protobuf/message.h> namespace google { @@ -113,7 +114,7 @@ } // Setup STARTUPINFO to redirect handles. - STARTUPINFOA startup_info; + STARTUPINFOW startup_info; ZeroMemory(&startup_info, sizeof(startup_info)); startup_info.cb = sizeof(startup_info); startup_info.dwFlags = STARTF_USESTDHANDLES; @@ -125,17 +126,30 @@ GOOGLE_LOG(FATAL) << "GetStdHandle: " << Win32ErrorMessage(GetLastError()); } + // get wide string version of program as the path may contain non-ascii characters + std::wstring wprogram; + if (!io::win32::strings::utf8_to_wcs(program.c_str(), &wprogram)) { + GOOGLE_LOG(FATAL) << "utf8_to_wcs: " << Win32ErrorMessage(GetLastError()); + } + // Invoking cmd.exe allows for '.bat' files from the path as well as '.exe'. + std::string command_line = "cmd.exe /c \"" + program + "\""; + + // get wide string version of command line as the path may contain non-ascii characters + std::wstring wcommand_line; + if (!io::win32::strings::utf8_to_wcs(command_line.c_str(), &wcommand_line)) { + GOOGLE_LOG(FATAL) << "utf8_to_wcs: " << Win32ErrorMessage(GetLastError()); + } + // Using a malloc'ed string because CreateProcess() can mutate its second // parameter. - char* command_line = - portable_strdup(("cmd.exe /c \"" + program + "\"").c_str()); + wchar_t *wcommand_line_copy = _wcsdup(wcommand_line.c_str()); // Create the process. PROCESS_INFORMATION process_info; - if (CreateProcessA((search_mode == SEARCH_PATH) ? nullptr : program.c_str(), - (search_mode == SEARCH_PATH) ? command_line : nullptr, + if (CreateProcessW((search_mode == SEARCH_PATH) ? nullptr : wprogram.c_str(), + (search_mode == SEARCH_PATH) ? wcommand_line_copy : NULL, nullptr, // process security attributes nullptr, // thread security attributes TRUE, // inherit handles? @@ -155,7 +169,7 @@ CloseHandleOrDie(stdin_pipe_read); CloseHandleOrDie(stdout_pipe_write); - free(command_line); + free(wcommand_line_copy); } bool Subprocess::Communicate(const Message& input, Message* output,
diff --git a/src/google/protobuf/generated_message_tctable_impl.h b/src/google/protobuf/generated_message_tctable_impl.h index f4bfb4d..67349b4 100644 --- a/src/google/protobuf/generated_message_tctable_impl.h +++ b/src/google/protobuf/generated_message_tctable_impl.h
@@ -32,6 +32,7 @@ #define GOOGLE_PROTOBUF_GENERATED_MESSAGE_TCTABLE_IMPL_H__ #include <cstdint> +#include <cstdlib> #include <type_traits> #include <google/protobuf/port.h> @@ -268,11 +269,11 @@ #ifndef NDEBUG template <size_t align> -#ifndef _MSC_VER -[[noreturn]] -#endif void AlignFail(uintptr_t address) { GOOGLE_LOG(FATAL) << "Unaligned (" << align << ") access at " << address; + + // Explicit abort to let compilers know this function does not return + abort(); } extern template void AlignFail<4>(uintptr_t);
diff --git a/src/google/protobuf/io/coded_stream.h b/src/google/protobuf/io/coded_stream.h index a8b5eb5..e428f55 100644 --- a/src/google/protobuf/io/coded_stream.h +++ b/src/google/protobuf/io/coded_stream.h
@@ -680,7 +680,7 @@ if (PROTOBUF_PREDICT_FALSE(end_ - ptr < size)) { return WriteRawFallback(data, size, ptr); } - std::memcpy(ptr, data, size); + std::memcpy(ptr, data, static_cast<unsigned int>(size)); return ptr + size; } // Writes the buffer specified by data, size to the stream. Possibly by @@ -1776,7 +1776,7 @@ inline uint8_t* CodedOutputStream::WriteRawToArray(const void* data, int size, uint8_t* target) { - memcpy(target, data, size); + memcpy(target, data, static_cast<unsigned int>(size)); return target + size; }
diff --git a/src/google/protobuf/map.h b/src/google/protobuf/map.h index a0e1b61..d0aa010 100644 --- a/src/google/protobuf/map.h +++ b/src/google/protobuf/map.h
@@ -379,6 +379,7 @@ public: using key_type = Key; using mapped_type = T; + using init_type = std::pair<Key, T>; using value_type = MapPair<Key, T>; using pointer = value_type*; @@ -421,6 +422,22 @@ ~Map() {} private: + template <typename P> + struct SameAsElementReference + : std::is_same<typename std::remove_cv< + typename std::remove_reference<reference>::type>::type, + typename std::remove_cv< + typename std::remove_reference<P>::type>::type> {}; + + template <class P> + using RequiresInsertable = + typename std::enable_if<std::is_convertible<P, init_type>::value || + SameAsElementReference<P>::value, + int>::type; + template <class P> + using RequiresNotInit = + typename std::enable_if<!std::is_same<P, init_type>::value, int>::type; + using Allocator = internal::MapAllocator<void*>; // InnerMap is a generic hash-based map. It doesn't contain any @@ -1270,7 +1287,6 @@ const_iterator cbegin() const { return begin(); } const_iterator cend() const { return end(); } - // Capacity size_type size() const { return elements_.size(); } bool empty() const { return size() == 0; } @@ -1351,15 +1367,17 @@ elements_.try_emplace(std::forward<K>(k), std::forward<Args>(args)...); return std::pair<iterator, bool>(iterator(p.first), p.second); } - std::pair<iterator, bool> insert(const value_type& value) { - return try_emplace(value.first, value.second); + std::pair<iterator, bool> insert(init_type&& value) { + return try_emplace(std::move(value.first), std::move(value.second)); } - std::pair<iterator, bool> insert(value_type&& value) { - return try_emplace(value.first, std::move(value.second)); + template <typename P, RequiresInsertable<P> = 0> + std::pair<iterator, bool> insert(P&& value) { + return try_emplace(std::forward<P>(value).first, + std::forward<P>(value).second); } template <typename... Args> std::pair<iterator, bool> emplace(Args&&... args) { - return insert(value_type(std::forward<Args>(args)...)); + return EmplaceInternal(Rank0{}, std::forward<Args>(args)...); } template <class InputIt> void insert(InputIt first, InputIt last) { @@ -1368,7 +1386,12 @@ try_emplace(pair.first, pair.second); } } - void insert(std::initializer_list<value_type> values) { + void insert(std::initializer_list<init_type> values) { + insert(values.begin(), values.end()); + } + template <typename P, RequiresNotInit<P> = 0, + RequiresInsertable<const P&> = 0> + void insert(std::initializer_list<P> values) { insert(values.begin(), values.end()); } @@ -1429,6 +1452,23 @@ } private: + struct Rank1 {}; + struct Rank0 : Rank1 {}; + + // We try to construct `init_type` from `Args` with a fall back to + // `value_type`. The latter is less desired as it unconditionally makes a copy + // of `value_type::first`. + template <typename... Args> + auto EmplaceInternal(Rank0, Args&&... args) -> + typename std::enable_if<std::is_constructible<init_type, Args...>::value, + std::pair<iterator, bool>>::type { + return insert(init_type(std::forward<Args>(args)...)); + } + template <typename... Args> + std::pair<iterator, bool> EmplaceInternal(Rank1, Args&&... args) { + return insert(value_type(std::forward<Args>(args)...)); + } + Arena* arena() const { return elements_.arena(); } InnerMap elements_;
diff --git a/src/google/protobuf/map_test.inc b/src/google/protobuf/map_test.inc index 550d986..041ac82 100644 --- a/src/google/protobuf/map_test.inc +++ b/src/google/protobuf/map_test.inc
@@ -737,6 +737,47 @@ EXPECT_FALSE(result2.second); } +TEST_F(MapImplTest, InsertSingleBraceInitList) { + int32_t key = 0; + int32_t value1 = 100; + int32_t value2 = 101; + + // Insert a non-existing key. + auto result1 = map_.insert({key, value1}); + ExpectSingleElement(key, value1); + + auto it1 = result1.first; + EXPECT_EQ(key, it1->first); + EXPECT_EQ(value1, it1->second); + EXPECT_TRUE(result1.second); + + // Insert an existing key. + auto result2 = map_.insert({key, value2}); + ExpectSingleElement(key, value1); + + auto it2 = result2.first; + EXPECT_TRUE(it1 == it2); + EXPECT_FALSE(result2.second); +} + +TEST_F(MapImplTest, InsertSingleBraceInitListTypeMismatch) { + int32_t key = 0; + int32_t value1 = 100; + int32_t value2 = 101; + Map<int64_t, int64_t> m; + + // Insert a non-existing key. + auto result1 = m.insert({key, value1}); + EXPECT_TRUE(result1.second); + + // Insert an existing key. + auto result2 = m.insert({key, value2}); + EXPECT_FALSE(result2.second); + + EXPECT_TRUE(result1.first == result2.first); +} + + TEST_F(MapImplTest, TryEmplace) { using ::testing::Pair; using ::testing::UnorderedElementsAre; @@ -769,6 +810,20 @@ m, UnorderedElementsAre(Pair(1, "one"), Pair(2, "two"), Pair(42, "aaa"))); } +TEST_F(MapImplTest, EmplaceKeyOnly) { + using ::testing::Pair; + using ::testing::UnorderedElementsAre; + + Map<int32_t, std::string> m; + + m.emplace(1); + EXPECT_EQ(m.size(), 1); + + const int32_t key = 42; + m.emplace(key); + EXPECT_THAT(m, UnorderedElementsAre(Pair(1, ""), Pair(42, ""))); +} + struct CountedInstance { CountedInstance() { ++num_created; } CountedInstance(const CountedInstance&) : CountedInstance() {}
diff --git a/src/google/protobuf/port_def.inc b/src/google/protobuf/port_def.inc index 1220682..2e861d2 100644 --- a/src/google/protobuf/port_def.inc +++ b/src/google/protobuf/port_def.inc
@@ -191,6 +191,7 @@ #define PROTOBUF_FUTURE_REMOVE_CLEARED_API 1 // Used to escape C++20 keywords. +// TODO(mkruskal): ping b/238664698 when this lands in opensource. // Owner: mkruskal@ #define PROTOBUF_FUTURE_CPP20_KEYWORDS 1 #else @@ -559,6 +560,10 @@ #error PROTOBUF_FORCE_COPY_DEFAULT_STRING was previously defined #endif +#ifdef PROTOBUF_FORCE_ALLOCATION_ON_CONSTRUCTION +#error PROTOBUF_FORCE_ALLOCATION_ON_CONSTRUCTION was previously defined +#endif + #ifdef PROTOBUF_FALLTHROUGH_INTENDED #error PROTOBUF_FALLTHROUGH_INTENDED was previously defined #endif @@ -664,14 +669,15 @@ #ifdef PROTOBUF_CONSTINIT #error PROTOBUF_CONSTINIT was previously defined #endif -#if defined(__cpp_constinit) +#if defined(__cpp_constinit) && !defined(_MSC_VER) #define PROTOBUF_CONSTINIT constinit #define PROTOBUF_CONSTEXPR constexpr // Some older Clang versions incorrectly raise an error about // constant-initializing weak default instance pointers. Versions 12.0 and // higher seem to work, except that XCode 12.5.1 shows the error even though it // uses Clang 12.0.5. -#elif __has_cpp_attribute(clang::require_constant_initialization) && \ +// Clang-cl on Windows raises error also. +#elif !defined(_MSC_VER) && __has_cpp_attribute(clang::require_constant_initialization) && \ ((defined(__APPLE__) && __clang_major__ >= 13) || \ (!defined(__APPLE__) && __clang_major__ >= 12)) #define PROTOBUF_CONSTINIT [[clang::require_constant_initialization]] @@ -679,6 +685,10 @@ #elif PROTOBUF_GNUC_MIN(12, 2) #define PROTOBUF_CONSTINIT __constinit #define PROTOBUF_CONSTEXPR constexpr +// MSVC 17 currently seems to raise an error about constant-initialized pointers. +#elif defined(_MSC_VER) && _MSC_VER >= 1930 +#define PROTOBUF_CONSTINIT +#define PROTOBUF_CONSTEXPR constexpr #else #define PROTOBUF_CONSTINIT #define PROTOBUF_CONSTEXPR
diff --git a/src/google/protobuf/port_undef.inc b/src/google/protobuf/port_undef.inc index 5732b19..4ad9d33 100644 --- a/src/google/protobuf/port_undef.inc +++ b/src/google/protobuf/port_undef.inc
@@ -75,6 +75,7 @@ #undef PROTOBUF_FORCE_RESET_IN_CLEAR #undef PROTOBUF_FUZZ_MESSAGE_SPACE_USED_LONG #undef PROTOBUF_FORCE_COPY_DEFAULT_STRING +#undef PROTOBUF_FORCE_ALLOCATION_ON_CONSTRUCTION #undef PROTOBUF_NAMESPACE_OPEN #undef PROTOBUF_NAMESPACE_CLOSE #undef PROTOBUF_UNUSED
diff --git a/src/google/protobuf/repeated_field.h b/src/google/protobuf/repeated_field.h index 3fbe499..e504274 100644 --- a/src/google/protobuf/repeated_field.h +++ b/src/google/protobuf/repeated_field.h
@@ -311,6 +311,7 @@ // This is public due to it being called by generated code. inline void InternalSwap(RepeatedField* other); + private: template <typename T> friend class Arena::InternalHelper; @@ -338,7 +339,7 @@ // current_size_. This function is intended to be the only place where // current_size_ is modified. inline int ExchangeCurrentSize(int new_size) { - int prev_size = current_size_; + const int prev_size = current_size_; current_size_ = new_size; return prev_size; } @@ -355,6 +356,7 @@ } }; + // If total_size_ == 0 this points to an Arena otherwise it points to the // elements member of a Rep struct. Using this invariant allows the storage of // the arena pointer without an extra allocation in the constructor. @@ -471,7 +473,7 @@ void Add(Element val) { if (index_ == capacity_) { - repeated_field_->ExchangeCurrentSize(index_); + repeated_field_->current_size_ = index_; repeated_field_->Reserve(index_ + 1); capacity_ = repeated_field_->total_size_; buffer_ = repeated_field_->unsafe_elements();
diff --git a/src/google/protobuf/util/BUILD.bazel b/src/google/protobuf/util/BUILD.bazel index d7c3385..2d09db8 100644 --- a/src/google/protobuf/util/BUILD.bazel +++ b/src/google/protobuf/util/BUILD.bazel
@@ -118,7 +118,7 @@ hdrs = ["zero_copy_sink.h"], copts = COPTS, strip_include_prefix = "/src", - visibility = ["//visibility:private"], + visibility = ["//pkg:__pkg__"], deps = [ "//src/google/protobuf", "//src/google/protobuf/io",
diff --git a/src/google/protobuf/util/json_util.h b/src/google/protobuf/util/json_util.h index 4f4594e..8fbab5a 100644 --- a/src/google/protobuf/util/json_util.h +++ b/src/google/protobuf/util/json_util.h
@@ -93,6 +93,9 @@ // Converts from protobuf message to JSON and appends it to |output|. This is a // simple wrapper of BinaryToJsonString(). It will use the DescriptorPool of the // passed-in message to resolve Any types. +// +// Please note that non-OK statuses are not a stable output of this API and +// subject to change without notice. PROTOBUF_EXPORT util::Status MessageToJsonString(const Message& message, std::string* output, const JsonOptions& options); @@ -105,6 +108,9 @@ // Converts from JSON to protobuf message. This is a simple wrapper of // JsonStringToBinary(). It will use the DescriptorPool of the passed-in // message to resolve Any types. +// +// Please note that non-OK statuses are not a stable output of this API and +// subject to change without notice. PROTOBUF_EXPORT util::Status JsonStringToMessage( StringPiece input, Message* message, const JsonParseOptions& options); @@ -119,6 +125,9 @@ // 2. input is not valid protobuf wire format, or conflicts with the type // information returned by TypeResolver. // Note that unknown fields will be discarded silently. +// +// Please note that non-OK statuses are not a stable output of this API and +// subject to change without notice. PROTOBUF_EXPORT util::Status BinaryToJsonStream( TypeResolver* resolver, const std::string& type_url, io::ZeroCopyInputStream* binary_input, @@ -150,6 +159,9 @@ // 1. TypeResolver fails to resolve a type. // 2. input is not valid JSON format, or conflicts with the type // information returned by TypeResolver. +// +// Please note that non-OK statuses are not a stable output of this API and +// subject to change without notice. PROTOBUF_EXPORT util::Status JsonToBinaryStream( TypeResolver* resolver, const std::string& type_url, io::ZeroCopyInputStream* json_input,
diff --git a/src/google/protobuf/util/json_util_test.cc b/src/google/protobuf/util/json_util_test.cc index 1ff638b..9401d41 100644 --- a/src/google/protobuf/util/json_util_test.cc +++ b/src/google/protobuf/util/json_util_test.cc
@@ -539,6 +539,13 @@ JsonParseOptions options; options.ignore_unknown_fields = true; EXPECT_OK(ToProto<TestMessage>(R"({"unknownName":0})", options)); + + TestMessage m; + m.GetReflection()->MutableUnknownFields(&m)->AddFixed32(9001, 9001); + m.GetReflection()->MutableUnknownFields(&m)->AddFixed64(9001, 9001); + m.GetReflection()->MutableUnknownFields(&m)->AddVarint(9001, 9001); + m.GetReflection()->MutableUnknownFields(&m)->AddLengthDelimited(9001, "9001"); + EXPECT_THAT(ToJson(m), IsOkAndHolds("{}")); } TEST_P(JsonTest, TestParseErrors) {