all: implement strip_enum_prefix editions feature

This change required updating editions_defaults.binpb with
--edition_defaults_maximum=2024 so that we can use edition 2024 in our
testdata/enumprefix.proto test file.

For end users, this feature will only be available once:
1. protoc declares support for edition 2024 (expected early 2025).
2. protoc-gen-go declares support for edition 2024.

related to golang/protobuf#513

Change-Id: Ib8daeecae39ef32eff942279707d256c312f2a53
Reviewed-on: https://go-review.googlesource.com/c/protobuf/+/618979
Reviewed-by: Lasse Folger <lassefolger@google.com>
Reviewed-by: Mike Kruskal <mkruskal@google.com>
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
Reviewed-by: Damien Neil <dneil@google.com>
diff --git a/cmd/protoc-gen-go/enumprefix_test.go b/cmd/protoc-gen-go/enumprefix_test.go
new file mode 100644
index 0000000..523e75d
--- /dev/null
+++ b/cmd/protoc-gen-go/enumprefix_test.go
@@ -0,0 +1,29 @@
+// Copyright 2024 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import (
+	"testing"
+
+	"google.golang.org/protobuf/cmd/protoc-gen-go/testdata/enumprefix"
+)
+
+func TestStripEnumPrefix(t *testing.T) {
+	// The file default for enumprefix.proto is to strip prefixes:
+	_ = enumprefix.Strip_ZERO
+
+	// The enum Both should generate both names:
+	_ = enumprefix.Both_ZERO
+	_ = enumprefix.Both_BOTH_ZERO
+
+	// The enum BothNoPrefix is configured to generate both names, but there is
+	// no prefix to be stripped, so only an unmodified name is generated.
+	_ = enumprefix.BothNoPrefix_ZERO
+
+	// The enum BothButOne is configured to generate both names, except for the
+	// ONE value, where only the prefixed name is generated.
+	_ = enumprefix.BothButOne_ZERO
+	_ = enumprefix.BothButOne_BOTH_BUT_ONE_ONE
+}
diff --git a/cmd/protoc-gen-go/internal_gengo/main.go b/cmd/protoc-gen-go/internal_gengo/main.go
index dfd16b2..a4c4595 100644
--- a/cmd/protoc-gen-go/internal_gengo/main.go
+++ b/cmd/protoc-gen-go/internal_gengo/main.go
@@ -260,6 +260,7 @@
 
 	// Enum value constants.
 	g.P("const (")
