Add new features to io::Printer for improving compactness of output:

- Custom "chomp the next ;"-like behavior for all variable substitutions.
  The precise behavior of whitespace after a $...$; has also been changed, to
  produce more compact output.
- Non-emitted comments, which allow comments to exist inline in raw
  strings that will not be emitted in the final output.
- Prevent recursion when evaluating callback substitutions.

PiperOrigin-RevId: 477475045
diff --git a/objectivec/GPBAny.pbobjc.h b/objectivec/GPBAny.pbobjc.h
index bb19e5f..a61df0a 100644
--- a/objectivec/GPBAny.pbobjc.h
+++ b/objectivec/GPBAny.pbobjc.h
@@ -5,7 +5,6 @@
 #import "GPBDescriptor.h"
 #import "GPBMessage.h"
 #import "GPBRootObject.h"
-
 #if GOOGLE_PROTOBUF_OBJC_VERSION < 30005
 #error This file was generated by a newer version of protoc which is incompatible with your Protocol Buffer library sources.
 #endif
diff --git a/objectivec/GPBAny.pbobjc.m b/objectivec/GPBAny.pbobjc.m
index 5091217..a282ae9 100644
--- a/objectivec/GPBAny.pbobjc.m
+++ b/objectivec/GPBAny.pbobjc.m
@@ -4,21 +4,17 @@
 
 #import "GPBProtocolBuffers_RuntimeSupport.h"
 #import "GPBAny.pbobjc.h"
-
 // @@protoc_insertion_point(imports)
 
 #pragma clang diagnostic push
 #pragma clang diagnostic ignored "-Wdeprecated-declarations"
-
 #pragma mark - GPBAnyRoot
 
 @implementation GPBAnyRoot
 
 // No extensions in the file and no imports, so no need to generate
 // +extensionRegistry.
-
 @end
