Browse Source

Sync from Piper @307316823

PROTOBUF_SYNC_PIPER
Joshua Haberman 5 years ago
parent
commit
bb30225f06
55 changed files with 416 additions and 476 deletions
  1. 0 0
      README.md
  2. 1 0
      docs/third_party.md
  3. 2 2
      java/pom.xml
  4. 1 1
      kokoro/linux/dockerfile/push_testing_images.sh
  5. 0 3
      kokoro/linux/dockerfile/release/ruby_rake_compiler/Dockerfile
  6. 23 0
      kokoro/linux/dockerfile/test/python27/Dockerfile
  7. 23 0
      kokoro/linux/dockerfile/test/python35/Dockerfile
  8. 23 0
      kokoro/linux/dockerfile/test/python36/Dockerfile
  9. 23 0
      kokoro/linux/dockerfile/test/python37/Dockerfile
  10. 23 0
      kokoro/linux/dockerfile/test/python38/Dockerfile
  11. 0 39
      kokoro/linux/dockerfile/test/python_jessie/Dockerfile
  12. 0 49
      kokoro/linux/dockerfile/test/python_stretch/Dockerfile
  13. 1 1
      kokoro/linux/python27/build.sh
  14. 1 1
      kokoro/linux/python27_cpp/build.sh
  15. 0 18
      kokoro/linux/python33/build.sh
  16. 0 11
      kokoro/linux/python33/continuous.cfg
  17. 0 11
      kokoro/linux/python33/presubmit.cfg
  18. 0 18
      kokoro/linux/python33_cpp/build.sh
  19. 0 11
      kokoro/linux/python33_cpp/continuous.cfg
  20. 0 11
      kokoro/linux/python33_cpp/presubmit.cfg
  21. 0 18
      kokoro/linux/python34/build.sh
  22. 0 11
      kokoro/linux/python34/continuous.cfg
  23. 0 11
      kokoro/linux/python34/presubmit.cfg
  24. 0 18
      kokoro/linux/python34_cpp/build.sh
  25. 0 11
      kokoro/linux/python34_cpp/continuous.cfg
  26. 0 11
      kokoro/linux/python34_cpp/presubmit.cfg
  27. 1 1
      kokoro/linux/python35/build.sh
  28. 1 1
      kokoro/linux/python35_cpp/build.sh
  29. 1 1
      kokoro/linux/python36/build.sh
  30. 1 1
      kokoro/linux/python36_cpp/build.sh
  31. 1 1
      kokoro/linux/python37/build.sh
  32. 1 1
      kokoro/linux/python37_cpp/build.sh
  33. 1 1
      kokoro/linux/python38/build.sh
  34. 1 1
      kokoro/linux/python38_cpp/build.sh
  35. 0 6
      kokoro/release/ruby/linux/prepare_build.sh
  36. 1 0
      kokoro/release/ruby/linux/ruby/ruby_build.sh
  37. 24 5
      kokoro/release/ruby/macos/ruby/ruby_build_environment.sh
  38. 159 104
      objectivec/GPBUtilities.m
  39. 0 5
      objectivec/GPBUtilities_PackagePrivate.h
  40. 16 15
      python/google/protobuf/pyext/message.cc
  41. 31 29
      python/google/protobuf/text_format.py
  42. 7 2
      ruby/Rakefile
  43. 2 2
      ruby/google-protobuf.gemspec
  44. 1 1
      ruby/tests/common_tests.rb
  45. 1 0
      ruby/tests/repeated_field_test.rb
  46. 2 0
      src/google/protobuf/arena_impl.h
  47. 6 2
      src/google/protobuf/compiler/command_line_interface.cc
  48. 4 5
      src/google/protobuf/compiler/java/java_enum_field_lite.cc
  49. 4 5
      src/google/protobuf/compiler/java/java_message_field_lite.cc
  50. 4 5
      src/google/protobuf/compiler/java/java_primitive_field_lite.cc
  51. 5 5
      src/google/protobuf/compiler/java/java_string_field_lite.cc
  52. 9 9
      src/google/protobuf/descriptor.h
  53. 3 11
      src/google/protobuf/proto3_arena_unittest.cc
  54. 4 1
      src/google/protobuf/util/internal/protostream_objectsource.h
  55. 4 0
      tests.sh

File diff suppressed because it is too large
+ 0 - 0
README.md


+ 1 - 0
docs/third_party.md

@@ -82,6 +82,7 @@ These are projects we know about implementing Protocol Buffers for other program
 * Prolog: http://www.swi-prolog.org/pldoc/package/protobufs.html
 * Python: https://github.com/google/protobuf (Google-official implementation)
 * Python: https://github.com/eigenein/protobuf
+* Python: https://github.com/danielgtaylor/python-betterproto
 * R: http://cran.r-project.org/package=RProtoBuf
 * Ruby: http://code.google.com/p/ruby-protobuf/
 * Ruby: http://github.com/mozy/ruby-protocol-buffers

+ 2 - 2
java/pom.xml

@@ -93,12 +93,12 @@
       <dependency>
         <groupId>com.google.guava</groupId>
         <artifactId>guava</artifactId>
-        <version>28.2-android</version>
+        <version>29.0-android</version>
       </dependency>
       <dependency>
         <groupId>com.google.guava</groupId>
         <artifactId>guava-testlib</artifactId>
-        <version>28.2-android</version>
+        <version>29.0-android</version>
         <scope>test</scope>
       </dependency>
       <dependency>

+ 1 - 1
kokoro/linux/dockerfile/push_testing_images.sh

@@ -8,7 +8,7 @@ cd kokoro/linux/dockerfile
 
 DOCKERHUB_ORGANIZATION=protobuftesting
 
-for DOCKERFILE_DIR in test/* release/*
+for DOCKERFILE_DIR in test/*
 do
   # Generate image name based on Dockerfile checksum. That works well as long
   # as can count on dockerfiles being written in a way that changing the logical

+ 0 - 3
kokoro/linux/dockerfile/release/ruby_rake_compiler/Dockerfile

@@ -1,3 +0,0 @@
-FROM grpctesting/rake-compiler-dock_53c22085d091183c528303791e7771359f699bcf
-
-RUN /bin/bash -l -c "gem update --system '2.7.9' && gem install bundler"

+ 23 - 0
kokoro/linux/dockerfile/test/python27/Dockerfile

@@ -0,0 +1,23 @@
+FROM python:2.7-buster
+
+# Install dependencies.  We start with the basic ones require to build protoc
+# and the C++ build
+RUN apt-get update && apt-get install -y \
+  autoconf \
+  autotools-dev \
+  build-essential \
+  bzip2 \
+  ccache \
+  curl \
+  gcc \
+  git \
+  libc6 \
+  libc6-dbg \
+  libc6-dev \
+  libgtest-dev \
+  libtool \
+  make \
+  parallel \
+  time \
+  wget \
+  && apt-get clean

+ 23 - 0
kokoro/linux/dockerfile/test/python35/Dockerfile

@@ -0,0 +1,23 @@
+FROM python:3.5-buster
+
+# Install dependencies.  We start with the basic ones require to build protoc
+# and the C++ build
+RUN apt-get update && apt-get install -y \
+  autoconf \
+  autotools-dev \
+  build-essential \
+  bzip2 \
+  ccache \
+  curl \
+  gcc \
+  git \
+  libc6 \
+  libc6-dbg \
+  libc6-dev \
+  libgtest-dev \
+  libtool \
+  make \
+  parallel \
+  time \
+  wget \
+  && apt-get clean

+ 23 - 0
kokoro/linux/dockerfile/test/python36/Dockerfile

@@ -0,0 +1,23 @@
+FROM python:3.6-buster
+
+# Install dependencies.  We start with the basic ones require to build protoc
+# and the C++ build
+RUN apt-get update && apt-get install -y \
+  autoconf \
+  autotools-dev \
+  build-essential \
+  bzip2 \
+  ccache \
+  curl \
+  gcc \
+  git \
+  libc6 \
+  libc6-dbg \
+  libc6-dev \
+  libgtest-dev \
+  libtool \
+  make \
+  parallel \
+  time \
+  wget \
+  && apt-get clean

+ 23 - 0
kokoro/linux/dockerfile/test/python37/Dockerfile

@@ -0,0 +1,23 @@
+FROM python:3.7-buster
+
+# Install dependencies.  We start with the basic ones require to build protoc
+# and the C++ build
+RUN apt-get update && apt-get install -y \
+  autoconf \
+  autotools-dev \
+  build-essential \
+  bzip2 \
+  ccache \
+  curl \
+  gcc \
+  git \
+  libc6 \
+  libc6-dbg \
+  libc6-dev \
+  libgtest-dev \
+  libtool \
+  make \
+  parallel \
+  time \
+  wget \
+  && apt-get clean

+ 23 - 0
kokoro/linux/dockerfile/test/python38/Dockerfile

@@ -0,0 +1,23 @@
+FROM python:3.8-buster
+
+# Install dependencies.  We start with the basic ones require to build protoc
+# and the C++ build
+RUN apt-get update && apt-get install -y \
+  autoconf \
+  autotools-dev \
+  build-essential \
+  bzip2 \
+  ccache \
+  curl \
+  gcc \
+  git \
+  libc6 \
+  libc6-dbg \
+  libc6-dev \
+  libgtest-dev \
+  libtool \
+  make \
+  parallel \
+  time \
+  wget \
+  && apt-get clean

+ 0 - 39
kokoro/linux/dockerfile/test/python_jessie/Dockerfile

@@ -1,39 +0,0 @@
-FROM debian:jessie
-
-# Install dependencies.  We start with the basic ones require to build protoc
-# and the C++ build
-RUN apt-get update && apt-get install -y \
-  autoconf \
-  autotools-dev \
-  build-essential \
-  bzip2 \
-  ccache \
-  curl \
-  gcc \
-  git \
-  libc6 \
-  libc6-dbg \
-  libc6-dev \
-  libgtest-dev \
-  libtool \
-  make \
-  parallel \
-  time \
-  wget \
-  && apt-get clean
-
-# Install python dependencies
-RUN apt-get update && apt-get install -y \
-  python-setuptools \
-  python-all-dev \
-  python3-all-dev \
-  python-pip
-
-# Install Python packages from PyPI
-RUN pip install --upgrade pip==10.0.1
-RUN pip install virtualenv
-RUN pip install six==1.10.0 twisted==17.5.0
-
-# Install pip and virtualenv for Python 3.4
-RUN curl https://bootstrap.pypa.io/get-pip.py | python3.4
-RUN python3.4 -m pip install virtualenv

+ 0 - 49
kokoro/linux/dockerfile/test/python_stretch/Dockerfile

@@ -1,49 +0,0 @@
-FROM debian:stretch
-
-# Install dependencies.  We start with the basic ones require to build protoc
-# and the C++ build
-RUN apt-get update && apt-get install -y \
-  autoconf \
-  autotools-dev \
-  build-essential \
-  bzip2 \
-  ccache \
-  curl \
-  gcc \
-  git \
-  libc6 \
-  libc6-dbg \
-  libc6-dev \
-  libgtest-dev \
-  libtool \
-  make \
-  parallel \
-  time \
-  wget \
-  && apt-get clean
-
-# Install Python 2.7
-RUN apt-get update && apt-get install -y python2.7 python-all-dev
-RUN curl https://bootstrap.pypa.io/get-pip.py | python2.7
-
-# Install python dependencies
-RUN apt-get update && apt-get install -y \
-  python-setuptools \
-  python-pip
-
-# Add Debian 'testing' repository
-RUN echo 'deb http://ftp.de.debian.org/debian testing main' >> /etc/apt/sources.list
-RUN echo 'APT::Default-Release "stable";' | tee -a /etc/apt/apt.conf.d/00local
-
-# Install Python3
-RUN apt-get update && apt-get -t testing install -y \
-  python3.5 \
-  python3.6 \
-  python3.7 \
-  python3.8 \
-  python3-all-dev
-
-RUN curl https://bootstrap.pypa.io/get-pip.py | python3.5
-RUN curl https://bootstrap.pypa.io/get-pip.py | python3.6
-RUN curl https://bootstrap.pypa.io/get-pip.py | python3.7
-RUN curl https://bootstrap.pypa.io/get-pip.py | python3.8

+ 1 - 1
kokoro/linux/python27/build.sh

@@ -11,7 +11,7 @@
 cd $(dirname $0)/../../..
 
 export DOCKERHUB_ORGANIZATION=protobuftesting
-export DOCKERFILE_DIR=kokoro/linux/dockerfile/test/python_jessie
+export DOCKERFILE_DIR=kokoro/linux/dockerfile/test/python27
 export DOCKER_RUN_SCRIPT=kokoro/linux/pull_request_in_docker.sh
 export OUTPUT_DIR=testoutput
 export TEST_SET="python27"

+ 1 - 1
kokoro/linux/python27_cpp/build.sh

@@ -11,7 +11,7 @@
 cd $(dirname $0)/../../..
 
 export DOCKERHUB_ORGANIZATION=protobuftesting
-export DOCKERFILE_DIR=kokoro/linux/dockerfile/test/python_jessie
+export DOCKERFILE_DIR=kokoro/linux/dockerfile/test/python27
 export DOCKER_RUN_SCRIPT=kokoro/linux/pull_request_in_docker.sh
 export OUTPUT_DIR=testoutput
 export TEST_SET="python27_cpp"

+ 0 - 18
kokoro/linux/python33/build.sh

@@ -1,18 +0,0 @@
-#!/bin/bash
-#
-# This is the top-level script we give to Kokoro as the entry point for
-# running the "pull request" project:
-#
-# This script selects a specific Dockerfile (for building a Docker image) and
-# a script to run inside that image.  Then we delegate to the general
-# build_and_run_docker.sh script.
-
-# Change to repo root
-cd $(dirname $0)/../../..
-
-export DOCKERHUB_ORGANIZATION=protobuftesting
-export DOCKERFILE_DIR=kokoro/linux/dockerfile/test/python_jessie
-export DOCKER_RUN_SCRIPT=kokoro/linux/pull_request_in_docker.sh
-export OUTPUT_DIR=testoutput
-export TEST_SET="python33"
-./kokoro/linux/build_and_run_docker.sh

+ 0 - 11
kokoro/linux/python33/continuous.cfg

@@ -1,11 +0,0 @@
-# Config file for running tests in Kokoro
-
-# Location of the build script in repository
-build_file: "protobuf/kokoro/linux/python/build.sh"
-timeout_mins: 120
-
-action {
-  define_artifacts {
-    regex: "**/sponge_log.xml"
-  }
-}

