Skip to content

Commit

Permalink
Include namespace in all identifiers.
Browse files Browse the repository at this point in the history
This change is the first step towards including a namespace
into all(*) C++ identifiers. In this commit, there is no
intentional functional difference: a single namespace continues
to apply to the entire #[cxx::bridge]; it just happens to be stored
differently.

(*) = This change aims to include a namespace for:

* C++ types
* C++ functions

but not for:

* C++ fields
* C++ enum variants
* Rust types/functions/anything.

A 'QualifiedIdent' struct is used for the first category of things;
plain old proc_macro2::Ident for the latter.

It may be that methods are being treated incorrectly, because they're
functions yet should not have a globally-scoped name. A subsequent
commit may need to fix that.

At the moment, the Namespace (included in each QualifiedIdent)
is ruthlessly cloned all over the place. As a given namespace is
likely to be applicable to many types and functions, it may
save significant memory in future to use Rc<> here. But let's not
optimise too early.

This commit does not currently output the namespace name in
any different ways or different places (intentionally).

syntax/mod.rs has a Boolean constant USE_FULLY_QUALIFIED_NAMES
which will enable that, and it completely breaks everything.
Substantial changes to both Rust and C++ code generation will
be required to use this.

It may be desirable to move the QualifiedIdent code out of
mod.rs.

The rough sequence of commits in mind are:

1) This commit (just stores the namespaces)
2) Use them when writing Rust and C++ code as necessary
3) Allow the current namespace attribute to be overridden
   by finer-grained namespace attributes on individual functions
4) Consider allowing sub-mods which can also have a namespace
   attribute.
5) Future: Introduce a resolution pass which tries to resolve a given
   identifier to a target symbol, after all symbols have been
   read. Support 'use' statements.
  • Loading branch information
