diff --git a/src/google/protobuf/compiler/cpp/field_generators/string_field.cc b/src/google/protobuf/compiler/cpp/field_generators/string_field.cc index 624d466c6a..439df1a4ba 100644 --- a/src/google/protobuf/compiler/cpp/field_generators/string_field.cc +++ b/src/google/protobuf/compiler/cpp/field_generators/string_field.cc @@ -234,9 +234,7 @@ void SingularString::GenerateAccessorDeclarations(io::Printer* p) const { // files that applied the ctype. The field can still be accessed via the // reflection interface since the reflection interface is independent of // the string's underlying representation. - bool unknown_ctype = GetDeclaredStringType() != pb::CppFeatures::STRING; - - if (unknown_ctype) { + if (internal::cpp::IsStringFieldWithPrivatizedAccessors(*field_)) { p->Emit(R"cc( private: // Hidden due to unknown ctype option. )cc"); @@ -817,9 +815,7 @@ class RepeatedString : public FieldGeneratorBase { }; void RepeatedString::GenerateAccessorDeclarations(io::Printer* p) const { - bool unknown_ctype = GetDeclaredStringType() != pb::CppFeatures::STRING; - - if (unknown_ctype) { + if (internal::cpp::IsStringFieldWithPrivatizedAccessors(*field_)) { p->Emit(R"cc( private: // Hidden due to unknown ctype option. )cc"); diff --git a/src/google/protobuf/compiler/cpp/field_generators/string_view_field.cc b/src/google/protobuf/compiler/cpp/field_generators/string_view_field.cc index af3e76c8fb..c9869f3686 100644 --- a/src/google/protobuf/compiler/cpp/field_generators/string_view_field.cc +++ b/src/google/protobuf/compiler/cpp/field_generators/string_view_field.cc @@ -635,13 +635,7 @@ class RepeatedStringView : public FieldGeneratorBase { }; void RepeatedStringView::GenerateAccessorDeclarations(io::Printer* p) const { - bool unknown_ctype = GetDeclaredStringType() != pb::CppFeatures::VIEW; - - if (unknown_ctype) { - p->Emit(R"cc( - private: // Hidden due to unknown ctype option. - )cc"); - } + ABSL_DCHECK(GetDeclaredStringType() == pb::CppFeatures::VIEW); auto v1 = p->WithVars(AnnotatedAccessors(field_, {"", "_internal_"})); auto v2 = p->WithVars( diff --git a/src/google/protobuf/compiler/rust/accessors/accessors.cc b/src/google/protobuf/compiler/rust/accessors/accessors.cc index 0e6991a3b2..d85f76a3ea 100644 --- a/src/google/protobuf/compiler/rust/accessors/accessors.cc +++ b/src/google/protobuf/compiler/rust/accessors/accessors.cc @@ -23,18 +23,35 @@ namespace protobuf { namespace compiler { namespace rust { -namespace { +bool IsSupportedField(Context& ctx, const FieldDescriptor& field) { + if (ctx.is_upb()) { + // All fields supported on upb kernel. + return true; + } -std::unique_ptr AccessorGeneratorFor( - Context& ctx, const FieldDescriptor& field) { // TODO: We do not support repeated strings on C++ kernel if // they are not string_view or string type. - if (ctx.is_cpp() && field.is_repeated() && + if (field.is_repeated() && field.cpp_type() == FieldDescriptor::CPPTYPE_STRING && field.cpp_string_type() != FieldDescriptor::CppStringType::kView && field.cpp_string_type() != FieldDescriptor::CppStringType::kString) { - return std::make_unique( - "unsupported repeated string type"); + return false; + } + + // If cpp has made the accessors private, we can't make accessors on top. + if (internal::cpp::IsStringFieldWithPrivatizedAccessors(field)) { + return false; + } + + return true; +} + +namespace { + +std::unique_ptr AccessorGeneratorFor( + Context& ctx, const FieldDescriptor& field) { + if (!IsSupportedField(ctx, field)) { + return std::make_unique(); } if (field.is_map()) { diff --git a/src/google/protobuf/compiler/rust/accessors/accessors.h b/src/google/protobuf/compiler/rust/accessors/accessors.h index 222c096c6b..a6c528537f 100644 --- a/src/google/protobuf/compiler/rust/accessors/accessors.h +++ b/src/google/protobuf/compiler/rust/accessors/accessors.h @@ -17,6 +17,11 @@ namespace protobuf { namespace compiler { namespace rust { +// Returns true if the field will have accessors generated for it. This will +// return true for nearly all fields; there are a few edge cases of string +// types that we don't generate accessors for. +bool IsSupportedField(Context& ctx, const FieldDescriptor& field); + // Generates the Rust accessors: expected to be called once each for each // Message, MessageMut and MessageView's impl. void GenerateAccessorMsgImpl(Context& ctx, const FieldDescriptor& field, diff --git a/src/google/protobuf/compiler/rust/accessors/generator.h b/src/google/protobuf/compiler/rust/accessors/generator.h index 8b7da67a10..701c18d975 100644 --- a/src/google/protobuf/compiler/rust/accessors/generator.h +++ b/src/google/protobuf/compiler/rust/accessors/generator.h @@ -124,13 +124,9 @@ class RepeatedField final : public AccessorGenerator { class UnsupportedField final : public AccessorGenerator { public: - explicit UnsupportedField(std::string reason) : reason_(std::move(reason)) {} ~UnsupportedField() override = default; void InMsgImpl(Context& ctx, const FieldDescriptor& field, AccessorCase accessor_case) const override; - - private: - std::string reason_; }; class Map final : public AccessorGenerator { diff --git a/src/google/protobuf/compiler/rust/accessors/unsupported_field.cc b/src/google/protobuf/compiler/rust/accessors/unsupported_field.cc index 1ca66f63ef..2131b479b7 100644 --- a/src/google/protobuf/compiler/rust/accessors/unsupported_field.cc +++ b/src/google/protobuf/compiler/rust/accessors/unsupported_field.cc @@ -18,10 +18,10 @@ namespace rust { void UnsupportedField::InMsgImpl(Context& ctx, const FieldDescriptor& field, AccessorCase accessor_case) const { - ctx.Emit({{"reason", reason_}}, R"rs( - // Unsupported! :( Reason: $reason$ + ctx.Emit(R"rs( + // Unsupported field! :( + )rs"); - ctx.printer().PrintRaw("\n"); } } // namespace rust diff --git a/src/google/protobuf/compiler/rust/oneof.cc b/src/google/protobuf/compiler/rust/oneof.cc index 3d74643348..54ea6ad943 100644 --- a/src/google/protobuf/compiler/rust/oneof.cc +++ b/src/google/protobuf/compiler/rust/oneof.cc @@ -15,6 +15,7 @@ #include "absl/strings/string_view.h" #include "google/protobuf/compiler/cpp/helpers.h" #include "google/protobuf/compiler/rust/accessors/accessor_case.h" +#include "google/protobuf/compiler/rust/accessors/accessors.h" #include "google/protobuf/compiler/rust/context.h" #include "google/protobuf/compiler/rust/naming.h" #include "google/protobuf/compiler/rust/rust_field_type.h" @@ -81,13 +82,28 @@ namespace rust { // } namespace { -// A user-friendly rust type for a view of this field with lifetime 'msg. -std::string RsTypeNameView(Context& ctx, const FieldDescriptor& field) { + +bool IsSupportedOneofFieldCase(Context& ctx, const FieldDescriptor& field) { + if (!IsSupportedField(ctx, field)) { + return false; + } + + // In addition to any fields that are otherwise unsupported, if the + // oneof contains a string or bytes field which is not string_view or string + // representation (namely, Cord or StringPiece), we don't support it + // currently. if (ctx.is_cpp() && field.cpp_type() == FieldDescriptor::CPPTYPE_STRING && - field.cpp_string_type() != FieldDescriptor::CppStringType::kView && - field.cpp_string_type() != FieldDescriptor::CppStringType::kString) { - return ""; // TODO: b/308792377 - ctype fields not supported yet. + field.cpp_string_type() != FieldDescriptor::CppStringType::kString && + field.cpp_string_type() != FieldDescriptor::CppStringType::kView) { + return false; } + return true; +} + +// A user-friendly rust type for a view of this field with lifetime 'msg. +std::string RsTypeNameView(Context& ctx, const FieldDescriptor& field) { + ABSL_CHECK(IsSupportedOneofFieldCase(ctx, field)); + switch (GetRustFieldType(field.type())) { case RustFieldType::INT32: case RustFieldType::INT64: @@ -121,10 +137,10 @@ void GenerateOneofDefinition(Context& ctx, const OneofDescriptor& oneof) { [&] { for (int i = 0; i < oneof.field_count(); ++i) { auto& field = *oneof.field(i); - std::string rs_type = RsTypeNameView(ctx, field); - if (rs_type.empty()) { + if (!IsSupportedOneofFieldCase(ctx, field)) { continue; } + std::string rs_type = RsTypeNameView(ctx, field); ctx.Emit({{"name", OneofCaseRsName(field)}, {"type", rs_type}, {"number", std::to_string(field.number())}}, @@ -159,6 +175,9 @@ void GenerateOneofDefinition(Context& ctx, const OneofDescriptor& oneof) { [&] { for (int i = 0; i < oneof.field_count(); ++i) { auto& field = *oneof.field(i); + if (!IsSupportedOneofFieldCase(ctx, field)) { + continue; + } ctx.Emit({{"name", OneofCaseRsName(field)}, {"number", std::to_string(field.number())}}, R"rs($name$ = $number$, @@ -169,6 +188,9 @@ void GenerateOneofDefinition(Context& ctx, const OneofDescriptor& oneof) { [&] { for (int i = 0; i < oneof.field_count(); ++i) { auto& field = *oneof.field(i); + if (!IsSupportedOneofFieldCase(ctx, field)) { + continue; + } ctx.Emit({{"name", OneofCaseRsName(field)}, {"number", std::to_string(field.number())}}, R"rs($number$ => Some($case_enum_name$::$name$), @@ -217,10 +239,10 @@ void GenerateOneofAccessors(Context& ctx, const OneofDescriptor& oneof, [&] { for (int i = 0; i < oneof.field_count(); ++i) { auto& field = *oneof.field(i); - std::string rs_type = RsTypeNameView(ctx, field); - if (rs_type.empty()) { + if (!IsSupportedOneofFieldCase(ctx, field)) { continue; } + std::string rs_type = RsTypeNameView(ctx, field); std::string field_name = FieldNameWithCollisionAvoidance(field); ctx.Emit( { diff --git a/src/google/protobuf/descriptor.cc b/src/google/protobuf/descriptor.cc index e2bd05f5de..4bed646e82 100644 --- a/src/google/protobuf/descriptor.cc +++ b/src/google/protobuf/descriptor.cc @@ -3960,16 +3960,15 @@ bool FieldDescriptor::has_optional_keyword() const { FieldDescriptor::CppStringType FieldDescriptor::cpp_string_type() const { ABSL_DCHECK(cpp_type() == FieldDescriptor::CPPTYPE_STRING); + + if (internal::cpp::IsStringFieldWithPrivatizedAccessors(*this)) { + return CppStringType::kString; + } + switch (features().GetExtension(pb::cpp).string_type()) { case pb::CppFeatures::VIEW: return CppStringType::kView; case pb::CppFeatures::CORD: - // In open-source, protobuf CORD is only supported for singular bytes - // fields. - if (type() != FieldDescriptor::TYPE_BYTES || is_repeated() || - is_extension()) { - return CppStringType::kString; - } return CppStringType::kCord; case pb::CppFeatures::STRING: return CppStringType::kString; @@ -9871,6 +9870,21 @@ bool IsLazilyInitializedFile(absl::string_view filename) { filename == "google/protobuf/descriptor.proto"; } +bool IsStringFieldWithPrivatizedAccessors(const FieldDescriptor& field) { + // In open-source, protobuf CORD is only supported for singular bytes + // fields. + if (field.cpp_type() == FieldDescriptor::CPPTYPE_STRING && + InternalFeatureHelper::GetFeatures(field) + .GetExtension(pb::cpp) + .string_type() == pb::CppFeatures::CORD && + (field.type() != FieldDescriptor::TYPE_BYTES || field.is_repeated() || + field.is_extension())) { + return true; + } + + return false; +} + } // namespace cpp } // namespace internal diff --git a/src/google/protobuf/descriptor.h b/src/google/protobuf/descriptor.h index 068b918de0..1222bac872 100644 --- a/src/google/protobuf/descriptor.h +++ b/src/google/protobuf/descriptor.h @@ -3035,6 +3035,14 @@ auto VisitDescriptorsInFileOrder(const FileDescriptor* file, } #endif // !SWIG +// Whether the given string field should have the accessors be privatized due +// to it being an unsupported type. If this returns true, cpp_string_type() +// returns kString for the storage, the C++ Generator will not generate +// public accessors for the type, but the field will sill be accessible via +// reflection. +PROTOBUF_EXPORT bool IsStringFieldWithPrivatizedAccessors( + const FieldDescriptor& field); + } // namespace cpp } // namespace internal