@ -3053,6 +3053,10 @@ void FieldDescriptor::CopyTo(FieldDescriptorProto* proto) const {
if ( & options ( ) ! = & FieldOptions : : default_instance ( ) ) {
if ( & options ( ) ! = & FieldOptions : : default_instance ( ) ) {
* proto - > mutable_options ( ) = options ( ) ;
* proto - > mutable_options ( ) = options ( ) ;
if ( proto_features_ - > GetExtension ( pb : : cpp ) . has_string_type ( ) ) {
// ctype must have been set in InferLegacyProtoFeatures so avoid copying.
proto - > mutable_options ( ) - > clear_ctype ( ) ;
}
}
}
RestoreFeaturesToOptions ( proto_features_ , proto ) ;
RestoreFeaturesToOptions ( proto_features_ , proto ) ;
@ -5466,6 +5470,24 @@ static void InferLegacyProtoFeatures(const FieldDescriptorProto& proto,
}
}
}
}
// TODO: we should update proto code to not need ctype to be set
// when string_type is set.
static void EnforceCTypeStringTypeConsistency (
Edition edition , FieldDescriptor : : CppType type ,
const pb : : CppFeatures & cpp_features , FieldOptions & options ) {
if ( & options = = & FieldOptions : : default_instance ( ) ) return ;
if ( edition < Edition : : EDITION_2024 & &
type = = FieldDescriptor : : CPPTYPE_STRING ) {
switch ( cpp_features . string_type ( ) ) {
case pb : : CppFeatures : : CORD :
options . set_ctype ( FieldOptions : : CORD ) ;
break ;
default :
break ;
}
}
}
template < class DescriptorT >
template < class DescriptorT >
void DescriptorBuilder : : ResolveFeaturesImpl (
void DescriptorBuilder : : ResolveFeaturesImpl (
Edition edition , const typename DescriptorT : : Proto & proto ,
Edition edition , const typename DescriptorT : : Proto & proto ,
@ -6091,6 +6113,24 @@ FileDescriptor* DescriptorBuilder::BuildFileImpl(
iter ! = options_to_interpret_ . end ( ) ; + + iter ) {
iter ! = options_to_interpret_ . end ( ) ; + + iter ) {
option_interpreter . InterpretNonExtensionOptions ( & ( * iter ) ) ;
option_interpreter . InterpretNonExtensionOptions ( & ( * iter ) ) ;
}
}
// TODO: move this check back to generator.cc once we no longer
// need to set both ctype and string_type internally.
internal : : VisitDescriptors (
* result , proto ,
[ & ] ( const FieldDescriptor & field , const FieldDescriptorProto & proto ) {
if ( field . options_ - > has_ctype ( ) & & field . options_ - > features ( )
. GetExtension ( pb : : cpp )
. has_string_type ( ) ) {
AddError (
field . full_name ( ) , proto , DescriptorPool : : ErrorCollector : : TYPE ,
absl : : StrFormat ( " Field %s specifies both string_type and ctype "
" which is not supported. " ,
field . full_name ( ) )
. c_str ( ) ) ;
}
} ) ;
// Handle feature resolution. This must occur after option interpretation,
// Handle feature resolution. This must occur after option interpretation,
// but before validation.
// but before validation.
internal : : VisitDescriptors (
internal : : VisitDescriptors (
@ -6108,6 +6148,14 @@ FileDescriptor* DescriptorBuilder::BuildFileImpl(
alloc ) ;
alloc ) ;
} ) ;
} ) ;
internal : : VisitDescriptors ( * result , [ & ] ( const FieldDescriptor & field ) {
EnforceCTypeStringTypeConsistency (
field . file ( ) - > edition ( ) , field . cpp_type ( ) ,
field . merged_features_ - > GetExtension ( pb : : cpp ) ,
const_cast < // NOLINT(google3-runtime-proto-const-cast)
FieldOptions & > ( * field . options_ ) ) ;
} ) ;
// Post-process cleanup for field features.
// Post-process cleanup for field features.
internal : : VisitDescriptors (
internal : : VisitDescriptors (
* result , proto ,
* result , proto ,