cmd/protoc-gen-go, runtime/protoimpl: enforce minimum and maximum versions

Generate the needed infrastructure to ensure that we can statically
enforce minimum and maximum versions. This enables us to have a policy
when we release v2 where it fails to build for:
* new generated code with really old runtimes
* new runtimes with really old generated code

Change-Id: Ib699ad62c06dff8f9285806394a741c18db00288
Reviewed-on: https://go-review.googlesource.com/c/protobuf/+/178546
Reviewed-by: Damien Neil <dneil@google.com>
diff --git a/runtime/protoimpl/impl.go b/runtime/protoimpl/impl.go
index 2eec9d9..fac3cfc 100644
--- a/runtime/protoimpl/impl.go
+++ b/runtime/protoimpl/impl.go
@@ -16,26 +16,46 @@
 	"google.golang.org/protobuf/internal/impl"
 )
 
-// Version is the current minor version of the package.
-// This is incremented every time the API of this package expands.
-const Version = 0 // v2.{Version}.x
+const (
+	// MaxVersion is the maximum supported version for generated .pb.go files;
+	// which is the current version of the package.
+	// This is incremented when the functionality of this package expands.
+	MaxVersion = 0
 
-var X impl.Export
+	// MinVersion is the minimum supported version for generated .pb.go files.
+	// This is incremented when the runtime drops support for old code.
+	MinVersion = 0
+
+	// Version is the current minor version of the runtime.
+	Version = MaxVersion // v2.{Version}.x
+
+	// TODO: Encode a date instead of the minor version?
+)
 
 type (
 	// EnforceVersion is used by code generated by protoc-gen-go
-	// to statically enforce a minimum version of this package.
-	// A compilation failure implies that this package is too old and
-	// needs to be updated to a more recent version.
+	// to statically enforce minimum and maximum versions of this package.
+	// A compilation failure implies either that:
+	//	* the runtime package is too old and needs to be updated OR
+	//	* the generated code is too old and needs to be regenerated.
 	//
-	// This package can be upgraded by running:
-	//	go get -u google.golang.org/protobuf/...
+	// The runtime package can be upgraded by running:
+	//	go get google.golang.org/protobuf
+	//
+	// The generated code can be regenerated by running:
+	//	protoc --go_out=${PROTOC_GEN_GO_ARGS} ${PROTO_FILES}
 	//
 	// Example usage by generated code:
-	//	const _ = protoimpl.EnforceVersion(protoimpl.Version - genVersion)
+	//	const (
+	//		// Verify that runtime/protoimpl is sufficiently up-to-date.
+	//		_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - genVersion)
+	//		// Verify that this generated code is sufficiently up-to-date.
+	//		_ = protoimpl.EnforceVersion(genVersion - protoimpl.MinVersion)
+	//	)
 	//
-	// If genVersion is lower than Version, then this results in a negative
-	// integer overflow failure when evaluating the uint constant.
+	// The genVersion is the current version used to generated the code.
+	// This compile-time check relies on negative integer overflow of a uint
+	// being a compilation failure (guaranteed by the Go specification).
 	EnforceVersion uint
 
 	MessageInfo = impl.MessageInfo
@@ -48,3 +68,5 @@
 
 	ExtensionFieldV1 = impl.ExtensionFieldV1
 )
+
+var X impl.Export