adetaylor committed Oct 24, 2020
1 parent cca5215 commit 75f435e
Show file tree
Hide file tree
Showing 12 changed files with 330 additions and 167 deletions.
4 changes: 2 additions & 2 deletions gen/src/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -109,10 +109,10 @@ pub(super) fn generate(syntax: File, opt: &Opt) -> Result<GeneratedCode> {
.ok_or(Error::NoBridgeMod)?;
let ref namespace = bridge.namespace;
let trusted = bridge.unsafety.is_some();
let ref apis = syntax::parse_items(errors, bridge.content, trusted);
let ref apis = syntax::parse_items(errors, bridge.content, trusted, namespace);
let ref types = Types::collect(errors, apis);
errors.propagate()?;
check::typecheck(errors, namespace, apis, types);
check::typecheck(errors, apis, types);
errors.propagate()?;
// Some callers may wish to generate both header and C++
// from the same token stream to avoid parsing twice. But others
Expand Down
44 changes: 23 additions & 21 deletions gen/src/write.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,9 @@ use crate::gen::{include, Opt};
use crate::syntax::atom::Atom::{self, *};
use crate::syntax::namespace::Namespace;
use crate::syntax::symbol::Symbol;
use crate::syntax::{mangle, Api, Enum, ExternFn, ExternType, Signature, Struct, Type, Types, Var};
use crate::syntax::{
mangle, Api, Enum, ExternFn, ExternType, QualifiedIdent, Signature, Struct, Type, Types, Var,
};
use proc_macro2::Ident;
use std::collections::HashMap;

Expand Down Expand Up @@ -133,7 +135,7 @@ pub(super) fn gen(
fn write_includes(out: &mut OutFile, types: &Types) {
for ty in types {
match ty {
Type::Ident(ident) => match Atom::from(ident) {
Type::Ident(ident) => match Atom::from_qualified_ident(ident) {
Some(U8) | Some(U16) | Some(U32) | Some(U64) | Some(I8) | Some(I16) | Some(I32)
| Some(I64) => out.include.cstdint = true,
Some(Usize) => out.include.cstddef = true,
Expand Down Expand Up @@ -349,11 +351,11 @@ fn write_struct(out: &mut OutFile, strct: &Struct) {
writeln!(out, "#endif // {}", guard);
}

fn write_struct_decl(out: &mut OutFile, ident: &Ident) {
fn write_struct_decl(out: &mut OutFile, ident: &QualifiedIdent) {
writeln!(out, "struct {};", ident);
}

fn write_struct_using(out: &mut OutFile, ident: &Ident) {
fn write_struct_using(out: &mut OutFile, ident: &QualifiedIdent) {
writeln!(out, "using {} = {};", ident, ident);
}

Expand Down Expand Up @@ -410,7 +412,7 @@ fn check_enum(out: &mut OutFile, enm: &Enum) {
}
}

fn check_trivial_extern_type(out: &mut OutFile, id: &Ident) {
fn check_trivial_extern_type(out: &mut OutFile, id: &QualifiedIdent) {
// NOTE: The following two static assertions are just nice-to-have and not
// necessary for soundness. That's because triviality is always declared by
// the user in the form of an unsafe impl of cxx::ExternType:
Expand Down Expand Up @@ -486,7 +488,7 @@ fn write_cxx_function_shim(
} else {
write_extern_return_type_space(out, &efn.ret, types);
}
let mangled = mangle::extern_fn(&out.namespace, efn);
let mangled = mangle::extern_fn(efn);
write!(out, "{}(", mangled);
if let Some(receiver) = &efn.receiver {
if receiver.mutability.is_none() {
Expand Down Expand Up @@ -632,17 +634,17 @@ fn write_function_pointer_trampoline(
types: &Types,
) {
out.next_section();
let r_trampoline = mangle::r_trampoline(&out.namespace, efn, var);
let r_trampoline = mangle::r_trampoline(efn, var);
let indirect_call = true;
write_rust_function_decl_impl(out, &r_trampoline, f, types, indirect_call);

out.next_section();
let c_trampoline = mangle::c_trampoline(&out.namespace, efn, var).to_string();
let c_trampoline = mangle::c_trampoline(efn, var).to_string();
write_rust_function_shim_impl(out, &c_trampoline, f, types, &r_trampoline, indirect_call);
}

fn write_rust_function_decl(out: &mut OutFile, efn: &ExternFn, types: &Types, _: &Option<String>) {
let link_name = mangle::extern_fn(&out.namespace, efn);
let link_name = mangle::extern_fn(efn);
let indirect_call = false;
write_rust_function_decl_impl(out, &link_name, efn, types, indirect_call);
}
Expand Down Expand Up @@ -700,7 +702,7 @@ fn write_rust_function_shim(out: &mut OutFile, efn: &ExternFn, types: &Types) {
None => efn.ident.cxx.to_string(),
Some(receiver) => format!("{}::{}", receiver.ty, efn.ident.cxx),
};
let invoke = mangle::extern_fn(&out.namespace, efn);
let invoke = mangle::extern_fn(efn);
let indirect_call = false;
write_rust_function_shim_impl(out, &local_name, efn, types, &invoke, indirect_call);
}
Expand Down Expand Up @@ -923,7 +925,7 @@ fn write_extern_arg(out: &mut OutFile, arg: &Var, types: &Types) {

fn write_type(out: &mut OutFile, ty: &Type) {
match ty {
Type::Ident(ident) => match Atom::from(ident) {
Type::Ident(ident) => match Atom::from_qualified_ident(ident) {
Some(atom) => write_atom(out, atom),
None => write!(out, "{}", ident),
},
Expand Down Expand Up @@ -1061,14 +1063,14 @@ fn write_generic_instantiations(out: &mut OutFile, types: &Types) {
}
} else if let Type::RustVec(ty) = ty {
if let Type::Ident(inner) = &ty.inner {
if Atom::from(inner).is_none() {
if Atom::from_qualified_ident(inner).is_none() {
out.next_section();
write_rust_vec_extern(out, inner);
}
}
} else if let Type::UniquePtr(ptr) = ty {
if let Type::Ident(inner) = &ptr.inner {
if Atom::from(inner).is_none()
if Atom::from_qualified_ident(inner).is_none()
&& (!types.aliases.contains_key(inner) || types.explicit_impls.contains(ty))
{
out.next_section();
Expand All @@ -1077,7 +1079,7 @@ fn write_generic_instantiations(out: &mut OutFile, types: &Types) {
}
} else if let Type::CxxVector(ptr) = ty {
if let Type::Ident(inner) = &ptr.inner {
if Atom::from(inner).is_none()
if Atom::from_qualified_ident(inner).is_none()
&& (!types.aliases.contains_key(inner) || types.explicit_impls.contains(ty))
{
out.next_section();
Expand All @@ -1097,7 +1099,7 @@ fn write_generic_instantiations(out: &mut OutFile, types: &Types) {
}
} else if let Type::RustVec(ty) = ty {
if let Type::Ident(inner) = &ty.inner {
if Atom::from(inner).is_none() {
if Atom::from_qualified_ident(inner).is_none() {
write_rust_vec_impl(out, inner);
}
}
Expand All @@ -1107,7 +1109,7 @@ fn write_generic_instantiations(out: &mut OutFile, types: &Types) {
out.end_block("namespace rust");
}

fn write_rust_box_extern(out: &mut OutFile, ident: &Ident) {
fn write_rust_box_extern(out: &mut OutFile, ident: &QualifiedIdent) {
let mut inner = String::new();
for name in &out.namespace {
inner += &name.to_string();
Expand All @@ -1131,7 +1133,7 @@ fn write_rust_box_extern(out: &mut OutFile, ident: &Ident) {
writeln!(out, "#endif // CXXBRIDGE05_RUST_BOX_{}", instance);
}

fn write_rust_vec_extern(out: &mut OutFile, element: &Ident) {
fn write_rust_vec_extern(out: &mut OutFile, element: &QualifiedIdent) {
let element = Type::Ident(element.clone());
let inner = to_typename(&out.namespace, &element);
let instance = to_mangled(&out.namespace, &element);
Expand Down Expand Up @@ -1166,7 +1168,7 @@ fn write_rust_vec_extern(out: &mut OutFile, element: &Ident) {
writeln!(out, "#endif // CXXBRIDGE05_RUST_VEC_{}", instance);
}

fn write_rust_box_impl(out: &mut OutFile, ident: &Ident) {
fn write_rust_box_impl(out: &mut OutFile, ident: &QualifiedIdent) {
let mut inner = String::new();
for name in &out.namespace {
inner += &name.to_string();
Expand All @@ -1186,7 +1188,7 @@ fn write_rust_box_impl(out: &mut OutFile, ident: &Ident) {
writeln!(out, "}}");
}

fn write_rust_vec_impl(out: &mut OutFile, element: &Ident) {
fn write_rust_vec_impl(out: &mut OutFile, element: &QualifiedIdent) {
let element = Type::Ident(element.clone());
let inner = to_typename(&out.namespace, &element);
let instance = to_mangled(&out.namespace, &element);
Expand Down Expand Up @@ -1225,7 +1227,7 @@ fn write_rust_vec_impl(out: &mut OutFile, element: &Ident) {
writeln!(out, "}}");
}

fn write_unique_ptr(out: &mut OutFile, ident: &Ident, types: &Types) {
fn write_unique_ptr(out: &mut OutFile, ident: &QualifiedIdent, types: &Types) {
let ty = Type::Ident(ident.clone());
let instance = to_mangled(&out.namespace, &ty);

Expand Down Expand Up @@ -1315,7 +1317,7 @@ fn write_unique_ptr_common(out: &mut OutFile, ty: &Type, types: &Types) {
writeln!(out, "}}");
}

fn write_cxx_vector(out: &mut OutFile, vector_ty: &Type, element: &Ident, types: &Types) {
fn write_cxx_vector(out: &mut OutFile, vector_ty: &Type, element: &QualifiedIdent, types: &Types) {
let element = Type::Ident(element.clone());
let inner = to_typename(&out.namespace, &element);
let instance = to_mangled(&out.namespace, &element);
Expand Down
55 changes: 25 additions & 30 deletions macro/src/expand.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@ use crate::syntax::namespace::Namespace;
use crate::syntax::report::Errors;
use crate::syntax::symbol::Symbol;
use crate::syntax::{
self, check, mangle, Api, Enum, ExternFn, ExternType, Impl, Signature, Struct, Type, TypeAlias,
Types,
self, check, mangle, Api, Enum, ExternFn, ExternType, Impl, QualifiedIdent, Signature, Struct,
Type, TypeAlias, Types,
};
use proc_macro2::{Ident, Span, TokenStream};
use quote::{format_ident, quote, quote_spanned, ToTokens};
Expand All @@ -17,11 +17,11 @@ pub fn bridge(mut ffi: Module) -> Result<TokenStream> {
let ref mut errors = Errors::new();
let content = mem::take(&mut ffi.content);
let trusted = ffi.unsafety.is_some();
let ref apis = syntax::parse_items(errors, content, trusted);
let namespace = &ffi.namespace;
let ref apis = syntax::parse_items(errors, content, trusted, namespace);
let ref types = Types::collect(errors, apis);
errors.propagate()?;
let namespace = &ffi.namespace;
check::typecheck(errors, namespace, apis, types);
check::typecheck(errors, apis, types);
errors.propagate()?;

Ok(expand(ffi, apis, types))
Expand Down Expand Up @@ -51,11 +51,9 @@ fn expand(ffi: Module, apis: &[Api], types: &Types) -> TokenStream {
}
}
Api::CxxFunction(efn) => {
expanded.extend(expand_cxx_function_shim(namespace, efn, types));
}
Api::RustFunction(efn) => {
hidden.extend(expand_rust_function_shim(namespace, efn, types))
expanded.extend(expand_cxx_function_shim(efn, types));
}
Api::RustFunction(efn) => hidden.extend(expand_rust_function_shim(efn, types)),
Api::TypeAlias(alias) => {
expanded.extend(expand_type_alias(alias));
hidden.extend(expand_type_alias_verify(namespace, alias, types));
Expand All @@ -67,27 +65,27 @@ fn expand(ffi: Module, apis: &[Api], types: &Types) -> TokenStream {
let explicit_impl = types.explicit_impls.get(ty);
if let Type::RustBox(ty) = ty {
if let Type::Ident(ident) = &ty.inner {
if Atom::from(ident).is_none() {
if Atom::from_qualified_ident(ident).is_none() {
hidden.extend(expand_rust_box(namespace, ident));
}
}
} else if let Type::RustVec(ty) = ty {
if let Type::Ident(ident) = &ty.inner {
if Atom::from(ident).is_none() {
if Atom::from_qualified_ident(ident).is_none() {
hidden.extend(expand_rust_vec(namespace, ident));
}
}
} else if let Type::UniquePtr(ptr) = ty {
if let Type::Ident(ident) = &ptr.inner {
if Atom::from(ident).is_none()
if Atom::from_qualified_ident(ident).is_none()
&& (explicit_impl.is_some() || !types.aliases.contains_key(ident))
{
expanded.extend(expand_unique_ptr(namespace, ident, types, explicit_impl));
}
}
} else if let Type::CxxVector(ptr) = ty {
if let Type::Ident(ident) = &ptr.inner {
if Atom::from(ident).is_none()
if Atom::from_qualified_ident(ident).is_none()
&& (explicit_impl.is_some() || !types.aliases.contains_key(ident))
{
// Generate impl for CxxVector<T> if T is a struct or opaque
Expand Down Expand Up @@ -205,7 +203,7 @@ fn expand_cxx_type(namespace: &Namespace, ety: &ExternType) -> TokenStream {
}
}

fn expand_cxx_function_decl(namespace: &Namespace, efn: &ExternFn, types: &Types) -> TokenStream {
fn expand_cxx_function_decl(efn: &ExternFn, types: &Types) -> TokenStream {
let receiver = efn.receiver.iter().map(|receiver| {
let receiver_type = receiver.ty();
quote!(_: #receiver_type)
Expand Down Expand Up @@ -236,17 +234,17 @@ fn expand_cxx_function_decl(namespace: &Namespace, efn: &ExternFn, types: &Types
let ret = expand_extern_type(efn.ret.as_ref().unwrap());
outparam = Some(quote!(__return: *mut #ret));
}
let link_name = mangle::extern_fn(namespace, efn);
let link_name = mangle::extern_fn(efn);
let local_name = format_ident!("__{}", efn.ident.rust);
quote! {
#[link_name = #link_name]
fn #local_name(#(#all_args,)* #outparam) #ret;
}
}

fn expand_cxx_function_shim(namespace: &Namespace, efn: &ExternFn, types: &Types) -> TokenStream {
fn expand_cxx_function_shim(efn: &ExternFn, types: &Types) -> TokenStream {
let doc = &efn.doc;
let decl = expand_cxx_function_decl(namespace, efn, types);
let decl = expand_cxx_function_decl(efn, types);
let receiver = efn.receiver.iter().map(|receiver| {
let ampersand = receiver.ampersand;
let mutability = receiver.mutability;
Expand Down Expand Up @@ -306,9 +304,7 @@ fn expand_cxx_function_shim(namespace: &Namespace, efn: &ExternFn, types: &Types
.filter_map(|arg| {
if let Type::Fn(f) = &arg.ty {
let var = &arg.ident;
Some(expand_function_pointer_trampoline(
namespace, efn, var, f, types,
))
Some(expand_function_pointer_trampoline(efn, var, f, types))
} else {
None
}
Expand Down Expand Up @@ -445,14 +441,13 @@ fn expand_cxx_function_shim(namespace: &Namespace, efn: &ExternFn, types: &Types
}

fn expand_function_pointer_trampoline(
namespace: &Namespace,
efn: &ExternFn,
var: &Ident,
sig: &Signature,
types: &Types,
) -> TokenStream {
let c_trampoline = mangle::c_trampoline(namespace, efn, var);
let r_trampoline = mangle::r_trampoline(namespace, efn, var);
let c_trampoline = mangle::c_trampoline(efn, var);
let r_trampoline = mangle::r_trampoline(efn, var);
let local_name = parse_quote!(__);
let catch_unwind_label = format!("::{}::{}", efn.ident.rust, var);
let shim = expand_rust_function_shim_impl(
Expand Down Expand Up @@ -508,8 +503,8 @@ fn expand_rust_type_assert_sized(ety: &ExternType) -> TokenStream {
}
}

fn expand_rust_function_shim(namespace: &Namespace, efn: &ExternFn, types: &Types) -> TokenStream {
let link_name = mangle::extern_fn(namespace, efn);
fn expand_rust_function_shim(efn: &ExternFn, types: &Types) -> TokenStream {
let link_name = mangle::extern_fn(efn);
let local_name = format_ident!("__{}", efn.ident.rust);
let catch_unwind_label = format!("::{}", efn.ident.rust);
let invoke = Some(&efn.ident.rust);
Expand Down Expand Up @@ -712,7 +707,7 @@ fn expand_type_alias_verify(
verify
}

fn type_id(namespace: &Namespace, ident: &Ident) -> TokenStream {
fn type_id(namespace: &Namespace, ident: &QualifiedIdent) -> TokenStream {
let mut path = String::new();
for name in namespace {
path += &name.to_string();
Expand All @@ -725,7 +720,7 @@ fn type_id(namespace: &Namespace, ident: &Ident) -> TokenStream {
}
}

fn expand_rust_box(namespace: &Namespace, ident: &Ident) -> TokenStream {
fn expand_rust_box(namespace: &Namespace, ident: &QualifiedIdent) -> TokenStream {
let link_prefix = format!("cxxbridge05$box${}{}$", namespace, ident);
let link_uninit = format!("{}uninit", link_prefix);
let link_drop = format!("{}drop", link_prefix);
Expand Down Expand Up @@ -754,7 +749,7 @@ fn expand_rust_box(namespace: &Namespace, ident: &Ident) -> TokenStream {
}
}

fn expand_rust_vec(namespace: &Namespace, elem: &Ident) -> TokenStream {
fn expand_rust_vec(namespace: &Namespace, elem: &QualifiedIdent) -> TokenStream {
let link_prefix = format!("cxxbridge05$rust_vec${}{}$", namespace, elem);
let link_new = format!("{}new", link_prefix);
let link_drop = format!("{}drop", link_prefix);
Expand Down Expand Up @@ -801,7 +796,7 @@ fn expand_rust_vec(namespace: &Namespace, elem: &Ident) -> TokenStream {

fn expand_unique_ptr(
namespace: &Namespace,
ident: &Ident,
ident: &QualifiedIdent,
types: &Types,
explicit_impl: Option<&Impl>,
) -> TokenStream {
Expand Down Expand Up @@ -884,7 +879,7 @@ fn expand_unique_ptr(

fn expand_cxx_vector(
namespace: &Namespace,
elem: &Ident,
elem: &QualifiedIdent,
explicit_impl: Option<&Impl>,
) -> TokenStream {
let _ = explicit_impl;
Expand Down
Loading

0 comments on commit 75f435e

Please sign in to comment.