+ 0 - 11
kokoro/linux/python33/presubmit.cfg

@@ -1,11 +0,0 @@
-# Config file for running tests in Kokoro
-
-# Location of the build script in repository
-build_file: "protobuf/kokoro/linux/python/build.sh"
-timeout_mins: 120
-
-action {
-  define_artifacts {
-    regex: "**/sponge_log.xml"
-  }
-}

+ 0 - 18
kokoro/linux/python33_cpp/build.sh

@@ -1,18 +0,0 @@
-#!/bin/bash
-#
-# This is the top-level script we give to Kokoro as the entry point for
-# running the "pull request" project:
-#
-# This script selects a specific Dockerfile (for building a Docker image) and
-# a script to run inside that image.  Then we delegate to the general
-# build_and_run_docker.sh script.
-
-# Change to repo root
-cd $(dirname $0)/../../..
-
-export DOCKERHUB_ORGANIZATION=protobuftesting
-export DOCKERFILE_DIR=kokoro/linux/dockerfile/test/python_jessie
-export DOCKER_RUN_SCRIPT=kokoro/linux/pull_request_in_docker.sh
-export OUTPUT_DIR=testoutput
-export TEST_SET="python33_cpp"
-./kokoro/linux/build_and_run_docker.sh

+ 0 - 11
kokoro/linux/python33_cpp/continuous.cfg

@@ -1,11 +0,0 @@
-# Config file for running tests in Kokoro
-
-# Location of the build script in repository
-build_file: "protobuf/kokoro/linux/python_cpp/build.sh"
-timeout_mins: 120
-
-action {
-  define_artifacts {
-    regex: "**/sponge_log.xml"
-  }
-}

+ 0 - 11
kokoro/linux/python33_cpp/presubmit.cfg

@@ -1,11 +0,0 @@
-# Config file for running tests in Kokoro
-
-# Location of the build script in repository
-build_file: "protobuf/kokoro/linux/python_cpp/build.sh"
-timeout_mins: 120
-
-action {
-  define_artifacts {
-    regex: "**/sponge_log.xml"
-  }
-}

+ 0 - 18
kokoro/linux/python34/build.sh

@@ -1,18 +0,0 @@
-#!/bin/bash
-#
-# This is the top-level script we give to Kokoro as the entry point for
-# running the "pull request" project:
-#
-# This script selects a specific Dockerfile (for building a Docker image) and
-# a script to run inside that image.  Then we delegate to the general
-# build_and_run_docker.sh script.
-
-# Change to repo root
-cd $(dirname $0)/../../..
-
-export DOCKERHUB_ORGANIZATION=protobuftesting
-export DOCKERFILE_DIR=kokoro/linux/dockerfile/test/python_jessie
-export DOCKER_RUN_SCRIPT=kokoro/linux/pull_request_in_docker.sh
-export OUTPUT_DIR=testoutput
-export TEST_SET="python34"
-./kokoro/linux/build_and_run_docker.sh

+ 0 - 11
kokoro/linux/python34/continuous.cfg

@@ -1,11 +0,0 @@
-# Config file for running tests in Kokoro
-
-# Location of the build script in repository
-build_file: "protobuf/kokoro/linux/python/build.sh"
-timeout_mins: 120
-
-action {
-  define_artifacts {
-    regex: "**/sponge_log.xml"
-  }
-}

+ 0 - 11
kokoro/linux/python34/presubmit.cfg

@@ -1,11 +0,0 @@
-# Config file for running tests in Kokoro
-
-# Location of the build script in repository
-build_file: "protobuf/kokoro/linux/python/build.sh"
-timeout_mins: 120
-
-action {
-  define_artifacts {
-    regex: "**/sponge_log.xml"
-  }
-}

+ 0 - 18
kokoro/linux/python34_cpp/build.sh

@@ -1,18 +0,0 @@
-#!/bin/bash
-#
-# This is the top-level script we give to Kokoro as the entry point for
-# running the "pull request" project:
-#
-# This script selects a specific Dockerfile (for building a Docker image) and
-# a script to run inside that image.  Then we delegate to the general
-# build_and_run_docker.sh script.
-
-# Change to repo root
-cd $(dirname $0)/../../..
-
-export DOCKERHUB_ORGANIZATION=protobuftesting
-export DOCKERFILE_DIR=kokoro/linux/dockerfile/test/python_jessie
-export DOCKER_RUN_SCRIPT=kokoro/linux/pull_request_in_docker.sh
-export OUTPUT_DIR=testoutput
-export TEST_SET="python34_cpp"
-./kokoro/linux/build_and_run_docker.sh

+ 0 - 11
kokoro/linux/python34_cpp/continuous.cfg

@@ -1,11 +0,0 @@
-# Config file for running tests in Kokoro
-
-# Location of the build script in repository
-build_file: "protobuf/kokoro/linux/python_cpp/build.sh"
-timeout_mins: 120
-
-action {
-  define_artifacts {
-    regex: "**/sponge_log.xml"
-  }
-}

+ 0 - 11
kokoro/linux/python34_cpp/presubmit.cfg

@@ -1,11 +0,0 @@
-# Config file for running tests in Kokoro
-
-# Location of the build script in repository
-build_file: "protobuf/kokoro/linux/python_cpp/build.sh"
-timeout_mins: 120
-
-action {
-  define_artifacts {
-    regex: "**/sponge_log.xml"
-  }
-}

+ 1 - 1
kokoro/linux/python35/build.sh

@@ -11,7 +11,7 @@
 cd $(dirname $0)/../../..
 
 export DOCKERHUB_ORGANIZATION=protobuftesting
-export DOCKERFILE_DIR=kokoro/linux/dockerfile/test/python_stretch
+export DOCKERFILE_DIR=kokoro/linux/dockerfile/test/python35
 export DOCKER_RUN_SCRIPT=kokoro/linux/pull_request_in_docker.sh
 export OUTPUT_DIR=testoutput
 export TEST_SET="python35"

+ 1 - 1
kokoro/linux/python35_cpp/build.sh

@@ -11,7 +11,7 @@
 cd $(dirname $0)/../../..
 
 export DOCKERHUB_ORGANIZATION=protobuftesting