-
 #pragma mark - GPBAnyRoot_FileDescriptor
 
 static GPBFileDescriptor *GPBAnyRoot_FileDescriptor(void) {
@@ -95,7 +91,6 @@
 
 @end
 
-
 #pragma clang diagnostic pop
 
 // @@protoc_insertion_point(global_scope)
diff --git a/objectivec/GPBApi.pbobjc.h b/objectivec/GPBApi.pbobjc.h
index bbae2ed..73ed270 100644
--- a/objectivec/GPBApi.pbobjc.h
+++ b/objectivec/GPBApi.pbobjc.h
@@ -7,7 +7,6 @@
 #import "GPBRootObject.h"
 #import "GPBSourceContext.pbobjc.h"
 #import "GPBType.pbobjc.h"
-
 #if GOOGLE_PROTOBUF_OBJC_VERSION < 30005
 #error This file was generated by a newer version of protoc which is incompatible with your Protocol Buffer library sources.
 #endif
diff --git a/objectivec/GPBApi.pbobjc.m b/objectivec/GPBApi.pbobjc.m
index 33ca398..5dc4298 100644
--- a/objectivec/GPBApi.pbobjc.m
+++ b/objectivec/GPBApi.pbobjc.m
@@ -4,13 +4,11 @@
 
 #import "GPBProtocolBuffers_RuntimeSupport.h"
 #import "GPBApi.pbobjc.h"
-
 // @@protoc_insertion_point(imports)
 
 #pragma clang diagnostic push
 #pragma clang diagnostic ignored "-Wdeprecated-declarations"
 #pragma clang diagnostic ignored "-Wdollar-in-identifier-extension"
-
 #pragma mark - Objective C Class declarations
 // Forward declarations of Objective C classes that we can use as
 // static values in struct initializers.
@@ -26,9 +24,7 @@
 
 // No extensions in the file and none of the imports (direct or indirect)
 // defined extensions, so no need to generate +extensionRegistry.
-
 @end
-
 #pragma mark - GPBApiRoot_FileDescriptor
 
 static GPBFileDescriptor *GPBApiRoot_FileDescriptor(void) {
@@ -349,7 +345,6 @@
 
 @end
 
-
 #pragma clang diagnostic pop
 
 // @@protoc_insertion_point(global_scope)
diff --git a/objectivec/GPBDuration.pbobjc.h b/objectivec/GPBDuration.pbobjc.h
index 05c63d8..2472a09 100644
--- a/objectivec/GPBDuration.pbobjc.h
+++ b/objectivec/GPBDuration.pbobjc.h
@@ -5,7 +5,6 @@
 #import "GPBDescriptor.h"
 #import "GPBMessage.h"
 #import "GPBRootObject.h"
-
 #if GOOGLE_PROTOBUF_OBJC_VERSION < 30005
 #error This file was generated by a newer version of protoc which is incompatible with your Protocol Buffer library sources.
 #endif
diff --git a/objectivec/GPBDuration.pbobjc.m b/objectivec/GPBDuration.pbobjc.m
index c3edc24..8110772 100644
--- a/objectivec/GPBDuration.pbobjc.m
+++ b/objectivec/GPBDuration.pbobjc.m
@@ -4,21 +4,17 @@
 
 #import "GPBProtocolBuffers_RuntimeSupport.h"
 #import "GPBDuration.pbobjc.h"
-
 // @@protoc_insertion_point(imports)
 
 #pragma clang diagnostic push
 #pragma clang diagnostic ignored "-Wdeprecated-declarations"
-
 #pragma mark - GPBDurationRoot
 
 @implementation GPBDurationRoot
 
 // No extensions in the file and no imports, so no need to generate
 // +extensionRegistry.
-
 @end
-
 #pragma mark - GPBDurationRoot_FileDescriptor
 
 static GPBFileDescriptor *GPBDurationRoot_FileDescriptor(void) {
@@ -90,7 +86,6 @@
 
 @end
 
-
 #pragma clang diagnostic pop
 
 // @@protoc_insertion_point(global_scope)
diff --git a/objectivec/GPBEmpty.pbobjc.h b/objectivec/GPBEmpty.pbobjc.h
index 3de240d..adc2e74 100644
--- a/objectivec/GPBEmpty.pbobjc.h
+++ b/objectivec/GPBEmpty.pbobjc.h
@@ -5,7 +5,6 @@
 #import "GPBDescriptor.h"
 #import "GPBMessage.h"
 #import "GPBRootObject.h"
-
 #if GOOGLE_PROTOBUF_OBJC_VERSION < 30005
 #error This file was generated by a newer version of protoc which is incompatible with your Protocol Buffer library sources.
 #endif
diff --git a/objectivec/GPBEmpty.pbobjc.m b/objectivec/GPBEmpty.pbobjc.m
index e5f3fd0..67275bb 100644
--- a/objectivec/GPBEmpty.pbobjc.m
+++ b/objectivec/GPBEmpty.pbobjc.m
@@ -4,21 +4,17 @@
 
 #import "GPBProtocolBuffers_RuntimeSupport.h"
 #import "GPBEmpty.pbobjc.h"
-
 // @@protoc_insertion_point(imports)
 
 #pragma clang diagnostic push
 #pragma clang diagnostic ignored "-Wdeprecated-declarations"
-
 #pragma mark - GPBEmptyRoot
 
 @implementation GPBEmptyRoot
 
 // No extensions in the file and no imports, so no need to generate
 // +extensionRegistry.
-
 @end
-
 #pragma mark - GPBEmptyRoot_FileDescriptor
 
 static GPBFileDescriptor *GPBEmptyRoot_FileDescriptor(void) {
@@ -66,7 +62,6 @@
 
 @end
 
-
 #pragma clang diagnostic pop
 
 // @@protoc_insertion_point(global_scope)
diff --git a/objectivec/GPBFieldMask.pbobjc.h b/objectivec/GPBFieldMask.pbobjc.h
index 3e7d349..ca0ba5d 100644
--- a/objectivec/GPBFieldMask.pbobjc.h
+++ b/objectivec/GPBFieldMask.pbobjc.h
@@ -5,7 +5,6 @@
 #import "GPBDescriptor.h"
 #import "GPBMessage.h"
 #import "GPBRootObject.h"
-
 #if GOOGLE_PROTOBUF_OBJC_VERSION < 30005
 #error This file was generated by a newer version of protoc which is incompatible with your Protocol Buffer library sources.
 #endif
diff --git a/objectivec/GPBFieldMask.pbobjc.m b/objectivec/GPBFieldMask.pbobjc.m
index 83edddf..b008f61 100644
--- a/objectivec/GPBFieldMask.pbobjc.m
+++ b/objectivec/GPBFieldMask.pbobjc.m
@@ -4,21 +4,17 @@
 
 #import "GPBProtocolBuffers_RuntimeSupport.h"
 #import "GPBFieldMask.pbobjc.h"
-
 // @@protoc_insertion_point(imports)
 
 #pragma clang diagnostic push
 #pragma clang diagnostic ignored "-Wdeprecated-declarations"
-
 #pragma mark - GPBFieldMaskRoot
 
 @implementation GPBFieldMaskRoot
 
 // No extensions in the file and no imports, so no need to generate
 // +extensionRegistry.
-
 @end
-
 #pragma mark - GPBFieldMaskRoot_FileDescriptor
 
 static GPBFileDescriptor *GPBFieldMaskRoot_FileDescriptor(void) {
@@ -79,7 +75,6 @@
 
 @end
 
-
 #pragma clang diagnostic pop
 
 // @@protoc_insertion_point(global_scope)
diff --git a/objectivec/GPBSourceContext.pbobjc.h b/objectivec/GPBSourceContext.pbobjc.h
index a55939a..cb379a5 100644
--- a/objectivec/GPBSourceContext.pbobjc.h
+++ b/objectivec/GPBSourceContext.pbobjc.h
@@ -5,7 +5,6 @@
 #import "GPBDescriptor.h"
 #import "GPBMessage.h"
 #import "GPBRootObject.h"
-
 #if GOOGLE_PROTOBUF_OBJC_VERSION < 30005
 #error This file was generated by a newer version of protoc which is incompatible with your Protocol Buffer library sources.
 #endif
diff --git a/objectivec/GPBSourceContext.pbobjc.m b/objectivec/GPBSourceContext.pbobjc.m
index cc8bb0b..a70cccd 100644
--- a/objectivec/GPBSourceContext.pbobjc.m
+++ b/objectivec/GPBSourceContext.pbobjc.m
@@ -4,21 +4,17 @@
 
 #import "GPBProtocolBuffers_RuntimeSupport.h"
 #import "GPBSourceContext.pbobjc.h"
-
 // @@protoc_insertion_point(imports)
 
 #pragma clang diagnostic push
 #pragma clang diagnostic ignored "-Wdeprecated-declarations"
-
 #pragma mark - GPBSourceContextRoot
 
 @implementation GPBSourceContextRoot
 
 // No extensions in the file and no imports, so no need to generate
 // +extensionRegistry.
-
 @end
-
 #pragma mark - GPBSourceContextRoot_FileDescriptor
 
 static GPBFileDescriptor *GPBSourceContextRoot_FileDescriptor(void) {
@@ -79,7 +75,6 @@
 
 @end
 
-
 #pragma clang diagnostic pop
 
 // @@protoc_insertion_point(global_scope)
diff --git a/objectivec/GPBStruct.pbobjc.h b/objectivec/GPBStruct.pbobjc.h
index 9bedafc..3f009d9 100644
--- a/objectivec/GPBStruct.pbobjc.h
+++ b/objectivec/GPBStruct.pbobjc.h
@@ -5,7 +5,6 @@
 #import "GPBDescriptor.h"
 #import "GPBMessage.h"
 #import "GPBRootObject.h"
-
 #if GOOGLE_PROTOBUF_OBJC_VERSION < 30005
 #error This file was generated by a newer version of protoc which is incompatible with your Protocol Buffer library sources.
 #endif
diff --git a/objectivec/GPBStruct.pbobjc.m b/objectivec/GPBStruct.pbobjc.m
index 9aa14da..2538a3e 100644
--- a/objectivec/GPBStruct.pbobjc.m
+++ b/objectivec/GPBStruct.pbobjc.m
@@ -4,7 +4,6 @@
 
 #import "GPBProtocolBuffers_RuntimeSupport.h"
 #import "GPBStruct.pbobjc.h"
-
 #import <stdatomic.h>
 
 // @@protoc_insertion_point(imports)
@@ -13,7 +12,6 @@
 #pragma clang diagnostic ignored "-Wdeprecated-declarations"
 #pragma clang diagnostic ignored "-Wdirect-ivar-access"
 #pragma clang diagnostic ignored "-Wdollar-in-identifier-extension"
-
 #pragma mark - Objective C Class declarations
 // Forward declarations of Objective C classes that we can use as
 // static values in struct initializers.
@@ -28,9 +26,7 @@
 
 // No extensions in the file and no imports, so no need to generate
 // +extensionRegistry.
-
 @end
-
 #pragma mark - GPBStructRoot_FileDescriptor
 
 static GPBFileDescriptor *GPBStructRoot_FileDescriptor(void) {
@@ -293,7 +289,6 @@
 
 @end
 
-
 #pragma clang diagnostic pop
 
 // @@protoc_insertion_point(global_scope)
diff --git a/objectivec/GPBTimestamp.pbobjc.h b/objectivec/GPBTimestamp.pbobjc.h
index a374a0a..fbc249c 100644
--- a/objectivec/GPBTimestamp.pbobjc.h
+++ b/objectivec/GPBTimestamp.pbobjc.h
@@ -5,7 +5,6 @@
 #import "GPBDescriptor.h"
 #import "GPBMessage.h"
 #import "GPBRootObject.h"
-
 #if GOOGLE_PROTOBUF_OBJC_VERSION < 30005
 #error This file was generated by a newer version of protoc which is incompatible with your Protocol Buffer library sources.
 #endif
diff --git a/objectivec/GPBTimestamp.pbobjc.m b/objectivec/GPBTimestamp.pbobjc.m
index 81bdcd9..7446610 100644
--- a/objectivec/GPBTimestamp.pbobjc.m
+++ b/objectivec/GPBTimestamp.pbobjc.m
@@ -4,21 +4,17 @@
 
 #import "GPBProtocolBuffers_RuntimeSupport.h"
 #import "GPBTimestamp.pbobjc.h"
-
 // @@protoc_insertion_point(imports)
 
 #pragma clang diagnostic push
 #pragma clang diagnostic ignored "-Wdeprecated-declarations"
-
 #pragma mark - GPBTimestampRoot
 
 @implementation GPBTimestampRoot
 
 // No extensions in the file and no imports, so no need to generate
 // +extensionRegistry.
-
 @end
-
 #pragma mark - GPBTimestampRoot_FileDescriptor
 
 static GPBFileDescriptor *GPBTimestampRoot_FileDescriptor(void) {
@@ -90,7 +86,6 @@
 
 @end
 
-
 #pragma clang diagnostic pop
 
 // @@protoc_insertion_point(global_scope)
diff --git a/objectivec/GPBType.pbobjc.h b/objectivec/GPBType.pbobjc.h
index 6eb1d04..ebf05ff 100644
--- a/objectivec/GPBType.pbobjc.h
+++ b/objectivec/GPBType.pbobjc.h
@@ -7,7 +7,6 @@
 #import "GPBRootObject.h"
 #import "GPBAny.pbobjc.h"
 #import "GPBSourceContext.pbobjc.h"
-
 #if GOOGLE_PROTOBUF_OBJC_VERSION < 30005
 #error This file was generated by a newer version of protoc which is incompatible with your Protocol Buffer library sources.
 #endif
diff --git a/objectivec/GPBType.pbobjc.m b/objectivec/GPBType.pbobjc.m
index 7a4b657..a4d37df 100644
--- a/objectivec/GPBType.pbobjc.m
+++ b/objectivec/GPBType.pbobjc.m
@@ -4,7 +4,6 @@
 
 #import "GPBProtocolBuffers_RuntimeSupport.h"
 #import "GPBType.pbobjc.h"
-
 #import <stdatomic.h>
 
 // @@protoc_insertion_point(imports)
@@ -12,7 +11,6 @@
 #pragma clang diagnostic push
 #pragma clang diagnostic ignored "-Wdeprecated-declarations"
 #pragma clang diagnostic ignored "-Wdollar-in-identifier-extension"
-
 #pragma mark - Objective C Class declarations
 // Forward declarations of Objective C classes that we can use as
 // static values in struct initializers.
@@ -29,9 +27,7 @@
 
 // No extensions in the file and none of the imports (direct or indirect)
 // defined extensions, so no need to generate +extensionRegistry.
-
 @end
-
 #pragma mark - GPBTypeRoot_FileDescriptor
 
 static GPBFileDescriptor *GPBTypeRoot_FileDescriptor(void) {
@@ -707,7 +703,6 @@
 
 @end
 
-
 #pragma clang diagnostic pop
 
 // @@protoc_insertion_point(global_scope)
diff --git a/objectivec/GPBWrappers.pbobjc.h b/objectivec/GPBWrappers.pbobjc.h
index 11e220b..52dc884 100644
--- a/objectivec/GPBWrappers.pbobjc.h
+++ b/objectivec/GPBWrappers.pbobjc.h
@@ -5,7 +5,6 @@
 #import "GPBDescriptor.h"
 #import "GPBMessage.h"
 #import "GPBRootObject.h"
-
 #if GOOGLE_PROTOBUF_OBJC_VERSION < 30005
 #error This file was generated by a newer version of protoc which is incompatible with your Protocol Buffer library sources.
 #endif
diff --git a/objectivec/GPBWrappers.pbobjc.m b/objectivec/GPBWrappers.pbobjc.m
index 817a74c..03a55cc 100644
--- a/objectivec/GPBWrappers.pbobjc.m
+++ b/objectivec/GPBWrappers.pbobjc.m
@@ -4,21 +4,17 @@
 
 #import "GPBProtocolBuffers_RuntimeSupport.h"
 #import "GPBWrappers.pbobjc.h"
-
 // @@protoc_insertion_point(imports)
 
 #pragma clang diagnostic push
 #pragma clang diagnostic ignored "-Wdeprecated-declarations"
-
 #pragma mark - GPBWrappersRoot
 
 @implementation GPBWrappersRoot
 
 // No extensions in the file and no imports, so no need to generate
 // +extensionRegistry.
-
 @end
-
 #pragma mark - GPBWrappersRoot_FileDescriptor
 
 static GPBFileDescriptor *GPBWrappersRoot_FileDescriptor(void) {
@@ -438,7 +434,6 @@
 
 @end
 
-
 #pragma clang diagnostic pop
 
 // @@protoc_insertion_point(global_scope)
diff --git a/src/google/protobuf/compiler/command_line_interface.cc b/src/google/protobuf/compiler/command_line_interface.cc
index 6a44b04..f31b31a 100644
--- a/src/google/protobuf/compiler/command_line_interface.cc
+++ b/src/google/protobuf/compiler/command_line_interface.cc
@@ -786,6 +786,9 @@
 CommandLineInterface::MemoryOutputStream::~MemoryOutputStream() {
   // Make sure all data has been written.
   inner_.reset();
+  // DO NOT SUBMIT
+  // std::cerr << "## wrote " << filename_ << "\n";
+  // std::cerr << data_ << "\n###\n";
 
   // Insert into the directory.
   auto pair = directory_->files_.insert({filename_, ""});
diff --git a/src/google/protobuf/compiler/cpp/message.cc b/src/google/protobuf/compiler/cpp/message.cc
index 58beb66..7b3c1c0 100644
--- a/src/google/protobuf/compiler/cpp/message.cc
+++ b/src/google/protobuf/compiler/cpp/message.cc
@@ -2319,7 +2319,7 @@
     for (int i = 0; i < has_bit_indices_.size(); i++) {
       const std::string index =
           has_bit_indices_[i] >= 0 ? absl::StrCat(has_bit_indices_[i]) : "~0u";
-      format("$1$,\n", index);
+      format("$1$, // ???\n", index);
     }
   }
   if (!inlined_string_indices_.empty()) {
diff --git a/src/google/protobuf/compiler/plugin.pb.cc b/src/google/protobuf/compiler/plugin.pb.cc
index f77a0e3..cc66803 100644
--- a/src/google/protobuf/compiler/plugin.pb.cc
+++ b/src/google/protobuf/compiler/plugin.pb.cc
@@ -111,10 +111,10 @@
     PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::compiler::Version, _impl_.minor_),
     PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::compiler::Version, _impl_.patch_),
     PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::compiler::Version, _impl_.suffix_),
-    1,
-    2,
-    3,
-    0,
+    1, // ???
+    2, // ???
+    3, // ???
+    0, // ???
     PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::compiler::CodeGeneratorRequest, _impl_._has_bits_),
     PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::compiler::CodeGeneratorRequest, _internal_metadata_),
     ~0u,  // no _extensions_
@@ -127,10 +127,10 @@
     PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::compiler::CodeGeneratorRequest, _impl_.parameter_),
     PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::compiler::CodeGeneratorRequest, _impl_.proto_file_),
     PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::compiler::CodeGeneratorRequest, _impl_.compiler_version_),
-    ~0u,
-    0,
-    ~0u,
-    1,
+    ~0u, // ???
+    0, // ???
+    ~0u, // ???
+    1, // ???
     PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::compiler::CodeGeneratorResponse_File, _impl_._has_bits_),
     PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::compiler::CodeGeneratorResponse_File, _internal_metadata_),
     ~0u,  // no _extensions_
@@ -143,10 +143,10 @@
     PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::compiler::CodeGeneratorResponse_File, _impl_.insertion_point_),
     PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::compiler::CodeGeneratorResponse_File, _impl_.content_),
     PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::compiler::CodeGeneratorResponse_File, _impl_.generated_code_info_),
