[fidl] Empty services now compile successfully

This CL fixes fidlgen backends for HLCPP, LLCPP, and Rust so that an
empty FIDL service such as `service Foo {};` produces bindings that
compile successfully.

Test: fx build # builds FIDL golden libraries
Bug: 62521
Change-Id: I7c22ba5579e1ae53b2664513ac520115fe68a8ca
Reviewed-on: https://fuchsia-review.googlesource.com/c/fuchsia/+/442624
Reviewed-by: Mitchell Kember <mkember@google.com>
Reviewed-by: Adam Lesinski <adamlesinski@google.com>
Testability-Review: Mitchell Kember <mkember@google.com>
Testability-Review: Adam Lesinski <adamlesinski@google.com>
Commit-Queue: Mitchell Kember <mkember@google.com>
diff --git a/garnet/go/src/fidl/compiler/backend/goldens/bindings_denylist.test.json.h.golden b/garnet/go/src/fidl/compiler/backend/goldens/bindings_denylist.test.json.h.golden
index 375388d..3ccbbb4 100644
--- a/garnet/go/src/fidl/compiler/backend/goldens/bindings_denylist.test.json.h.golden
+++ b/garnet/go/src/fidl/compiler/backend/goldens/bindings_denylist.test.json.h.golden
@@ -32,10 +32,9 @@
 class OnlyHlcpp::Handler final {
  public:
   /// Constructs a new |Handler|. Does not take ownership of |service|.
-  explicit Handler(::fidl::ServiceHandlerBase* service) : service_(service) {}
+  explicit Handler(::fidl::ServiceHandlerBase* service) { (void)service; }
 
  private:
-  ::fidl::ServiceHandlerBase* const service_;
 };
 #endif  // __Fuchsia
 
diff --git a/garnet/go/src/fidl/compiler/backend/goldens/doc_comments.test.json.rs.golden b/garnet/go/src/fidl/compiler/backend/goldens/doc_comments.test.json.rs.golden
index 0344974..cc884eb 100644
--- a/garnet/go/src/fidl/compiler/backend/goldens/doc_comments.test.json.rs.golden
+++ b/garnet/go/src/fidl/compiler/backend/goldens/doc_comments.test.json.rs.golden
@@ -659,10 +659,10 @@
 impl fidl::endpoints::UnifiedServiceRequest for ServiceRequest {
     type Service = ServiceMarker;
 
-    fn dispatch(name: &str, channel: fidl::AsyncChannel) -> Self {
+    fn dispatch(name: &str, _channel: fidl::AsyncChannel) -> Self {
         match name {
             "interface" => Self::Interface(
-                <InterfaceRequestStream as fidl::endpoints::RequestStream>::from_channel(channel),
+                <InterfaceRequestStream as fidl::endpoints::RequestStream>::from_channel(_channel),
             ),
             _ => panic!("no such member protocol name for service Service"),
         }
diff --git a/garnet/go/src/fidl/compiler/backend/goldens/service.test.json.h.golden b/garnet/go/src/fidl/compiler/backend/goldens/service.test.json.h.golden
index cca0bef..ba20f49 100644
--- a/garnet/go/src/fidl/compiler/backend/goldens/service.test.json.h.golden
+++ b/garnet/go/src/fidl/compiler/backend/goldens/service.test.json.h.golden
@@ -536,10 +536,9 @@
 class EmptyService::Handler final {
  public:
   /// Constructs a new |Handler|. Does not take ownership of |service|.
-  explicit Handler(::fidl::ServiceHandlerBase* service) : service_(service) {}
+  explicit Handler(::fidl::ServiceHandlerBase* service) { (void)service; }
 
  private:
-  ::fidl::ServiceHandlerBase* const service_;
 };
 #endif  // __Fuchsia
 }  // namespace service
diff --git a/garnet/go/src/fidl/compiler/backend/goldens/service.test.json.llcpp.h.golden b/garnet/go/src/fidl/compiler/backend/goldens/service.test.json.llcpp.h.golden
index 745e612..9e06c6c 100644
--- a/garnet/go/src/fidl/compiler/backend/goldens/service.test.json.llcpp.h.golden
+++ b/garnet/go/src/fidl/compiler/backend/goldens/service.test.json.llcpp.h.golden
@@ -906,12 +906,12 @@
 
    public:
     ServiceClient(::zx::channel dir,
-                  ::fidl::internal::ConnectMemberFunc connect_func)
-        : dir_(std::move(dir)), connect_func_(connect_func) {}
+                  ::fidl::internal::ConnectMemberFunc connect_func) {
+      (void)dir;
+      (void)connect_func;
+    }
 
    private:
-    ::zx::channel dir_;
-    ::fidl::internal::ConnectMemberFunc connect_func_;
   };
 
   // Facilitates member protocol registration for servers.
