@@ -51,7 +51,8 @@ - (instancetype)initWithFieldDescription:(void *)description
5151 file : (GPBFileDescriptor *)file
5252 includesDefault : (BOOL )includesDefault
5353 usesClassRefs : (BOOL )usesClassRefs
54- proto3OptionalKnown : (BOOL )proto3OptionalKnown ;
54+ proto3OptionalKnown : (BOOL )proto3OptionalKnown
55+ closedEnumSupportKnown : (BOOL )closedEnumSupportKnown ;
5556
5657@end
5758
@@ -60,7 +61,8 @@ - (instancetype)initWithName:(NSString *)name
6061 valueNames : (const char *)valueNames
6162 values : (const int32_t *)values
6263 count : (uint32_t )valueCount
63- enumVerifier : (GPBEnumValidationFunc)enumVerifier ;
64+ enumVerifier : (GPBEnumValidationFunc)enumVerifier
65+ flags : (GPBEnumDescriptorInitializationFlags)flags ;
6466@end
6567
6668// Direct access is use for speed, to avoid even internally declaring things
@@ -150,6 +152,8 @@ + (instancetype)allocDescriptorForClass:(Class)messageClass
150152 BOOL fieldsIncludeDefault = (flags & GPBDescriptorInitializationFlag_FieldsWithDefault) != 0 ;
151153 BOOL usesClassRefs = (flags & GPBDescriptorInitializationFlag_UsesClassRefs) != 0 ;
152154 BOOL proto3OptionalKnown = (flags & GPBDescriptorInitializationFlag_Proto3OptionalKnown) != 0 ;
155+ BOOL closedEnumSupportKnown =
156+ (flags & GPBDescriptorInitializationFlag_ClosedEnumSupportKnown) != 0 ;
153157
154158 void *desc;
155159 for (uint32_t i = 0 ; i < fieldCount; ++i) {
@@ -164,7 +168,8 @@ + (instancetype)allocDescriptorForClass:(Class)messageClass
164168 file: file
165169 includesDefault: fieldsIncludeDefault
166170 usesClassRefs: usesClassRefs
167- proto3OptionalKnown: proto3OptionalKnown];
171+ proto3OptionalKnown: proto3OptionalKnown
172+ closedEnumSupportKnown: closedEnumSupportKnown];
168173 [fields addObject: fieldDescriptor];
169174 [fieldDescriptor release ];
170175 }
@@ -475,7 +480,8 @@ - (instancetype)initWithFieldDescription:(void *)description
475480 file : (GPBFileDescriptor *)file
476481 includesDefault : (BOOL )includesDefault
477482 usesClassRefs : (BOOL )usesClassRefs
478- proto3OptionalKnown : (BOOL )proto3OptionalKnown {
483+ proto3OptionalKnown : (BOOL )proto3OptionalKnown
484+ closedEnumSupportKnown : (BOOL )closedEnumSupportKnown {
479485 if ((self = [super init ])) {
480486 GPBMessageFieldDescription *coreDesc;
481487 if (includesDefault) {
@@ -506,6 +512,21 @@ - (instancetype)initWithFieldDescription:(void *)description
506512 }
507513 }
508514
515+ // If the ClosedEnum flag wasn't known (i.e. generated code from an older
516+ // version), compute the flag for the rest of the runtime.
517+ if (!closedEnumSupportKnown) {
518+ // NOTE: This isn't correct, it is using the syntax of the file that
519+ // declared the field, not the syntax of the file that declared the
520+ // enum; but for older generated code, that's all we have and that happens
521+ // to be what the runtime was doing (even though it was wrong). This is
522+ // only wrong in the rare cases an enum is declared in a proto3 syntax
523+ // file but used for a field in the proto2 syntax file.
524+ BOOL isClosedEnum = (dataType == GPBDataTypeEnum && file.syntax != GPBFileSyntaxProto3);
525+ if (isClosedEnum) {
526+ coreDesc->flags |= GPBFieldClosedEnum;
527+ }
528+ }
529+
509530 if (isMapOrArray) {
510531 // map<>/repeated fields get a *Count property (inplace of a has*) to
511532 // support checking if there are any entries without triggering
@@ -535,9 +556,14 @@ - (instancetype)initWithFieldDescription:(void *)description
535556 NSAssert (msgClass_, @" Class %s not defined" , className);
536557 }
537558 } else if (dataType == GPBDataTypeEnum) {
559+ enumDescriptor_ = coreDesc->dataTypeSpecific .enumDescFunc ();
560+ #if defined(DEBUG) && DEBUG
538561 NSAssert ((coreDesc->flags & GPBFieldHasEnumDescriptor) != 0,
539562 @"Field must have GPBFieldHasEnumDescriptor set");
540- enumDescriptor_ = coreDesc->dataTypeSpecific .enumDescFunc ();
563+ NSAssert (!closedEnumSupportKnown ||
564+ (((coreDesc->flags & GPBFieldClosedEnum) != 0) == enumDescriptor_.isClosed),
565+ @"Internal error, ClosedEnum flag doesn't agree with EnumDescriptor");
566+ #endif // DEBUG
541567 }
542568
543569 // Non map<>/repeated fields can have defaults in proto2 syntax.
@@ -740,6 +766,7 @@ @implementation GPBEnumDescriptor {
740766 const uint8_t *extraTextFormatInfo_;
741767 uint32_t *nameOffsets_;
742768 uint32_t valueCount_;
769+ uint32_t flags_;
743770}
744771
745772@synthesize name = name_;
@@ -749,12 +776,14 @@ + (instancetype)allocDescriptorForName:(NSString *)name
749776 valueNames : (const char *)valueNames
750777 values : (const int32_t *)values
751778 count : (uint32_t )valueCount
752- enumVerifier : (GPBEnumValidationFunc)enumVerifier {
779+ enumVerifier : (GPBEnumValidationFunc)enumVerifier
780+ flags : (GPBEnumDescriptorInitializationFlags)flags {
753781 GPBEnumDescriptor *descriptor = [[self alloc ] initWithName: name
754782 valueNames: valueNames
755783 values: values
756784 count: valueCount
757- enumVerifier: enumVerifier];
785+ enumVerifier: enumVerifier
786+ flags: flags];
758787 return descriptor;
759788}
760789
@@ -763,29 +792,61 @@ + (instancetype)allocDescriptorForName:(NSString *)name
763792 values : (const int32_t *)values
764793 count : (uint32_t )valueCount
765794 enumVerifier : (GPBEnumValidationFunc)enumVerifier
795+ flags : (GPBEnumDescriptorInitializationFlags)flags
766796 extraTextFormatInfo : (const char *)extraTextFormatInfo {
767797 // Call the common case.
768798 GPBEnumDescriptor *descriptor = [self allocDescriptorForName: name
769799 valueNames: valueNames
770800 values: values
771801 count: valueCount
772- enumVerifier: enumVerifier];
802+ enumVerifier: enumVerifier
803+ flags: flags];
773804 // Set the extra info.
774805 descriptor->extraTextFormatInfo_ = (const uint8_t *)extraTextFormatInfo;
775806 return descriptor;
776807}
777808
809+ + (instancetype )allocDescriptorForName : (NSString *)name
810+ valueNames : (const char *)valueNames
811+ values : (const int32_t *)values
812+ count : (uint32_t )valueCount
813+ enumVerifier : (GPBEnumValidationFunc)enumVerifier {
814+ return [self allocDescriptorForName: name
815+ valueNames: valueNames
816+ values: values
817+ count: valueCount
818+ enumVerifier: enumVerifier
819+ flags: GPBEnumDescriptorInitializationFlag_None];
820+ }
821+
822+ + (instancetype )allocDescriptorForName : (NSString *)name
823+ valueNames : (const char *)valueNames
824+ values : (const int32_t *)values
825+ count : (uint32_t )valueCount
826+ enumVerifier : (GPBEnumValidationFunc)enumVerifier
827+ extraTextFormatInfo : (const char *)extraTextFormatInfo {
828+ return [self allocDescriptorForName: name
829+ valueNames: valueNames
830+ values: values
831+ count: valueCount
832+ enumVerifier: enumVerifier
833+ flags: GPBEnumDescriptorInitializationFlag_None
834+ extraTextFormatInfo: extraTextFormatInfo];
835+ }
836+
778837- (instancetype )initWithName : (NSString *)name
779838 valueNames : (const char *)valueNames
780839 values : (const int32_t *)values
781840 count : (uint32_t )valueCount
782- enumVerifier : (GPBEnumValidationFunc)enumVerifier {
841+ enumVerifier : (GPBEnumValidationFunc)enumVerifier
842+ flags : (GPBEnumDescriptorInitializationFlags)flags {
783843 if ((self = [super init ])) {
784844 name_ = [name copy ];
785845 valueNames_ = valueNames;
786846 values_ = values;
787847 valueCount_ = valueCount;
788848 enumVerifier_ = enumVerifier;
849+ flags_ = flags;
789850 }
790851 return self;
791852}
@@ -796,6 +857,10 @@ - (void)dealloc {
796857 [super dealloc ];
797858}
798859
860+ - (BOOL )isClosed {
861+ return (flags_ & GPBEnumDescriptorInitializationFlag_IsClosed) != 0 ;
862+ }
863+
799864- (void )calcValueNameOffsets {
800865 @synchronized (self) {
801866 if (nameOffsets_ != NULL ) {
0 commit comments