-    0,
-    1,
-    2,
-    3,
+    0, // ???
+    1, // ???
+    2, // ???
+    3, // ???
     PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::compiler::CodeGeneratorResponse, _impl_._has_bits_),
     PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::compiler::CodeGeneratorResponse, _internal_metadata_),
     ~0u,  // no _extensions_
@@ -158,9 +158,9 @@
     PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::compiler::CodeGeneratorResponse, _impl_.error_),
     PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::compiler::CodeGeneratorResponse, _impl_.supported_features_),
     PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::compiler::CodeGeneratorResponse, _impl_.file_),
-    0,
-    1,
-    ~0u,
+    0, // ???
+    1, // ???
+    ~0u, // ???
 };
 
 static const ::_pbi::MigrationSchema
@@ -262,7 +262,6 @@
 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 && _MSC_VER < 1912))
 // ===================================================================
diff --git a/src/google/protobuf/compiler/plugin.pb.h b/src/google/protobuf/compiler/plugin.pb.h
index c4fda8c..ef75749 100644
--- a/src/google/protobuf/compiler/plugin.pb.h
+++ b/src/google/protobuf/compiler/plugin.pb.h
@@ -37,7 +37,6 @@
 
 // Must be included last.
 #include "google/protobuf/port_def.inc"
-
 #define PROTOBUF_INTERNAL_EXPORT_google_2fprotobuf_2fcompiler_2fplugin_2eproto PROTOC_EXPORT
 #ifdef major
 #undef major
@@ -45,7 +44,6 @@
 #ifdef minor
 #undef minor
 #endif  // minor