-export DOCKERFILE_DIR=kokoro/linux/dockerfile/test/python_stretch
+export DOCKERFILE_DIR=kokoro/linux/dockerfile/test/python35
 export DOCKER_RUN_SCRIPT=kokoro/linux/pull_request_in_docker.sh
 export OUTPUT_DIR=testoutput
 export TEST_SET="python35_cpp"

+ 1 - 1
kokoro/linux/python36/build.sh

@@ -11,7 +11,7 @@
 cd $(dirname $0)/../../..
 
 export DOCKERHUB_ORGANIZATION=protobuftesting
-export DOCKERFILE_DIR=kokoro/linux/dockerfile/test/python_stretch
+export DOCKERFILE_DIR=kokoro/linux/dockerfile/test/python36
 export DOCKER_RUN_SCRIPT=kokoro/linux/pull_request_in_docker.sh
 export OUTPUT_DIR=testoutput
 export TEST_SET="python36"

+ 1 - 1
kokoro/linux/python36_cpp/build.sh

@@ -11,7 +11,7 @@
 cd $(dirname $0)/../../..
 
 export DOCKERHUB_ORGANIZATION=protobuftesting
-export DOCKERFILE_DIR=kokoro/linux/dockerfile/test/python_stretch
+export DOCKERFILE_DIR=kokoro/linux/dockerfile/test/python36
 export DOCKER_RUN_SCRIPT=kokoro/linux/pull_request_in_docker.sh
 export OUTPUT_DIR=testoutput
 export TEST_SET="python36_cpp"

+ 1 - 1
kokoro/linux/python37/build.sh

@@ -11,7 +11,7 @@
 cd $(dirname $0)/../../..
 
 export DOCKERHUB_ORGANIZATION=protobuftesting
-export DOCKERFILE_DIR=kokoro/linux/dockerfile/test/python_stretch
+export DOCKERFILE_DIR=kokoro/linux/dockerfile/test/python37
 export DOCKER_RUN_SCRIPT=kokoro/linux/pull_request_in_docker.sh
 export OUTPUT_DIR=testoutput
 export TEST_SET="python37"

+ 1 - 1
kokoro/linux/python37_cpp/build.sh

@@ -11,7 +11,7 @@
 cd $(dirname $0)/../../..
 
 export DOCKERHUB_ORGANIZATION=protobuftesting
-export DOCKERFILE_DIR=kokoro/linux/dockerfile/test/python_stretch
+export DOCKERFILE_DIR=kokoro/linux/dockerfile/test/python37
 export DOCKER_RUN_SCRIPT=kokoro/linux/pull_request_in_docker.sh
 export OUTPUT_DIR=testoutput
 export TEST_SET="python37_cpp"

+ 1 - 1
kokoro/linux/python38/build.sh

@@ -11,7 +11,7 @@
 cd $(dirname $0)/../../..
 
 export DOCKERHUB_ORGANIZATION=protobuftesting
-export DOCKERFILE_DIR=kokoro/linux/dockerfile/test/python_stretch
+export DOCKERFILE_DIR=kokoro/linux/dockerfile/test/python38
 export DOCKER_RUN_SCRIPT=kokoro/linux/pull_request_in_docker.sh
 export OUTPUT_DIR=testoutput
 export TEST_SET="python38"

+ 1 - 1
kokoro/linux/python38_cpp/build.sh

@@ -11,7 +11,7 @@
 cd $(dirname $0)/../../..
 
 export DOCKERHUB_ORGANIZATION=protobuftesting
-export DOCKERFILE_DIR=kokoro/linux/dockerfile/test/python_stretch
+export DOCKERFILE_DIR=kokoro/linux/dockerfile/test/python38
 export DOCKER_RUN_SCRIPT=kokoro/linux/pull_request_in_docker.sh
 export OUTPUT_DIR=testoutput
 export TEST_SET="python38_cpp"

+ 0 - 6
kokoro/release/ruby/linux/prepare_build.sh

@@ -7,12 +7,6 @@ echo 'DOCKER_OPTS="${DOCKER_OPTS} --graph=/tmpfs/docker"' | sudo tee --append /e
 echo 'DOCKER_OPTS="${DOCKER_OPTS} --registry-mirror=https://mirror.gcr.io"' | sudo tee --append /etc/default/docker
 sudo service docker restart
 
-# Download Docker images from DockerHub
-DOCKERHUB_ORGANIZATION=protobuftesting
-DOCKERFILE_DIR=kokoro/linux/dockerfile/release/ruby_rake_compiler
-DOCKERFILE_PREFIX=$(basename $DOCKERFILE_DIR)
-export RAKE_COMPILER_DOCK_IMAGE=${DOCKERHUB_ORGANIZATION}/${DOCKERFILE_PREFIX}_$(sha1sum $DOCKERFILE_DIR/Dockerfile | cut -f1 -d\ )
-
 # All artifacts come here
 mkdir artifacts
 export ARTIFACT_DIR=$(pwd)/artifacts

+ 1 - 0
kokoro/release/ruby/linux/ruby/ruby_build.sh

@@ -11,6 +11,7 @@ fi
 
 umask 0022
 pushd ruby