+	anyOldName := false
 	for _, value := range e.Values {
 		g.AnnotateSymbol(value.GoIdent.GoName, protogen.Annotation{Location: value.Location})
 		leadingComments := appendDeprecationSuffix(value.Comments.Leading,
@@ -268,9 +269,26 @@
 		g.P(leadingComments,
 			value.GoIdent, " ", e.GoIdent, " = ", value.Desc.Number(),
 			trailingComment(value.Comments.Trailing))
+
+		if value.PrefixedAlias.GoName != "" &&
+			value.PrefixedAlias.GoName != value.GoIdent.GoName {
+			anyOldName = true
+		}
 	}
 	g.P(")")
 	g.P()
+	if anyOldName {
+		g.P("// Old (prefixed) names for ", e.GoIdent, " enum values.")
+		g.P("const (")
+		for _, value := range e.Values {
+			if value.PrefixedAlias.GoName != "" &&
+				value.PrefixedAlias.GoName != value.GoIdent.GoName {
+				g.P(value.PrefixedAlias, " ", e.GoIdent, " = ", value.GoIdent)
+			}
+		}
+		g.P(")")
+		g.P()
+	}
 
 	// Enum value maps.
 	g.P("// Enum value maps for ", e.GoIdent, ".")
diff --git a/cmd/protoc-gen-go/testdata/enumprefix/enumprefix.pb.go b/cmd/protoc-gen-go/testdata/enumprefix/enumprefix.pb.go
new file mode 100644
index 0000000..d9b7f4e
--- /dev/null
+++ b/cmd/protoc-gen-go/testdata/enumprefix/enumprefix.pb.go
@@ -0,0 +1,294 @@
+// Copyright 2024 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Code generated by protoc-gen-go. DO NOT EDIT.
+// source: cmd/protoc-gen-go/testdata/enumprefix/enumprefix.proto
+
+package enumprefix
+
+import (
+	protoreflect "google.golang.org/protobuf/reflect/protoreflect"
+	protoimpl "google.golang.org/protobuf/runtime/protoimpl"
+	_ "google.golang.org/protobuf/types/gofeaturespb"
+	reflect "reflect"
+	sync "sync"
+)
+
+type Strip int32
+
+const (
+	Strip_ZERO Strip = 0
+	Strip_ONE  Strip = 1
+)
+
+// Enum value maps for Strip.
+var (
+	Strip_name = map[int32]string{
+		0: "STRIP_ZERO",
+		1: "STRIP_ONE",
+	}
+	Strip_value = map[string]int32{
+		"STRIP_ZERO": 0,
+		"STRIP_ONE":  1,
+	}
+)
+
+func (x Strip) Enum() *Strip {
+	p := new(Strip)
+	*p = x
+	return p
+}
+
+func (x Strip) String() string {
+	return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))
+}
+
+func (Strip) Descriptor() protoreflect.EnumDescriptor {
+	return file_cmd_protoc_gen_go_testdata_enumprefix_enumprefix_proto_enumTypes[0].Descriptor()
+}
+
+func (Strip) Type() protoreflect.EnumType {
+	return &file_cmd_protoc_gen_go_testdata_enumprefix_enumprefix_proto_enumTypes[0]
+}
+
+func (x Strip) Number() protoreflect.EnumNumber {
+	return protoreflect.EnumNumber(x)
+}
+
+// Deprecated: Use Strip.Descriptor instead.
+func (Strip) EnumDescriptor() ([]byte, []int) {
+	return file_cmd_protoc_gen_go_testdata_enumprefix_enumprefix_proto_rawDescGZIP(), []int{0}
+}
+
+type Both int32
+
+const (
+	Both_ZERO Both = 0
+	Both_ONE  Both = 1
+)
+
+// Old (prefixed) names for Both enum values.
+const (
+	Both_BOTH_ZERO Both = Both_ZERO
+	Both_BOTH_ONE  Both = Both_ONE
+)
+
+// Enum value maps for Both.
+var (
+	Both_name = map[int32]string{
+		0: "BOTH_ZERO",
+		1: "BOTH_ONE",
+	}
+	Both_value = map[string]int32{
+		"BOTH_ZERO": 0,
+		"BOTH_ONE":  1,
+	}
+)
+
+func (x Both) Enum() *Both {
+	p := new(Both)
+	*p = x
+	return p
+}
+
+func (x Both) String() string {
+	return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))
+}
+
+func (Both) Descriptor() protoreflect.EnumDescriptor {
+	return file_cmd_protoc_gen_go_testdata_enumprefix_enumprefix_proto_enumTypes[1].Descriptor()
+}
+
+func (Both) Type() protoreflect.EnumType {
+	return &file_cmd_protoc_gen_go_testdata_enumprefix_enumprefix_proto_enumTypes[1]
+}
+
+func (x Both) Number() protoreflect.EnumNumber {
+	return protoreflect.EnumNumber(x)
+}
+
+// Deprecated: Use Both.Descriptor instead.
+func (Both) EnumDescriptor() ([]byte, []int) {
+	return file_cmd_protoc_gen_go_testdata_enumprefix_enumprefix_proto_rawDescGZIP(), []int{1}
+}
+
+type BothNoPrefix int32
+
+const (
+	BothNoPrefix_ZERO BothNoPrefix = 0
+	BothNoPrefix_ONE  BothNoPrefix = 1
+)
+
+// Enum value maps for BothNoPrefix.
+var (
+	BothNoPrefix_name = map[int32]string{
+		0: "ZERO",
+		1: "ONE",
+	}
+	BothNoPrefix_value = map[string]int32{
+		"ZERO": 0,
+		"ONE":  1,
+	}
+)
+
+func (x BothNoPrefix) Enum() *BothNoPrefix {
+	p := new(BothNoPrefix)
+	*p = x
+	return p
+}
+
+func (x BothNoPrefix) String() string {
+	return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))
+}
+
+func (BothNoPrefix) Descriptor() protoreflect.EnumDescriptor {
+	return file_cmd_protoc_gen_go_testdata_enumprefix_enumprefix_proto_enumTypes[2].Descriptor()
+}
+
+func (BothNoPrefix) Type() protoreflect.EnumType {
+	return &file_cmd_protoc_gen_go_testdata_enumprefix_enumprefix_proto_enumTypes[2]
+}
+
+func (x BothNoPrefix) Number() protoreflect.EnumNumber {
+	return protoreflect.EnumNumber(x)
+}
+
+// Deprecated: Use BothNoPrefix.Descriptor instead.
+func (BothNoPrefix) EnumDescriptor() ([]byte, []int) {
+	return file_cmd_protoc_gen_go_testdata_enumprefix_enumprefix_proto_rawDescGZIP(), []int{2}
+}
+
+type BothButOne int32
+
+const (
+	BothButOne_ZERO             BothButOne = 0
+	BothButOne_BOTH_BUT_ONE_ONE BothButOne = 1
+)
+
+// Old (prefixed) names for BothButOne enum values.
+const (
+	BothButOne_BOTH_BUT_ONE_ZERO BothButOne = BothButOne_ZERO
+)
+
+// Enum value maps for BothButOne.
+var (
+	BothButOne_name = map[int32]string{
+		0: "BOTH_BUT_ONE_ZERO",
+		1: "BOTH_BUT_ONE_ONE",
+	}
+	BothButOne_value = map[string]int32{
+		"BOTH_BUT_ONE_ZERO": 0,
+		"BOTH_BUT_ONE_ONE":  1,
+	}
+)
+
+func (x BothButOne) Enum() *BothButOne {
+	p := new(BothButOne)
+	*p = x
+	return p
+}
+
+func (x BothButOne) String() string {
+	return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))
+}
+
+func (BothButOne) Descriptor() protoreflect.EnumDescriptor {
+	return file_cmd_protoc_gen_go_testdata_enumprefix_enumprefix_proto_enumTypes[3].Descriptor()
+}
+
+func (BothButOne) Type() protoreflect.EnumType {
+	return &file_cmd_protoc_gen_go_testdata_enumprefix_enumprefix_proto_enumTypes[3]
+}
+
+func (x BothButOne) Number() protoreflect.EnumNumber {
+	return protoreflect.EnumNumber(x)
+}
+
+// Deprecated: Use BothButOne.Descriptor instead.
+func (BothButOne) EnumDescriptor() ([]byte, []int) {
+	return file_cmd_protoc_gen_go_testdata_enumprefix_enumprefix_proto_rawDescGZIP(), []int{3}
+}
+
+var File_cmd_protoc_gen_go_testdata_enumprefix_enumprefix_proto protoreflect.FileDescriptor
+
+var file_cmd_protoc_gen_go_testdata_enumprefix_enumprefix_proto_rawDesc = []byte{
+	0x0a, 0x36, 0x63, 0x6d, 0x64, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x2d, 0x67, 0x65, 0x6e,
+	0x2d, 0x67, 0x6f, 0x2f, 0x74, 0x65, 0x73, 0x74, 0x64, 0x61, 0x74, 0x61, 0x2f, 0x65, 0x6e, 0x75,
+	0x6d, 0x70, 0x72, 0x65, 0x66, 0x69, 0x78, 0x2f, 0x65, 0x6e, 0x75, 0x6d, 0x70, 0x72, 0x65, 0x66,
+	0x69, 0x78, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x19, 0x67, 0x6f, 0x70, 0x72, 0x6f, 0x74,
+	0x6f, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x2e, 0x65, 0x6e, 0x75, 0x6d, 0x70, 0x72, 0x65,
+	0x66, 0x69, 0x78, 0x1a, 0x21, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x74,
+	0x6f, 0x62, 0x75, 0x66, 0x2f, 0x67, 0x6f, 0x5f, 0x66, 0x65, 0x61, 0x74, 0x75, 0x72, 0x65, 0x73,
+	0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2a, 0x26, 0x0a, 0x05, 0x53, 0x74, 0x72, 0x69, 0x70, 0x12,
+	0x0e, 0x0a, 0x0a, 0x53, 0x54, 0x52, 0x49, 0x50, 0x5f, 0x5a, 0x45, 0x52, 0x4f, 0x10, 0x00, 0x12,
+	0x0d, 0x0a, 0x09, 0x53, 0x54, 0x52, 0x49, 0x50, 0x5f, 0x4f, 0x4e, 0x45, 0x10, 0x01, 0x2a, 0x2c,
+	0x0a, 0x04, 0x42, 0x6f, 0x74, 0x68, 0x12, 0x0d, 0x0a, 0x09, 0x42, 0x4f, 0x54, 0x48, 0x5f, 0x5a,
+	0x45, 0x52, 0x4f, 0x10, 0x00, 0x12, 0x0c, 0x0a, 0x08, 0x42, 0x4f, 0x54, 0x48, 0x5f, 0x4f, 0x4e,
+	0x45, 0x10, 0x01, 0x1a, 0x07, 0x3a, 0x05, 0xd2, 0x3e, 0x02, 0x18, 0x02, 0x2a, 0x2a, 0x0a, 0x0c,
+	0x42, 0x6f, 0x74, 0x68, 0x4e, 0x6f, 0x50, 0x72, 0x65, 0x66, 0x69, 0x78, 0x12, 0x08, 0x0a, 0x04,
+	0x5a, 0x45, 0x52, 0x4f, 0x10, 0x00, 0x12, 0x07, 0x0a, 0x03, 0x4f, 0x4e, 0x45, 0x10, 0x01, 0x1a,
+	0x07, 0x3a, 0x05, 0xd2, 0x3e, 0x02, 0x18, 0x02, 0x2a, 0x4b, 0x0a, 0x0a, 0x42, 0x6f, 0x74, 0x68,
+	0x42, 0x75, 0x74, 0x4f, 0x6e, 0x65, 0x12, 0x15, 0x0a, 0x11, 0x42, 0x4f, 0x54, 0x48, 0x5f, 0x42,
+	0x55, 0x54, 0x5f, 0x4f, 0x4e, 0x45, 0x5f, 0x5a, 0x45, 0x52, 0x4f, 0x10, 0x00, 0x12, 0x1d, 0x0a,
+	0x10, 0x42, 0x4f, 0x54, 0x48, 0x5f, 0x42, 0x55, 0x54, 0x5f, 0x4f, 0x4e, 0x45, 0x5f, 0x4f, 0x4e,
+	0x45, 0x10, 0x01, 0x1a, 0x07, 0x12, 0x05, 0xd2, 0x3e, 0x02, 0x18, 0x01, 0x1a, 0x07, 0x3a, 0x05,
+	0xd2, 0x3e, 0x02, 0x18, 0x02, 0x42, 0x4a, 0x5a, 0x40, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e,
+	0x67, 0x6f, 0x6c, 0x61, 0x6e, 0x67, 0x2e, 0x6f, 0x72, 0x67, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f,
+	0x62, 0x75, 0x66, 0x2f, 0x63, 0x6d, 0x64, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x2d, 0x67,
+	0x65, 0x6e, 0x2d, 0x67, 0x6f, 0x2f, 0x74, 0x65, 0x73, 0x74, 0x64, 0x61, 0x74, 0x61, 0x2f, 0x65,
+	0x6e, 0x75, 0x6d, 0x70, 0x72, 0x65, 0x66, 0x69, 0x78, 0x92, 0x03, 0x05, 0xd2, 0x3e, 0x02, 0x18,
+	0x03, 0x62, 0x08, 0x65, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x70, 0xe9, 0x07,
+}
+
+var (
+	file_cmd_protoc_gen_go_testdata_enumprefix_enumprefix_proto_rawDescOnce sync.Once
+	file_cmd_protoc_gen_go_testdata_enumprefix_enumprefix_proto_rawDescData = file_cmd_protoc_gen_go_testdata_enumprefix_enumprefix_proto_rawDesc
+)
+
+func file_cmd_protoc_gen_go_testdata_enumprefix_enumprefix_proto_rawDescGZIP() []byte {
+	file_cmd_protoc_gen_go_testdata_enumprefix_enumprefix_proto_rawDescOnce.Do(func() {
+		file_cmd_protoc_gen_go_testdata_enumprefix_enumprefix_proto_rawDescData = protoimpl.X.CompressGZIP(file_cmd_protoc_gen_go_testdata_enumprefix_enumprefix_proto_rawDescData)
+	})
+	return file_cmd_protoc_gen_go_testdata_enumprefix_enumprefix_proto_rawDescData
+}
+
+var file_cmd_protoc_gen_go_testdata_enumprefix_enumprefix_proto_enumTypes = make([]protoimpl.EnumInfo, 4)
+var file_cmd_protoc_gen_go_testdata_enumprefix_enumprefix_proto_goTypes = []any{
+	(Strip)(0),        // 0: goproto.protoc.enumprefix.Strip
+	(Both)(0),         // 1: goproto.protoc.enumprefix.Both
+	(BothNoPrefix)(0), // 2: goproto.protoc.enumprefix.BothNoPrefix
+	(BothButOne)(0),   // 3: goproto.protoc.enumprefix.BothButOne
+}
+var file_cmd_protoc_gen_go_testdata_enumprefix_enumprefix_proto_depIdxs = []int32{
+	0, // [0:0] is the sub-list for method output_type
+	0, // [0:0] is the sub-list for method input_type
+	0, // [0:0] is the sub-list for extension type_name
+	0, // [0:0] is the sub-list for extension extendee
+	0, // [0:0] is the sub-list for field type_name
+}
+
+func init() { file_cmd_protoc_gen_go_testdata_enumprefix_enumprefix_proto_init() }
+func file_cmd_protoc_gen_go_testdata_enumprefix_enumprefix_proto_init() {
+	if File_cmd_protoc_gen_go_testdata_enumprefix_enumprefix_proto != nil {
+		return
+	}
+	type x struct{}
+	out := protoimpl.TypeBuilder{
+		File: protoimpl.DescBuilder{
+			GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
+			RawDescriptor: file_cmd_protoc_gen_go_testdata_enumprefix_enumprefix_proto_rawDesc,
+			NumEnums:      4,
+			NumMessages:   0,
+			NumExtensions: 0,
+			NumServices:   0,
+		},
+		GoTypes:           file_cmd_protoc_gen_go_testdata_enumprefix_enumprefix_proto_goTypes,
+		DependencyIndexes: file_cmd_protoc_gen_go_testdata_enumprefix_enumprefix_proto_depIdxs,
+		EnumInfos:         file_cmd_protoc_gen_go_testdata_enumprefix_enumprefix_proto_enumTypes,
+	}.Build()
+	File_cmd_protoc_gen_go_testdata_enumprefix_enumprefix_proto = out.File
+	file_cmd_protoc_gen_go_testdata_enumprefix_enumprefix_proto_rawDesc = nil
+	file_cmd_protoc_gen_go_testdata_enumprefix_enumprefix_proto_goTypes = nil
+	file_cmd_protoc_gen_go_testdata_enumprefix_enumprefix_proto_depIdxs = nil
+}
diff --git a/cmd/protoc-gen-go/testdata/enumprefix/enumprefix.proto b/cmd/protoc-gen-go/testdata/enumprefix/enumprefix.proto
new file mode 100644
index 0000000..525ce14
--- /dev/null
+++ b/cmd/protoc-gen-go/testdata/enumprefix/enumprefix.proto
@@ -0,0 +1,39 @@
+// Copyright 2024 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+edition = "2024";
+
+package goproto.protoc.enumprefix;
+
+import "google/protobuf/go_features.proto";
+
+option go_package = "google.golang.org/protobuf/cmd/protoc-gen-go/testdata/enumprefix";
+option features.(pb.go).strip_enum_prefix = STRIP_ENUM_PREFIX_STRIP;
+
+enum Strip {
+  STRIP_ZERO = 0;
+  STRIP_ONE = 1;
+}
+
+enum Both {
+  option features.(pb.go).strip_enum_prefix = STRIP_ENUM_PREFIX_GENERATE_BOTH;
+
+  BOTH_ZERO = 0;
+  BOTH_ONE = 1;
+}
+
+enum BothNoPrefix {
+  option features.(pb.go).strip_enum_prefix = STRIP_ENUM_PREFIX_GENERATE_BOTH;
+
+  ZERO = 0;
+  ONE = 1;
+}
+
+enum BothButOne {
+  option features.(pb.go).strip_enum_prefix = STRIP_ENUM_PREFIX_GENERATE_BOTH;
+
+  BOTH_BUT_ONE_ZERO = 0;
+  BOTH_BUT_ONE_ONE = 1
+      [features.(pb.go).strip_enum_prefix = STRIP_ENUM_PREFIX_KEEP];
+}
diff --git a/cmd/protoc-gen-go/testdata/gen_test.go b/cmd/protoc-gen-go/testdata/gen_test.go
index 6aa236c..8724e4a 100644
--- a/cmd/protoc-gen-go/testdata/gen_test.go
+++ b/cmd/protoc-gen-go/testdata/gen_test.go
@@ -9,6 +9,7 @@
 import (
 	_ "google.golang.org/protobuf/cmd/protoc-gen-go/testdata/annotations"
 	_ "google.golang.org/protobuf/cmd/protoc-gen-go/testdata/comments"
+	_ "google.golang.org/protobuf/cmd/protoc-gen-go/testdata/enumprefix"
 	_ "google.golang.org/protobuf/cmd/protoc-gen-go/testdata/extensions/base"
 	_ "google.golang.org/protobuf/cmd/protoc-gen-go/testdata/extensions/ext"
 	_ "google.golang.org/protobuf/cmd/protoc-gen-go/testdata/extensions/extra"
diff --git a/compiler/protogen/protogen.go b/compiler/protogen/protogen.go
index 966728e..c2c9e9d 100644
--- a/compiler/protogen/protogen.go
+++ b/compiler/protogen/protogen.go
@@ -28,6 +28,7 @@
 	"strings"
 
 	"google.golang.org/protobuf/encoding/prototext"
+	"google.golang.org/protobuf/internal/filedesc"
 	"google.golang.org/protobuf/internal/genid"
 	"google.golang.org/protobuf/internal/strs"
 	"google.golang.org/protobuf/proto"
@@ -37,6 +38,7 @@
 
 	"google.golang.org/protobuf/types/descriptorpb"
 	"google.golang.org/protobuf/types/dynamicpb"
+	"google.golang.org/protobuf/types/gofeaturespb"
 	"google.golang.org/protobuf/types/pluginpb"
 )
 