-
 PROTOBUF_NAMESPACE_OPEN
 namespace internal {
 class AnyMetadata;
@@ -82,7 +80,6 @@
 template <>
 PROTOC_EXPORT ::PROTOBUF_NAMESPACE_ID::compiler::Version* Arena::CreateMaybeMessage<::PROTOBUF_NAMESPACE_ID::compiler::Version>(Arena*);
 PROTOBUF_NAMESPACE_CLOSE
-
 PROTOBUF_NAMESPACE_OPEN
 namespace compiler {
 enum CodeGeneratorResponse_Feature : int {
@@ -113,7 +110,6 @@
   return ::PROTOBUF_NAMESPACE_ID::internal::ParseNamedEnum<CodeGeneratorResponse_Feature>(
       CodeGeneratorResponse_Feature_descriptor(), name, value);
 }
-
 // ===================================================================
 
 
@@ -966,11 +962,10 @@
   union { Impl_ _impl_; };
   friend struct ::TableStruct_google_2fprotobuf_2fcompiler_2fplugin_2eproto;
 };
+
 // ===================================================================
 
 
-
-
 // ===================================================================
 
 
@@ -1796,12 +1791,10 @@
 #ifdef __GNUC__
 #pragma GCC diagnostic pop
 #endif  // __GNUC__
-
 // @@protoc_insertion_point(namespace_scope)
 }  // namespace compiler
 PROTOBUF_NAMESPACE_CLOSE
 
-
 PROTOBUF_NAMESPACE_OPEN
 
 template <>
@@ -1812,9 +1805,7 @@
 }
 
 PROTOBUF_NAMESPACE_CLOSE
-
 // @@protoc_insertion_point(global_scope)
 
 #include "google/protobuf/port_undef.inc"
-
 #endif  // GOOGLE_PROTOBUF_INCLUDED_google_2fprotobuf_2fcompiler_2fplugin_2eproto_2epb_2eh
diff --git a/src/google/protobuf/descriptor.pb.cc b/src/google/protobuf/descriptor.pb.cc
index 6b750b1..1dccfa3 100644
--- a/src/google/protobuf/descriptor.pb.cc
+++ b/src/google/protobuf/descriptor.pb.cc
@@ -569,19 +569,19 @@
     PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::FileDescriptorProto, _impl_.source_code_info_),
     PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::FileDescriptorProto, _impl_.syntax_),
     PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::FileDescriptorProto, _impl_.edition_),
-    0,
-    1,
-    ~0u,
-    ~0u,
-    ~0u,
-    ~0u,
-    ~0u,
-    ~0u,
-    ~0u,
-    4,
-    5,
-    2,
-    3,
+    0, // ???
+    1, // ???
+    ~0u, // ???
+    ~0u, // ???
+    ~0u, // ???
+    ~0u, // ???
+    ~0u, // ???
+    ~0u, // ???
+    ~0u, // ???
+    4, // ???
+    5, // ???
+    2, // ???
+    3, // ???
     PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::DescriptorProto_ExtensionRange, _impl_._has_bits_),
     PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::DescriptorProto_ExtensionRange, _internal_metadata_),
     ~0u,  // no _extensions_
@@ -593,9 +593,9 @@
     PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::DescriptorProto_ExtensionRange, _impl_.start_),
     PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::DescriptorProto_ExtensionRange, _impl_.end_),
     PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::DescriptorProto_ExtensionRange, _impl_.options_),
-    1,
-    2,
-    0,
+    1, // ???
+    2, // ???
+    0, // ???
     PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::DescriptorProto_ReservedRange, _impl_._has_bits_),
     PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::DescriptorProto_ReservedRange, _internal_metadata_),
     ~0u,  // no _extensions_
@@ -606,8 +606,8 @@
     ~0u,  // no sizeof(Split)
     PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::DescriptorProto_ReservedRange, _impl_.start_),
     PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::DescriptorProto_ReservedRange, _impl_.end_),
-    0,
-    1,
+    0, // ???
+    1, // ???
     PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::DescriptorProto, _impl_._has_bits_),
     PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::DescriptorProto, _internal_metadata_),
     ~0u,  // no _extensions_
@@ -626,16 +626,16 @@
     PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::DescriptorProto, _impl_.options_),
     PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::DescriptorProto, _impl_.reserved_range_),
     PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::DescriptorProto, _impl_.reserved_name_),
-    0,
-    ~0u,
-    ~0u,
-    ~0u,
-    ~0u,
-    ~0u,
-    ~0u,
-    1,
-    ~0u,
-    ~0u,
+    0, // ???
+    ~0u, // ???
+    ~0u, // ???
+    ~0u, // ???
+    ~0u, // ???
+    ~0u, // ???
+    ~0u, // ???
+    1, // ???
+    ~0u, // ???
+    ~0u, // ???
     ~0u,  // no _has_bits_
     PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::ExtensionRangeOptions, _internal_metadata_),
     PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::ExtensionRangeOptions, _impl_._extensions_),
@@ -664,17 +664,17 @@
     PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::FieldDescriptorProto, _impl_.json_name_),
     PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::FieldDescriptorProto, _impl_.options_),
     PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::FieldDescriptorProto, _impl_.proto3_optional_),
-    0,
-    6,
-    9,
-    10,
-    2,
-    1,
-    3,
-    7,
-    4,
-    5,
-    8,
+    0, // ???
+    6, // ???
+    9, // ???
+    10, // ???
+    2, // ???
+    1, // ???
+    3, // ???
+    7, // ???
+    4, // ???
+    5, // ???
+    8, // ???
     PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::OneofDescriptorProto, _impl_._has_bits_),
     PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::OneofDescriptorProto, _internal_metadata_),
     ~0u,  // no _extensions_
@@ -685,8 +685,8 @@
     ~0u,  // no sizeof(Split)
     PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::OneofDescriptorProto, _impl_.name_),
     PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::OneofDescriptorProto, _impl_.options_),
-    0,
-    1,
+    0, // ???
+    1, // ???
     PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::EnumDescriptorProto_EnumReservedRange, _impl_._has_bits_),
     PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::EnumDescriptorProto_EnumReservedRange, _internal_metadata_),
     ~0u,  // no _extensions_
@@ -697,8 +697,8 @@
     ~0u,  // no sizeof(Split)
     PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::EnumDescriptorProto_EnumReservedRange, _impl_.start_),
     PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::EnumDescriptorProto_EnumReservedRange, _impl_.end_),
-    0,
-    1,
+    0, // ???
+    1, // ???
     PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::EnumDescriptorProto, _impl_._has_bits_),
     PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::EnumDescriptorProto, _internal_metadata_),
     ~0u,  // no _extensions_
@@ -712,11 +712,11 @@
     PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::EnumDescriptorProto, _impl_.options_),
     PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::EnumDescriptorProto, _impl_.reserved_range_),
     PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::EnumDescriptorProto, _impl_.reserved_name_),
-    0,
-    ~0u,
-    1,
-    ~0u,
-    ~0u,
+    0, // ???
+    ~0u, // ???
+    1, // ???
+    ~0u, // ???
+    ~0u, // ???
     PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::EnumValueDescriptorProto, _impl_._has_bits_),
     PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::EnumValueDescriptorProto, _internal_metadata_),
     ~0u,  // no _extensions_
@@ -728,9 +728,9 @@
     PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::EnumValueDescriptorProto, _impl_.name_),
     PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::EnumValueDescriptorProto, _impl_.number_),
     PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::EnumValueDescriptorProto, _impl_.options_),
-    0,
-    2,
-    1,
+    0, // ???
+    2, // ???
+    1, // ???
     PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::ServiceDescriptorProto, _impl_._has_bits_),
     PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::ServiceDescriptorProto, _internal_metadata_),
     ~0u,  // no _extensions_
@@ -742,9 +742,9 @@
     PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::ServiceDescriptorProto, _impl_.name_),
     PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::ServiceDescriptorProto, _impl_.method_),
     PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::ServiceDescriptorProto, _impl_.options_),
-    0,
-    ~0u,
-    1,
+    0, // ???
+    ~0u, // ???
+    1, // ???
     PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::MethodDescriptorProto, _impl_._has_bits_),
     PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::MethodDescriptorProto, _internal_metadata_),
     ~0u,  // no _extensions_
@@ -759,12 +759,12 @@
     PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::MethodDescriptorProto, _impl_.options_),
     PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::MethodDescriptorProto, _impl_.client_streaming_),
     PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::MethodDescriptorProto, _impl_.server_streaming_),
