Merge pull request #9026 from haberman/merge-release

Merge 3.18.x release branch to master
diff --git a/WORKSPACE b/WORKSPACE
index 94aa8d8..37d70ea 100644
--- a/WORKSPACE
+++ b/WORKSPACE
@@ -40,6 +40,7 @@
     artifacts = [
         "com.google.code.gson:gson:2.8.6",
         "com.google.errorprone:error_prone_annotations:2.3.2",
+        "com.google.j2objc:j2obj_annotations:1.3",
         "com.google.guava:guava:30.1.1-jre",
         "com.google.truth:truth:1.1.2",
         "junit:junit:4.12",
@@ -74,6 +75,11 @@
 )
 
 bind(
+    name = "j2objc_annotations",
+    actual = "@maven//:com_google_j2objc_j2objc_annotations",
+)
+
+bind(
     name = "junit",
     actual = "@maven//:junit_junit",
 )
diff --git a/cmake/install.cmake b/cmake/install.cmake
index ef5bb13..4e1c5de 100644
--- a/cmake/install.cmake
+++ b/cmake/install.cmake
@@ -30,9 +30,8 @@
 
 if (protobuf_BUILD_PROTOC_BINARIES)
   install(TARGETS protoc EXPORT protobuf-targets
-    RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
-    BUNDLE DESTINATION ${CMAKE_INSTALL_BINDIR}
-    COMPONENT protoc)
+    RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} COMPONENT protoc
+    BUNDLE DESTINATION ${CMAKE_INSTALL_BINDIR} COMPONENT protoc)
   if (UNIX AND NOT APPLE)
     set_property(TARGET protoc
       PROPERTY INSTALL_RPATH "$ORIGIN/../${CMAKE_INSTALL_LIBDIR}")
diff --git a/docs/options.md b/docs/options.md
index b789744..159951a 100644
--- a/docs/options.md
+++ b/docs/options.md
@@ -205,7 +205,7 @@
    * Website: https://github.com/envoyproxy/protoc-gen-validate
    * Extensions: 1071
 
-1. protokt
+1. Protokt
    * Website: https://github.com/open-toast/protokt
    * Extensions: 1072
 
@@ -288,3 +288,7 @@
 1. Container Object Storage Interface (COSI)
    * Website: https://github.com/kubernetes-sigs/container-object-storage-interface-spec
    * Extension: 1115-1124
+
+1. Protoc-gen-jsonschema
+   * Website: https://github.com/chrusty/protoc-gen-jsonschema
+   * Extension: 1125-1129
diff --git a/docs/third_party.md b/docs/third_party.md
index 4075327..ca2ac63 100644
--- a/docs/third_party.md
+++ b/docs/third_party.md
@@ -70,6 +70,7 @@
 * Kotlin: https://github.com/marcoferrer/kroto-plus
 * Kotlin: https://github.com/Kotlin/kotlinx.serialization
 * Kotlin: https://github.com/ButterCam/sisyphus
+* Kotlin: https://github.com/open-toast/protokt
 * Lua: http://code.google.com/p/protoc-gen-lua/
 * Lua: http://github.com/indygreg/lua-protobuf
 * Lua: https://github.com/Neopallium/lua-pb
diff --git a/java/README.md b/java/README.md
index 6864375..849f9b0 100644
--- a/java/README.md
+++ b/java/README.md
@@ -23,7 +23,7 @@
 <dependency>
   <groupId>com.google.protobuf</groupId>
   <artifactId>protobuf-java</artifactId>
-  <version>3.17.3</version>
+  <version>3.18.0</version>
 </dependency>
 ```
 
@@ -37,7 +37,7 @@
 <dependency>
   <groupId>com.google.protobuf</groupId>
   <artifactId>protobuf-java-util</artifactId>
-  <version>3.17.3</version>
+  <version>3.18.0</version>
 </dependency>
 ```
 
@@ -45,7 +45,7 @@
 
 If you are using Gradle, add the following to your `build.gradle` file's dependencies:
 ```
-    implementation 'com.google.protobuf:protobuf-java:3.17.3'
+    implementation 'com.google.protobuf:protobuf-java:3.18.0'
 ```
 Again, be sure to check that the version number matches (or is newer than) the version number of protoc that you are using.
 
diff --git a/java/util/BUILD b/java/util/BUILD
index bd773ee..02e5549 100644
--- a/java/util/BUILD
+++ b/java/util/BUILD
@@ -12,6 +12,7 @@
     visibility = ["//visibility:public"],
     deps = [
         "//external:error_prone_annotations",
+        "//external:j2objc_annotations",
         "//external:gson",
         "//external:guava",
         "//java/core",
diff --git a/java/util/pom.xml b/java/util/pom.xml
index 7266f8f..8a8e159 100644
--- a/java/util/pom.xml
+++ b/java/util/pom.xml
@@ -28,6 +28,11 @@
       <version>2.5.1</version>
     </dependency>
     <dependency>
+      <groupId>com.google.j2objc</groupId>
+      <artifactId>j2objc-annotations</artifactId>
+      <version>1.3</version>
+    </dependency>
+    <dependency>
       <groupId>com.google.guava</groupId>
       <artifactId>guava-testlib</artifactId>
       <scope>test</scope>
diff --git a/kokoro/linux/dockerfile/test/java_stretch/Dockerfile b/kokoro/linux/dockerfile/test/java_stretch/Dockerfile
index 3e72046..b9f562a 100644
--- a/kokoro/linux/dockerfile/test/java_stretch/Dockerfile
+++ b/kokoro/linux/dockerfile/test/java_stretch/Dockerfile
@@ -24,7 +24,7 @@
   maven \
   openjdk-8-jdk \
   # Python dependencies
-  python-setuptools \
-  python-pip \
+  python3-setuptools \
+  python3-pip \
   virtualenv \
   && apt-get clean
diff --git a/objectivec/DevTools/check_version_stamps.sh b/objectivec/DevTools/check_version_stamps.sh
index 1acbe2a..a3524cb 100755
--- a/objectivec/DevTools/check_version_stamps.sh
+++ b/objectivec/DevTools/check_version_stamps.sh
@@ -25,7 +25,7 @@
   # Collect version from generator sources.
   local GeneratorVersion=$( \
       cat "${GeneratorSrc}" \
-          | sed -n -e "s:const int32 ${ConstantName} = \([0-9]*\);:\1:p"
+          | sed -n -e "s:const int32_t ${ConstantName} = \([0-9]*\);:\1:p"
   )
   if [[ -z "${GeneratorVersion}" ]] ; then
       die "Failed to find ${ConstantName} in the generator source (${GeneratorSrc})."
diff --git a/python/google/protobuf/descriptor.py b/python/google/protobuf/descriptor.py
index 0f7bd17..61c242f 100644
--- a/python/google/protobuf/descriptor.py
+++ b/python/google/protobuf/descriptor.py
@@ -951,7 +951,7 @@
     public_dependencies (list[FileDescriptor]): A subset of
       :attr:`dependencies`, which were declared as "public".
     message_types_by_name (dict(str, Descriptor)): Mapping from message names
-      to their :class:`Desctiptor`.
+      to their :class:`Descriptor`.
     enum_types_by_name (dict(str, EnumDescriptor)): Mapping from enum names to
       their :class:`EnumDescriptor`.
     extensions_by_name (dict(str, FieldDescriptor)): Mapping from extension
diff --git a/python/setup.py b/python/setup.py
index 33d7420..e0760f0 100755
--- a/python/setup.py
+++ b/python/setup.py
@@ -308,4 +308,5 @@
       },
       install_requires=install_requires,
       ext_modules=ext_module_list,
+      python_requires='>=3.5',
   )
diff --git a/src/google/protobuf/compiler/cpp/cpp_enum.cc b/src/google/protobuf/compiler/cpp/cpp_enum.cc
index c9b9c20..6ae5cf4 100644
--- a/src/google/protobuf/compiler/cpp/cpp_enum.cc
+++ b/src/google/protobuf/compiler/cpp/cpp_enum.cc
@@ -409,10 +409,10 @@
     std::string parent = ClassName(descriptor_->containing_type(), false);
     // Before C++17, we must define the static constants which were
     // declared in the header, to give the linker a place to put them.
-    // But pre-2015 MSVC++ insists that we not.
+    // But MSVC++ pre-2015 and post-2017 (version 15.5+) insists that we not.
     format(
         "#if (__cplusplus < 201703) && "
-        "(!defined(_MSC_VER) || _MSC_VER >= 1900)\n");
+        "(!defined(_MSC_VER) || (_MSC_VER >= 1900 && _MSC_VER < 1912))\n");
 
     for (int i = 0; i < descriptor_->value_count(); i++) {
       format("constexpr $classname$ $1$::$2$;\n", parent,
@@ -428,7 +428,7 @@
 
     format(
         "#endif  // (__cplusplus < 201703) && "
-        "(!defined(_MSC_VER) || _MSC_VER >= 1900)\n");
+        "(!defined(_MSC_VER) || (_MSC_VER >= 1900 && _MSC_VER < 1912))\n");
   }
 }
 
diff --git a/src/google/protobuf/compiler/cpp/cpp_extension.cc b/src/google/protobuf/compiler/cpp/cpp_extension.cc
index 6475285..8604da5 100644
--- a/src/google/protobuf/compiler/cpp/cpp_extension.cc
+++ b/src/google/protobuf/compiler/cpp/cpp_extension.cc
@@ -158,7 +158,7 @@
   // Likewise, class members need to declare the field constant variable.
   if (IsScoped()) {
     format(
-        "#if !defined(_MSC_VER) || _MSC_VER >= 1900\n"
+        "#if !defined(_MSC_VER) || (_MSC_VER >= 1900 && _MSC_VER < 1912)\n"
         "const int $scope$$constant_name$;\n"
         "#endif\n");
   }