@@ -574,6 +576,12 @@
 
 	GoIdent GoIdent // name of the generated Go declaration
 
+	// PrefixedAlias is usually empty, except when the strip_enum_prefix feature
+	// for this enum was set to GENERATE_BOTH, in which case PrefixedAlias holds
+	// the old name which should be generated as an alias for the new name for
+	// compatibility.
+	PrefixedAlias GoIdent
+
 	Parent *Enum // enum in which this value is declared
 
 	Location Location   // location of this enum value
@@ -590,14 +598,46 @@
 		parentIdent = message.GoIdent
 	}
 	name := parentIdent.GoName + "_" + string(desc.Name())
+	var prefixedName string
 	loc := enum.Location.appendPath(genid.EnumDescriptorProto_Value_field_number, desc.Index())
-	return &EnumValue{
+	if ed, ok := enum.Desc.(*filedesc.Enum); ok {
+		prefix := strings.Replace(strings.ToLower(string(enum.Desc.Name())), "_", "", -1)
+
+		// Start with the StripEnumPrefix of the enum descriptor,
+		// then override it with the StripEnumPrefix of the enum value descriptor,
+		// if any.
+		sep := ed.L1.EditionFeatures.StripEnumPrefix
+		evof := desc.Options().(*descriptorpb.EnumValueOptions).GetFeatures()
+		if proto.HasExtension(evof, gofeaturespb.E_Go) {
+			gf := proto.GetExtension(evof, gofeaturespb.E_Go).(*gofeaturespb.GoFeatures)
+			if gf.StripEnumPrefix != nil {
+				sep = int(*gf.StripEnumPrefix)
+			}
+		}
+
+		switch sep {
+		case genid.GoFeatures_STRIP_ENUM_PREFIX_KEEP_enum_value:
+			// keep long name
+
+		case genid.GoFeatures_STRIP_ENUM_PREFIX_STRIP_enum_value:
+			name = parentIdent.GoName + "_" + strs.TrimEnumPrefix(string(desc.Name()), prefix)
+
+		case genid.GoFeatures_STRIP_ENUM_PREFIX_GENERATE_BOTH_enum_value:
+			prefixedName = name
+			name = parentIdent.GoName + "_" + strs.TrimEnumPrefix(string(desc.Name()), prefix)
+		}
+	}
+	ev := &EnumValue{
 		Desc:     desc,
 		GoIdent:  f.GoImportPath.Ident(name),
 		Parent:   enum,
 		Location: loc,
 		Comments: makeCommentSet(gen, f.Desc.SourceLocations().ByDescriptor(desc)),
 	}
+	if prefixedName != "" {
+		ev.PrefixedAlias = f.GoImportPath.Ident(prefixedName)
+	}
+	return ev
 }
 
 // A Message describes a message.