-    0,
-    1,
-    2,
-    3,
-    4,
-    5,
+    0, // ???
+    1, // ???
+    2, // ???
+    3, // ???
+    4, // ???
+    5, // ???
     PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::FileOptions, _impl_._has_bits_),
     PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::FileOptions, _internal_metadata_),
     PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::FileOptions, _impl_._extensions_),
@@ -794,27 +794,27 @@
     PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::FileOptions, _impl_.php_metadata_namespace_),
     PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::FileOptions, _impl_.ruby_package_),
     PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::FileOptions, _impl_.uninterpreted_option_),
-    0,
-    1,
-    10,
-    11,
-    12,
-    18,
-    2,
-    13,
-    14,
-    15,
-    16,
-    17,
-    19,
-    3,
-    4,
-    5,
-    6,
-    7,
-    8,
-    9,
-    ~0u,
+    0, // ???
+    1, // ???
+    10, // ???
+    11, // ???
+    12, // ???
+    18, // ???
+    2, // ???
+    13, // ???
+    14, // ???
+    15, // ???
+    16, // ???
+    17, // ???
+    19, // ???
+    3, // ???
+    4, // ???
+    5, // ???
+    6, // ???
+    7, // ???
+    8, // ???
+    9, // ???
+    ~0u, // ???
     PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::MessageOptions, _impl_._has_bits_),
     PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::MessageOptions, _internal_metadata_),
     PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::MessageOptions, _impl_._extensions_),
@@ -828,11 +828,11 @@
     PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::MessageOptions, _impl_.deprecated_),
     PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::MessageOptions, _impl_.map_entry_),
     PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::MessageOptions, _impl_.uninterpreted_option_),
-    0,
-    1,
-    2,
-    3,
-    ~0u,
+    0, // ???
+    1, // ???
+    2, // ???
+    3, // ???
+    ~0u, // ???
     PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::FieldOptions, _impl_._has_bits_),
     PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::FieldOptions, _internal_metadata_),
     PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::FieldOptions, _impl_._extensions_),
@@ -849,14 +849,14 @@
     PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::FieldOptions, _impl_.deprecated_),
     PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::FieldOptions, _impl_.weak_),
     PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::FieldOptions, _impl_.uninterpreted_option_),
-    0,
-    2,
-    1,
-    3,
-    4,
-    5,
-    6,
-    ~0u,
+    0, // ???
+    2, // ???
+    1, // ???
+    3, // ???
+    4, // ???
+    5, // ???
+    6, // ???
+    ~0u, // ???
     ~0u,  // no _has_bits_
     PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::OneofOptions, _internal_metadata_),
     PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::OneofOptions, _impl_._extensions_),
@@ -877,9 +877,9 @@
     PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::EnumOptions, _impl_.allow_alias_),
     PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::EnumOptions, _impl_.deprecated_),
     PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::EnumOptions, _impl_.uninterpreted_option_),
-    0,
-    1,
-    ~0u,
+    0, // ???
+    1, // ???
+    ~0u, // ???
     PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::EnumValueOptions, _impl_._has_bits_),
     PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::EnumValueOptions, _internal_metadata_),
     PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::EnumValueOptions, _impl_._extensions_),
@@ -890,8 +890,8 @@
     ~0u,  // no sizeof(Split)
     PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::EnumValueOptions, _impl_.deprecated_),
     PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::EnumValueOptions, _impl_.uninterpreted_option_),
-    0,
-    ~0u,
+    0, // ???
+    ~0u, // ???
     PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::ServiceOptions, _impl_._has_bits_),
     PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::ServiceOptions, _internal_metadata_),
     PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::ServiceOptions, _impl_._extensions_),
@@ -902,8 +902,8 @@
     ~0u,  // no sizeof(Split)
     PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::ServiceOptions, _impl_.deprecated_),
     PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::ServiceOptions, _impl_.uninterpreted_option_),
-    0,
-    ~0u,
+    0, // ???
+    ~0u, // ???
     PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::MethodOptions, _impl_._has_bits_),
     PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::MethodOptions, _internal_metadata_),
     PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::MethodOptions, _impl_._extensions_),
@@ -915,9 +915,9 @@
     PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::MethodOptions, _impl_.deprecated_),
     PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::MethodOptions, _impl_.idempotency_level_),
     PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::MethodOptions, _impl_.uninterpreted_option_),
-    0,
-    1,
-    ~0u,
+    0, // ???
+    1, // ???
+    ~0u, // ???
     PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::UninterpretedOption_NamePart, _impl_._has_bits_),
     PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::UninterpretedOption_NamePart, _internal_metadata_),
     ~0u,  // no _extensions_
@@ -928,8 +928,8 @@
     ~0u,  // no sizeof(Split)
     PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::UninterpretedOption_NamePart, _impl_.name_part_),
     PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::UninterpretedOption_NamePart, _impl_.is_extension_),
-    0,
-    1,
+    0, // ???
+    1, // ???
     PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::UninterpretedOption, _impl_._has_bits_),
     PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::UninterpretedOption, _internal_metadata_),
     ~0u,  // no _extensions_
@@ -945,13 +945,13 @@
     PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::UninterpretedOption, _impl_.double_value_),
     PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::UninterpretedOption, _impl_.string_value_),
     PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::UninterpretedOption, _impl_.aggregate_value_),
-    ~0u,
-    0,
-    3,
-    4,
-    5,
-    1,
-    2,
+    ~0u, // ???
+    0, // ???
+    3, // ???
+    4, // ???
+    5, // ???
+    1, // ???
+    2, // ???
     PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::SourceCodeInfo_Location, _impl_._has_bits_),
     PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::SourceCodeInfo_Location, _internal_metadata_),
     ~0u,  // no _extensions_
@@ -965,11 +965,11 @@
     PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::SourceCodeInfo_Location, _impl_.leading_comments_),
     PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::SourceCodeInfo_Location, _impl_.trailing_comments_),
     PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::SourceCodeInfo_Location, _impl_.leading_detached_comments_),
-    ~0u,
-    ~0u,
-    0,
-    1,
-    ~0u,
+    ~0u, // ???
+    ~0u, // ???
+    0, // ???
+    1, // ???
+    ~0u, // ???
     ~0u,  // no _has_bits_
     PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::SourceCodeInfo, _internal_metadata_),
     ~0u,  // no _extensions_
@@ -992,11 +992,11 @@
     PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::GeneratedCodeInfo_Annotation, _impl_.begin_),
     PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::GeneratedCodeInfo_Annotation, _impl_.end_),
     PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::GeneratedCodeInfo_Annotation, _impl_.semantic_),
-    ~0u,
-    0,
-    1,
-    2,
-    3,
+    ~0u, // ???
+    0, // ???
+    1, // ???
+    2, // ???
+    3, // ???
     ~0u,  // no _has_bits_
     PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::GeneratedCodeInfo, _internal_metadata_),
     ~0u,  // no _extensions_