+gem install bundler -v 2.1.4
 bundle install && bundle exec rake gem:native
 ls pkg
 mv pkg/* $ARTIFACT_DIR

+ 24 - 5
kokoro/release/ruby/macos/ruby/ruby_build_environment.sh

@@ -6,7 +6,11 @@ set +ex  # rvm script is very verbose and exits with errorcode
 source $HOME/.rvm/scripts/rvm
 set -e  # rvm commands are very verbose
 time rvm install 2.5.0
-rvm use 2.5.0 --default
+rvm use 2.5.0
+gem install rake-compiler --no-document
+gem install bundler --no-document
+time rvm install 2.7.0
+rvm use 2.7.0 --default
 gem install rake-compiler --no-document
 gem install bundler --no-document
 rvm osx-ssl-certs status all
@@ -17,13 +21,13 @@ rm -rf ~/.rake-compiler
 
 CROSS_RUBY=$(mktemp tmpfile.XXXXXXXX)
 
-curl https://raw.githubusercontent.com/rake-compiler/rake-compiler/v1.0.3/tasks/bin/cross-ruby.rake > "$CROSS_RUBY"
+curl https://raw.githubusercontent.com/rake-compiler/rake-compiler/v1.1.0/tasks/bin/cross-ruby.rake > "$CROSS_RUBY"
 
 # See https://github.com/grpc/grpc/issues/12161 for verconf.h patch details
 patch "$CROSS_RUBY" << EOF
 --- cross-ruby.rake	2018-04-10 11:32:16.000000000 -0700
 +++ patched	2018-04-10 11:40:25.000000000 -0700
-@@ -133,8 +133,10 @@
+@@ -141,8 +141,10 @@
      "--host=#{MINGW_HOST}",
      "--target=#{MINGW_TARGET}",
      "--build=#{RUBY_BUILD}",
@@ -35,9 +39,9 @@ patch "$CROSS_RUBY" << EOF
      '--with-ext='
    ]
 
-@@ -151,6 +153,7 @@
+@@ -159,6 +161,7 @@
  # make
- file "#{USER_HOME}/builds/#{MINGW_HOST}/#{RUBY_CC_VERSION}/ruby.exe" => ["#{USER_HOME}/builds/#{MINGW_HOST}/#{RUBY_CC_VERSION}/Makefile"] do |t|
+ file "#{build_dir}/ruby.exe" => ["#{build_dir}/Makefile"] do |t|
    chdir File.dirname(t.prerequisites.first) do
 +    sh "test -s verconf.h || rm -f verconf.h"  # if verconf.h has size 0, make sure it gets re-built by make
      sh MAKE
@@ -47,10 +51,25 @@ EOF
 
 MAKE="make -j8"
 
+set +x # rvm commands are very verbose
+rvm use 2.7.0
+set -x
+ruby --version | grep 'ruby 2.7.0'
+for v in 2.7.0 ; do
+  ccache -c
+  rake -f "$CROSS_RUBY" cross-ruby VERSION="$v" HOST=x86_64-darwin11 MAKE="$MAKE"
+done
+set +x
+rvm use 2.5.0
+set -x
+ruby --version | grep 'ruby 2.5.0'
 for v in 2.6.0 2.5.1 2.4.0 2.3.0 ; do
   ccache -c
   rake -f "$CROSS_RUBY" cross-ruby VERSION="$v" HOST=x86_64-darwin11 MAKE="$MAKE"
 done
+set +x
+rvm use 2.7.0
+set -x
 
 sed 's/x86_64-darwin-11/universal-darwin/' ~/.rake-compiler/config.yml > "$CROSS_RUBY"
 mv "$CROSS_RUBY" ~/.rake-compiler/config.yml

+ 159 - 104
objectivec/GPBUtilities.m

@@ -267,17 +267,18 @@ void GPBClearMessageField(GPBMessage *self, GPBFieldDescriptor *field) {
     return;
   }
 
+  GPBMessageFieldDescription *fieldDesc = field->description_;
   if (GPBFieldStoresObject(field)) {
     // Object types are handled slightly differently, they need to be released.
     uint8_t *storage = (uint8_t *)self->messageStorage_;
-    id *typePtr = (id *)&storage[field->description_->offset];
+    id *typePtr = (id *)&storage[fieldDesc->offset];
     [*typePtr release];
     *typePtr = nil;
   } else {
     // POD types just need to clear the has bit as the Get* method will
     // fetch the default when needed.
   }
-  GPBSetHasIvarField(self, field, NO);
+  GPBSetHasIvar(self, fieldDesc->hasIndex, fieldDesc->number, NO);
 }
 
 BOOL GPBGetHasIvar(GPBMessage *self, int32_t idx, uint32_t fieldNumber) {
@@ -356,6 +357,9 @@ void GPBMaybeClearOneof(GPBMessage *self, GPBOneofDescriptor *oneof,
 //%TYPE GPBGetMessage##NAME##Field(GPBMessage *self,
 //% TYPE$S            NAME$S       GPBFieldDescriptor *field) {
 //%#if defined(DEBUG) && DEBUG
+//%  NSCAssert([[self descriptor] fieldWithNumber:field.number] == field,
+//%            @"FieldDescriptor %@ doesn't appear to be for %@ messages.",
+//%            field.name, [self class]);
 //%  NSCAssert(DataTypesEquivalent(GPBGetFieldDataType(field),
 //%                                GPBDataType##NAME),
 //%            @"Attempting to get value of TYPE from field %@ "
@@ -377,15 +381,10 @@ void GPBMaybeClearOneof(GPBMessage *self, GPBOneofDescriptor *oneof,
 //%                   NAME$S     GPBFieldDescriptor *field,
 //%                   NAME$S     TYPE value) {
 //%  if (self == nil || field == nil) return;
-//%  GPBFileSyntax syntax = [self descriptor].file.syntax;
-//%  GPBSet##NAME##IvarWithFieldInternal(self, field, value, syntax);
-//%}
-//%
-//%void GPBSet##NAME##IvarWithFieldInternal(GPBMessage *self,
-//%            NAME$S                     GPBFieldDescriptor *field,
-//%            NAME$S                     TYPE value,
-//%            NAME$S                     GPBFileSyntax syntax) {
 //%#if defined(DEBUG) && DEBUG
+//%  NSCAssert([[self descriptor] fieldWithNumber:field.number] == field,
+//%            @"FieldDescriptor %@ doesn't appear to be for %@ messages.",
+//%            field.name, [self class]);
 //%  NSCAssert(DataTypesEquivalent(GPBGetFieldDataType(field),
 //%                                GPBDataType##NAME),
 //%            @"Attempting to set field %@ of %@ which is of type %@ with "
@@ -393,9 +392,17 @@ void GPBMaybeClearOneof(GPBMessage *self, GPBOneofDescriptor *oneof,
 //%            [self class], field.name,
 //%            TypeToString(GPBGetFieldDataType(field)));
 //%#endif
+//%  GPBFileSyntax syntax = [self descriptor].file.syntax;
+//%  GPBSet##NAME##IvarWithFieldInternal(self, field, value, syntax);
+//%}
+//%
+//%void GPBSet##NAME##IvarWithFieldInternal(GPBMessage *self,
+//%            NAME$S                     GPBFieldDescriptor *field,
+//%            NAME$S                     TYPE value,
+//%            NAME$S                     GPBFileSyntax syntax) {
 //%  GPBOneofDescriptor *oneof = field->containingOneof_;
+//%  GPBMessageFieldDescription *fieldDesc = field->description_;
 //%  if (oneof) {
-//%    GPBMessageFieldDescription *fieldDesc = field->description_;
 //%    GPBMaybeClearOneof(self, oneof, fieldDesc->hasIndex, fieldDesc->number);
 //%  }
 //%#if defined(DEBUG) && DEBUG
@@ -407,14 +414,14 @@ void GPBMaybeClearOneof(GPBMessage *self, GPBOneofDescriptor *oneof,
 //%  if (self->messageStorage_ == NULL) return;
 //%#endif
 //%  uint8_t *storage = (uint8_t *)self->messageStorage_;
-//%  TYPE *typePtr = (TYPE *)&storage[field->description_->offset];
+//%  TYPE *typePtr = (TYPE *)&storage[fieldDesc->offset];
 //%  *typePtr = value;
 //%  // proto2: any value counts as having been set; proto3, it
 //%  // has to be a non zero value or be in a oneof.
 //%  BOOL hasValue = ((syntax == GPBFileSyntaxProto2)
 //%                   || (value != (TYPE)0)
 //%                   || (field->containingOneof_ != NULL));
-//%  GPBSetHasIvarField(self, field, hasValue);
+//%  GPBSetHasIvar(self, fieldDesc->hasIndex, fieldDesc->number, hasValue);
 //%  GPBBecomeVisibleToAutocreator(self);
 //%}
 //%
@@ -579,12 +586,12 @@ void GPBSetRetainedObjectIvarWithFieldInternal(GPBMessage *self,
     // valueData/valueMessage.
   }
 #endif  // DEBUG
+  GPBMessageFieldDescription *fieldDesc = field->description_;
   if (!isMapOrArray) {
     // Non repeated/map can be in an oneof, clear any existing value from the
     // oneof.
     GPBOneofDescriptor *oneof = field->containingOneof_;
     if (oneof) {
-      GPBMessageFieldDescription *fieldDesc = field->description_;
       GPBMaybeClearOneof(self, oneof, fieldDesc->hasIndex, fieldDesc->number);
     }
     // Clear "has" if they are being set to nil.
@@ -608,10 +615,10 @@ void GPBSetRetainedObjectIvarWithFieldInternal(GPBMessage *self,
         value = nil;
       }
     }
-    GPBSetHasIvarField(self, field, setHasValue);
+    GPBSetHasIvar(self, fieldDesc->hasIndex, fieldDesc->number, setHasValue);
   }
   uint8_t *storage = (uint8_t *)self->messageStorage_;
-  id *typePtr = (id *)&storage[field->description_->offset];
+  id *typePtr = (id *)&storage[fieldDesc->offset];
 
   id oldValue = *typePtr;
 
@@ -678,6 +685,16 @@ id GPBGetObjectIvarWithFieldNoAutocreate(GPBMessage *self,
 
 // Only exists for public api, no core code should use this.
 int32_t GPBGetMessageEnumField(GPBMessage *self, GPBFieldDescriptor *field) {
+  #if defined(DEBUG) && DEBUG
+    NSCAssert([[self descriptor] fieldWithNumber:field.number] == field,
+              @"FieldDescriptor %@ doesn't appear to be for %@ messages.",
+              field.name, [self class]);
+    NSCAssert(GPBGetFieldDataType(field) == GPBDataTypeEnum,
+              @"Attempting to get value of type Enum from field %@ "
+              @"of %@ which is of type %@.",
+              [self class], field.name,
+              TypeToString(GPBGetFieldDataType(field)));
+  #endif
   GPBFileSyntax syntax = [self descriptor].file.syntax;
   return GPBGetEnumIvarWithFieldInternal(self, field, syntax);
 }
@@ -685,13 +702,6 @@ int32_t GPBGetMessageEnumField(GPBMessage *self, GPBFieldDescriptor *field) {
 int32_t GPBGetEnumIvarWithFieldInternal(GPBMessage *self,
                                         GPBFieldDescriptor *field,
                                         GPBFileSyntax syntax) {
-#if defined(DEBUG) && DEBUG
-  NSCAssert(GPBGetFieldDataType(field) == GPBDataTypeEnum,
-            @"Attempting to get value of type Enum from field %@ "
-            @"of %@ which is of type %@.",
-            [self class], field.name,
-            TypeToString(GPBGetFieldDataType(field)));
-#endif
   int32_t result = GPBGetMessageInt32Field(self, field);
   // If this is presevering unknown enums, make sure the value is valid before
   // returning it.
@@ -705,6 +715,16 @@ int32_t GPBGetEnumIvarWithFieldInternal(GPBMessage *self,
 // Only exists for public api, no core code should use this.
 void GPBSetMessageEnumField(GPBMessage *self, GPBFieldDescriptor *field,
                             int32_t value) {
+  #if defined(DEBUG) && DEBUG
+    NSCAssert([[self descriptor] fieldWithNumber:field.number] == field,
+              @"FieldDescriptor %@ doesn't appear to be for %@ messages.",
+              field.name, [self class]);
+    NSCAssert(GPBGetFieldDataType(field) == GPBDataTypeEnum,
+              @"Attempting to set field %@ of %@ which is of type %@ with "
+              @"value of type Enum.",
+              [self class], field.name,
+              TypeToString(GPBGetFieldDataType(field)));
+  #endif
   GPBFileSyntax syntax = [self descriptor].file.syntax;
   GPBSetInt32IvarWithFieldInternal(self, field, value, syntax);
 }
@@ -712,13 +732,6 @@ void GPBSetMessageEnumField(GPBMessage *self, GPBFieldDescriptor *field,
 void GPBSetEnumIvarWithFieldInternal(GPBMessage *self,
                                      GPBFieldDescriptor *field, int32_t value,
                                      GPBFileSyntax syntax) {
-#if defined(DEBUG) && DEBUG
-  NSCAssert(GPBGetFieldDataType(field) == GPBDataTypeEnum,
-            @"Attempting to set field %@ of %@ which is of type %@ with "
-            @"value of type Enum.",
-            [self class], field.name,
-            TypeToString(GPBGetFieldDataType(field)));
-#endif
   // Don't allow in unknown values.  Proto3 can use the Raw method.
   if (![field isValidEnumValue:value]) {
     [NSException raise:NSInvalidArgumentException
@@ -745,6 +758,9 @@ void GPBSetMessageRawEnumField(GPBMessage *self, GPBFieldDescriptor *field,
 BOOL GPBGetMessageBoolField(GPBMessage *self,
                             GPBFieldDescriptor *field) {
 #if defined(DEBUG) && DEBUG
+  NSCAssert([[self descriptor] fieldWithNumber:field.number] == field,
+            @"FieldDescriptor %@ doesn't appear to be for %@ messages.",
+            field.name, [self class]);
   NSCAssert(DataTypesEquivalent(GPBGetFieldDataType(field), GPBDataTypeBool),
             @"Attempting to get value of type bool from field %@ "
             @"of %@ which is of type %@.",
@@ -768,6 +784,16 @@ void GPBSetMessageBoolField(GPBMessage *self,
                             GPBFieldDescriptor *field,
                             BOOL value) {
   if (self == nil || field == nil) return;
+  #if defined(DEBUG) && DEBUG
+    NSCAssert([[self descriptor] fieldWithNumber:field.number] == field,
+              @"FieldDescriptor %@ doesn't appear to be for %@ messages.",
+              field.name, [self class]);
+    NSCAssert(DataTypesEquivalent(GPBGetFieldDataType(field), GPBDataTypeBool),
+              @"Attempting to set field %@ of %@ which is of type %@ with "
+              @"value of type bool.",
+              [self class], field.name,
+              TypeToString(GPBGetFieldDataType(field)));
+  #endif
   GPBFileSyntax syntax = [self descriptor].file.syntax;
   GPBSetBoolIvarWithFieldInternal(self, field, value, syntax);
 }
@@ -776,13 +802,6 @@ void GPBSetBoolIvarWithFieldInternal(GPBMessage *self,
                                      GPBFieldDescriptor *field,
                                      BOOL value,
                                      GPBFileSyntax syntax) {
-#if defined(DEBUG) && DEBUG
-  NSCAssert(DataTypesEquivalent(GPBGetFieldDataType(field), GPBDataTypeBool),
-            @"Attempting to set field %@ of %@ which is of type %@ with "
-            @"value of type bool.",
-            [self class], field.name,
-            TypeToString(GPBGetFieldDataType(field)));
-#endif
   GPBMessageFieldDescription *fieldDesc = field->description_;
   GPBOneofDescriptor *oneof = field->containingOneof_;
   if (oneof) {
@@ -800,7 +819,7 @@ void GPBSetBoolIvarWithFieldInternal(GPBMessage *self,
   BOOL hasValue = ((syntax == GPBFileSyntaxProto2)
                    || (value != (BOOL)0)
                    || (field->containingOneof_ != NULL));
-  GPBSetHasIvarField(self, field, hasValue);
+  GPBSetHasIvar(self, fieldDesc->hasIndex, fieldDesc->number, hasValue);
   GPBBecomeVisibleToAutocreator(self);
 }
 
@@ -811,6 +830,9 @@ void GPBSetBoolIvarWithFieldInternal(GPBMessage *self,
 int32_t GPBGetMessageInt32Field(GPBMessage *self,
                                 GPBFieldDescriptor *field) {
 #if defined(DEBUG) && DEBUG
+  NSCAssert([[self descriptor] fieldWithNumber:field.number] == field,
+            @"FieldDescriptor %@ doesn't appear to be for %@ messages.",
+            field.name, [self class]);
   NSCAssert(DataTypesEquivalent(GPBGetFieldDataType(field),
                                 GPBDataTypeInt32),
             @"Attempting to get value of int32_t from field %@ "
@@ -832,15 +854,10 @@ void GPBSetMessageInt32Field(GPBMessage *self,
                              GPBFieldDescriptor *field,
                              int32_t value) {
   if (self == nil || field == nil) return;
-  GPBFileSyntax syntax = [self descriptor].file.syntax;
-  GPBSetInt32IvarWithFieldInternal(self, field, value, syntax);
-}
-
-void GPBSetInt32IvarWithFieldInternal(GPBMessage *self,
-                                      GPBFieldDescriptor *field,
-                                      int32_t value,
-                                      GPBFileSyntax syntax) {
 #if defined(DEBUG) && DEBUG
+  NSCAssert([[self descriptor] fieldWithNumber:field.number] == field,
+            @"FieldDescriptor %@ doesn't appear to be for %@ messages.",
+            field.name, [self class]);
   NSCAssert(DataTypesEquivalent(GPBGetFieldDataType(field),
                                 GPBDataTypeInt32),
             @"Attempting to set field %@ of %@ which is of type %@ with "
@@ -848,9 +865,17 @@ void GPBSetInt32IvarWithFieldInternal(GPBMessage *self,
             [self class], field.name,
             TypeToString(GPBGetFieldDataType(field)));
 #endif
+  GPBFileSyntax syntax = [self descriptor].file.syntax;
+  GPBSetInt32IvarWithFieldInternal(self, field, value, syntax);
+}
+
+void GPBSetInt32IvarWithFieldInternal(GPBMessage *self,
+                                      GPBFieldDescriptor *field,
+                                      int32_t value,
+                                      GPBFileSyntax syntax) {
   GPBOneofDescriptor *oneof = field->containingOneof_;
+  GPBMessageFieldDescription *fieldDesc = field->description_;
   if (oneof) {
-    GPBMessageFieldDescription *fieldDesc = field->description_;
     GPBMaybeClearOneof(self, oneof, fieldDesc->hasIndex, fieldDesc->number);
   }
 #if defined(DEBUG) && DEBUG
@@ -862,14 +887,14 @@ void GPBSetInt32IvarWithFieldInternal(GPBMessage *self,
   if (self->messageStorage_ == NULL) return;
 #endif
   uint8_t *storage = (uint8_t *)self->messageStorage_;
-  int32_t *typePtr = (int32_t *)&storage[field->description_->offset];
+  int32_t *typePtr = (int32_t *)&storage[fieldDesc->offset];
   *typePtr = value;
   // proto2: any value counts as having been set; proto3, it
   // has to be a non zero value or be in a oneof.
   BOOL hasValue = ((syntax == GPBFileSyntaxProto2)
                    || (value != (int32_t)0)
                    || (field->containingOneof_ != NULL));
-  GPBSetHasIvarField(self, field, hasValue);
+  GPBSetHasIvar(self, fieldDesc->hasIndex, fieldDesc->number, hasValue);
   GPBBecomeVisibleToAutocreator(self);
 }
 
@@ -881,6 +906,9 @@ void GPBSetInt32IvarWithFieldInternal(GPBMessage *self,
 uint32_t GPBGetMessageUInt32Field(GPBMessage *self,
                                   GPBFieldDescriptor *field) {
 #if defined(DEBUG) && DEBUG
+  NSCAssert([[self descriptor] fieldWithNumber:field.number] == field,
+            @"FieldDescriptor %@ doesn't appear to be for %@ messages.",
+            field.name, [self class]);
   NSCAssert(DataTypesEquivalent(GPBGetFieldDataType(field),
                                 GPBDataTypeUInt32),
             @"Attempting to get value of uint32_t from field %@ "
@@ -902,15 +930,10 @@ void GPBSetMessageUInt32Field(GPBMessage *self,
                               GPBFieldDescriptor *field,
                               uint32_t value) {
   if (self == nil || field == nil) return;
-  GPBFileSyntax syntax = [self descriptor].file.syntax;
-  GPBSetUInt32IvarWithFieldInternal(self, field, value, syntax);
-}
-
-void GPBSetUInt32IvarWithFieldInternal(GPBMessage *self,
-                                       GPBFieldDescriptor *field,
-                                       uint32_t value,
-                                       GPBFileSyntax syntax) {
 #if defined(DEBUG) && DEBUG
+  NSCAssert([[self descriptor] fieldWithNumber:field.number] == field,
+            @"FieldDescriptor %@ doesn't appear to be for %@ messages.",
+            field.name, [self class]);
   NSCAssert(DataTypesEquivalent(GPBGetFieldDataType(field),
                                 GPBDataTypeUInt32),
             @"Attempting to set field %@ of %@ which is of type %@ with "
@@ -918,9 +941,17 @@ void GPBSetUInt32IvarWithFieldInternal(GPBMessage *self,
             [self class], field.name,
             TypeToString(GPBGetFieldDataType(field)));
 #endif
+  GPBFileSyntax syntax = [self descriptor].file.syntax;
+  GPBSetUInt32IvarWithFieldInternal(self, field, value, syntax);
+}
+
+void GPBSetUInt32IvarWithFieldInternal(GPBMessage *self,
+                                       GPBFieldDescriptor *field,
+                                       uint32_t value,
+                                       GPBFileSyntax syntax) {
   GPBOneofDescriptor *oneof = field->containingOneof_;
+  GPBMessageFieldDescription *fieldDesc = field->description_;
   if (oneof) {
-    GPBMessageFieldDescription *fieldDesc = field->description_;
     GPBMaybeClearOneof(self, oneof, fieldDesc->hasIndex, fieldDesc->number);
   }
 #if defined(DEBUG) && DEBUG
@@ -932,14 +963,14 @@ void GPBSetUInt32IvarWithFieldInternal(GPBMessage *self,
   if (self->messageStorage_ == NULL) return;
 #endif
   uint8_t *storage = (uint8_t *)self->messageStorage_;
-  uint32_t *typePtr = (uint32_t *)&storage[field->description_->offset];
+  uint32_t *typePtr = (uint32_t *)&storage[fieldDesc->offset];
   *typePtr = value;
   // proto2: any value counts as having been set; proto3, it
   // has to be a non zero value or be in a oneof.
   BOOL hasValue = ((syntax == GPBFileSyntaxProto2)
                    || (value != (uint32_t)0)
                    || (field->containingOneof_ != NULL));
-  GPBSetHasIvarField(self, field, hasValue);
+  GPBSetHasIvar(self, fieldDesc->hasIndex, fieldDesc->number, hasValue);
   GPBBecomeVisibleToAutocreator(self);
 }
 
@@ -951,6 +982,9 @@ void GPBSetUInt32IvarWithFieldInternal(GPBMessage *self,
 int64_t GPBGetMessageInt64Field(GPBMessage *self,
                                 GPBFieldDescriptor *field) {
 #if defined(DEBUG) && DEBUG
+  NSCAssert([[self descriptor] fieldWithNumber:field.number] == field,
+            @"FieldDescriptor %@ doesn't appear to be for %@ messages.",
+            field.name, [self class]);
   NSCAssert(DataTypesEquivalent(GPBGetFieldDataType(field),
                                 GPBDataTypeInt64),
             @"Attempting to get value of int64_t from field %@ "
@@ -972,15 +1006,10 @@ void GPBSetMessageInt64Field(GPBMessage *self,
                              GPBFieldDescriptor *field,
                              int64_t value) {
   if (self == nil || field == nil) return;
-  GPBFileSyntax syntax = [self descriptor].file.syntax;
-  GPBSetInt64IvarWithFieldInternal(self, field, value, syntax);
-}
-
-void GPBSetInt64IvarWithFieldInternal(GPBMessage *self,
-                                      GPBFieldDescriptor *field,
-                                      int64_t value,
-                                      GPBFileSyntax syntax) {
 #if defined(DEBUG) && DEBUG
+  NSCAssert([[self descriptor] fieldWithNumber:field.number] == field,
+            @"FieldDescriptor %@ doesn't appear to be for %@ messages.",
+            field.name, [self class]);
   NSCAssert(DataTypesEquivalent(GPBGetFieldDataType(field),
                                 GPBDataTypeInt64),
             @"Attempting to set field %@ of %@ which is of type %@ with "
@@ -988,9 +1017,17 @@ void GPBSetInt64IvarWithFieldInternal(GPBMessage *self,
             [self class], field.name,
             TypeToString(GPBGetFieldDataType(field)));
 #endif
+  GPBFileSyntax syntax = [self descriptor].file.syntax;
+  GPBSetInt64IvarWithFieldInternal(self, field, value, syntax);
+}
+
+void GPBSetInt64IvarWithFieldInternal(GPBMessage *self,
+                                      GPBFieldDescriptor *field,
+                                      int64_t value,
+                                      GPBFileSyntax syntax) {
   GPBOneofDescriptor *oneof = field->containingOneof_;
+  GPBMessageFieldDescription *fieldDesc = field->description_;
   if (oneof) {
-    GPBMessageFieldDescription *fieldDesc = field->description_;
     GPBMaybeClearOneof(self, oneof, fieldDesc->hasIndex, fieldDesc->number);
   }
 #if defined(DEBUG) && DEBUG
@@ -1002,14 +1039,14 @@ void GPBSetInt64IvarWithFieldInternal(GPBMessage *self,
   if (self->messageStorage_ == NULL) return;
 #endif
   uint8_t *storage = (uint8_t *)self->messageStorage_;
-  int64_t *typePtr = (int64_t *)&storage[field->description_->offset];
+  int64_t *typePtr = (int64_t *)&storage[fieldDesc->offset];
   *typePtr = value;
   // proto2: any value counts as having been set; proto3, it
   // has to be a non zero value or be in a oneof.
   BOOL hasValue = ((syntax == GPBFileSyntaxProto2)
                    || (value != (int64_t)0)
                    || (field->containingOneof_ != NULL));
-  GPBSetHasIvarField(self, field, hasValue);
+  GPBSetHasIvar(self, fieldDesc->hasIndex, fieldDesc->number, hasValue);
   GPBBecomeVisibleToAutocreator(self);
 }
 
@@ -1021,6 +1058,9 @@ void GPBSetInt64IvarWithFieldInternal(GPBMessage *self,
 uint64_t GPBGetMessageUInt64Field(GPBMessage *self,
                                   GPBFieldDescriptor *field) {
 #if defined(DEBUG) && DEBUG
+  NSCAssert([[self descriptor] fieldWithNumber:field.number] == field,
+            @"FieldDescriptor %@ doesn't appear to be for %@ messages.",
+            field.name, [self class]);
   NSCAssert(DataTypesEquivalent(GPBGetFieldDataType(field),
                                 GPBDataTypeUInt64),
             @"Attempting to get value of uint64_t from field %@ "
@@ -1042,15 +1082,10 @@ void GPBSetMessageUInt64Field(GPBMessage *self,
                               GPBFieldDescriptor *field,
                               uint64_t value) {
   if (self == nil || field == nil) return;
-  GPBFileSyntax syntax = [self descriptor].file.syntax;
-  GPBSetUInt64IvarWithFieldInternal(self, field, value, syntax);
-}
-
-void GPBSetUInt64IvarWithFieldInternal(GPBMessage *self,
-                                       GPBFieldDescriptor *field,
-                                       uint64_t value,
-                                       GPBFileSyntax syntax) {
 #if defined(DEBUG) && DEBUG
+  NSCAssert([[self descriptor] fieldWithNumber:field.number] == field,
+            @"FieldDescriptor %@ doesn't appear to be for %@ messages.",
+            field.name, [self class]);
   NSCAssert(DataTypesEquivalent(GPBGetFieldDataType(field),
                                 GPBDataTypeUInt64),
             @"Attempting to set field %@ of %@ which is of type %@ with "
@@ -1058,9 +1093,17 @@ void GPBSetUInt64IvarWithFieldInternal(GPBMessage *self,
             [self class], field.name,
             TypeToString(GPBGetFieldDataType(field)));
 #endif
+  GPBFileSyntax syntax = [self descriptor].file.syntax;
+  GPBSetUInt64IvarWithFieldInternal(self, field, value, syntax);
+}
+
+void GPBSetUInt64IvarWithFieldInternal(GPBMessage *self,
+                                       GPBFieldDescriptor *field,
+                                       uint64_t value,
+                                       GPBFileSyntax syntax) {
   GPBOneofDescriptor *oneof = field->containingOneof_;
+  GPBMessageFieldDescription *fieldDesc = field->description_;
   if (oneof) {
-    GPBMessageFieldDescription *fieldDesc = field->description_;
     GPBMaybeClearOneof(self, oneof, fieldDesc->hasIndex, fieldDesc->number);
   }
 #if defined(DEBUG) && DEBUG
@@ -1072,14 +1115,14 @@ void GPBSetUInt64IvarWithFieldInternal(GPBMessage *self,
   if (self->messageStorage_ == NULL) return;
 #endif
   uint8_t *storage = (uint8_t *)self->messageStorage_;
-  uint64_t *typePtr = (uint64_t *)&storage[field->description_->offset];
+  uint64_t *typePtr = (uint64_t *)&storage[fieldDesc->offset];
   *typePtr = value;
   // proto2: any value counts as having been set; proto3, it
   // has to be a non zero value or be in a oneof.
   BOOL hasValue = ((syntax == GPBFileSyntaxProto2)
                    || (value != (uint64_t)0)
                    || (field->containingOneof_ != NULL));
-  GPBSetHasIvarField(self, field, hasValue);
+  GPBSetHasIvar(self, fieldDesc->hasIndex, fieldDesc->number, hasValue);
   GPBBecomeVisibleToAutocreator(self);
 }
 
@@ -1091,6 +1134,9 @@ void GPBSetUInt64IvarWithFieldInternal(GPBMessage *self,
 float GPBGetMessageFloatField(GPBMessage *self,
                               GPBFieldDescriptor *field) {
 #if defined(DEBUG) && DEBUG
+  NSCAssert([[self descriptor] fieldWithNumber:field.number] == field,
+            @"FieldDescriptor %@ doesn't appear to be for %@ messages.",
+            field.name, [self class]);
   NSCAssert(DataTypesEquivalent(GPBGetFieldDataType(field),
                                 GPBDataTypeFloat),
             @"Attempting to get value of float from field %@ "
@@ -1112,15 +1158,10 @@ void GPBSetMessageFloatField(GPBMessage *self,
                              GPBFieldDescriptor *field,
                              float value) {
   if (self == nil || field == nil) return;
-  GPBFileSyntax syntax = [self descriptor].file.syntax;
-  GPBSetFloatIvarWithFieldInternal(self, field, value, syntax);
-}
-
-void GPBSetFloatIvarWithFieldInternal(GPBMessage *self,
-                                      GPBFieldDescriptor *field,
-                                      float value,
-                                      GPBFileSyntax syntax) {
 #if defined(DEBUG) && DEBUG
+  NSCAssert([[self descriptor] fieldWithNumber:field.number] == field,
+            @"FieldDescriptor %@ doesn't appear to be for %@ messages.",
+            field.name, [self class]);
   NSCAssert(DataTypesEquivalent(GPBGetFieldDataType(field),
                                 GPBDataTypeFloat),
             @"Attempting to set field %@ of %@ which is of type %@ with "
@@ -1128,9 +1169,17 @@ void GPBSetFloatIvarWithFieldInternal(GPBMessage *self,
             [self class], field.name,
             TypeToString(GPBGetFieldDataType(field)));
 #endif
+  GPBFileSyntax syntax = [self descriptor].file.syntax;
+  GPBSetFloatIvarWithFieldInternal(self, field, value, syntax);
+}
+
+void GPBSetFloatIvarWithFieldInternal(GPBMessage *self,
+                                      GPBFieldDescriptor *field,
+                                      float value,
+                                      GPBFileSyntax syntax) {
   GPBOneofDescriptor *oneof = field->containingOneof_;
+  GPBMessageFieldDescription *fieldDesc = field->description_;
   if (oneof) {
-    GPBMessageFieldDescription *fieldDesc = field->description_;
     GPBMaybeClearOneof(self, oneof, fieldDesc->hasIndex, fieldDesc->number);
   }
 #if defined(DEBUG) && DEBUG
@@ -1142,14 +1191,14 @@ void GPBSetFloatIvarWithFieldInternal(GPBMessage *self,
   if (self->messageStorage_ == NULL) return;
 #endif
   uint8_t *storage = (uint8_t *)self->messageStorage_;
-  float *typePtr = (float *)&storage[field->description_->offset];
+  float *typePtr = (float *)&storage[fieldDesc->offset];
   *typePtr = value;
   // proto2: any value counts as having been set; proto3, it
   // has to be a non zero value or be in a oneof.
   BOOL hasValue = ((syntax == GPBFileSyntaxProto2)
                    || (value != (float)0)
                    || (field->containingOneof_ != NULL));
-  GPBSetHasIvarField(self, field, hasValue);
+  GPBSetHasIvar(self, fieldDesc->hasIndex, fieldDesc->number, hasValue);
   GPBBecomeVisibleToAutocreator(self);
 }
 
@@ -1161,6 +1210,9 @@ void GPBSetFloatIvarWithFieldInternal(GPBMessage *self,
 double GPBGetMessageDoubleField(GPBMessage *self,
                                 GPBFieldDescriptor *field) {
 #if defined(DEBUG) && DEBUG
+  NSCAssert([[self descriptor] fieldWithNumber:field.number] == field,
+            @"FieldDescriptor %@ doesn't appear to be for %@ messages.",
+            field.name, [self class]);
   NSCAssert(DataTypesEquivalent(GPBGetFieldDataType(field),
                                 GPBDataTypeDouble),
             @"Attempting to get value of double from field %@ "
@@ -1182,15 +1234,10 @@ void GPBSetMessageDoubleField(GPBMessage *self,
                               GPBFieldDescriptor *field,
                               double value) {
   if (self == nil || field == nil) return;
-  GPBFileSyntax syntax = [self descriptor].file.syntax;
-  GPBSetDoubleIvarWithFieldInternal(self, field, value, syntax);
-}
-
-void GPBSetDoubleIvarWithFieldInternal(GPBMessage *self,
-                                       GPBFieldDescriptor *field,
-                                       double value,
-                                       GPBFileSyntax syntax) {
 #if defined(DEBUG) && DEBUG
+  NSCAssert([[self descriptor] fieldWithNumber:field.number] == field,
+            @"FieldDescriptor %@ doesn't appear to be for %@ messages.",
+            field.name, [self class]);
   NSCAssert(DataTypesEquivalent(GPBGetFieldDataType(field),
                                 GPBDataTypeDouble),
             @"Attempting to set field %@ of %@ which is of type %@ with "
@@ -1198,9 +1245,17 @@ void GPBSetDoubleIvarWithFieldInternal(GPBMessage *self,
             [self class], field.name,
             TypeToString(GPBGetFieldDataType(field)));
 #endif
+  GPBFileSyntax syntax = [self descriptor].file.syntax;
+  GPBSetDoubleIvarWithFieldInternal(self, field, value, syntax);
+}
+
+void GPBSetDoubleIvarWithFieldInternal(GPBMessage *self,
+                                       GPBFieldDescriptor *field,
+                                       double value,
+                                       GPBFileSyntax syntax) {
   GPBOneofDescriptor *oneof = field->containingOneof_;
+  GPBMessageFieldDescription *fieldDesc = field->description_;
   if (oneof) {
-    GPBMessageFieldDescription *fieldDesc = field->description_;
     GPBMaybeClearOneof(self, oneof, fieldDesc->hasIndex, fieldDesc->number);
   }
 #if defined(DEBUG) && DEBUG
@@ -1212,14 +1267,14 @@ void GPBSetDoubleIvarWithFieldInternal(GPBMessage *self,
   if (self->messageStorage_ == NULL) return;
 #endif
   uint8_t *storage = (uint8_t *)self->messageStorage_;
-  double *typePtr = (double *)&storage[field->description_->offset];
+  double *typePtr = (double *)&storage[fieldDesc->offset];
   *typePtr = value;
   // proto2: any value counts as having been set; proto3, it
   // has to be a non zero value or be in a oneof.
   BOOL hasValue = ((syntax == GPBFileSyntaxProto2)
                    || (value != (double)0)
                    || (field->containingOneof_ != NULL));
-  GPBSetHasIvarField(self, field, hasValue);
+  GPBSetHasIvar(self, fieldDesc->hasIndex, fieldDesc->number, hasValue);
   GPBBecomeVisibleToAutocreator(self);
 }
 

+ 0 - 5
objectivec/GPBUtilities_PackagePrivate.h

@@ -206,11 +206,6 @@ GPBGetHasIvarField(GPBMessage *self, GPBFieldDescriptor *field) {
   GPBMessageFieldDescription *fieldDesc = field->description_;
   return GPBGetHasIvar(self, fieldDesc->hasIndex, fieldDesc->number);
 }
-GPB_INLINE void GPBSetHasIvarField(GPBMessage *self, GPBFieldDescriptor *field,
-                                   BOOL value) {
-  GPBMessageFieldDescription *fieldDesc = field->description_;
-  GPBSetHasIvar(self, fieldDesc->hasIndex, fieldDesc->number, value);
-}
 
 void GPBMaybeClearOneof(GPBMessage *self, GPBOneofDescriptor *oneof,
                         int32_t oneofHasIndex, uint32_t fieldNumberNotToClear);

+ 16 - 15
python/google/protobuf/pyext/message.cc

@@ -1427,8 +1427,7 @@ bool CheckHasPresence(const FieldDescriptor* field_descriptor, bool in_oneof) {
     return false;
   }
 
-  if (field_descriptor->containing_oneof() == NULL &&
-      !field_descriptor->is_singular_with_presence()) {
+  if (!field_descriptor->has_presence()) {
     PyErr_Format(PyExc_ValueError,
                  "Can't test non-optional, non-submessage field \"%s.%s\" for "
                  "presence in proto3.",
@@ -2171,19 +2170,21 @@ static PyObject* RichCompare(CMessage* self, PyObject* other, int opid) {
   // If other is not a message, it cannot be equal.
   if (!PyObject_TypeCheck(other, CMessage_Type)) {
     equals = false;
-  }
-  const google::protobuf::Message* other_message =
-      reinterpret_cast<CMessage*>(other)->message;
-  // If messages don't have the same descriptors, they are not equal.
-  if (equals &&
-      self->message->GetDescriptor() != other_message->GetDescriptor()) {
-    equals = false;
-  }
-  // Check the message contents.
-  if (equals && !google::protobuf::util::MessageDifferencer::Equals(
-          *self->message,
-          *reinterpret_cast<CMessage*>(other)->message)) {
-    equals = false;
+  } else {
+    // Otherwise, we have a CMessage whose message we can inspect.
+    const google::protobuf::Message* other_message =
+        reinterpret_cast<CMessage*>(other)->message;
+    // If messages don't have the same descriptors, they are not equal.
+    if (equals &&
+        self->message->GetDescriptor() != other_message->GetDescriptor()) {
+      equals = false;
+    }
+    // Check the message contents.
+    if (equals &&
+        !google::protobuf::util::MessageDifferencer::Equals(
+            *self->message, *reinterpret_cast<CMessage*>(other)->message)) {
+      equals = false;
+    }
   }
 
   if (equals ^ (opid == Py_EQ)) {

+ 31 - 29
python/google/protobuf/text_format.py

@@ -120,20 +120,21 @@ class TextWriter(object):
     return self._writer.getvalue()
 
 
-def MessageToString(message,
-                    as_utf8=False,
-                    as_one_line=False,
-                    use_short_repeated_primitives=False,
-                    pointy_brackets=False,
-                    use_index_order=False,
-                    float_format=None,
-                    double_format=None,
-                    use_field_number=False,
-                    descriptor_pool=None,
-                    indent=0,
-                    message_formatter=None,
-                    print_unknown_fields=False,
-                    force_colon=False):
+def MessageToString(
+    message,
+    as_utf8=False,
+    as_one_line=False,
+    use_short_repeated_primitives=False,
+    pointy_brackets=False,
+    use_index_order=False,
+    float_format=None,
+    double_format=None,
+    use_field_number=False,
+    descriptor_pool=None,
+    indent=0,
+    message_formatter=None,
+    print_unknown_fields=False,
+    force_colon=False):
   # type: (...) -> str
   """Convert protobuf message to text format.
 
@@ -329,21 +330,22 @@ WIRETYPE_START_GROUP = 3
 class _Printer(object):
   """Text format printer for protocol message."""
 
-  def __init__(self,
-               out,
-               indent=0,
-               as_utf8=False,
-               as_one_line=False,
-               use_short_repeated_primitives=False,
-               pointy_brackets=False,
-               use_index_order=False,
-               float_format=None,
-               double_format=None,
-               use_field_number=False,
-               descriptor_pool=None,
-               message_formatter=None,
-               print_unknown_fields=False,
-               force_colon=False):
+  def __init__(
+      self,
+      out,
+      indent=0,
+      as_utf8=False,
+      as_one_line=False,
+      use_short_repeated_primitives=False,
+      pointy_brackets=False,
+      use_index_order=False,
+      float_format=None,
+      double_format=None,
+      use_field_number=False,
+      descriptor_pool=None,
+      message_formatter=None,
+      print_unknown_fields=False,
+      force_colon=False):
     """Initialize the Printer.
 
     Double values can be formatted compactly with 15 digits of precision

+ 7 - 2
ruby/Rakefile

@@ -70,13 +70,18 @@ else
 
   task 'gem:windows' do
     require 'rake_compiler_dock'
-    RakeCompilerDock.sh "bundle && IN_DOCKER=true rake cross native gem RUBY_CC_VERSION=2.6.0:2.5.0:2.4.0:2.3.0"
+    ['x86-mingw32', 'x64-mingw32', 'x86_64-linux', 'x86-linux'].each do |plat|
+      RakeCompilerDock.sh <<-"EOT", platform: plat
+        bundle && \
+        IN_DOCKER=true rake native:#{plat} pkg/#{spec.full_name}-#{plat}.gem RUBY_CC_VERSION=2.7.0:2.6.0:2.5.0:2.4.0:2.3.0
+      EOT
+    end
   end
 
   if RUBY_PLATFORM =~ /darwin/
     task 'gem:native' do
       system "rake genproto"
-      system "rake cross native gem RUBY_CC_VERSION=2.6.0:2.5.1:2.4.0:2.3.0"
+      system "rake cross native gem RUBY_CC_VERSION=2.7.0:2.6.0:2.5.1:2.4.0:2.3.0"
     end
   else
     task 'gem:native' => [:genproto, 'gem:windows']

+ 2 - 2
ruby/google-protobuf.gemspec

@@ -17,13 +17,13 @@ Gem::Specification.new do |s|
   else
     s.files     += Dir.glob('ext/**/*')
     s.extensions= ["ext/google/protobuf_c/extconf.rb"]