diff --git a/internal/cmd/generate-protos/main.go b/internal/cmd/generate-protos/main.go
index 071dc73..5d352cf 100644
--- a/internal/cmd/generate-protos/main.go
+++ b/internal/cmd/generate-protos/main.go
@@ -16,6 +16,7 @@
 	"path"
 	"path/filepath"
 	"regexp"
+	"slices"
 	"sort"
 	"strconv"
 	"strings"
@@ -95,9 +96,13 @@
 		panic("protobuf source root is not set")
 	}
 
+	// Generate editions_defaults.binpb first before generating any code for
+	// protos: the .proto files might specify a very recent edition for which
+	// editions_default.binpb was not yet updated.
+	generateEditionsDefaults()
+
 	generateLocalProtos()
 	generateRemoteProtos()
-	generateEditionsDefaults()
 }
 
 func generateEditionsDefaults() {
@@ -108,7 +113,7 @@
 	// the flag in the form "${EDITION}". To work around this, we trim the
 	// "EDITION_" prefix.
 	minEdition := strings.TrimPrefix(fmt.Sprint(editionssupport.Minimum), "EDITION_")
-	maxEdition := strings.TrimPrefix(fmt.Sprint(editionssupport.Maximum), "EDITION_")
+	maxEdition := strings.TrimPrefix(fmt.Sprint(editionssupport.MaximumKnown), "EDITION_")
 	cmd := exec.Command(
 		"protoc",
 		"--edition_defaults_out", dest,
@@ -279,8 +284,15 @@
 	cmd := exec.Command(
 		"protoc",
 		"--plugin=protoc-gen-go="+os.Args[0],
-		"--experimental_allow_proto3_optional",
-		"--experimental_editions")
+		"--experimental_allow_proto3_optional")
+	if slices.ContainsFunc(args, func(s string) bool {
+		return strings.Contains(s, "cmd/protoc-gen-go/testdata/") ||
+			strings.Contains(s, "internal/testprotos/")
+	}) {
+		// Our testprotos use edition features of upcoming editions that protoc
+		// has not yet declared support for:
+		cmd.Args = append(cmd.Args, "--experimental_editions")
+	}
 	cmd.Args = append(cmd.Args, args...)
 	cmd.Env = append(os.Environ(), "RUN_AS_PROTOC_PLUGIN=1")
 	out, err := cmd.CombinedOutput()
diff --git a/internal/editiondefaults/editions_defaults.binpb b/internal/editiondefaults/editions_defaults.binpb
index ff6a383..2c0693d 100644
--- a/internal/editiondefaults/editions_defaults.binpb
+++ b/internal/editiondefaults/editions_defaults.binpb
Binary files differ
diff --git a/internal/editionssupport/editions.go b/internal/editionssupport/editions.go
index 08dad76..bf1aba0 100644
--- a/internal/editionssupport/editions.go
+++ b/internal/editionssupport/editions.go
@@ -10,4 +10,9 @@
 const (
 	Minimum = descriptorpb.Edition_EDITION_PROTO2
 	Maximum = descriptorpb.Edition_EDITION_2023
+
+	// MaximumKnown is the maximum edition that is known to Go Protobuf, but not
+	// declared as supported. In other words: end users cannot use it, but
+	// testprotos inside Go Protobuf can.
+	MaximumKnown = descriptorpb.Edition_EDITION_2024
 )
diff --git a/internal/filedesc/desc.go b/internal/filedesc/desc.go
index fa790e0..f325298 100644
--- a/internal/filedesc/desc.go
+++ b/internal/filedesc/desc.go
@@ -32,6 +32,7 @@
 	EditionProto2      Edition = 998
 	EditionProto3      Edition = 999
 	Edition2023        Edition = 1000
+	Edition2024        Edition = 1001
 	EditionUnsupported Edition = 100000
 )
 
