Split `Arena::Construct` into two methods, one which assumes we are using arenas.

This allows us to avoid a conditional in `DoCreateMessage`, which is only called when we are using arenas.

Note that we also remove the logic for constructing a wrapper type around the allocated `T`, as this logic was erroneous (and also never triggered). If a `T` was allocated, we only allocated enough memory for `T`, so constructing a `typename internal::FieldArenaRep<T>::Type` is UB. This never triggers because all callers of `Construct` would have already translated `T` to its arena rep, and the arena rep of an arena rep is always itself.

PiperOrigin-RevId: 811233885
diff --git a/src/google/protobuf/arena.h b/src/google/protobuf/arena.h
index db91617..5cee1ac 100644
--- a/src/google/protobuf/arena.h
+++ b/src/google/protobuf/arena.h
@@ -451,28 +451,34 @@
         is_arena_constructable;
 
     template <typename... Args>
+    static T* PROTOBUF_NONNULL ConstructOnArena(void* PROTOBUF_NONNULL ptr,
+                                                Arena& arena, Args&&... args) {
+      // TODO - ClangTidy gives warnings for calling the deprecated
+      // `RepeatedPtrField(Arena*)` constructor here, but this is the correct
+      // way to call it as it will allow us to silently switch to a different
+      // constructor once arena pointers are removed from RepeatedPtrFields.
+      // While this constructor exists, we will call the `InternalVisibility`
+      // override to silence the warning.
+      //
+      // Note: RepeatedPtrFieldBase is sometimes constructed internally, and it
+      // doesn't have `InternalVisibility` constructors.
+      if constexpr (std::is_base_of_v<internal::RepeatedPtrFieldBase, T> &&
+                    !std::is_same_v<T, internal::RepeatedPtrFieldBase>) {
+        return new (ptr) T(internal::InternalVisibility(), &arena,
+                           static_cast<Args&&>(args)...);
+      } else {
+        return new (ptr) T(&arena, static_cast<Args&&>(args)...);
+      }
+    }
+
+    template <typename... Args>
     static T* PROTOBUF_NONNULL Construct(void* PROTOBUF_NONNULL ptr,
                                          Arena* PROTOBUF_NULLABLE arena,
                                          Args&&... args) {
-      if constexpr (internal::IsRepeatedPtrFieldType<T>::value) {
-        using ArenaRepT = typename internal::FieldArenaRep<T>::Type;
-        // TODO - ClangTidy gives warnings for calling the
-        // deprecated `RepeatedPtrField(Arena*)` constructor here, but this is
-        // the correct way to call it as it will allow us to silently switch to
-        // a different constructor once arena pointers are removed from
-        // RepeatedPtrFields. While this constructor exists, we will call the
-        // `InternalVisibility` override to silence the warning.
-        if constexpr (std::is_same_v<ArenaRepT,
-                                     internal::RepeatedPtrFieldBase>) {
-          // RepeatedPtrFieldBase is sometimes constructed internally, and it
-          // doesn't have `InternalVisibility` constructors.
-          return new (ptr) ArenaRepT(arena, static_cast<Args&&>(args)...);
-        } else {
-          return new (ptr) ArenaRepT(internal::InternalVisibility(), arena,
-                                     static_cast<Args&&>(args)...);
-        }
+      if (ABSL_PREDICT_FALSE(arena == nullptr)) {
+        return new (ptr) T(static_cast<Args&&>(args)...);
       } else {
-        return new (ptr) T(arena, static_cast<Args&&>(args)...);
+        return ConstructOnArena(ptr, *arena, static_cast<Args&&>(args)...);
       }
     }
 
@@ -633,8 +639,8 @@
 
   template <typename T, typename... Args>
   PROTOBUF_NDEBUG_INLINE T* PROTOBUF_NONNULL DoCreateMessage(Args&&... args) {
-    return InternalHelper<T>::Construct(
-        AllocateInternal<T, is_destructor_skippable<T>::value>(), this,
+    return InternalHelper<T>::ConstructOnArena(
+        AllocateInternal<T, is_destructor_skippable<T>::value>(), *this,
         std::forward<Args>(args)...);
   }