@@ -919,11 +919,11 @@
    public:
     // Constructs a FIDL Service-typed handler. Does not take ownership of
     // |service_handler|.
-    explicit Handler(::llcpp::fidl::ServiceHandlerInterface* service_handler)
-        : service_handler_(service_handler) {}
+    explicit Handler(::llcpp::fidl::ServiceHandlerInterface* service_handler) {
+      (void)service_handler;
+    }
 
    private:
-    ::llcpp::fidl::ServiceHandlerInterface* service_handler_;  // Not owned.
   };
 };
 
diff --git a/garnet/go/src/fidl/compiler/backend/goldens/service.test.json.rs.golden b/garnet/go/src/fidl/compiler/backend/goldens/service.test.json.rs.golden
index c6c261f0b..81997ff 100644
--- a/garnet/go/src/fidl/compiler/backend/goldens/service.test.json.rs.golden
+++ b/garnet/go/src/fidl/compiler/backend/goldens/service.test.json.rs.golden
@@ -709,7 +709,7 @@
 impl fidl::endpoints::UnifiedServiceRequest for EmptyServiceRequest {
     type Service = EmptyServiceMarker;
 
-    fn dispatch(name: &str, channel: fidl::AsyncChannel) -> Self {
+    fn dispatch(name: &str, _channel: fidl::AsyncChannel) -> Self {
         match name {
             _ => panic!("no such member protocol name for service EmptyService"),
         }
@@ -755,11 +755,11 @@
 impl fidl::endpoints::UnifiedServiceRequest for SingleMemberServiceRequest {
     type Service = SingleMemberServiceMarker;
 
-    fn dispatch(name: &str, channel: fidl::AsyncChannel) -> Self {
+    fn dispatch(name: &str, _channel: fidl::AsyncChannel) -> Self {
         match name {
             "single_member" => Self::SingleMember(
                 <FirstProtocolRequestStream as fidl::endpoints::RequestStream>::from_channel(
-                    channel,
+                    _channel,
                 ),
             ),
             _ => panic!("no such member protocol name for service SingleMemberService"),
@@ -814,16 +814,16 @@
 impl fidl::endpoints::UnifiedServiceRequest for MultiHeterogeneousMemberServiceRequest {
     type Service = MultiHeterogeneousMemberServiceMarker;
 
-    fn dispatch(name: &str, channel: fidl::AsyncChannel) -> Self {
+    fn dispatch(name: &str, _channel: fidl::AsyncChannel) -> Self {
         match name {
             "first_member" => Self::FirstMember(
                 <FirstProtocolRequestStream as fidl::endpoints::RequestStream>::from_channel(
-                    channel,
+                    _channel,
                 ),
             ),
             "second_member" => Self::SecondMember(
                 <SecondProtocolRequestStream as fidl::endpoints::RequestStream>::from_channel(
-                    channel,
+                    _channel,
                 ),
             ),
             _ => panic!("no such member protocol name for service MultiHeterogeneousMemberService"),
@@ -884,16 +884,16 @@
 impl fidl::endpoints::UnifiedServiceRequest for MultiHomogeneousMemberServiceRequest {
     type Service = MultiHomogeneousMemberServiceMarker;
 
-    fn dispatch(name: &str, channel: fidl::AsyncChannel) -> Self {
+    fn dispatch(name: &str, _channel: fidl::AsyncChannel) -> Self {
         match name {
             "first_member" => Self::FirstMember(
                 <FirstProtocolRequestStream as fidl::endpoints::RequestStream>::from_channel(
-                    channel,
+                    _channel,
                 ),
             ),
             "second_member" => Self::SecondMember(
                 <FirstProtocolRequestStream as fidl::endpoints::RequestStream>::from_channel(
-                    channel,
+                    _channel,
                 ),
             ),
             _ => panic!("no such member protocol name for service MultiHomogeneousMemberService"),
diff --git a/tools/fidl/fidlgen_hlcpp/BUILD.gn b/tools/fidl/fidlgen_hlcpp/BUILD.gn
index 0f39ad8..044e853 100644
--- a/tools/fidl/fidlgen_hlcpp/BUILD.gn
+++ b/tools/fidl/fidlgen_hlcpp/BUILD.gn
@@ -87,10 +87,6 @@
     # TODO(fxbug.dev/62520): Insert enum/bits <-> primitive conversions.
     "//zircon/tools/fidl/testdata:fidl.test.consts",
 
-    # TODO(fxbug.dev/62521): Make empty service compile.
-    "//zircon/tools/fidl/testdata:fidl.test.bindingsdenylist",
-    "//zircon/tools/fidl/testdata:fidl.test.service",
-
     # TODO(fxbug.dev/62533): Fix many issues.
     "//zircon/tools/fidl/testdata:fidl.test.handles",
   ]
diff --git a/tools/fidl/fidlgen_hlcpp/codegen/service.tmpl.go b/tools/fidl/fidlgen_hlcpp/codegen/service.tmpl.go
index af08277..f23ed5a 100644
--- a/tools/fidl/fidlgen_hlcpp/codegen/service.tmpl.go
+++ b/tools/fidl/fidlgen_hlcpp/codegen/service.tmpl.go
@@ -42,7 +42,12 @@
 class {{ .Name }}::Handler final {
  public:
   /// Constructs a new |Handler|. Does not take ownership of |service|.
-  explicit Handler(::fidl::ServiceHandlerBase* service) : service_(service) {}
+  explicit Handler(::fidl::ServiceHandlerBase* service)
+  {{- with .Members }}
+      : service_(service) {}
+  {{- else }}
+      { (void)service; }
+  {{- end }}
 
   {{- range .Members }}
   /// Adds member "{{ .Name }}" to the service instance. |handler| is invoked when a connection
@@ -57,7 +62,9 @@
   {{- end }}
 
  private:
+  {{- with .Members }}
   ::fidl::ServiceHandlerBase* const service_;
+  {{- end }}
 };
 #endif // __Fuchsia
 {{- end }}
diff --git a/tools/fidl/fidlgen_llcpp/BUILD.gn b/tools/fidl/fidlgen_llcpp/BUILD.gn
index 7bbf53d..d97e686 100644
--- a/tools/fidl/fidlgen_llcpp/BUILD.gn
+++ b/tools/fidl/fidlgen_llcpp/BUILD.gn
@@ -95,9 +95,6 @@
 
     # TODO(fxbug.dev/62532): Fix many issues.
     "//zircon/tools/fidl/testdata:fidl.test.protocolrequest",
-
-    # TODO(fxbug.dev/62521): Make empty service compile.
-    "//zircon/tools/fidl/testdata:fidl.test.service",
   ]
 
   if (host_toolchain == current_toolchain) {
@@ -117,6 +114,7 @@
       "//zircon/tools/fidl/testdata:fidl.test.inheritancewithrecursivedecl",
       "//zircon/tools/fidl/testdata:fidl.test.protocols",
       "//zircon/tools/fidl/testdata:fidl.test.requestflexibleenvelope",
+      "//zircon/tools/fidl/testdata:fidl.test.service",
       "//zircon/tools/fidl/testdata:fidl.test.unionsandwich",
       "//zircon/tools/fidl/testdata/foreign_type_in_response_used_through_compose:bottom",
       "//zircon/tools/fidl/testdata/foreign_type_in_response_used_through_compose:middle",
@@ -135,7 +133,6 @@
       #"//zircon/tools/fidl/testdata:fidl.test.handlesintypes",
       #"//zircon/tools/fidl/testdata:fidl.test.nullable",
       #"//zircon/tools/fidl/testdata:fidl.test.protocolrequest",
-      #"//zircon/tools/fidl/testdata:fidl.test.service",
       #"//zircon/tools/fidl/testdata:fidl.test.union",
     ]
   }
diff --git a/tools/fidl/fidlgen_llcpp/codegen/fragment_service.tmpl.go b/tools/fidl/fidlgen_llcpp/codegen/fragment_service.tmpl.go
index 36f03a8..5c75ec6 100644
--- a/tools/fidl/fidlgen_llcpp/codegen/fragment_service.tmpl.go
+++ b/tools/fidl/fidlgen_llcpp/codegen/fragment_service.tmpl.go
@@ -24,7 +24,11 @@
     ServiceClient() = delete;
    public:
     ServiceClient(::zx::channel dir, ::fidl::internal::ConnectMemberFunc connect_func)
-    : dir_(std::move(dir)), connect_func_(connect_func) {}
+    {{- with .Members }}
+        : dir_(std::move(dir)), connect_func_(connect_func) {}
+    {{- else }}
+        { (void)dir; (void)connect_func; }
+    {{- end }}
     {{- range .Members }}
   {{ "" }}
     // Connects to the member protocol "{{ .Name }}". Returns a |fidl::ClientChannel| on
@@ -56,8 +60,10 @@
     {{- end }}
 
    private:
+   {{- with .Members }}
     ::zx::channel dir_;
     ::fidl::internal::ConnectMemberFunc connect_func_;
+   {{- end }}
   };
 
   // Facilitates member protocol registration for servers.
@@ -65,7 +71,11 @@
    public:
     // Constructs a FIDL Service-typed handler. Does not take ownership of |service_handler|.
     explicit Handler(::llcpp::fidl::ServiceHandlerInterface* service_handler)
+    {{- with .Members }}
         : service_handler_(service_handler) {}
+    {{- else }}
+        { (void)service_handler; }
+    {{- end }}
 
     {{- range .Members }}
     {{ "" }}
@@ -81,7 +91,9 @@
     {{- end }}
 
    private:
+   {{- with .Members }}
     ::llcpp::fidl::ServiceHandlerInterface* service_handler_;  // Not owned.
+   {{- end }}
   };
 };
 {{- end }}
diff --git a/tools/fidl/fidlgen_rust/BUILD.gn b/tools/fidl/fidlgen_rust/BUILD.gn
index ff4d79c..e288afc 100644
--- a/tools/fidl/fidlgen_rust/BUILD.gn
+++ b/tools/fidl/fidlgen_rust/BUILD.gn
@@ -86,9 +86,6 @@
 
     # TODO(fxbug.dev/62524): Fix Ord/Hash trait issue with fidl::Resource.
     "//zircon/tools/fidl/testdata:fidl.test.handles",
-
-    # TODO(fxbug.dev/62521): Make empty service compile.
-    "//zircon/tools/fidl/testdata:fidl.test.service",
   ]
 
   deps = []
diff --git a/tools/fidl/fidlgen_rust/codegen/service.tmpl.go b/tools/fidl/fidlgen_rust/codegen/service.tmpl.go
index c7655a4..3a1d05f 100644
--- a/tools/fidl/fidlgen_rust/codegen/service.tmpl.go
+++ b/tools/fidl/fidlgen_rust/codegen/service.tmpl.go
@@ -36,11 +36,11 @@
 impl fidl::endpoints::UnifiedServiceRequest for {{ $service.Name }}Request {
     type Service = {{ $service.Name }}Marker;
 
-    fn dispatch(name: &str, channel: fidl::AsyncChannel) -> Self {
+    fn dispatch(name: &str, _channel: fidl::AsyncChannel) -> Self {
         match name {
             {{- range $member := $service.Members }}
             "{{ $member.Name }}" => Self::{{ $member.CamelName }}(
-                <{{ $member.ProtocolType }}RequestStream as fidl::endpoints::RequestStream>::from_channel(channel),
+                <{{ $member.ProtocolType }}RequestStream as fidl::endpoints::RequestStream>::from_channel(_channel),
             ),
             {{- end }}
             _ => panic!("no such member protocol name for service {{ $service.Name }}"),