@@ -77,28 +78,42 @@
 		Locations SourceLocations
 	}
 
+	// EditionFeatures is a frequently-instantiated struct, so please take care
+	// to minimize padding when adding new fields to this struct (add them in
+	// the right place/order).
 	EditionFeatures struct {
+		// StripEnumPrefix determines if the plugin generates enum value
+		// constants as-is, with their prefix stripped, or both variants.
+		StripEnumPrefix int
+
 		// IsFieldPresence is true if field_presence is EXPLICIT
 		// https://protobuf.dev/editions/features/#field_presence
 		IsFieldPresence bool
+
 		// IsFieldPresence is true if field_presence is LEGACY_REQUIRED
 		// https://protobuf.dev/editions/features/#field_presence
 		IsLegacyRequired bool
+
 		// IsOpenEnum is true if enum_type is OPEN
 		// https://protobuf.dev/editions/features/#enum_type
 		IsOpenEnum bool
+
 		// IsPacked is true if repeated_field_encoding is PACKED
 		// https://protobuf.dev/editions/features/#repeated_field_encoding
 		IsPacked bool
+
 		// IsUTF8Validated is true if utf_validation is VERIFY
 		// https://protobuf.dev/editions/features/#utf8_validation
 		IsUTF8Validated bool
+
 		// IsDelimitedEncoded is true if message_encoding is DELIMITED
 		// https://protobuf.dev/editions/features/#message_encoding
 		IsDelimitedEncoded bool
+
 		// IsJSONCompliant is true if json_format is ALLOW
 		// https://protobuf.dev/editions/features/#json_format
 		IsJSONCompliant bool
+
 		// GenerateLegacyUnmarshalJSON determines if the plugin generates the
 		// UnmarshalJSON([]byte) error method for enums.
 		GenerateLegacyUnmarshalJSON bool
diff --git a/internal/filedesc/editions.go b/internal/filedesc/editions.go
index fd4d0c8..7611796 100644
--- a/internal/filedesc/editions.go
+++ b/internal/filedesc/editions.go
@@ -32,6 +32,10 @@
 			v, m := protowire.ConsumeVarint(b)
 			b = b[m:]
 			parent.GenerateLegacyUnmarshalJSON = protowire.DecodeBool(v)
+		case genid.GoFeatures_StripEnumPrefix_field_number:
+			v, m := protowire.ConsumeVarint(b)
+			b = b[m:]
+			parent.StripEnumPrefix = int(v)
 		default:
 			panic(fmt.Sprintf("unkown field number %d while unmarshalling GoFeatures", num))
 		}
diff --git a/internal/genid/go_features_gen.go b/internal/genid/go_features_gen.go
index 7f67cbb..09792d9 100644
--- a/internal/genid/go_features_gen.go
+++ b/internal/genid/go_features_gen.go
@@ -21,13 +21,30 @@
 // Field names for pb.GoFeatures.
 const (
 	GoFeatures_LegacyUnmarshalJsonEnum_field_name protoreflect.Name = "legacy_unmarshal_json_enum"
+	GoFeatures_StripEnumPrefix_field_name         protoreflect.Name = "strip_enum_prefix"
 
 	GoFeatures_LegacyUnmarshalJsonEnum_field_fullname protoreflect.FullName = "pb.GoFeatures.legacy_unmarshal_json_enum"
+	GoFeatures_StripEnumPrefix_field_fullname         protoreflect.FullName = "pb.GoFeatures.strip_enum_prefix"
 )
 
 // Field numbers for pb.GoFeatures.
 const (
 	GoFeatures_LegacyUnmarshalJsonEnum_field_number protoreflect.FieldNumber = 1
+	GoFeatures_StripEnumPrefix_field_number         protoreflect.FieldNumber = 3
+)
+
+// Full and short names for pb.GoFeatures.StripEnumPrefix.
+const (
+	GoFeatures_StripEnumPrefix_enum_fullname = "pb.GoFeatures.StripEnumPrefix"
+	GoFeatures_StripEnumPrefix_enum_name     = "StripEnumPrefix"
+)
+
+// Enum values for pb.GoFeatures.StripEnumPrefix.
+const (
+	GoFeatures_STRIP_ENUM_PREFIX_UNSPECIFIED_enum_value   = 0
+	GoFeatures_STRIP_ENUM_PREFIX_KEEP_enum_value          = 1
+	GoFeatures_STRIP_ENUM_PREFIX_GENERATE_BOTH_enum_value = 2
+	GoFeatures_STRIP_ENUM_PREFIX_STRIP_enum_value         = 3
 )
 
 // Extension numbers