-    s.add_development_dependency "rake-compiler-dock", "~> 0.6.0"
+    s.add_development_dependency "rake-compiler-dock", ">= 1.0.1", "< 2.0"
   end
   s.test_files  = ["tests/basic.rb",
                   "tests/stress.rb",
                   "tests/generated_code_test.rb"]
   s.required_ruby_version = '>= 2.3'
-  s.add_development_dependency "rake-compiler", "~> 0.9.5"
+  s.add_development_dependency "rake-compiler", "~> 1.1.0"
   s.add_development_dependency "test-unit", '~> 3.0', '>= 3.0.9'
   s.add_development_dependency "rubygems-tasks", "~> 0.2.4"
 end

+ 1 - 1
ruby/tests/common_tests.rb

@@ -1739,7 +1739,7 @@ module CommonTests
     m.freeze
 
     frozen_error = assert_raise(FrozenErrorType) { m.optional_int32 = 20 }
-    assert_equal "can't modify frozen #{proto_module}::TestMessage", frozen_error.message
+    assert_match "can't modify frozen #{proto_module}::TestMessage", frozen_error.message
     assert_equal 10, m.optional_int32
     assert_equal true, m.frozen?
 

+ 1 - 0
ruby/tests/repeated_field_test.rb

@@ -20,6 +20,7 @@ class RepeatedFieldTest < Test::Unit::TestCase
       :iter_for_each_with_index, :dimensions, :copy_data, :copy_data_simple,
       :nitems, :iter_for_reverse_each, :indexes, :append, :prepend]
     arr_methods -= [:union, :difference, :filter!]