@@ -1316,7 +1316,6 @@
 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 && _MSC_VER < 1912))
 const ::PROTOBUF_NAMESPACE_ID::EnumDescriptor* FieldDescriptorProto_Label_descriptor() {
@@ -1342,7 +1341,6 @@
 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 && _MSC_VER < 1912))
 const ::PROTOBUF_NAMESPACE_ID::EnumDescriptor* FileOptions_OptimizeMode_descriptor() {
@@ -1368,7 +1366,6 @@
 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 && _MSC_VER < 1912))
 const ::PROTOBUF_NAMESPACE_ID::EnumDescriptor* FieldOptions_CType_descriptor() {
@@ -1394,7 +1391,6 @@
 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 && _MSC_VER < 1912))
 const ::PROTOBUF_NAMESPACE_ID::EnumDescriptor* FieldOptions_JSType_descriptor() {
@@ -1420,7 +1416,6 @@
 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 && _MSC_VER < 1912))
 const ::PROTOBUF_NAMESPACE_ID::EnumDescriptor* MethodOptions_IdempotencyLevel_descriptor() {
@@ -1446,7 +1441,6 @@
 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 && _MSC_VER < 1912))
 const ::PROTOBUF_NAMESPACE_ID::EnumDescriptor* GeneratedCodeInfo_Annotation_Semantic_descriptor() {
@@ -1472,7 +1466,6 @@
 constexpr GeneratedCodeInfo_Annotation_Semantic GeneratedCodeInfo_Annotation::Semantic_MIN;
 constexpr GeneratedCodeInfo_Annotation_Semantic GeneratedCodeInfo_Annotation::Semantic_MAX;
 constexpr int GeneratedCodeInfo_Annotation::Semantic_ARRAYSIZE;
-
 #endif  // (__cplusplus < 201703) &&
         // (!defined(_MSC_VER) || (_MSC_VER >= 1900 && _MSC_VER < 1912))
 // ===================================================================
diff --git a/src/google/protobuf/descriptor.pb.h b/src/google/protobuf/descriptor.pb.h
index 40413f1..0d7471b 100644
--- a/src/google/protobuf/descriptor.pb.h
+++ b/src/google/protobuf/descriptor.pb.h
@@ -36,9 +36,7 @@
 
 // Must be included last.
 #include "google/protobuf/port_def.inc"
-
 #define PROTOBUF_INTERNAL_EXPORT_google_2fprotobuf_2fdescriptor_2eproto PROTOBUF_EXPORT
-
 PROTOBUF_NAMESPACE_OPEN
 namespace internal {
 class AnyMetadata;
@@ -188,7 +186,6 @@
 template <>
 PROTOBUF_EXPORT ::PROTOBUF_NAMESPACE_ID::UninterpretedOption_NamePart* Arena::CreateMaybeMessage<::PROTOBUF_NAMESPACE_ID::UninterpretedOption_NamePart>(Arena*);
 PROTOBUF_NAMESPACE_CLOSE
-
 PROTOBUF_NAMESPACE_OPEN
 enum FieldDescriptorProto_Type : int {
   FieldDescriptorProto_Type_TYPE_DOUBLE = 1,
@@ -408,7 +405,6 @@
   return ::PROTOBUF_NAMESPACE_ID::internal::ParseNamedEnum<GeneratedCodeInfo_Annotation_Semantic>(
       GeneratedCodeInfo_Annotation_Semantic_descriptor(), name, value);
 }
-
 // ===================================================================
 
 
@@ -8291,11 +8287,10 @@
   union { Impl_ _impl_; };
   friend struct ::TableStruct_google_2fprotobuf_2fdescriptor_2eproto;
 };
+
 // ===================================================================
 
 
-
-
 // ===================================================================
 
 
@@ -14240,11 +14235,9 @@
 #ifdef __GNUC__
 #pragma GCC diagnostic pop
 #endif  // __GNUC__
-
 // @@protoc_insertion_point(namespace_scope)
 PROTOBUF_NAMESPACE_CLOSE
 
-
 PROTOBUF_NAMESPACE_OPEN
 
 template <>
@@ -14291,9 +14284,7 @@
 }
 
 PROTOBUF_NAMESPACE_CLOSE
-
 // @@protoc_insertion_point(global_scope)
 
 #include "google/protobuf/port_undef.inc"
-
 #endif  // GOOGLE_PROTOBUF_INCLUDED_google_2fprotobuf_2fdescriptor_2eproto_2epb_2eh
diff --git a/src/google/protobuf/io/BUILD.bazel b/src/google/protobuf/io/BUILD.bazel
index 88f1ee1..01009e1 100644
--- a/src/google/protobuf/io/BUILD.bazel
+++ b/src/google/protobuf/io/BUILD.bazel
@@ -68,6 +68,7 @@
         "@com_google_absl//absl/base:core_headers",
         "@com_google_absl//absl/cleanup",
         "@com_google_absl//absl/container:flat_hash_map",
+        "@com_google_absl//absl/container:flat_hash_set",
         "@com_google_absl//absl/functional:function_ref",
         "@com_google_absl//absl/strings",
         "@com_google_absl//absl/strings:str_format",
diff --git a/src/google/protobuf/io/printer.cc b/src/google/protobuf/io/printer.cc
index 289f5bf..096947a 100644
--- a/src/google/protobuf/io/printer.cc
+++ b/src/google/protobuf/io/printer.cc
@@ -49,7 +49,6 @@
 #include "absl/container/flat_hash_map.h"
 #include "absl/strings/ascii.h"
 #include "absl/strings/escaping.h"
-#include "absl/strings/match.h"
 #include "absl/strings/str_cat.h"
 #include "absl/strings/str_format.h"
 #include "absl/strings/string_view.h"