diff --git a/reflect/protodesc/desc.go b/reflect/protodesc/desc.go
index 8fbecb4..69a0505 100644
--- a/reflect/protodesc/desc.go
+++ b/reflect/protodesc/desc.go
@@ -13,6 +13,8 @@
 package protodesc
 
 import (
+	"strings"
+
 	"google.golang.org/protobuf/internal/editionssupport"
 	"google.golang.org/protobuf/internal/errors"
 	"google.golang.org/protobuf/internal/filedesc"
@@ -102,13 +104,17 @@
 	default:
 		return nil, errors.New("invalid syntax: %q", fd.GetSyntax())
 	}
-	if f.L1.Syntax == protoreflect.Editions && (fd.GetEdition() < editionssupport.Minimum || fd.GetEdition() > editionssupport.Maximum) {
-		return nil, errors.New("use of edition %v not yet supported by the Go Protobuf runtime", fd.GetEdition())
-	}
 	f.L1.Path = fd.GetName()
 	if f.L1.Path == "" {
 		return nil, errors.New("file path must be populated")
 	}
+	if f.L1.Syntax == protoreflect.Editions && (fd.GetEdition() < editionssupport.Minimum || fd.GetEdition() > editionssupport.Maximum) {
+		// Allow cmd/protoc-gen-go/testdata to use any edition for easier
+		// testing of upcoming edition features.
+		if !strings.HasPrefix(fd.GetName(), "cmd/protoc-gen-go/testdata/") {
+			return nil, errors.New("use of edition %v not yet supported by the Go Protobuf runtime", fd.GetEdition())
+		}
+	}
 	f.L1.Package = protoreflect.FullName(fd.GetPackage())
 	if !f.L1.Package.IsValid() && f.L1.Package != "" {
 		return nil, errors.New("invalid package: %q", f.L1.Package)
diff --git a/reflect/protodesc/editions.go b/reflect/protodesc/editions.go
index 002e004..d0aeab9 100644
--- a/reflect/protodesc/editions.go
+++ b/reflect/protodesc/editions.go
@@ -43,6 +43,8 @@
 		return descriptorpb.Edition_EDITION_PROTO3
 	case filedesc.Edition2023:
 		return descriptorpb.Edition_EDITION_2023
+	case filedesc.Edition2024:
+		return descriptorpb.Edition_EDITION_2024
 	default:
 		panic(fmt.Sprintf("unknown value for edition: %v", ed))
 	}
@@ -127,6 +129,9 @@
 		if luje := goFeatures.LegacyUnmarshalJsonEnum; luje != nil {
 			parentFS.GenerateLegacyUnmarshalJSON = *luje
 		}
+		if sep := goFeatures.StripEnumPrefix; sep != nil {
+			parentFS.StripEnumPrefix = int(*sep)
+		}
 	}
 
 	return parentFS
diff --git a/src/google/protobuf/go_features.proto b/src/google/protobuf/go_features.proto
index 4d026f5..7ab74f5 100644
--- a/src/google/protobuf/go_features.proto
+++ b/src/google/protobuf/go_features.proto
@@ -32,4 +32,26 @@
     edition_defaults = { edition: EDITION_LEGACY, value: "true" },
     edition_defaults = { edition: EDITION_PROTO3, value: "false" }
   ];
+
+  enum StripEnumPrefix {
+    STRIP_ENUM_PREFIX_UNSPECIFIED = 0;
+    STRIP_ENUM_PREFIX_KEEP = 1;
+    STRIP_ENUM_PREFIX_GENERATE_BOTH = 2;
+    STRIP_ENUM_PREFIX_STRIP = 3;
+  }
+
+  optional StripEnumPrefix strip_enum_prefix = 3 [
+    retention = RETENTION_RUNTIME,
+    targets = TARGET_TYPE_ENUM,
+    targets = TARGET_TYPE_ENUM_ENTRY,
+    targets = TARGET_TYPE_FILE,
+    feature_support = {
+      edition_introduced: EDITION_2024,
+    },
+    // TODO: change the default to STRIP_ENUM_PREFIX_STRIP for edition 2025.
+    edition_defaults = {
+      edition: EDITION_LEGACY,
+      value: "STRIP_ENUM_PREFIX_KEEP"
+    }
+  ];
 }
diff --git a/types/gofeaturespb/go_features.pb.go b/types/gofeaturespb/go_features.pb.go
index c7e860f..5067b89 100644
--- a/types/gofeaturespb/go_features.pb.go
+++ b/types/gofeaturespb/go_features.pb.go
@@ -18,13 +18,76 @@
 	sync "sync"
 )
 
