Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Experimental support for enum variant names and discriminant values retrieved from C++ #847

Merged
merged 22 commits into from
Apr 23, 2021

Conversation

dtolnay
Copy link
Owner

@dtolnay dtolnay commented Apr 23, 2021

This PR adds an optional feature based on https://github.com/dtolnay/clang-ast to extract information about shared enums (variant names, discriminant values, repr type) from a serialized Clang AST of the associated C++ headers.

The user-facing change is:

  #[cxx::bridge]
  mod ffi {
      extern "C++" {
          include!("path/to/ServiceManager.h");
      }

      ...

-     #[repr(i32)]
      enum ServiceState {
-         DISABLED = 0,
-         ENABLED = 1,
-         PRODUCTION = 2,
-         QA_SERVICE = 4,
-         IN_REPAIR = 8,
+         #![variants_from_header]
      }
  }

Wiring up an AST dump in a Buck-based build looks something like:

def rust_library(
        name,
        env = {},
        cxx_bridge = None,
        cxx_deps = None,
        **kwargs):
    if cxx_bridge:
        rust_cxx_bridge(
            name = "%s@bridge" % name,
            src = cxx_bridge,
            deps = cxx_deps,
        )

        clang_ast(
            name = "%s@ast" % name,
            header = ":%s@bridge=generated.h" % name,
            deps = cpp_deps,
        )

        env["CXX_CLANG_AST"] = "$(location :%s@ast)" % name

    native.rust_library(
        name = name,
        env = env,
        **kwargs,
    )

where clang_ast() is a simple bzl macro implemented as a genrule that runs clang++ -Xclang -ast-dump=json -fsyntax-only $(location {header}) -I$(location {deps}) -x c++, and rust_cxx_bridge is like tools/buck/rust_cxx_bridge.bzl.

This is experimental for now but opens up some interesting possibilities, such as:

  • Rustfix-compatible autofix suggestion if you've written an incompatible signature (i.e. as opposed to a C++ type error later in the generated code)
  • Automatically using type Kind = Trivial for extern "C++" types which have a trivial definition, thereby making them available by value in Rust

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

1 participant