diff --git a/src/google/protobuf/compiler/objectivec/objectivec_file.cc b/src/google/protobuf/compiler/objectivec/objectivec_file.cc
index be2be2c..d9f43a5 100644
--- a/src/google/protobuf/compiler/objectivec/objectivec_file.cc
+++ b/src/google/protobuf/compiler/objectivec/objectivec_file.cc
@@ -52,7 +52,7 @@
 namespace {
 
 // This is also found in GPBBootstrap.h, and needs to be kept in sync.
-const int32 GOOGLE_PROTOBUF_OBJC_VERSION = 30004;
+const int32_t GOOGLE_PROTOBUF_OBJC_VERSION = 30004;
 
 const char* kHeaderExtension = ".pbobjc.h";
 
diff --git a/src/google/protobuf/compiler/objectivec/objectivec_generator.cc b/src/google/protobuf/compiler/objectivec/objectivec_generator.cc
index d5a2b6b..a03b860 100644
--- a/src/google/protobuf/compiler/objectivec/objectivec_generator.cc
+++ b/src/google/protobuf/compiler/objectivec/objectivec_generator.cc
@@ -44,6 +44,28 @@
 namespace compiler {
 namespace objectivec {
 
+namespace {
+
+// Convert a string with "yes"/"no" (case insensitive) to a boolean, returning
+// true/false for if the input string was a valid value. If the input string is
+// invalid, `result` is unchanged.
+bool StringToBool(const std::string& value, bool* result) {
+  std::string upper_value(value);
+  UpperString(&upper_value);
+  if (upper_value == "NO") {
+    *result = false;
+    return true;
+  }
+  if (upper_value == "YES") {
+    *result = true;
+    return true;
+  }
+
+  return false;
+}
+
+}  // namespace
+
 ObjectiveCGenerator::ObjectiveCGenerator() {}
 
 ObjectiveCGenerator::~ObjectiveCGenerator() {}
@@ -101,6 +123,31 @@
         generation_options.expected_prefixes_suppressions.push_back(
             std::string(split_piece));
       }
+    } else if (options[i].first == "prefixes_must_be_registered") {
+      // If objc prefix file option value must be registered to be used. This
+      // option has no meaning if an "expected_prefixes_path" isn't set. The
+      // available options are:
+      //   "no": They don't have to be registered.
+      //   "yes": They must be registered and an error will be raised if a files
+      //     tried to use a prefix that isn't registered.
+      // Default is "no".
+      if (!StringToBool(options[i].second,
+                        &generation_options.prefixes_must_be_registered)) {
+        *error = "error: Unknown value for prefixes_must_be_registered: " + options[i].second;
+        return false;
+      }
+    } else if (options[i].first == "require_prefixes") {
+      // If every file must have an objc prefix file option to be used. The
+      // available options are:
+      //   "no": Files can be generated without the prefix option.
+      //   "yes": Files must have the objc prefix option, and an error will be
+      //     raised if a files doesn't have one.
+      // Default is "no".
+      if (!StringToBool(options[i].second,
+                        &generation_options.require_prefixes)) {
+        *error = "error: Unknown value for require_prefixes: " + options[i].second;
+        return false;
+      }
     } else if (options[i].first == "generate_for_named_framework") {
       // The name of the framework that protos are being generated for. This
       // will cause the #import statements to be framework based using this
@@ -146,12 +193,9 @@
       // is just what to do if that isn't set. The available options are:
       //   "no": Not prefixed (the existing mode).
       //   "yes": Make a prefix out of the proto package.
-      std::string upper_value(options[i].second);
-      UpperString(&upper_value);
-      if (upper_value == "NO") {
-        SetUseProtoPackageAsDefaultPrefix(false);
-      } else if (upper_value == "YES") {
-        SetUseProtoPackageAsDefaultPrefix(true);
+      bool value = false;
+      if (StringToBool(options[i].second, &value)) {
+        SetUseProtoPackageAsDefaultPrefix(value);
       } else {
         *error = "error: Unknown use_package_as_prefix: " + options[i].second;
         return false;
diff --git a/src/google/protobuf/compiler/objectivec/objectivec_helpers.cc b/src/google/protobuf/compiler/objectivec/objectivec_helpers.cc
index 78491d2..a90adba 100644
--- a/src/google/protobuf/compiler/objectivec/objectivec_helpers.cc
+++ b/src/google/protobuf/compiler/objectivec/objectivec_helpers.cc
@@ -178,6 +178,8 @@
     expected_prefixes_suppressions =
         Split(suppressions, ";", true);
   }
+  prefixes_must_be_registered = false;
+  require_prefixes = false;
 }
 
 namespace {
@@ -992,7 +994,7 @@
 
         // Must convert to a standard byte order for packing length into
         // a cstring.
-        uint32 length = ghtonl(default_string.length());
+        uint32_t length = ghtonl(default_string.length());
         std::string bytes((const char*)&length, sizeof(length));
         bytes.append(default_string);
         return "(NSData*)\"" + EscapeTrigraphs(CEscape(bytes)) + "\"";
@@ -1227,6 +1229,7 @@
 bool ValidateObjCClassPrefix(
     const FileDescriptor* file, const std::string& expected_prefixes_path,
     const std::map<std::string, std::string>& expected_package_prefixes,
+    bool prefixes_must_be_registered, bool require_prefixes,
     std::string* out_error) {
   // Reminder: An explicit prefix option of "" is valid in case the default
   // prefixing is set to use the proto package and a file needs to be generated
@@ -1265,6 +1268,12 @@
 
   // If there was no prefix option, we're done at this point.
   if (!has_prefix) {
+    if (require_prefixes) {
+      *out_error =
+        "error: '" + file->name() + "' does not have a required 'option" +
+        " objc_class_prefix'.";
+      return false;
+    }
     return true;
   }
 
@@ -1344,9 +1353,18 @@
     std::cerr.flush();
   }
 
-  // Check: Warning - If the given package/prefix pair wasn't expected, issue a
-  // warning suggesting it gets added to the file.
+  // Check: Error/Warning - If the given package/prefix pair wasn't expected,
+  // issue a error/warning to added to the file.
   if (have_expected_prefix_file) {
+    if (prefixes_must_be_registered) {
+      *out_error =
+        "error: '" + file->name() + "' has 'option objc_class_prefix = \"" +
+        prefix + "\";', but it is not registered; add it to the expected" +
+        " prefixes file (" + expected_prefixes_path + ") for the package" +
+        "'" + package + "'.";
+      return false;
+    }
+
     std::cerr
          << "protoc:0: warning: Found unexpected 'option objc_class_prefix = \""
          << prefix << "\";' in '" << file->name() << "';"
@@ -1391,6 +1409,8 @@
         ValidateObjCClassPrefix(files[i],
                                 generation_options.expected_prefixes_path,
                                 expected_package_prefixes,
+                                generation_options.prefixes_must_be_registered,
+                                generation_options.require_prefixes,
                                 out_error);
     if (!is_valid) {
       return false;
@@ -1403,7 +1423,7 @@
 
 TextFormatDecodeData::~TextFormatDecodeData() { }
 
-void TextFormatDecodeData::AddString(int32 key,
+void TextFormatDecodeData::AddString(int32_t key,
                                      const std::string& input_for_decode,
                                      const std::string& desired_output) {
   for (std::vector<DataEntry>::const_iterator i = entries_.begin();
@@ -1459,12 +1479,12 @@
   }
 
  private:
-  static constexpr uint8 kAddUnderscore = 0x80;
+  static constexpr uint8_t kAddUnderscore = 0x80;
 
-  static constexpr uint8 kOpAsIs = 0x00;
-  static constexpr uint8 kOpFirstUpper = 0x40;
-  static constexpr uint8 kOpFirstLower = 0x20;
-  static constexpr uint8 kOpAllUpper = 0x60;
+  static constexpr uint8_t kOpAsIs = 0x00;
+  static constexpr uint8_t kOpFirstUpper = 0x40;
+  static constexpr uint8_t kOpFirstLower = 0x20;
+  static constexpr uint8_t kOpAllUpper = 0x60;
 
   static constexpr int kMaxSegmentLen = 0x1f;
 
@@ -1474,7 +1494,7 @@
   }
 
   void Push() {
-    uint8 op = (op_ | segment_len_);
+    uint8_t op = (op_ | segment_len_);
     if (need_underscore_) op |= kAddUnderscore;
     if (op != 0) {
       decode_data_ += (char)op;
@@ -1506,7 +1526,7 @@
 
   bool need_underscore_;
   bool is_all_upper_;
-  uint8 op_;
+  uint8_t op_;
   int segment_len_;
 
   std::string decode_data_;
diff --git a/src/google/protobuf/compiler/objectivec/objectivec_helpers.h b/src/google/protobuf/compiler/objectivec/objectivec_helpers.h
index 02615e0..aa2211e 100644
--- a/src/google/protobuf/compiler/objectivec/objectivec_helpers.h
+++ b/src/google/protobuf/compiler/objectivec/objectivec_helpers.h
@@ -67,6 +67,8 @@
   std::string generate_for_named_framework;
   std::string named_framework_to_proto_path_mappings_path;
   std::string runtime_import_prefix;
+  bool prefixes_must_be_registered;
+  bool require_prefixes;
 };
 
 // Escape C++ trigraphs by escaping question marks to "\?".
diff --git a/src/google/protobuf/compiler/plugin.pb.cc b/src/google/protobuf/compiler/plugin.pb.cc
index c4849ad..af2d1de 100644
--- a/src/google/protobuf/compiler/plugin.pb.cc
+++ b/src/google/protobuf/compiler/plugin.pb.cc
@@ -207,13 +207,13 @@
   }
 }
 
-#if (__cplusplus < 201703) && (!defined(_MSC_VER) || _MSC_VER >= 1900)
+#if (__cplusplus < 201703) && (!defined(_MSC_VER) || (_MSC_VER >= 1900 && _MSC_VER < 1912))
 constexpr CodeGeneratorResponse_Feature CodeGeneratorResponse::FEATURE_NONE;
 constexpr CodeGeneratorResponse_Feature CodeGeneratorResponse::FEATURE_PROTO3_OPTIONAL;
 constexpr CodeGeneratorResponse_Feature CodeGeneratorResponse::Feature_MIN;
 constexpr CodeGeneratorResponse_Feature CodeGeneratorResponse::Feature_MAX;
 constexpr int CodeGeneratorResponse::Feature_ARRAYSIZE;
-#endif  // (__cplusplus < 201703) && (!defined(_MSC_VER) || _MSC_VER >= 1900)
+#endif  // (__cplusplus < 201703) && (!defined(_MSC_VER) || (_MSC_VER >= 1900 && _MSC_VER < 1912))
 
 // ===================================================================
 
diff --git a/src/google/protobuf/descriptor.cc b/src/google/protobuf/descriptor.cc
index aa3f8b7..00e3e15 100644
--- a/src/google/protobuf/descriptor.cc
+++ b/src/google/protobuf/descriptor.cc
@@ -344,7 +344,7 @@
 
 static const char* const kNonLinkedWeakMessageReplacementName = "google.protobuf.Empty";
 
-#if !defined(_MSC_VER) || _MSC_VER >= 1900
+#if !defined(_MSC_VER) || (_MSC_VER >= 1900 && _MSC_VER < 1912)
 const int FieldDescriptor::kMaxNumber;
 const int FieldDescriptor::kFirstReservedNumber;
 const int FieldDescriptor::kLastReservedNumber;
@@ -6033,7 +6033,7 @@
 
 void DescriptorBuilder::CrossLinkExtensionRange(
     Descriptor::ExtensionRange* range,
-    const DescriptorProto::ExtensionRange& proto) {
+    const DescriptorProto::ExtensionRange& /*proto*/) {
   if (range->options_ == nullptr) {
     range->options_ = &ExtensionRangeOptions::default_instance();
   }
@@ -6675,8 +6675,8 @@
 }
 
 void DescriptorBuilder::ValidateExtensionRangeOptions(
-    const std::string& full_name, Descriptor::ExtensionRange* extension_range,
-    const DescriptorProto_ExtensionRange& proto) {
+    const std::string& /*full_name*/, Descriptor::ExtensionRange* /*extension_range*/,
+    const DescriptorProto_ExtensionRange& /*proto*/) {
 }
 
 void DescriptorBuilder::ValidateServiceOptions(
@@ -7554,7 +7554,7 @@
  public:
   DescriptorBuilder* builder_;
 
-  const Descriptor* FindAnyType(const Message& message,
+  const Descriptor* FindAnyType(const Message& /*message*/,
                                 const std::string& prefix,
                                 const std::string& name) const override {
     if (prefix != internal::kTypeGoogleApisComPrefix &&
@@ -7747,7 +7747,7 @@
 }
 
 void DescriptorBuilder::LogUnusedDependency(const FileDescriptorProto& proto,
-                                            const FileDescriptor* result) {
+                                            const FileDescriptor* /*result*/) {
 
   if (!unused_dependency_.empty()) {
     auto itr = pool_->unused_import_track_files_.find(proto.name());
@@ -7769,7 +7769,7 @@
 }
 
 Symbol DescriptorPool::CrossLinkOnDemandHelper(StringPiece name,
-                                               bool expecting_enum) const {
+                                               bool /*expecting_enum*/) const {
   auto lookup_name = std::string(name);
   if (!lookup_name.empty() && lookup_name[0] == '.') {
     lookup_name = lookup_name.substr(1);
diff --git a/src/google/protobuf/descriptor.pb.cc b/src/google/protobuf/descriptor.pb.cc
index 2f7f951..1e6a472 100644
--- a/src/google/protobuf/descriptor.pb.cc
+++ b/src/google/protobuf/descriptor.pb.cc
@@ -1120,7 +1120,7 @@
   }
 }
 
-#if (__cplusplus < 201703) && (!defined(_MSC_VER) || _MSC_VER >= 1900)
+#if (__cplusplus < 201703) && (!defined(_MSC_VER) || (_MSC_VER >= 1900 && _MSC_VER < 1912))
 constexpr FieldDescriptorProto_Type FieldDescriptorProto::TYPE_DOUBLE;
 constexpr FieldDescriptorProto_Type FieldDescriptorProto::TYPE_FLOAT;
 constexpr FieldDescriptorProto_Type FieldDescriptorProto::TYPE_INT64;
@@ -1142,7 +1142,7 @@
 constexpr FieldDescriptorProto_Type FieldDescriptorProto::Type_MIN;
 constexpr FieldDescriptorProto_Type FieldDescriptorProto::Type_MAX;
 constexpr int FieldDescriptorProto::Type_ARRAYSIZE;
-#endif  // (__cplusplus < 201703) && (!defined(_MSC_VER) || _MSC_VER >= 1900)
+#endif  // (__cplusplus < 201703) && (!defined(_MSC_VER) || (_MSC_VER >= 1900 && _MSC_VER < 1912))
 const ::PROTOBUF_NAMESPACE_ID::EnumDescriptor* FieldDescriptorProto_Label_descriptor() {
   ::PROTOBUF_NAMESPACE_ID::internal::AssignDescriptors(&descriptor_table_google_2fprotobuf_2fdescriptor_2eproto);
   return file_level_enum_descriptors_google_2fprotobuf_2fdescriptor_2eproto[1];
@@ -1158,14 +1158,14 @@
   }
 }
 
-#if (__cplusplus < 201703) && (!defined(_MSC_VER) || _MSC_VER >= 1900)
+#if (__cplusplus < 201703) && (!defined(_MSC_VER) || (_MSC_VER >= 1900 && _MSC_VER < 1912))
 constexpr FieldDescriptorProto_Label FieldDescriptorProto::LABEL_OPTIONAL;
 constexpr FieldDescriptorProto_Label FieldDescriptorProto::LABEL_REQUIRED;
 constexpr FieldDescriptorProto_Label FieldDescriptorProto::LABEL_REPEATED;
 constexpr FieldDescriptorProto_Label FieldDescriptorProto::Label_MIN;
 constexpr FieldDescriptorProto_Label FieldDescriptorProto::Label_MAX;
 constexpr int FieldDescriptorProto::Label_ARRAYSIZE;
-#endif  // (__cplusplus < 201703) && (!defined(_MSC_VER) || _MSC_VER >= 1900)
+#endif  // (__cplusplus < 201703) && (!defined(_MSC_VER) || (_MSC_VER >= 1900 && _MSC_VER < 1912))
 const ::PROTOBUF_NAMESPACE_ID::EnumDescriptor* FileOptions_OptimizeMode_descriptor() {
   ::PROTOBUF_NAMESPACE_ID::internal::AssignDescriptors(&descriptor_table_google_2fprotobuf_2fdescriptor_2eproto);
   return file_level_enum_descriptors_google_2fprotobuf_2fdescriptor_2eproto[2];
@@ -1181,14 +1181,14 @@
   }
 }
 
-#if (__cplusplus < 201703) && (!defined(_MSC_VER) || _MSC_VER >= 1900)
+#if (__cplusplus < 201703) && (!defined(_MSC_VER) || (_MSC_VER >= 1900 && _MSC_VER < 1912))
 constexpr FileOptions_OptimizeMode FileOptions::SPEED;
 constexpr FileOptions_OptimizeMode FileOptions::CODE_SIZE;
 constexpr FileOptions_OptimizeMode FileOptions::LITE_RUNTIME;
 constexpr FileOptions_OptimizeMode FileOptions::OptimizeMode_MIN;
 constexpr FileOptions_OptimizeMode FileOptions::OptimizeMode_MAX;
 constexpr int FileOptions::OptimizeMode_ARRAYSIZE;
-#endif  // (__cplusplus < 201703) && (!defined(_MSC_VER) || _MSC_VER >= 1900)
+#endif  // (__cplusplus < 201703) && (!defined(_MSC_VER) || (_MSC_VER >= 1900 && _MSC_VER < 1912))
 const ::PROTOBUF_NAMESPACE_ID::EnumDescriptor* FieldOptions_CType_descriptor() {
   ::PROTOBUF_NAMESPACE_ID::internal::AssignDescriptors(&descriptor_table_google_2fprotobuf_2fdescriptor_2eproto);
   return file_level_enum_descriptors_google_2fprotobuf_2fdescriptor_2eproto[3];
@@ -1204,14 +1204,14 @@
   }
 }
 
-#if (__cplusplus < 201703) && (!defined(_MSC_VER) || _MSC_VER >= 1900)
+#if (__cplusplus < 201703) && (!defined(_MSC_VER) || (_MSC_VER >= 1900 && _MSC_VER < 1912))
 constexpr FieldOptions_CType FieldOptions::STRING;
 constexpr FieldOptions_CType FieldOptions::CORD;
 constexpr FieldOptions_CType FieldOptions::STRING_PIECE;
 constexpr FieldOptions_CType FieldOptions::CType_MIN;
 constexpr FieldOptions_CType FieldOptions::CType_MAX;
 constexpr int FieldOptions::CType_ARRAYSIZE;
-#endif  // (__cplusplus < 201703) && (!defined(_MSC_VER) || _MSC_VER >= 1900)
+#endif  // (__cplusplus < 201703) && (!defined(_MSC_VER) || (_MSC_VER >= 1900 && _MSC_VER < 1912))
 const ::PROTOBUF_NAMESPACE_ID::EnumDescriptor* FieldOptions_JSType_descriptor() {
   ::PROTOBUF_NAMESPACE_ID::internal::AssignDescriptors(&descriptor_table_google_2fprotobuf_2fdescriptor_2eproto);
   return file_level_enum_descriptors_google_2fprotobuf_2fdescriptor_2eproto[4];
@@ -1227,14 +1227,14 @@
   }
 }
 
-#if (__cplusplus < 201703) && (!defined(_MSC_VER) || _MSC_VER >= 1900)
+#if (__cplusplus < 201703) && (!defined(_MSC_VER) || (_MSC_VER >= 1900 && _MSC_VER < 1912))
 constexpr FieldOptions_JSType FieldOptions::JS_NORMAL;
 constexpr FieldOptions_JSType FieldOptions::JS_STRING;
 constexpr FieldOptions_JSType FieldOptions::JS_NUMBER;
 constexpr FieldOptions_JSType FieldOptions::JSType_MIN;
 constexpr FieldOptions_JSType FieldOptions::JSType_MAX;
 constexpr int FieldOptions::JSType_ARRAYSIZE;
-#endif  // (__cplusplus < 201703) && (!defined(_MSC_VER) || _MSC_VER >= 1900)
+#endif  // (__cplusplus < 201703) && (!defined(_MSC_VER) || (_MSC_VER >= 1900 && _MSC_VER < 1912))
 const ::PROTOBUF_NAMESPACE_ID::EnumDescriptor* MethodOptions_IdempotencyLevel_descriptor() {
   ::PROTOBUF_NAMESPACE_ID::internal::AssignDescriptors(&descriptor_table_google_2fprotobuf_2fdescriptor_2eproto);
   return file_level_enum_descriptors_google_2fprotobuf_2fdescriptor_2eproto[5];
@@ -1250,14 +1250,14 @@
   }
 }
 
-#if (__cplusplus < 201703) && (!defined(_MSC_VER) || _MSC_VER >= 1900)
+#if (__cplusplus < 201703) && (!defined(_MSC_VER) || (_MSC_VER >= 1900 && _MSC_VER < 1912))
 constexpr MethodOptions_IdempotencyLevel MethodOptions::IDEMPOTENCY_UNKNOWN;
 constexpr MethodOptions_IdempotencyLevel MethodOptions::NO_SIDE_EFFECTS;
 constexpr MethodOptions_IdempotencyLevel MethodOptions::IDEMPOTENT;
 constexpr MethodOptions_IdempotencyLevel MethodOptions::IdempotencyLevel_MIN;
 constexpr MethodOptions_IdempotencyLevel MethodOptions::IdempotencyLevel_MAX;
 constexpr int MethodOptions::IdempotencyLevel_ARRAYSIZE;
-#endif  // (__cplusplus < 201703) && (!defined(_MSC_VER) || _MSC_VER >= 1900)
+#endif  // (__cplusplus < 201703) && (!defined(_MSC_VER) || (_MSC_VER >= 1900 && _MSC_VER < 1912))
 
 // ===================================================================
 
diff --git a/src/google/protobuf/extension_set.cc b/src/google/protobuf/extension_set.cc
index df95bc0..bbb7ae1 100644
--- a/src/google/protobuf/extension_set.cc
+++ b/src/google/protobuf/extension_set.cc
@@ -1968,8 +1968,10 @@
   map_ = new_map;
 }
 
+#if (__cplusplus < 201703) && (!defined(_MSC_VER) || (_MSC_VER >= 1900 && _MSC_VER < 1912))
 // static
 constexpr uint16_t ExtensionSet::kMaximumFlatCapacity;
+#endif //  (__cplusplus < 201703) && (!defined(_MSC_VER) || (_MSC_VER >= 1900 && _MSC_VER < 1912))
 
 void ExtensionSet::Erase(int key) {
   if (PROTOBUF_PREDICT_FALSE(is_large())) {
diff --git a/src/google/protobuf/generated_message_reflection.cc b/src/google/protobuf/generated_message_reflection.cc
index 99c0c25..3582dcc 100644
--- a/src/google/protobuf/generated_message_reflection.cc
+++ b/src/google/protobuf/generated_message_reflection.cc
@@ -1611,7 +1611,7 @@
 
 const std::string& Reflection::GetStringReference(const Message& message,
                                                   const FieldDescriptor* field,
-                                                  std::string* scratch) const {
+                                                  std::string* /*scratch*/) const {
   USAGE_CHECK_ALL(GetStringReference, SINGULAR, STRING);
   if (field->is_extension()) {
     return GetExtensionSet(message).GetString(field->number(),
@@ -1699,7 +1699,7 @@
 
 const std::string& Reflection::GetRepeatedStringReference(
     const Message& message, const FieldDescriptor* field, int index,
-    std::string* scratch) const {
+    std::string* /*scratch*/) const {
   USAGE_CHECK_ALL(GetRepeatedStringReference, REPEATED, STRING);
   if (field->is_extension()) {
     return GetExtensionSet(message).GetRepeatedString(field->number(), index);
@@ -2237,7 +2237,7 @@
 void* Reflection::MutableRawRepeatedField(Message* message,
                                           const FieldDescriptor* field,
                                           FieldDescriptor::CppType cpptype,
-                                          int ctype,
+                                          int /*ctype*/,
                                           const Descriptor* desc) const {
   USAGE_CHECK_REPEATED("MutableRawRepeatedField");
   CheckInvalidAccess(schema_, field);
@@ -2656,7 +2656,7 @@
 
 void* Reflection::MutableRawRepeatedString(Message* message,
                                            const FieldDescriptor* field,
-                                           bool is_string) const {
+                                           bool /*is_string*/) const {
   return MutableRawRepeatedField(message, field,
                                  FieldDescriptor::CPPTYPE_STRING,
                                  FieldOptions::STRING, nullptr);
@@ -3011,7 +3011,7 @@
 }
 
 void UnknownFieldSetSerializer(const uint8_t* base, uint32_t offset,
-                               uint32_t tag, uint32_t has_offset,
+                               uint32_t /*tag*/, uint32_t /*has_offset*/,
                                io::CodedOutputStream* output) {
   const void* ptr = base + offset;
   const InternalMetadata* metadata = static_cast<const InternalMetadata*>(ptr);
diff --git a/src/google/protobuf/generated_message_tctable_impl.h b/src/google/protobuf/generated_message_tctable_impl.h
index 33a351d..4ae5410 100644
--- a/src/google/protobuf/generated_message_tctable_impl.h
+++ b/src/google/protobuf/generated_message_tctable_impl.h
@@ -187,12 +187,17 @@
  protected:
   static inline PROTOBUF_ALWAYS_INLINE const char* Return(
       PROTOBUF_TC_PARAM_DECL) {
+    (void)data;
+    (void)ctx;
     SyncHasbits(msg, hasbits, table);
     return ptr;
   }
 
   static inline PROTOBUF_ALWAYS_INLINE const char* Error(
       PROTOBUF_TC_PARAM_DECL) {
+    (void)data;
+    (void)ctx;
+    (void)ptr;
     SyncHasbits(msg, hasbits, table);
     return nullptr;
   }
@@ -224,6 +229,7 @@
       ctx->SetLastTag(tag);
       return ptr;
     }
+    (void)data;
     uint32_t num = tag >> 3;
     if (table->extension_range_low <= num &&
         num <= table->extension_range_high) {
diff --git a/src/google/protobuf/generated_message_util.cc b/src/google/protobuf/generated_message_util.cc
index 374635f..0b1cdd5 100644
--- a/src/google/protobuf/generated_message_util.cc
+++ b/src/google/protobuf/generated_message_util.cc
@@ -316,7 +316,7 @@
 // Helper to branch to fast path if possible
 void SerializeMessageDispatch(const MessageLite& msg,
                               const FieldMetadata* field_table, int num_fields,
-                              int32_t cached_size,
+                              int32_t /*cached_size*/,
                               io::CodedOutputStream* output) {
   const uint8_t* base = reinterpret_cast<const uint8_t*>(&msg);
   SerializeInternal(base, field_table, num_fields, output);
@@ -325,7 +325,7 @@
 // Helper to branch to fast path if possible
 void SerializeMessageDispatch(const MessageLite& msg,
                               const FieldMetadata* field_table, int num_fields,
-                              int32_t cached_size, ArrayOutput* output) {
+                              int32_t /*cached_size*/, ArrayOutput* output) {
   const uint8_t* base = reinterpret_cast<const uint8_t*>(&msg);
   output->ptr = SerializeInternalToArray(base, field_table, num_fields,
                                          output->is_deterministic, output->ptr);
@@ -523,7 +523,7 @@
 template <>
 struct PackedFieldHelper<WireFormatLite::TYPE_STRING> {
   template <typename O>
-  static void Serialize(const void* field, const FieldMetadata& md, O* output) {
+  static void Serialize(const void* /*field*/, const FieldMetadata& md, O* /*output*/) {
     GOOGLE_LOG(FATAL) << "Not implemented field number " << md.tag << " with type "
                << md.type;
   }
@@ -726,7 +726,7 @@
 }
 
 void UnknownFieldSerializerLite(const uint8_t* ptr, uint32_t offset,
-                                uint32_t tag, uint32_t has_offset,
+                                uint32_t /*tag*/, uint32_t /*has_offset*/,
                                 io::CodedOutputStream* output) {
   output->WriteString(
       reinterpret_cast<const InternalMetadata*>(ptr + offset)
diff --git a/src/google/protobuf/io/io_win32.cc b/src/google/protobuf/io/io_win32.cc
index d22ceac..ed8ab19 100644
--- a/src/google/protobuf/io/io_win32.cc
+++ b/src/google/protobuf/io/io_win32.cc
@@ -266,7 +266,7 @@
 #endif
 }
 
-int mkdir(const char* path, int _mode) {
+int mkdir(const char* path, int /*_mode*/) {
 #ifdef SUPPORT_LONGPATHS
   wstring wpath;
   if (!as_windows_path(path, &wpath)) {
diff --git a/src/google/protobuf/io/zero_copy_stream_impl.cc b/src/google/protobuf/io/zero_copy_stream_impl.cc
index 0986ea2..fc75e3ef 100644
--- a/src/google/protobuf/io/zero_copy_stream_impl.cc
+++ b/src/google/protobuf/io/zero_copy_stream_impl.cc
@@ -170,7 +170,7 @@
 
 // ===================================================================
 
-FileOutputStream::FileOutputStream(int file_descriptor, int block_size)
+FileOutputStream::FileOutputStream(int file_descriptor, int /*block_size*/)
     : CopyingOutputStreamAdaptor(&copying_output_),
       copying_output_(file_descriptor) {}
 
diff --git a/src/google/protobuf/message_lite.cc b/src/google/protobuf/message_lite.cc
index 85d0e07..e4cb649 100644
--- a/src/google/protobuf/message_lite.cc
+++ b/src/google/protobuf/message_lite.cc
@@ -118,7 +118,7 @@
 }
 
 // Returns true of all required fields are present / have values.
-inline bool CheckFieldPresence(const internal::ParseContext& ctx,
+inline bool CheckFieldPresence(const internal::ParseContext& /*ctx*/,
                                const MessageLite& msg,
                                MessageLite::ParseFlags parse_flags) {
   if (PROTOBUF_PREDICT_FALSE((parse_flags & MessageLite::kMergePartial) != 0)) {
diff --git a/src/google/protobuf/parse_context.cc b/src/google/protobuf/parse_context.cc
index db7004f..b515427 100644
--- a/src/google/protobuf/parse_context.cc
+++ b/src/google/protobuf/parse_context.cc
@@ -205,7 +205,7 @@
 }
 
 const char* EpsCopyInputStream::SkipFallback(const char* ptr, int size) {
-  return AppendSize(ptr, size, [](const char* p, int s) {});
+  return AppendSize(ptr, size, [](const char* /*p*/, int /*s*/) {});
 }
 
 const char* EpsCopyInputStream::ReadStringFallback(const char* ptr, int size,
@@ -237,7 +237,7 @@
 template <int>
 void byteswap(void* p);
 template <>
-void byteswap<1>(void* p) {}
+void byteswap<1>(void* /*p*/) {}
 template <>
 void byteswap<4>(void* p) {
   *static_cast<uint32_t*>(p) = bswap_32(*static_cast<uint32_t*>(p));
diff --git a/src/google/protobuf/port_def.inc b/src/google/protobuf/port_def.inc
index 28b1d8f..d3b08ea 100644
--- a/src/google/protobuf/port_def.inc
+++ b/src/google/protobuf/port_def.inc
@@ -568,7 +568,7 @@
 // https://github.com/protocolbuffers/protobuf/issues/8310
 // Does not work yet with Visual Studio 2019 Update 16.10
 #define PROTOBUF_CONSTINIT constinit
-#elif __has_cpp_attribute(clang::require_constant_initialization)
+#elif !defined(_MSC_VER) && __has_cpp_attribute(clang::require_constant_initialization)
 #define PROTOBUF_CONSTINIT [[clang::require_constant_initialization]]
 #else
 #define PROTOBUF_CONSTINIT
diff --git a/src/google/protobuf/reflection_internal.h b/src/google/protobuf/reflection_internal.h
index 3ccf4a0..4a8a9bd 100644
--- a/src/google/protobuf/reflection_internal.h
+++ b/src/google/protobuf/reflection_internal.h
@@ -43,25 +43,25 @@
 // corresponding random-access methods.
 class RandomAccessRepeatedFieldAccessor : public RepeatedFieldAccessor {
  public:
-  Iterator* BeginIterator(const Field* data) const override {
+  Iterator* BeginIterator(const Field* /*data*/) const override {
     return PositionToIterator(0);
   }
   Iterator* EndIterator(const Field* data) const override {
     return PositionToIterator(this->Size(data));
   }
-  Iterator* CopyIterator(const Field* data,
+  Iterator* CopyIterator(const Field* /*data*/,
                          const Iterator* iterator) const override {
     return const_cast<Iterator*>(iterator);
   }
-  Iterator* AdvanceIterator(const Field* data,
+  Iterator* AdvanceIterator(const Field* /*data*/,
                             Iterator* iterator) const override {
     return PositionToIterator(IteratorToPosition(iterator) + 1);
   }
-  bool EqualsIterator(const Field* data, const Iterator* a,
+  bool EqualsIterator(const Field* /*data*/, const Iterator* a,
                       const Iterator* b) const override {
     return a == b;
   }
-  void DeleteIterator(const Field* data, Iterator* iterator) const override {}
+  void DeleteIterator(const Field* /*data*/, Iterator* /*iterator*/) const override {}
   const Value* GetIteratorValue(const Field* data, const Iterator* iterator,
                                 Value* scratch_space) const override {
     return Get(data, static_cast<int>(IteratorToPosition(iterator)),
@@ -257,7 +257,7 @@
   // Convert a MapEntry message stored in the underlying MapFieldBase to an
   // object that will be returned by this accessor.
   virtual const Value* ConvertFromEntry(const Message& value,
-                                        Value* scratch_space) const {
+                                        Value* /*scratch_space*/) const {
     return static_cast<const Value*>(&value);
   }
 };
@@ -285,7 +285,7 @@
     return *static_cast<const T*>(value);
   }
   const Value* ConvertFromT(const T& value,
-                            Value* scratch_space) const override {
+                            Value* /*scratch_space*/) const override {
     return static_cast<const Value*>(&value);
   }
 };
@@ -325,7 +325,7 @@
     *result = *static_cast<const std::string*>(value);
   }
   const Value* ConvertFromT(const std::string& value,
-                            Value* scratch_space) const override {
+                            Value* /*scratch_space*/) const override {
     return static_cast<const Value*>(&value);
   }
 };
@@ -352,7 +352,7 @@
     result->CopyFrom(*static_cast<const Message*>(value));
   }
   const Value* ConvertFromT(const Message& value,
-                            Value* scratch_space) const override {
+                            Value* /*scratch_space*/) const override {
     return static_cast<const Value*>(&value);
   }
 };
diff --git a/src/google/protobuf/stubs/mathutil.h b/src/google/protobuf/stubs/mathutil.h
index 7116d2d..1d16bce 100644
--- a/src/google/protobuf/stubs/mathutil.h
+++ b/src/google/protobuf/stubs/mathutil.h
@@ -51,7 +51,7 @@
 // types.
 template <typename T,
           typename std::enable_if<std::is_integral<T>::value, int>::type = 0>
-bool IsNan(T val) {
+bool IsNan(T /*val*/) {
   return false;
 }
 
diff --git a/src/google/protobuf/stubs/statusor.h b/src/google/protobuf/stubs/statusor.h
index a569502..20e603e 100644
--- a/src/google/protobuf/stubs/statusor.h
+++ b/src/google/protobuf/stubs/statusor.h
@@ -166,7 +166,7 @@
 template<typename T>
 struct StatusOrHelper::Specialize {
   // For non-pointer T, a reference can never be nullptr.
-  static inline bool IsValueNull(const T& t) { return false; }
+  static inline bool IsValueNull(const T& /*t*/) { return false; }
 };
 
 template<typename T>
diff --git a/src/google/protobuf/text_format.cc b/src/google/protobuf/text_format.cc
index 6c2a01c..4207c4a 100644
--- a/src/google/protobuf/text_format.cc
+++ b/src/google/protobuf/text_format.cc
@@ -1439,8 +1439,8 @@
 class TextFormat::Printer::DebugStringFieldValuePrinter
     : public TextFormat::FastFieldValuePrinter {
  public:
-  void PrintMessageStart(const Message& message, int field_index,
-                         int field_count, bool single_line_mode,
+  void PrintMessageStart(const Message& /*message*/, int /*field_index*/,
+                         int /*field_count*/, bool single_line_mode,
                          BaseTextGenerator* generator) const override {
     // This is safe as only TextGenerator is used with
     // DebugStringFieldValuePrinter.
@@ -1491,7 +1491,7 @@
 }
 
 MessageFactory* TextFormat::Finder::FindExtensionFactory(
-    const FieldDescriptor* field) const {
+    const FieldDescriptor* /*field*/) const {
   return nullptr;
 }
 
@@ -1757,7 +1757,7 @@
   generator->PrintString(!std::isnan(val) ? SimpleDtoa(val) : "nan");
 }
 void TextFormat::FastFieldValuePrinter::PrintEnum(
-    int32_t val, const std::string& name, BaseTextGenerator* generator) const {
+    int32_t /*val*/, const std::string& name, BaseTextGenerator* generator) const {
   generator->PrintString(name);
 }
 
@@ -1772,13 +1772,13 @@
   PrintString(val, generator);
 }
 void TextFormat::FastFieldValuePrinter::PrintFieldName(
-    const Message& message, int field_index, int field_count,
+    const Message& message, int /*field_index*/, int /*field_count*/,
     const Reflection* reflection, const FieldDescriptor* field,
     BaseTextGenerator* generator) const {
   PrintFieldName(message, reflection, field, generator);
 }
 void TextFormat::FastFieldValuePrinter::PrintFieldName(
-    const Message& message, const Reflection* reflection,
+    const Message& /*message*/, const Reflection* /*reflection*/,
     const FieldDescriptor* field, BaseTextGenerator* generator) const {
   if (field->is_extension()) {
     generator->PrintLiteral("[");
@@ -1792,7 +1792,7 @@
   }
 }
 void TextFormat::FastFieldValuePrinter::PrintMessageStart(
-    const Message& message, int field_index, int field_count,
+    const Message& /*message*/, int /*field_index*/, int /*field_count*/,
     bool single_line_mode, BaseTextGenerator* generator) const {
   if (single_line_mode) {
     generator->PrintLiteral(" { ");
@@ -1801,12 +1801,12 @@
   }
 }
 bool TextFormat::FastFieldValuePrinter::PrintMessageContent(
-    const Message& message, int field_index, int field_count,
-    bool single_line_mode, BaseTextGenerator* generator) const {
+    const Message& /*message*/, int /*field_index*/, int /*field_count*/,
+    bool /*single_line_mode*/, BaseTextGenerator* /*generator*/) const {
   return false;  // Use the default printing function.
 }
 void TextFormat::FastFieldValuePrinter::PrintMessageEnd(
-    const Message& message, int field_index, int field_count,
+    const Message& /*message*/, int /*field_index*/, int /*field_count*/,
     bool single_line_mode, BaseTextGenerator* generator) const {
   if (single_line_mode) {
     generator->PrintLiteral("} ");
@@ -1868,7 +1868,7 @@
                  TextFormat::BaseTextGenerator* generator) const override {
     generator->PrintString(delegate_->PrintEnum(val, name));
   }
-  void PrintFieldName(const Message& message, int field_index, int field_count,
+  void PrintFieldName(const Message& message, int /*field_index*/, int /*field_count*/,
                       const Reflection* reflection,
                       const FieldDescriptor* field,
                       TextFormat::BaseTextGenerator* generator) const override {
diff --git a/src/google/protobuf/type.pb.cc b/src/google/protobuf/type.pb.cc
index ffa3b20..88fa46c 100644
--- a/src/google/protobuf/type.pb.cc
+++ b/src/google/protobuf/type.pb.cc
@@ -272,7 +272,7 @@
   }
 }
 
-#if (__cplusplus < 201703) && (!defined(_MSC_VER) || _MSC_VER >= 1900)
+#if (__cplusplus < 201703) && (!defined(_MSC_VER) || (_MSC_VER >= 1900 && _MSC_VER < 1912))
 constexpr Field_Kind Field::TYPE_UNKNOWN;
 constexpr Field_Kind Field::TYPE_DOUBLE;
 constexpr Field_Kind Field::TYPE_FLOAT;
@@ -295,7 +295,7 @@
 constexpr Field_Kind Field::Kind_MIN;
 constexpr Field_Kind Field::Kind_MAX;
 constexpr int Field::Kind_ARRAYSIZE;
-#endif  // (__cplusplus < 201703) && (!defined(_MSC_VER) || _MSC_VER >= 1900)
+#endif  // (__cplusplus < 201703) && (!defined(_MSC_VER) || (_MSC_VER >= 1900 && _MSC_VER < 1912))
 const ::PROTOBUF_NAMESPACE_ID::EnumDescriptor* Field_Cardinality_descriptor() {
   ::PROTOBUF_NAMESPACE_ID::internal::AssignDescriptors(&descriptor_table_google_2fprotobuf_2ftype_2eproto);
   return file_level_enum_descriptors_google_2fprotobuf_2ftype_2eproto[1];
@@ -312,7 +312,7 @@
   }
 }
 
-#if (__cplusplus < 201703) && (!defined(_MSC_VER) || _MSC_VER >= 1900)
+#if (__cplusplus < 201703) && (!defined(_MSC_VER) || (_MSC_VER >= 1900 && _MSC_VER < 1912))
 constexpr Field_Cardinality Field::CARDINALITY_UNKNOWN;
 constexpr Field_Cardinality Field::CARDINALITY_OPTIONAL;
 constexpr Field_Cardinality Field::CARDINALITY_REQUIRED;
@@ -320,7 +320,7 @@
 constexpr Field_Cardinality Field::Cardinality_MIN;
 constexpr Field_Cardinality Field::Cardinality_MAX;
 constexpr int Field::Cardinality_ARRAYSIZE;
-#endif  // (__cplusplus < 201703) && (!defined(_MSC_VER) || _MSC_VER >= 1900)
+#endif  // (__cplusplus < 201703) && (!defined(_MSC_VER) || (_MSC_VER >= 1900 && _MSC_VER < 1912))
 const ::PROTOBUF_NAMESPACE_ID::EnumDescriptor* Syntax_descriptor() {
   ::PROTOBUF_NAMESPACE_ID::internal::AssignDescriptors(&descriptor_table_google_2fprotobuf_2ftype_2eproto);
   return file_level_enum_descriptors_google_2fprotobuf_2ftype_2eproto[2];
diff --git a/src/google/protobuf/unknown_field_set.cc b/src/google/protobuf/unknown_field_set.cc
index 0d9bf62..2b66dc0 100644
--- a/src/google/protobuf/unknown_field_set.cc
+++ b/src/google/protobuf/unknown_field_set.cc
@@ -251,7 +251,7 @@
   }
 }
 
-void UnknownField::DeepCopy(const UnknownField& other) {
+void UnknownField::DeepCopy(const UnknownField& /*other*/) {
   switch (type()) {
     case UnknownField::TYPE_LENGTH_DELIMITED:
       data_.length_delimited_.string_value =
diff --git a/src/google/protobuf/util/field_comparator.cc b/src/google/protobuf/util/field_comparator.cc
index 46d5dba..5d8e865 100644
--- a/src/google/protobuf/util/field_comparator.cc
+++ b/src/google/protobuf/util/field_comparator.cc
@@ -58,7 +58,7 @@
 FieldComparator::ComparisonResult SimpleFieldComparator::SimpleCompare(
     const Message& message_1, const Message& message_2,
     const FieldDescriptor* field, int index_1, int index_2,
-    const util::FieldContext* field_context) {
+    const util::FieldContext* /*field_context*/) {
   const Reflection* reflection_1 = message_1.GetReflection();
   const Reflection* reflection_2 = message_2.GetReflection();
 
@@ -155,7 +155,7 @@
   return CompareDoubleOrFloat(field, value_1, value_2);
 }
 
-bool SimpleFieldComparator::CompareEnum(const FieldDescriptor& field,
+bool SimpleFieldComparator::CompareEnum(const FieldDescriptor& /*field*/,
                                         const EnumValueDescriptor* value_1,
                                         const EnumValueDescriptor* value_2) {
   return value_1->number() == value_2->number();
diff --git a/src/google/protobuf/util/internal/datapiece.h b/src/google/protobuf/util/internal/datapiece.h
index c27ea5c..efd9aba 100644
--- a/src/google/protobuf/util/internal/datapiece.h
+++ b/src/google/protobuf/util/internal/datapiece.h
@@ -97,7 +97,7 @@
         str_(value),
         use_strict_base64_decoding_(use_strict_base64_decoding) {}
   // Constructor for bytes. The second parameter is not used.
-  DataPiece(StringPiece value, bool dummy, bool use_strict_base64_decoding)
+  DataPiece(StringPiece value, bool /*dummy*/, bool use_strict_base64_decoding)
       : type_(TYPE_BYTES),
         str_(value),
         use_strict_base64_decoding_(use_strict_base64_decoding) {}
diff --git a/src/google/protobuf/util/internal/error_listener.h b/src/google/protobuf/util/internal/error_listener.h
index 07cb957..d8c5906 100644
--- a/src/google/protobuf/util/internal/error_listener.h
+++ b/src/google/protobuf/util/internal/error_listener.h
@@ -83,16 +83,16 @@
   NoopErrorListener() {}
   ~NoopErrorListener() override {}
 
-  void InvalidName(const LocationTrackerInterface& loc,
-                   StringPiece invalid_name,
-                   StringPiece message) override {}
+  void InvalidName(const LocationTrackerInterface& /*loc*/,
+                   StringPiece /*invalid_name*/,
+                   StringPiece /*message*/) override {}
 
-  void InvalidValue(const LocationTrackerInterface& loc,
-                    StringPiece type_name,
-                    StringPiece value) override {}
+  void InvalidValue(const LocationTrackerInterface& /*loc*/,
+                    StringPiece /*type_name*/,
+                    StringPiece /*value*/) override {}
 
-  void MissingField(const LocationTrackerInterface& loc,
-                    StringPiece missing_name) override {}
+  void MissingField(const LocationTrackerInterface& /*loc*/,
+                    StringPiece /*missing_name*/) override {}
 
  private:
   GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(NoopErrorListener);
diff --git a/src/google/protobuf/util/internal/json_stream_parser.cc b/src/google/protobuf/util/internal/json_stream_parser.cc
index ff692cd..e3f3870 100644
--- a/src/google/protobuf/util/internal/json_stream_parser.cc
+++ b/src/google/protobuf/util/internal/json_stream_parser.cc
@@ -863,7 +863,7 @@
 }
 
 util::Status JsonStreamParser::ReportFailure(StringPiece message,
-                                             ParseErrorType parse_code) {
+                                             ParseErrorType /*parse_code*/) {
   static const int kContextLength = 20;
   const char* p_start = p_.data();
   const char* json_start = json_.data();
diff --git a/src/google/protobuf/util/internal/protostream_objectsource.cc b/src/google/protobuf/util/internal/protostream_objectsource.cc
index 699f8e7..5674b22 100644
--- a/src/google/protobuf/util/internal/protostream_objectsource.cc
+++ b/src/google/protobuf/util/internal/protostream_objectsource.cc
@@ -252,7 +252,7 @@
 }
 
 util::StatusOr<uint32_t> ProtoStreamObjectSource::RenderMap(
-    const google::protobuf::Field* field, StringPiece name,
+    const google::protobuf::Field* field, StringPiece /*name*/,
     uint32_t list_tag, ObjectWriter* ow) const {
   const google::protobuf::Type* field_type =
       typeinfo_->GetTypeByTypeUrl(field->type_url());
@@ -375,7 +375,7 @@
 }
 
 util::Status ProtoStreamObjectSource::RenderDouble(
-    const ProtoStreamObjectSource* os, const google::protobuf::Type& type,
+    const ProtoStreamObjectSource* os, const google::protobuf::Type& /*type*/,
     StringPiece field_name, ObjectWriter* ow) {
   uint32_t tag = os->stream_->ReadTag();
   uint64_t buffer64 = 0;  // default value of Double wrapper value
@@ -388,7 +388,7 @@
 }
 
 util::Status ProtoStreamObjectSource::RenderFloat(
-    const ProtoStreamObjectSource* os, const google::protobuf::Type& type,
+    const ProtoStreamObjectSource* os, const google::protobuf::Type& /*type*/,
     StringPiece field_name, ObjectWriter* ow) {
   uint32_t tag = os->stream_->ReadTag();
   uint32_t buffer32 = 0;  // default value of Float wrapper value
@@ -401,7 +401,7 @@
 }
 
 util::Status ProtoStreamObjectSource::RenderInt64(
-    const ProtoStreamObjectSource* os, const google::protobuf::Type& type,
+    const ProtoStreamObjectSource* os, const google::protobuf::Type& /*type*/,
     StringPiece field_name, ObjectWriter* ow) {
   uint32_t tag = os->stream_->ReadTag();
   uint64_t buffer64 = 0;  // default value of Int64 wrapper value
@@ -414,7 +414,7 @@
 }
 
 util::Status ProtoStreamObjectSource::RenderUInt64(
-    const ProtoStreamObjectSource* os, const google::protobuf::Type& type,
+    const ProtoStreamObjectSource* os, const google::protobuf::Type& /*type*/,
     StringPiece field_name, ObjectWriter* ow) {
   uint32_t tag = os->stream_->ReadTag();
   uint64_t buffer64 = 0;  // default value of UInt64 wrapper value
@@ -427,7 +427,7 @@
 }
 
 util::Status ProtoStreamObjectSource::RenderInt32(
-    const ProtoStreamObjectSource* os, const google::protobuf::Type& type,
+    const ProtoStreamObjectSource* os, const google::protobuf::Type& /*type*/,
     StringPiece field_name, ObjectWriter* ow) {
   uint32_t tag = os->stream_->ReadTag();
   uint32_t buffer32 = 0;  // default value of Int32 wrapper value
@@ -440,7 +440,7 @@
 }
 
 util::Status ProtoStreamObjectSource::RenderUInt32(
-    const ProtoStreamObjectSource* os, const google::protobuf::Type& type,
+    const ProtoStreamObjectSource* os, const google::protobuf::Type& /*type*/,
     StringPiece field_name, ObjectWriter* ow) {
   uint32_t tag = os->stream_->ReadTag();
   uint32_t buffer32 = 0;  // default value of UInt32 wrapper value
@@ -453,7 +453,7 @@
 }
 
 util::Status ProtoStreamObjectSource::RenderBool(
-    const ProtoStreamObjectSource* os, const google::protobuf::Type& type,
+    const ProtoStreamObjectSource* os, const google::protobuf::Type& /*type*/,
     StringPiece field_name, ObjectWriter* ow) {
   uint32_t tag = os->stream_->ReadTag();
   uint64_t buffer64 = 0;  // results in 'false' value as default, which is the
@@ -467,7 +467,7 @@
 }
 
 util::Status ProtoStreamObjectSource::RenderString(
-    const ProtoStreamObjectSource* os, const google::protobuf::Type& type,
+    const ProtoStreamObjectSource* os, const google::protobuf::Type& /*type*/,
     StringPiece field_name, ObjectWriter* ow) {
   uint32_t tag = os->stream_->ReadTag();
   uint32_t buffer32;
@@ -482,7 +482,7 @@
 }
 
 util::Status ProtoStreamObjectSource::RenderBytes(
-    const ProtoStreamObjectSource* os, const google::protobuf::Type& type,
+    const ProtoStreamObjectSource* os, const google::protobuf::Type& /*type*/,
     StringPiece field_name, ObjectWriter* ow) {
   uint32_t tag = os->stream_->ReadTag();
   uint32_t buffer32;
diff --git a/src/google/protobuf/util/message_differencer.cc b/src/google/protobuf/util/message_differencer.cc
index 6d7f2f9..65beed6 100644
--- a/src/google/protobuf/util/message_differencer.cc
+++ b/src/google/protobuf/util/message_differencer.cc
@@ -78,25 +78,25 @@
 
   // Report that a field has been added into Message2.
   void ReportAdded(
-      const google::protobuf::Message& message1, const google::protobuf::Message& message2,
+      const google::protobuf::Message& /*message1*/, const google::protobuf::Message& /*message2*/,
       const std::vector<google::protobuf::util::MessageDifferencer::SpecificField>&
-          field_path) override {
+          /*field_path*/) override {
     ++num_diffs_;
   }
 
   // Report that a field has been deleted from Message1.
   void ReportDeleted(
-      const google::protobuf::Message& message1, const google::protobuf::Message& message2,
+      const google::protobuf::Message& /*message1*/, const google::protobuf::Message& /*message2*/,
       const std::vector<google::protobuf::util::MessageDifferencer::SpecificField>&
-          field_path) override {
+          /*field_path*/) override {
     ++num_diffs_;
   }
 
   // Report that the value of a field has been modified.
   void ReportModified(
-      const google::protobuf::Message& message1, const google::protobuf::Message& message2,
+      const google::protobuf::Message& /*message1*/, const google::protobuf::Message& /*message2*/,
       const std::vector<google::protobuf::util::MessageDifferencer::SpecificField>&
-          field_path) override {
+          /*field_path*/) override {
     ++num_diffs_;
   }
 
@@ -2104,7 +2104,7 @@
 }
 
 void MessageDifferencer::StreamReporter::ReportAdded(
-    const Message& message1, const Message& message2,
+    const Message& /*message1*/, const Message& message2,
     const std::vector<SpecificField>& field_path) {
   printer_->Print("added: ");
   PrintPath(field_path, false);
@@ -2114,7 +2114,7 @@
 }
 
 void MessageDifferencer::StreamReporter::ReportDeleted(
-    const Message& message1, const Message& message2,
+    const Message& message1, const Message& /*message2*/,
     const std::vector<SpecificField>& field_path) {
   printer_->Print("deleted: ");
   PrintPath(field_path, true);
@@ -2153,7 +2153,7 @@
 }
 
 void MessageDifferencer::StreamReporter::ReportMoved(
-    const Message& message1, const Message& message2,
+    const Message& message1, const Message& /*message2*/,
     const std::vector<SpecificField>& field_path) {
   printer_->Print("moved: ");
   PrintPath(field_path, true);
@@ -2165,7 +2165,7 @@
 }
 
 void MessageDifferencer::StreamReporter::ReportMatched(
-    const Message& message1, const Message& message2,
+    const Message& message1, const Message& /*message2*/,
     const std::vector<SpecificField>& field_path) {
   printer_->Print("matched: ");
   PrintPath(field_path, true);
@@ -2179,7 +2179,7 @@
 }
 
 void MessageDifferencer::StreamReporter::ReportIgnored(
-    const Message& message1, const Message& message2,
+    const Message& /*message1*/, const Message& /*message2*/,
     const std::vector<SpecificField>& field_path) {
   printer_->Print("ignored: ");
   PrintPath(field_path, true);
@@ -2197,7 +2197,7 @@
 }
 
 void MessageDifferencer::StreamReporter::ReportUnknownFieldIgnored(
-    const Message& message1, const Message& message2,
+    const Message& /*message1*/, const Message& /*message2*/,
     const std::vector<SpecificField>& field_path) {
   printer_->Print("ignored: ");
   PrintPath(field_path, true);
diff --git a/src/google/protobuf/wire_format_lite.cc b/src/google/protobuf/wire_format_lite.cc
index 04251d3..5a2ee29 100644
--- a/src/google/protobuf/wire_format_lite.cc
+++ b/src/google/protobuf/wire_format_lite.cc
@@ -53,7 +53,7 @@
 namespace protobuf {
 namespace internal {
 
-#if !defined(_MSC_VER) || _MSC_VER >= 1900
+#if !defined(_MSC_VER) || (_MSC_VER >= 1900 && _MSC_VER < 1912)
 // Old version of MSVC doesn't like definitions of inline constants, GCC
 // requires them.
 const int WireFormatLite::kMessageSetItemStartTag;
@@ -528,7 +528,7 @@
 }
 
 void WireFormatLite::WriteSubMessageMaybeToArray(
-    int size, const MessageLite& value, io::CodedOutputStream* output) {
+    int /*size*/, const MessageLite& value, io::CodedOutputStream* output) {
   output->SetCur(value._InternalSerialize(output->Cur(), output->EpsCopy()));
 }
 
@@ -571,7 +571,7 @@
 }
 
 void PrintUTF8ErrorLog(const char* field_name, const char* operation_str,
-                       bool emit_stacktrace) {
+                       bool /*emit_stacktrace*/) {
   std::string stacktrace;
   std::string quoted_field_name = "";
   if (field_name != nullptr) {
diff --git a/tests.sh b/tests.sh
index 1955b7b..5dc2eb6 100755
--- a/tests.sh
+++ b/tests.sh
@@ -112,8 +112,8 @@
   virtualenv --no-site-packages venv
   source venv/bin/activate
   pushd python
-  python setup.py clean build sdist
-  pip install dist/protobuf-*.tar.gz
+  python3 setup.py clean build sdist
+  pip3 install dist/protobuf-*.tar.gz
   popd
   deactivate
   rm -rf python/venv
diff --git a/toolchain/BUILD b/toolchain/BUILD
new file mode 100644
index 0000000..0f246dd
--- /dev/null
+++ b/toolchain/BUILD
@@ -0,0 +1,84 @@
+load(":cc_toolchain_config.bzl", "cc_toolchain_config")
+
+package(default_visibility = ["//visibility:public"])
+
+filegroup(name = "empty")
+
+LINUX_TOOLCHAINS = {
+    "linux-aarch64": "cc-compiler-linux-aarch64",
+    "linux-ppcle": "cc-compiler-linux-ppcle",
+    "linux-s390x": "cc-compiler-linux-s390x",
+    "linux-x86_32": "cc-compiler-linux-x86_32",
+    "linux-x86_64": "cc-compiler-linux-x86_64",
+}
+
+cc_toolchain_suite(
+    name = "clang_suite",
+    toolchains = LINUX_TOOLCHAINS
+)
+
+[
+    cc_toolchain(
+        name = toolchain,
+        all_files = ":empty",
+        compiler_files = ":empty",
+        dwp_files = ":empty",
+        dynamic_runtime_lib = ":empty",
+        linker_files = ":empty",
+        objcopy_files = ":empty",
+        output_licenses = ["restricted"],
+        static_runtime_lib = ":empty",
+        strip_files = ":empty",
+        toolchain_config = ":" + cpu + "-config",
+        toolchain_identifier = toolchain,
+    )
+    for cpu, toolchain in LINUX_TOOLCHAINS.items()
+]
+
+cc_toolchain_config(
+    name = "linux-aarch64-config",
+    bit_flag = "-m64",
+    include_flag = "-I/usr/aarch64-linux-gnu/include/c++/10/aarch64-linux-gnu/",
+    target_cpu = "aarch64",
+    target_full_name = "aarch64-linux-gnu",
+    toolchain_dir = "/usr/aarch64-linux-gnu/include",
+    toolchain_name = "linux_aarch64",
+)
+
+cc_toolchain_config(
+    name = "linux-ppcle-config",
+    bit_flag = "-m64",
+    include_flag = "-I/usr/powerpc64le-linux-gnu/include/c++/10/powerpc64le-linux-gnu/",
+    target_cpu = "ppc64",
+    target_full_name = "powerpc64le-linux-gnu",
+    toolchain_dir = "/usr/powerpc64le-linux-gnu/include",
+    toolchain_name = "linux_ppcle",
+)
+
+cc_toolchain_config(
+    name = "linux-s390x-config",
+    bit_flag = "-m64",
+    include_flag = "-I/usr/s390x-linux-gnu/include/c++/10/s390x-linux-gnu/",
+    target_cpu = "systemz",
+    target_full_name = "s390x-linux-gnu",
+    toolchain_dir = "/usr/s390x-linux-gnu/include",
+    toolchain_name = "linux_s390x",
+)
+
+cc_toolchain_config(
+    name = "linux-x86_32-config",
+    bit_flag = "-m32",
+    target_cpu = "x86_32",
+    target_full_name = "i386-linux-gnu",
+    toolchain_dir = "/usr/include/x86_32-linux-gnu",
+    toolchain_name = "linux_x86_32",
+)
+
+cc_toolchain_config(
+    name = "linux-x86_64-config",
+    bit_flag = "-m64",
+    target_cpu = "x86_64",
+    target_full_name = "x86_64-linux-gnu",
+    toolchain_dir = "/usr/include/x86_64-linux-gnu",
+    toolchain_name = "linux_x86_64",
+)
diff --git a/toolchain/cc_toolchain_config.bzl b/toolchain/cc_toolchain_config.bzl
new file mode 100644
index 0000000..eb730a9
--- /dev/null
+++ b/toolchain/cc_toolchain_config.bzl
@@ -0,0 +1,148 @@
+load("@bazel_tools//tools/build_defs/cc:action_names.bzl", "ACTION_NAMES")
+load(
+    "@bazel_tools//tools/cpp:cc_toolchain_config_lib.bzl",
+    "feature",
+    "flag_group",
+    "flag_set",
+    "tool",
+    "tool_path",
+)
+
+all_link_actions = [
+    ACTION_NAMES.cpp_link_executable,
+    ACTION_NAMES.cpp_link_dynamic_library,
+    ACTION_NAMES.cpp_link_nodeps_dynamic_library,
+]
+
+all_compile_actions = [
+    ACTION_NAMES.assemble,
+    ACTION_NAMES.preprocess_assemble,
+    ACTION_NAMES.linkstamp_compile,
+    ACTION_NAMES.c_compile,
+    ACTION_NAMES.cpp_compile,
+    ACTION_NAMES.cpp_header_parsing,
+    ACTION_NAMES.cpp_module_codegen,
+    ACTION_NAMES.cpp_module_compile,
+    ACTION_NAMES.clif_match,
+    ACTION_NAMES.lto_backend,
+]
+
+def _impl(ctx):
+  tool_paths = [
+      tool_path(
+          name = "gcc",
+          path = "/usr/local/bin/clang",
+      ),
+      tool_path(
+          name = "ld",
+          path = "/usr/bin/ld",
+      ),
+      tool_path(
+          name = "ar",
+          path = "/usr/bin/llvm-ar-11",
+      ),
+      tool_path(
+          name = "compat-ld",
+          path = "/usr/bin/ld",
+      ),
+      tool_path(
+          name = "cpp",
+          path = "/usr/bin/clang-cpp",
+      ),
+      tool_path(
+          name = "dwp",
+          path = "/usr/bin/llvm-dwp",
+      ),
+      tool_path(
+          name = "gcov",
+          path = "/usr/bin/llvm-profdata",
+      ),
+      tool_path(
+          name = "nm",
+          path = "/usr/bin/llvm-nm",
+      ),
+      tool_path(
+          name = "objcopy",
+          path = "/usr/bin/llvm-objcopy",
+      ),
+      tool_path(
+          name = "objdump",
+          path = "/usr/bin/llvm-objdump",
+      ),
+      tool_path(
+          name = "strip",
+          path = "/usr/bin/llvm-strip",
+      ),
+  ]
+
+  linker_flags = feature(
+      name = "default_linker_flags",
+      enabled = True,
+      flag_sets = [
+          flag_set(
+              actions = all_link_actions,
+              flag_groups = [
+                  flag_group(
+                      flags = [
+                          "-lstdc++",
+                          "--target=" + ctx.attr.target_full_name,
+                      ],
+                  ),
+              ],
+          ),
+      ],
+  )
+  compiler_flags = feature(
+      name = "default_compile_flags",
+      enabled = True,
+      flag_sets = [
+          flag_set(
+              actions = all_compile_actions,
+              flag_groups = [
+                  flag_group(
+                      flags = [
+                          ctx.attr.bit_flag,
+                          "-Wall",
+                          "-no-canonical-prefixes",
+                          "--target=" + ctx.attr.target_full_name,
+                          "-isystem",
+                          ctx.attr.toolchain_dir,
+                          ctx.attr.include_flag,
+                      ],
+                  ),
+              ],
+          ),
+      ],
+  )
+
+  return cc_common.create_cc_toolchain_config_info(
+      abi_libc_version = ctx.attr.target_cpu,
+      abi_version = ctx.attr.target_cpu,
+      ctx = ctx,
+      compiler = "clang",
+      cxx_builtin_include_directories = [
+          ctx.attr.toolchain_dir,
+          "/usr/include",
+          "/usr/lib/clang",
+      ],
+      features = [linker_flags, compiler_flags],
+      host_system_name = "local",
+      target_cpu = ctx.attr.target_cpu,
+      target_libc = ctx.attr.target_cpu,
+      target_system_name = ctx.attr.target_full_name,
+      toolchain_identifier = ctx.attr.toolchain_name,
+      tool_paths = tool_paths,
+  )
+
+cc_toolchain_config = rule(
+    implementation = _impl,
+    attrs = {
+        "bit_flag": attr.string(mandatory = True, values = ["-m32", "-m64"]),
+        "include_flag": attr.string(mandatory = False),
+        "target_cpu": attr.string(mandatory = True, values = ["aarch64", "ppc64", "systemz", "x86_32", "x86_64"]),
+        "target_full_name": attr.string(mandatory = True),
+        "toolchain_dir": attr.string(mandatory = True),
+        "toolchain_name": attr.string(mandatory = True),
+    },
+    provides = [CcToolchainConfigInfo],
+)
diff --git a/toolchain/toolchains.bazelrc b/toolchain/toolchains.bazelrc
new file mode 100644
index 0000000..1c17f55
--- /dev/null
+++ b/toolchain/toolchains.bazelrc
@@ -0,0 +1,8 @@
+build:cross_config --crosstool_top=//toolchain:clang_suite
+build:cross_config --host_crosstool_top=@bazel_tools//tools/cpp:toolchain
+
+build:linux-aarch64 --config=cross_config --cpu=linux-aarch64
+build:linux-ppcle --config=cross_config --cpu=linux-ppcle
+build:linux-s390x --config=cross_config --cpu=linux-s390x
+build:linux-x86_32 --config=cross_config --cpu=linux-x86_32
+build:linux-x86_64 --config=cross_config --cpu=linux-x86_64