+type GoFeatures_StripEnumPrefix int32
+
+const (
+	GoFeatures_STRIP_ENUM_PREFIX_UNSPECIFIED   GoFeatures_StripEnumPrefix = 0
+	GoFeatures_STRIP_ENUM_PREFIX_KEEP          GoFeatures_StripEnumPrefix = 1
+	GoFeatures_STRIP_ENUM_PREFIX_GENERATE_BOTH GoFeatures_StripEnumPrefix = 2
+	GoFeatures_STRIP_ENUM_PREFIX_STRIP         GoFeatures_StripEnumPrefix = 3
+)
+
+// Enum value maps for GoFeatures_StripEnumPrefix.
+var (
+	GoFeatures_StripEnumPrefix_name = map[int32]string{
+		0: "STRIP_ENUM_PREFIX_UNSPECIFIED",
+		1: "STRIP_ENUM_PREFIX_KEEP",
+		2: "STRIP_ENUM_PREFIX_GENERATE_BOTH",
+		3: "STRIP_ENUM_PREFIX_STRIP",
+	}
+	GoFeatures_StripEnumPrefix_value = map[string]int32{
+		"STRIP_ENUM_PREFIX_UNSPECIFIED":   0,
+		"STRIP_ENUM_PREFIX_KEEP":          1,
+		"STRIP_ENUM_PREFIX_GENERATE_BOTH": 2,
+		"STRIP_ENUM_PREFIX_STRIP":         3,
+	}
+)
+
+func (x GoFeatures_StripEnumPrefix) Enum() *GoFeatures_StripEnumPrefix {
+	p := new(GoFeatures_StripEnumPrefix)
+	*p = x
+	return p
+}
+
+func (x GoFeatures_StripEnumPrefix) String() string {
+	return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))
+}
+
+func (GoFeatures_StripEnumPrefix) Descriptor() protoreflect.EnumDescriptor {
+	return file_google_protobuf_go_features_proto_enumTypes[0].Descriptor()
+}
+
+func (GoFeatures_StripEnumPrefix) Type() protoreflect.EnumType {
+	return &file_google_protobuf_go_features_proto_enumTypes[0]
+}
+
+func (x GoFeatures_StripEnumPrefix) Number() protoreflect.EnumNumber {
+	return protoreflect.EnumNumber(x)
+}
+
+// Deprecated: Do not use.
+func (x *GoFeatures_StripEnumPrefix) UnmarshalJSON(b []byte) error {
+	num, err := protoimpl.X.UnmarshalJSONEnum(x.Descriptor(), b)
+	if err != nil {
+		return err
+	}
+	*x = GoFeatures_StripEnumPrefix(num)
+	return nil
+}
+
+// Deprecated: Use GoFeatures_StripEnumPrefix.Descriptor instead.
+func (GoFeatures_StripEnumPrefix) EnumDescriptor() ([]byte, []int) {
+	return file_google_protobuf_go_features_proto_rawDescGZIP(), []int{0, 0}
+}
+
 type GoFeatures struct {
 	state         protoimpl.MessageState
 	sizeCache     protoimpl.SizeCache
 	unknownFields protoimpl.UnknownFields
 
 	// Whether or not to generate the deprecated UnmarshalJSON method for enums.
-	LegacyUnmarshalJsonEnum *bool `protobuf:"varint,1,opt,name=legacy_unmarshal_json_enum,json=legacyUnmarshalJsonEnum" json:"legacy_unmarshal_json_enum,omitempty"`
+	LegacyUnmarshalJsonEnum *bool                       `protobuf:"varint,1,opt,name=legacy_unmarshal_json_enum,json=legacyUnmarshalJsonEnum" json:"legacy_unmarshal_json_enum,omitempty"`
+	StripEnumPrefix         *GoFeatures_StripEnumPrefix `protobuf:"varint,3,opt,name=strip_enum_prefix,json=stripEnumPrefix,enum=pb.GoFeatures_StripEnumPrefix" json:"strip_enum_prefix,omitempty"`
 }
 
 func (x *GoFeatures) Reset() {
@@ -64,6 +127,13 @@
 	return false
 }
 