@@ -139,13 +138,14 @@
 }
 
 absl::string_view Printer::LookupVar(absl::string_view var) {
-  LookupResult result = LookupInFrameStack(var, absl::MakeSpan(var_lookups_));
+  absl::optional<ValueView> result =
+      LookupInFrameStack(var, absl::MakeSpan(var_lookups_));
   GOOGLE_CHECK(result.has_value()) << "could not find " << var;
-  auto* view = absl::get_if<absl::string_view>(&*result);
-  GOOGLE_CHECK(view != nullptr) << "could not find " << var
-                         << "; found callback instead";
+  auto* str = absl::get_if<absl::string_view>(&result->value);
+  GOOGLE_CHECK(str != nullptr) << "could not find " << var
+                        << "; found callback instead";
 
-  return *view;
+  return *str;
 }
 
 bool Printer::Validate(bool cond, Printer::PrintOptions opts,
@@ -376,6 +376,19 @@
     char c = format.front();
     format = format.substr(1);
     if (c == '\n') {
+      if (at_start_of_line_) {
+        absl::string_view no_whitespace =
+            absl::StripLeadingAsciiWhitespace(next_chunk);
+        if (absl::ConsumePrefix(&no_whitespace, options_.comment_start) &&
+            absl::ConsumePrefix(&no_whitespace, "%")) {
+          // This is an elided comment. Skip printing it, and chomp whitespace
+          // as if we had just hit a newline.
+          indent_ = original_indent +
+                    ConsumeIndentForLine(raw_string_indent_len, format);
+          continue;
+        }
+      }
+
       PrintRaw(next_chunk);
       at_start_of_line_ = true;
       line_start_variables_.clear();
@@ -467,7 +480,7 @@
       continue;
     }
 
-    LookupResult sub;
+    absl::optional<ValueView> sub;
     absl::optional<AnnotationRecord> same_name_record;
     if (opts.allow_digit_substitutions && absl::ascii_isdigit(var[0])) {
       PrintRaw(next_chunk);
@@ -483,7 +496,7 @@
       if (idx == arg_index) {
         ++arg_index;
       }
-      sub = args[idx];
+      sub = ValueView{args[idx]};
     } else if (opts.use_annotation_frames &&
                (var == "_start" || var == "_end")) {
       bool is_start = var == "_start";
@@ -574,7 +587,7 @@
     size_t range_start = sink_.bytes_written();
     size_t range_end = sink_.bytes_written();
 
-    if (auto* str = absl::get_if<absl::string_view>(&*sub)) {
+    if (const auto* str = sub->AsString()) {
       if (at_start_of_line_ && str->empty()) {
         line_start_variables_.emplace_back(var);
       }
@@ -588,7 +601,7 @@
         PrintRaw(suffix);
       }
     } else {
-      auto* fnc = absl::get_if<std::function<void()>>(&*sub);
+      const auto* fnc = sub->AsCallback();
       GOOGLE_CHECK(fnc != nullptr);
 
       Validate(
@@ -596,13 +609,20 @@
           "substitution that resolves to callback cannot contain whitespace");
 
       range_start = sink_.bytes_written();
-      (*fnc)();
+      GOOGLE_CHECK((*fnc)())
+          << "forbidden callback recursion while evaluating variable \"" << var
+          << "\"";
       range_end = sink_.bytes_written();
+    }
 
-      // If we just evaluated a closure, and we are at the start of a line, that
-      // means it finished with a newline. If a newline follows immediately
-      // after, we drop it. This helps callback formatting "work as expected"
-      // with respect to forms like
+    if (!sub->consume_after.empty()) {
+      // DO NOT SUBMIT
+      // std::cerr << "## \"" << absl::CHexEscape(sub->consume_after) << "\"\n";
+      // std::cerr << "## rest: \"" << absl::CHexEscape(format) << "\"\n";
+      // If we just evaluated a substitution with "consume after" characters,
+      // and we are at the start of a line, that means it finished with a
+      // newline. If a newline follows immediately after, we drop it. This helps
+      // callback formatting "work as expected" with respect to forms like
       //
       //   class Foo {
       //     $methods$;
@@ -615,15 +635,23 @@
       //
       //   };
       //
-      // in many cases. We *also* do this if a ; or , follows the substitution,
-      // because this helps clang-format keep its head on in many cases.
-      // Users that need to keep the semi can write $foo$/**/;
-      if (!absl::ConsumePrefix(&format, ";")) {
-        absl::ConsumePrefix(&format, ",");
+      // in many cases. We *also* do this if an element of the `consume_after`
+      // set follows the substitution, because this helps clang-format keep
+      // its head on in many cases. Users that need to keep the semi can write
+      // $foo$/**/;
+      for (char c : sub->consume_after) {
+        if (absl::ConsumePrefix(&format, absl::string_view(&c, 1))) {
+          break;
+        }
       }
-      absl::ConsumePrefix(&format, "\n");
-      indent_ =
-          original_indent + ConsumeIndentForLine(raw_string_indent_len, format);
+      // std::cerr << "## trim: \"" << absl::CHexEscape(format) << "\"\n";
+      // Consume empty lines until we hit a nonempty line.
+      if (at_start_of_line_) {
+        while (absl::ConsumePrefix(&format, "\n")) {
+          indent_ = original_indent +
+                    ConsumeIndentForLine(raw_string_indent_len, format);
+        }
+      }
     }
 
     if (same_name_record.has_value() &&
diff --git a/src/google/protobuf/io/printer.h b/src/google/protobuf/io/printer.h
index 764e335..4a89dfe 100644
--- a/src/google/protobuf/io/printer.h
+++ b/src/google/protobuf/io/printer.h
@@ -50,6 +50,7 @@
 #include "google/protobuf/stubs/common.h"
 #include "absl/cleanup/cleanup.h"
 #include "absl/container/flat_hash_map.h"
+#include "absl/container/flat_hash_set.h"
 #include "absl/functional/function_ref.h"
 #include "absl/strings/str_format.h"
 #include "absl/strings/string_view.h"
@@ -172,6 +173,37 @@
 // will crash. Callers must statically know that every variable reference is
 // valid, and MUST NOT pass user-provided strings directly into Emit().
 //
+// Substitutions can be configured to "chomp" a single character after them, to
+// help make indentation work out. This can be configured by passing a
+// two-argument io::Printer::Value into Emit's substitution map:
+//
+//   p.Emit({{"var", io::Printer::Value{var_decl, ";"}}}, R"cc(
+//     class $class$ {
+//      public:
+//       $var$;
+//     };
+//   )cc");
+//
+// This will delete the ; after $var$, regardless of whether it was an empty
+// declaration or not. It will also intelligently attempt to clean up
+// empty lines that follow, if it was on an empty line; this promotes cleaner
+// formatting of the output.
+//
+// Any number of different characters can be potentially skipped, but only one
+// will actually be skipped. For example, callback substitutions (see below) use
+// ";," by default as their "chomping set".
+//
+// # Comments
+//
+// It may be desirable to place comments in a raw string that are strippesd out
+// before printing. This is done by following the configured comment string
+// in Options (// by default) with a %. For example:
+//
+//   p.Emit(R"cc(
+//     // Will be printed in the output.
+//     //% Won't be.
+//   )cc");
+//
 // # Callback Substitution
 //
 // Instead of passing a string into Emit(), it is possible to pass in a callback
@@ -232,6 +264,9 @@
 // NOTE: callbacks are *not* allowed with WithVars; callbacks should be local
 // to a specific Emit() call.
 //
+// Callbacks cannot be recursive. Attempting to expand $foo$ while the callback
+// that was expanded from $foo$ is executed will result in a crash.
+//
 // # Annotations
 //
 // If Printer is given an AnnotationCollector, it will use it to record which
@@ -425,31 +460,70 @@
     }
   };
 
-  // Sink type for constructing values to pass to WithVars() and Emit().
-  template <typename K, bool allow_callbacks>
-  struct VarDefinition {
-    using StringOrCallback = absl::variant<std::string, std::function<void()>>;
+  // Helper type for wrapping a variable substitution expansion result.
+  template <bool owned, bool allow_callbacks>
+  struct ValueImpl {
+   private:
+    template <typename T>
+    struct IsValueImpl : std::false_type {};
+    template <bool a, bool b>
+    struct IsValueImpl<ValueImpl<a, b>> : std::true_type {};
 
-    template <typename Key, typename Value>
-    VarDefinition(Key&& key, Value&& value)
-        : key(std::forward<Key>(key)),
-          value(ToStringOrCallback(std::forward<Value>(value), Rank2{})),
-          annotation(absl::nullopt) {}
+   public:
+    using StringType =
+        std::conditional_t<owned, std::string, absl::string_view>;
+    // These callbacks return false if this is a recursive call.
+    using Callback = std::function<bool()>;
+    using StringOrCallback = absl::variant<StringType, Callback>;
 
-    // NOTE: This is an overload rather than taking optional<AnnotationRecord>
-    // with a default argument of nullopt, because we want to pick up
-    // AnnotationRecord's user-defined conversions. Because going from
-    // e.g. Descriptor* -> optional<AnnotationRecord> requires two user-defined
-    // conversions, this does not work.
-    template <typename Key, typename Value>
-    VarDefinition(Key&& key, Value&& value, AnnotationRecord annotation)
-        : key(std::forward<Key>(key)),
-          value(ToStringOrCallback(std::forward<Value>(value), Rank2{})),
-          annotation(std::move(annotation)) {}
+    ValueImpl() = default;
 
-    K key;
+    // This is a template to avoid colliding with the copy constructor below.
+    template <typename Value,
+              std::enable_if_t<!IsValueImpl<absl::remove_cvref_t<Value>>::value,
+                               int> = 0>
+    ValueImpl(Value&& value)  // NOLINT
+        : value(ToStringOrCallback(std::forward<Value>(value), Rank2{})) {
+      if (absl::holds_alternative<Callback>(this->value)) {
+        consume_after = ";,";
+      }
+    }
+    template <typename Value,
+              std::enable_if_t<!IsValueImpl<Value>::value, int> = 0>
+    ValueImpl(Value&& value, std::string consume_after)
+        : value(ToStringOrCallback(std::forward<Value>(value), Rank2{})),
+          consume_after(std::move(consume_after)) {}
+
+    // Copy ctor/assign allow interconversion of the two template parameters.
+    template <bool that_owned, bool that_callbacks>
+    ValueImpl(const ValueImpl<that_owned, that_callbacks>& that) {  // NOLINT
+      *this = that;
+    }
+    template <bool that_owned, bool that_callbacks>
+    ValueImpl& operator=(const ValueImpl<that_owned, that_callbacks>& that) {
+      using ThatStringType =
+          typename ValueImpl<that_owned, that_callbacks>::StringType;
+
+      if (auto* str = absl::get_if<ThatStringType>(&that.value)) {
+        value = StringType(*str);
+      } else {
+        value = absl::get<Callback>(that.value);
+      }
+
+      consume_after = that.consume_after;
+      return *this;
+    }
+
+    const StringType* AsString() const {
+      return absl::get_if<StringType>(&value);
+    }
+
+    const Callback* AsCallback() const {
+      return absl::get_if<Callback>(&value);
+    }
+
     StringOrCallback value;
-    absl::optional<AnnotationRecord> annotation;
+    std::string consume_after;
 
    private:
     // go/ranked-overloads
@@ -463,22 +537,62 @@
     //
     // This is done to produce a better error message than the "candidate does
     // not match" SFINAE errors.
-    template <bool allowed = allow_callbacks>
-    StringOrCallback ToStringOrCallback(std::function<void()> cb, Rank2) {
+    template <typename Cb, bool allowed = allow_callbacks,
+              typename = decltype(std::declval<Cb&&>()())>
+    StringOrCallback ToStringOrCallback(Cb&& cb, Rank2) {
       static_assert(
           allowed, "callback-typed variables are not allowed in this location");
-      return cb;
+      return Callback(
+          [cb = std::forward<Cb>(cb), is_called = false]() mutable -> bool {
+            if (is_called) {
+              // Catch whether or not this function is being called recursively.
+              return false;
+            }
+            is_called = true;
+            cb();
+            is_called = false;
+            return true;
+          });
     }
 
     // Separate from the AlphaNum overload to avoid copies when taking strings
-    // by value.
-    StringOrCallback ToStringOrCallback(std::string s, Rank1) { return s; }
+    // by value when in `owned` mode.
+    StringOrCallback ToStringOrCallback(StringType s, Rank1) { return s; }
 
     StringOrCallback ToStringOrCallback(const absl::AlphaNum& s, Rank0) {
-      return std::string(s.Piece());
+      return StringType(s.Piece());
     }
   };
 
+  using ValueView = ValueImpl</*owned=*/false, /*allow_callbacks=*/true>;
+
+  // Sink type for constructing values to pass to WithVars() and Emit().
+  template <typename K, bool allow_callbacks>
+  struct VarDefinition {
+    using StringOrCallback = absl::variant<std::string, std::function<void()>>;
+
+    template <typename Key, typename Value>
+    VarDefinition(Key&& key, Value&& value)
+        : key(std::forward<Key>(key)),
+          value(std::forward<Value>(value)),
+          annotation(absl::nullopt) {}
+
+    // NOTE: This is an overload rather than taking optional<AnnotationRecord>
+    // with a default argument of nullopt, because we want to pick up
+    // AnnotationRecord's user-defined conversions. Because going from
+    // e.g. Descriptor* -> optional<AnnotationRecord> requires two user-defined
+    // conversions, this does not work.
+    template <typename Key, typename Value>
+    VarDefinition(Key&& key, Value&& value, AnnotationRecord annotation)
+        : key(std::forward<Key>(key)),
+          value(std::forward<Value>(value)),
+          annotation(std::move(annotation)) {}
+
+    K key;
+    ValueImpl</*owned=*/true, allow_callbacks> value;
+    absl::optional<AnnotationRecord> annotation;
+  };
+
   // Provide a helper to use heterogeneous lookup when it's available.
   template <class...>
   using void_t = void;
@@ -505,6 +619,8 @@
   static constexpr absl::string_view kProtocCodegenTrace =
       "PROTOC_CODEGEN_TRACE";
 
+  using Value = ValueImpl</*owned=*/true, /*allow_callbacks=*/false>;
+
   // Options for controlling how the output of a Printer is formatted.
   struct Options {
     Options() = default;
@@ -558,13 +674,14 @@
   // Returns an RAII object that pops the lookup frame.
   template <typename Map>
   auto WithVars(const Map* vars) {
-    var_lookups_.emplace_back([vars](absl::string_view var) -> LookupResult {
-      auto it = vars->find(ToStringKey<Map>(var));
-      if (it == vars->end()) {
-        return absl::nullopt;
-      }
-      return absl::string_view(it->second);
-    });
+    var_lookups_.emplace_back(
+        [vars](absl::string_view var) -> absl::optional<ValueView> {
+          auto it = vars->find(ToStringKey<Map>(var));
+          if (it == vars->end()) {
+            return absl::nullopt;
+          }
+          return ValueView(it->second);
+        });
     return absl::MakeCleanup([this] { var_lookups_.pop_back(); });
   }
 
@@ -577,14 +694,15 @@
   template <typename Map = absl::flat_hash_map<std::string, std::string>,
             std::enable_if_t<!std::is_pointer<Map>::value, int> = 0>
   auto WithVars(Map&& vars) {
-    var_lookups_.emplace_back([vars = std::forward<Map>(vars)](
-                                  absl::string_view var) -> LookupResult {
-      auto it = vars.find(ToStringKey<Map>(var));
-      if (it == vars.end()) {
-        return absl::nullopt;
-      }
-      return absl::string_view(it->second);
-    });
+    var_lookups_.emplace_back(
+        [vars = std::forward<Map>(vars)](
+            absl::string_view var) -> absl::optional<ValueView> {
+          auto it = vars.find(ToStringKey<Map>(var));
+          if (it == vars.end()) {
+            return absl::nullopt;
+          }
+          return ValueView(it->second);
+        });
     return absl::MakeCleanup([this] { var_lookups_.pop_back(); });
   }
 
@@ -856,10 +974,8 @@
   bool at_start_of_line_ = true;
   bool failed_ = false;
 
-  using LookupResult =
-      absl::optional<absl::variant<absl::string_view, std::function<void()>>>;
-
-  std::vector<std::function<LookupResult(absl::string_view)>> var_lookups_;
+  std::vector<std::function<absl::optional<ValueView>(absl::string_view)>>
+      var_lookups_;
 
   std::vector<
       std::function<absl::optional<AnnotationRecord>(absl::string_view)>>
@@ -878,8 +994,7 @@
 template <typename K, bool allow_callbacks>
 auto Printer::WithDefs(
     std::initializer_list<VarDefinition<K, allow_callbacks>> vars) {
-  absl::flat_hash_map<K, absl::variant<std::string, std::function<void()>>>
-      var_map;
+  absl::flat_hash_map<K, Value> var_map;
   var_map.reserve(vars.size());
 
   absl::flat_hash_map<K, AnnotationRecord> annotation_map;
@@ -893,20 +1008,14 @@
     }
   }
 
-  var_lookups_.emplace_back(
-      [map = std::move(var_map)](absl::string_view var) -> LookupResult {
-        auto it = map.find(var);
-        if (it == map.end()) {
-          return absl::nullopt;
-        }
-        if (auto* str = absl::get_if<std::string>(&it->second)) {
-          return absl::string_view(*str);
-        }
-
-        auto* f = absl::get_if<std::function<void()>>(&it->second);
-        GOOGLE_CHECK(f != nullptr);
-        return *f;
-      });
+  var_lookups_.emplace_back([map = std::move(var_map)](absl::string_view var)
+                                -> absl::optional<ValueView> {
+    auto it = map.find(var);
+    if (it == map.end()) {
+      return absl::nullopt;
+    }
+    return ValueView(it->second);
+  });
 
   bool has_annotations = !annotation_map.empty();
   if (has_annotations) {
diff --git a/src/google/protobuf/io/printer_unittest.cc b/src/google/protobuf/io/printer_unittest.cc
index d9c31cd..1e87ee8 100644
--- a/src/google/protobuf/io/printer_unittest.cc
+++ b/src/google/protobuf/io/printer_unittest.cc
@@ -594,6 +594,39 @@
             "};\n");
 }
 
+TEST_F(PrinterTest, EmitConsumeAfter) {
+  {
+    Printer printer(output());
+    printer.Emit(
+        {
+            {"class", "Foo"},
+            {"var", Printer::Value{"int x;", ";"}},
+        },
+        R"cc(
+          class $class$ {
+            $var$;
+          };
+        )cc");
+  }
+
+  EXPECT_EQ(written(),
+            "class Foo {\n"
+            "  int x;\n"
+            "};\n");
+}
+
+TEST_F(PrinterTest, EmitComments) {
+  {
+    Printer printer(output());
+    printer.Emit(R"cc(
+      // Yes.
+      //% No.
+    )cc");
+  }
+
+  EXPECT_EQ(written(), "// Yes.\n");
+}
+
 TEST_F(PrinterTest, EmitWithVars) {
   {
     Printer printer(output());
@@ -800,7 +833,6 @@
             "class Foo {\n"
             " public:\n"
             "  int bar() { return 42; }\n"
-            "\n"
             " private:\n"
             "  int bar_;\n"
             "};\n");