+    arr_methods -= [:intersection, :deconstruct] # ruby 2.7 methods we can ignore
     arr_methods.each do |method_name|
       assert m.repeated_string.respond_to?(method_name) == true, "does not respond to #{method_name}"
     end

+ 2 - 0
src/google/protobuf/arena_impl.h

@@ -135,6 +135,8 @@ class PROTOBUF_EXPORT ArenaImpl {
   void AddCleanup(void* elem, void (*cleanup)(void*));
 
  private:
+  friend class ArenaBenchmark;
+
   void* AllocateAlignedFallback(size_t n);
   void* AllocateAlignedAndAddCleanupFallback(size_t n, void (*cleanup)(void*));
   void AddCleanupFallback(void* elem, void (*cleanup)(void*));

+ 6 - 2
src/google/protobuf/compiler/command_line_interface.cc

@@ -1105,14 +1105,18 @@ PopulateSingleSimpleDescriptorDatabase(const std::string& descriptor_set_name) {
 bool CommandLineInterface::AllowProto3Optional(
     const FileDescriptor& file) const {
   if (allow_proto3_optional_) return true;
+
   // Whitelist all ads protos. Ads is an early adopter of this feature.
   if (file.name().find("google/ads/googleads") != std::string::npos) {
     return true;
   }
-  if (file.name() == "google/protobuf/unittest_proto3_optional.proto" ||
-      file.name() == "google/protobuf/internal/test_proto3_optional.proto") {
+
+  // Whitelist all protos testing proto3 optional.
+  if (file.name().find("test_proto3_optional") != std::string::npos) {
     return true;
   }
+
+
   return false;
 }
 

+ 4 - 5
src/google/protobuf/compiler/java/java_enum_field_lite.cc

@@ -103,9 +103,6 @@ void SetEnumVariables(const FieldDescriptor* descriptor, int messageBitIndex,
         ".getNumber()";
   }
 
-  // For repeated builders, the underlying list tracks mutability state.
-  (*variables)["is_mutable"] = (*variables)["name"] + "_.isModifiable()";
-
   (*variables)["get_has_field_bit_from_local"] =
       GenerateGetBitFromLocal(builderBitIndex);
   (*variables)["set_has_field_bit_to_local"] =
@@ -572,9 +569,11 @@ void RepeatedImmutableEnumFieldLiteGenerator::GenerateMembers(
   printer->Print(
       variables_,
       "private void ensure$capitalized_name$IsMutable() {\n"
-      "  if (!$is_mutable$) {\n"
+      // Use a temporary to avoid a redundant iget-object.
+      "  com.google.protobuf.Internal.IntList tmp = $name$_;\n"
+      "  if (!tmp.isModifiable()) {\n"
       "    $name$_ =\n"
-      "        com.google.protobuf.GeneratedMessageLite.mutableCopy($name$_);\n"
+      "        com.google.protobuf.GeneratedMessageLite.mutableCopy(tmp);\n"
       "  }\n"
       "}\n");
   WriteFieldAccessorDocComment(printer, descriptor_, LIST_INDEXED_SETTER);

+ 4 - 5
src/google/protobuf/compiler/java/java_message_field_lite.cc

@@ -89,9 +89,6 @@ void SetMessageVariables(const FieldDescriptor* descriptor, int messageBitIndex,
         (*variables)["name"] + "_ != null";
   }
 
-  // For repeated builders, the underlying list tracks mutability state.
-  (*variables)["is_mutable"] = (*variables)["name"] + "_.isModifiable()";
-
   (*variables)["get_has_field_bit_from_local"] =
       GenerateGetBitFromLocal(builderBitIndex);
   (*variables)["set_has_field_bit_to_local"] =
@@ -532,9 +529,11 @@ void RepeatedImmutableMessageFieldLiteGenerator::GenerateMembers(
   printer->Print(
       variables_,
       "private void ensure$capitalized_name$IsMutable() {\n"
-      "  if (!$is_mutable$) {\n"
+      // Use a temporary to avoid a redundant iget-object.
+      "  com.google.protobuf.Internal.ProtobufList<$type$> tmp = $name$_;\n"
+      "  if (!tmp.isModifiable()) {\n"
       "    $name$_ =\n"
-      "        com.google.protobuf.GeneratedMessageLite.mutableCopy($name$_);\n"
+      "        com.google.protobuf.GeneratedMessageLite.mutableCopy(tmp);\n"
       "   }\n"
       "}\n"
       "\n");

+ 4 - 5
src/google/protobuf/compiler/java/java_primitive_field_lite.cc

@@ -164,9 +164,6 @@ void SetPrimitiveVariables(const FieldDescriptor* descriptor,
     }
   }
 
-  // For repeated builders, the underlying list tracks mutability state.
-  (*variables)["is_mutable"] = (*variables)["name"] + "_.isModifiable()";
-
   (*variables)["get_has_field_bit_from_local"] =
       GenerateGetBitFromLocal(builderBitIndex);
   (*variables)["set_has_field_bit_to_local"] =
@@ -511,9 +508,11 @@ void RepeatedImmutablePrimitiveFieldLiteGenerator::GenerateMembers(
   printer->Print(
       variables_,
       "private void ensure$capitalized_name$IsMutable() {\n"
-      "  if (!$is_mutable$) {\n"
+      // Use a temporary to avoid a redundant iget-object.
+      "  $field_list_type$ tmp = $name$_;\n"
+      "  if (!tmp.isModifiable()) {\n"
       "    $name$_ =\n"
-      "        com.google.protobuf.GeneratedMessageLite.mutableCopy($name$_);\n"
+      "        com.google.protobuf.GeneratedMessageLite.mutableCopy(tmp);\n"
       "   }\n"
       "}\n");
 

+ 5 - 5
src/google/protobuf/compiler/java/java_string_field_lite.cc

@@ -104,9 +104,6 @@ void SetPrimitiveVariables(const FieldDescriptor* descriptor,
         "!" + (*variables)["name"] + "_.isEmpty()";
   }
 
-  // For repeated builders, the underlying list tracks mutability state.
-  (*variables)["is_mutable"] = (*variables)["name"] + "_.isModifiable()";
-
   (*variables)["get_has_field_bit_from_local"] =
       GenerateGetBitFromLocal(builderBitIndex);
   (*variables)["set_has_field_bit_to_local"] =
@@ -567,9 +564,12 @@ void RepeatedImmutableStringFieldLiteGenerator::GenerateMembers(
   printer->Print(
       variables_,
       "private void ensure$capitalized_name$IsMutable() {\n"
-      "  if (!$is_mutable$) {\n"
+      // Use a temporary to avoid a redundant iget-object.
+      "  com.google.protobuf.Internal.ProtobufList<java.lang.String> tmp =\n"
+      "      $name$_;"
+      "  if (!tmp.isModifiable()) {\n"
       "    $name$_ =\n"
-      "        com.google.protobuf.GeneratedMessageLite.mutableCopy($name$_);\n"
+      "        com.google.protobuf.GeneratedMessageLite.mutableCopy(tmp);\n"
       "   }\n"
       "}\n");
 

+ 9 - 9
src/google/protobuf/descriptor.h

@@ -693,13 +693,14 @@ class PROTOBUF_EXPORT FieldDescriptor {
   // .proto file. Excludes singular proto3 fields that do not have a label.
   bool has_optional_keyword() const;
 
-  // Returns true if this is a non-oneof field that tracks presence.
-  // This includes all "required" and "optional" fields in the .proto file,
-  // but excludes oneof fields and singular proto3 fields without "optional".
+  // Returns true if this field tracks presence, ie. does the message
+  // distinguish between "unset" and "present with default value."
+  // This includes required, optional, and oneof fields. It excludes maps,
+  // repeated fields, and singular proto3 fields without "optional".
   //
-  // In implementations that use hasbits, this method will probably indicate
-  // whether this field uses a hasbit.
-  bool is_singular_with_presence() const;
+  // For fields where has_presence() == true, the return value of
+  // Reflection::HasField() is semantically meaningful.
+  bool has_presence() const;
 
   // Index of this field within the message's field array, or the file or
   // extension scope's extensions array.
@@ -2182,10 +2183,9 @@ inline const OneofDescriptor* FieldDescriptor::real_containing_oneof() const {
              : nullptr;
 }
 
-inline bool FieldDescriptor::is_singular_with_presence() const {
+inline bool FieldDescriptor::has_presence() const {
   if (is_repeated()) return false;
-  if (real_containing_oneof()) return false;
-  return cpp_type() == CPPTYPE_MESSAGE || proto3_optional_ ||
+  return cpp_type() == CPPTYPE_MESSAGE || containing_oneof() ||
          file()->syntax() == FileDescriptor::SYNTAX_PROTO2;
 }
 

+ 3 - 11
src/google/protobuf/proto3_arena_unittest.cc

@@ -218,7 +218,7 @@ TEST(Proto3OptionalTest, OptionalFieldDescriptor) {
   for (int i = 0; i < d->field_count(); i++) {
     const FieldDescriptor* f = d->field(i);
     EXPECT_TRUE(f->has_optional_keyword()) << f->full_name();
-    EXPECT_TRUE(f->is_singular_with_presence()) << f->full_name();
+    EXPECT_TRUE(f->has_presence()) << f->full_name();
     EXPECT_TRUE(f->containing_oneof()) << f->full_name();
   }
 }
@@ -470,16 +470,8 @@ TEST(Proto3OptionalTest, ReflectiveSwapRoundTrip) {
 TEST(Proto3OptionalTest, PlainFields) {
   const Descriptor* d = TestAllTypes::descriptor();
 
-  for (int i = 0; i < d->field_count(); i++) {
-    const FieldDescriptor* f = d->field(i);
-    EXPECT_FALSE(f->has_optional_keyword()) << f->full_name();
-    if (f->is_optional() && f->cpp_type() != FieldDescriptor::CPPTYPE_MESSAGE) {
-      EXPECT_FALSE(f->is_singular_with_presence()) << f->full_name();
-    }
-  }
-
-  EXPECT_FALSE(
-      d->FindFieldByName("oneof_nested_message")->is_singular_with_presence());
+  EXPECT_FALSE(d->FindFieldByName("optional_int32")->has_presence());
+  EXPECT_TRUE(d->FindFieldByName("oneof_nested_message")->has_presence());
 }
 
 }  // namespace

+ 4 - 1
src/google/protobuf/util/internal/protostream_objectsource.h

@@ -160,6 +160,9 @@ class PROTOBUF_EXPORT ProtoStreamObjectSource : public ObjectSource {
       const google::protobuf::Field& field) const;
 
 
+  // Returns the input stream.
+  io::CodedInputStream* stream() const { return stream_; }
+
  private:
   ProtoStreamObjectSource(io::CodedInputStream* stream,
                           const TypeInfo* typeinfo,
@@ -281,7 +284,7 @@ class PROTOBUF_EXPORT ProtoStreamObjectSource : public ObjectSource {
                                          StringPiece field_name) const;
 
   // Input stream to read from. Ownership rests with the caller.
-  io::CodedInputStream* stream_;
+  mutable io::CodedInputStream* stream_;
 
   // Type information for all the types used in the descriptor. Used to find
   // google::protobuf::Type of nested messages/enums.

+ 4 - 0
tests.sh

@@ -436,6 +436,10 @@ build_ruby26() {
   internal_build_cpp  # For conformance tests.
   cd ruby && bash travis-test.sh ruby-2.6.0 && cd ..
 }
+build_ruby27() {
+  internal_build_cpp  # For conformance tests.
+  cd ruby && bash travis-test.sh ruby-2.7.0 && cd ..
+}
 
 build_javascript() {
   internal_build_cpp

Some files were not shown because too many files changed in this diff