+func (x *GoFeatures) GetStripEnumPrefix() GoFeatures_StripEnumPrefix {
+	if x != nil && x.StripEnumPrefix != nil {
+		return *x.StripEnumPrefix
+	}
+	return GoFeatures_STRIP_ENUM_PREFIX_UNSPECIFIED
+}
+
 var file_google_protobuf_go_features_proto_extTypes = []protoimpl.ExtensionInfo{
 	{
 		ExtendedType:  (*descriptorpb.FeatureSet)(nil),
@@ -88,7 +158,7 @@
 	0x66, 0x2f, 0x67, 0x6f, 0x5f, 0x66, 0x65, 0x61, 0x74, 0x75, 0x72, 0x65, 0x73, 0x2e, 0x70, 0x72,
 	0x6f, 0x74, 0x6f, 0x12, 0x02, 0x70, 0x62, 0x1a, 0x20, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f,
 	0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70,
-	0x74, 0x6f, 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0xcd, 0x01, 0x0a, 0x0a, 0x47, 0x6f,
+	0x74, 0x6f, 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0xe0, 0x03, 0x0a, 0x0a, 0x47, 0x6f,
 	0x46, 0x65, 0x61, 0x74, 0x75, 0x72, 0x65, 0x73, 0x12, 0xbe, 0x01, 0x0a, 0x1a, 0x6c, 0x65, 0x67,
 	0x61, 0x63, 0x79, 0x5f, 0x75, 0x6e, 0x6d, 0x61, 0x72, 0x73, 0x68, 0x61, 0x6c, 0x5f, 0x6a, 0x73,
 	0x6f, 0x6e, 0x5f, 0x65, 0x6e, 0x75, 0x6d, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x42, 0x80, 0x01,
@@ -101,14 +171,31 @@
 	0x20, 0x62, 0x65, 0x20, 0x72, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x64, 0x20, 0x69, 0x6e, 0x20, 0x61,
 	0x20, 0x66, 0x75, 0x74, 0x75, 0x72, 0x65, 0x20, 0x65, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x2e,
 	0x52, 0x17, 0x6c, 0x65, 0x67, 0x61, 0x63, 0x79, 0x55, 0x6e, 0x6d, 0x61, 0x72, 0x73, 0x68, 0x61,
-	0x6c, 0x4a, 0x73, 0x6f, 0x6e, 0x45, 0x6e, 0x75, 0x6d, 0x3a, 0x3c, 0x0a, 0x02, 0x67, 0x6f, 0x12,
-	0x1b, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75,
-	0x66, 0x2e, 0x46, 0x65, 0x61, 0x74, 0x75, 0x72, 0x65, 0x53, 0x65, 0x74, 0x18, 0xea, 0x07, 0x20,
-	0x01, 0x28, 0x0b, 0x32, 0x0e, 0x2e, 0x70, 0x62, 0x2e, 0x47, 0x6f, 0x46, 0x65, 0x61, 0x74, 0x75,
-	0x72, 0x65, 0x73, 0x52, 0x02, 0x67, 0x6f, 0x42, 0x2f, 0x5a, 0x2d, 0x67, 0x6f, 0x6f, 0x67, 0x6c,
-	0x65, 0x2e, 0x67, 0x6f, 0x6c, 0x61, 0x6e, 0x67, 0x2e, 0x6f, 0x72, 0x67, 0x2f, 0x70, 0x72, 0x6f,
-	0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x74, 0x79, 0x70, 0x65, 0x73, 0x2f, 0x67, 0x6f, 0x66, 0x65,
-	0x61, 0x74, 0x75, 0x72, 0x65, 0x73, 0x70, 0x62,
+	0x6c, 0x4a, 0x73, 0x6f, 0x6e, 0x45, 0x6e, 0x75, 0x6d, 0x12, 0x7c, 0x0a, 0x11, 0x73, 0x74, 0x72,
+	0x69, 0x70, 0x5f, 0x65, 0x6e, 0x75, 0x6d, 0x5f, 0x70, 0x72, 0x65, 0x66, 0x69, 0x78, 0x18, 0x03,
+	0x20, 0x01, 0x28, 0x0e, 0x32, 0x1e, 0x2e, 0x70, 0x62, 0x2e, 0x47, 0x6f, 0x46, 0x65, 0x61, 0x74,
+	0x75, 0x72, 0x65, 0x73, 0x2e, 0x53, 0x74, 0x72, 0x69, 0x70, 0x45, 0x6e, 0x75, 0x6d, 0x50, 0x72,
+	0x65, 0x66, 0x69, 0x78, 0x42, 0x30, 0x88, 0x01, 0x01, 0x98, 0x01, 0x06, 0x98, 0x01, 0x07, 0x98,
+	0x01, 0x01, 0xa2, 0x01, 0x1b, 0x12, 0x16, 0x53, 0x54, 0x52, 0x49, 0x50, 0x5f, 0x45, 0x4e, 0x55,
+	0x4d, 0x5f, 0x50, 0x52, 0x45, 0x46, 0x49, 0x58, 0x5f, 0x4b, 0x45, 0x45, 0x50, 0x18, 0x84, 0x07,
+	0xb2, 0x01, 0x03, 0x08, 0xe9, 0x07, 0x52, 0x0f, 0x73, 0x74, 0x72, 0x69, 0x70, 0x45, 0x6e, 0x75,
+	0x6d, 0x50, 0x72, 0x65, 0x66, 0x69, 0x78, 0x22, 0x92, 0x01, 0x0a, 0x0f, 0x53, 0x74, 0x72, 0x69,
+	0x70, 0x45, 0x6e, 0x75, 0x6d, 0x50, 0x72, 0x65, 0x66, 0x69, 0x78, 0x12, 0x21, 0x0a, 0x1d, 0x53,
+	0x54, 0x52, 0x49, 0x50, 0x5f, 0x45, 0x4e, 0x55, 0x4d, 0x5f, 0x50, 0x52, 0x45, 0x46, 0x49, 0x58,
+	0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, 0x1a,
+	0x0a, 0x16, 0x53, 0x54, 0x52, 0x49, 0x50, 0x5f, 0x45, 0x4e, 0x55, 0x4d, 0x5f, 0x50, 0x52, 0x45,
+	0x46, 0x49, 0x58, 0x5f, 0x4b, 0x45, 0x45, 0x50, 0x10, 0x01, 0x12, 0x23, 0x0a, 0x1f, 0x53, 0x54,
+	0x52, 0x49, 0x50, 0x5f, 0x45, 0x4e, 0x55, 0x4d, 0x5f, 0x50, 0x52, 0x45, 0x46, 0x49, 0x58, 0x5f,
+	0x47, 0x45, 0x4e, 0x45, 0x52, 0x41, 0x54, 0x45, 0x5f, 0x42, 0x4f, 0x54, 0x48, 0x10, 0x02, 0x12,
+	0x1b, 0x0a, 0x17, 0x53, 0x54, 0x52, 0x49, 0x50, 0x5f, 0x45, 0x4e, 0x55, 0x4d, 0x5f, 0x50, 0x52,
+	0x45, 0x46, 0x49, 0x58, 0x5f, 0x53, 0x54, 0x52, 0x49, 0x50, 0x10, 0x03, 0x3a, 0x3c, 0x0a, 0x02,
+	0x67, 0x6f, 0x12, 0x1b, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74,
+	0x6f, 0x62, 0x75, 0x66, 0x2e, 0x46, 0x65, 0x61, 0x74, 0x75, 0x72, 0x65, 0x53, 0x65, 0x74, 0x18,
+	0xea, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0e, 0x2e, 0x70, 0x62, 0x2e, 0x47, 0x6f, 0x46, 0x65,
+	0x61, 0x74, 0x75, 0x72, 0x65, 0x73, 0x52, 0x02, 0x67, 0x6f, 0x42, 0x2f, 0x5a, 0x2d, 0x67, 0x6f,
+	0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x67, 0x6f, 0x6c, 0x61, 0x6e, 0x67, 0x2e, 0x6f, 0x72, 0x67, 0x2f,
+	0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x74, 0x79, 0x70, 0x65, 0x73, 0x2f, 0x67,
+	0x6f, 0x66, 0x65, 0x61, 0x74, 0x75, 0x72, 0x65, 0x73, 0x70, 0x62,
 }
 
 var (
@@ -123,19 +210,22 @@
 	return file_google_protobuf_go_features_proto_rawDescData
 }
 
+var file_google_protobuf_go_features_proto_enumTypes = make([]protoimpl.EnumInfo, 1)
 var file_google_protobuf_go_features_proto_msgTypes = make([]protoimpl.MessageInfo, 1)
 var file_google_protobuf_go_features_proto_goTypes = []any{
-	(*GoFeatures)(nil),              // 0: pb.GoFeatures
-	(*descriptorpb.FeatureSet)(nil), // 1: google.protobuf.FeatureSet
+	(GoFeatures_StripEnumPrefix)(0), // 0: pb.GoFeatures.StripEnumPrefix
+	(*GoFeatures)(nil),              // 1: pb.GoFeatures
+	(*descriptorpb.FeatureSet)(nil), // 2: google.protobuf.FeatureSet
 }
 var file_google_protobuf_go_features_proto_depIdxs = []int32{
-	1, // 0: pb.go:extendee -> google.protobuf.FeatureSet
-	0, // 1: pb.go:type_name -> pb.GoFeatures
-	2, // [2:2] is the sub-list for method output_type
-	2, // [2:2] is the sub-list for method input_type
-	1, // [1:2] is the sub-list for extension type_name
-	0, // [0:1] is the sub-list for extension extendee
-	0, // [0:0] is the sub-list for field type_name
+	0, // 0: pb.GoFeatures.strip_enum_prefix:type_name -> pb.GoFeatures.StripEnumPrefix
+	2, // 1: pb.go:extendee -> google.protobuf.FeatureSet
+	1, // 2: pb.go:type_name -> pb.GoFeatures
+	3, // [3:3] is the sub-list for method output_type
+	3, // [3:3] is the sub-list for method input_type
+	2, // [2:3] is the sub-list for extension type_name
+	1, // [1:2] is the sub-list for extension extendee
+	0, // [0:1] is the sub-list for field type_name
 }
 
 func init() { file_google_protobuf_go_features_proto_init() }
@@ -148,13 +238,14 @@
 		File: protoimpl.DescBuilder{
 			GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
 			RawDescriptor: file_google_protobuf_go_features_proto_rawDesc,
-			NumEnums:      0,
+			NumEnums:      1,
 			NumMessages:   1,
 			NumExtensions: 1,
 			NumServices:   0,
 		},
 		GoTypes:           file_google_protobuf_go_features_proto_goTypes,
 		DependencyIndexes: file_google_protobuf_go_features_proto_depIdxs,
+		EnumInfos:         file_google_protobuf_go_features_proto_enumTypes,
 		MessageInfos:      file_google_protobuf_go_features_proto_msgTypes,
 		ExtensionInfos:    file_google_protobuf_go_features_proto_extTypes,
 	}.Build()