Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion engine/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ log = "0.4"
proc-macro2 = "1.0.11"
quote = "1.0"
indoc = "1.0"
autocxx-bindgen = "=0.59.9"
autocxx-bindgen = "=0.59.10"
#autocxx-bindgen = { git = "https://github.com/adetaylor/rust-bindgen", branch = "rvalue-references" }
itertools = "0.10"
cc = { version = "1.0", optional = true }
Expand Down
40 changes: 0 additions & 40 deletions engine/src/conversion/analysis/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,6 @@
// See the License for the specific language governing permissions and
// limitations under the License.

use syn::{Attribute, Ident};

use crate::conversion::convert_error::ErrorContext;

use super::{convert_error::ConvertErrorWithContext, ConvertError};

pub(crate) mod abstract_types;
pub(crate) mod casts;
pub(crate) mod ctypes;
Expand All @@ -30,37 +24,3 @@ pub(crate) mod tdef;
mod type_converter;

pub(crate) use name_check::check_names;

// Remove `bindgen_` attributes. They don't have a corresponding macro defined anywhere,
// so they will cause compilation errors if we leave them in.
// We may return an error if one of the bindgen attributes shows that the
// item can't be processed.
fn remove_bindgen_attrs(
attrs: &mut Vec<Attribute>,
id: Ident,
) -> Result<(), ConvertErrorWithContext> {
if has_attr(attrs, "bindgen_unused_template_param") {
return Err(ConvertErrorWithContext(
ConvertError::UnusedTemplateParam,
Some(ErrorContext::Item(id)),
));
}

fn is_bindgen_attr(attr: &Attribute) -> bool {
let segments = &attr.path.segments;
segments.len() == 1
&& segments
.first()
.unwrap()
.ident
.to_string()
.starts_with("bindgen_")
}

attrs.retain(|a| !is_bindgen_attr(a));
Ok(())
}

fn has_attr(attrs: &[Attribute], attr_name: &str) -> bool {
attrs.iter().any(|at| at.path.is_ident(attr_name))
}
7 changes: 5 additions & 2 deletions engine/src/conversion/analysis/pod/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ use crate::{
api::{AnalysisPhase, Api, ApiName, CppVisibility, StructDetails, TypeKind, UnanalyzedApi},
convert_error::{ConvertErrorWithContext, ErrorContext},
error_reporter::convert_apis,
parse::BindgenSemanticAttributes,
ConvertError,
},
types::{Namespace, QualifiedName},
Expand Down Expand Up @@ -115,7 +116,8 @@ fn analyze_enum(
name: ApiName,
mut item: ItemEnum,
) -> Result<Box<dyn Iterator<Item = Api<PodPhase>>>, ConvertErrorWithContext> {
super::remove_bindgen_attrs(&mut item.attrs, name.name.get_final_ident())?;
let metadata = BindgenSemanticAttributes::new_retaining_others(&mut item.attrs);
metadata.check_for_fatal_attrs(&name.name.get_final_ident())?;
Ok(Box::new(std::iter::once(Api::Enum { name, item })))
}

Expand All @@ -134,7 +136,8 @@ fn analyze_struct(
Some(ErrorContext::Item(id)),
));
}
super::remove_bindgen_attrs(&mut details.item.attrs, id.clone())?;
let metadata = BindgenSemanticAttributes::new_retaining_others(&mut details.item.attrs);
metadata.check_for_fatal_attrs(&id)?;
let bases = get_bases(&details.item);
let mut field_deps = HashSet::new();
let type_kind = if byvalue_checker.is_pod(&name.name) {
Expand Down
7 changes: 3 additions & 4 deletions engine/src/conversion/analysis/tdef.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,13 +23,12 @@ use crate::{
api::{AnalysisPhase, Api, ApiName, TypedefKind, UnanalyzedApi},
convert_error::{ConvertErrorWithContext, ErrorContext},
error_reporter::convert_apis,
parse::BindgenSemanticAttributes,
ConvertError,
},
types::QualifiedName,
};

use super::remove_bindgen_attrs;

pub(crate) struct TypedefAnalysis {
pub(crate) kind: TypedefKind,
pub(crate) deps: HashSet<QualifiedName>,
Expand Down Expand Up @@ -92,8 +91,8 @@ fn get_replacement_typedef(
extra_apis: &mut Vec<UnanalyzedApi>,
) -> Result<Api<TypedefPhase>, ConvertErrorWithContext> {
let mut converted_type = ity.clone();
let id = ity.ident.clone();
remove_bindgen_attrs(&mut converted_type.attrs, id)?;
let metadata = BindgenSemanticAttributes::new_retaining_others(&mut converted_type.attrs);
metadata.check_for_fatal_attrs(&ity.ident)?;
let type_conversion_results = type_converter.convert_type(
(*ity.ty).clone(),
name.name.get_namespace(),
Expand Down
193 changes: 193 additions & 0 deletions engine/src/conversion/parse/bindgen_semantic_attributes.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,193 @@
// Copyright 2022 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

use proc_macro2::{Ident, TokenStream};
use syn::{
parenthesized,
parse::{Parse, Parser},
Attribute, LitStr,
};

use crate::conversion::{
api::{CppVisibility, Layout, References, Virtualness},
convert_error::{ConvertErrorWithContext, ErrorContext},
ConvertError,
};

/// The set of all annotations that autocxx_bindgen has added
/// for our benefit.
#[derive(Debug)]
pub(crate) struct BindgenSemanticAttributes(Vec<BindgenSemanticAttribute>);

impl BindgenSemanticAttributes {
// Remove `bindgen_` attributes. They don't have a corresponding macro defined anywhere,
// so they will cause compilation errors if we leave them in.
// We may return an error if one of the bindgen attributes shows that the
// item can't be processed.
pub(crate) fn new_retaining_others(attrs: &mut Vec<Attribute>) -> Self {
let metadata = Self::new(attrs);
attrs.retain(|a| !(a.path.segments.last().unwrap().ident == "cpp_semantics"));
metadata
}

pub(crate) fn new(attrs: &[Attribute]) -> Self {
Self(
attrs
.iter()
.filter_map(|attr| {
if attr.path.segments.last().unwrap().ident == "cpp_semantics" {
let r: Result<BindgenSemanticAttribute, syn::Error> = attr.parse_args();
r.ok()
} else {
None
}
})
.collect(),
)
}

/// Some attributes indicate we can never handle a given item. Check for those.
pub(crate) fn check_for_fatal_attrs(
&self,
id_for_context: &Ident,
) -> Result<(), ConvertErrorWithContext> {
if self.has_attr("unused_template_param") {
Err(ConvertErrorWithContext(
ConvertError::UnusedTemplateParam,
Some(ErrorContext::Item(id_for_context.clone())),
))
} else {
Ok(())
}
}

/// Whether the given attribute is present.
pub(super) fn has_attr(&self, attr_name: &str) -> bool {
self.0.iter().any(|a| a.is_ident(attr_name))
}

/// The C++ visibility of the item.
pub(super) fn get_cpp_visibility(&self) -> CppVisibility {
if self.has_attr("visibility_private") {
CppVisibility::Private
} else if self.has_attr("visibility_protected") {
CppVisibility::Protected
} else {
CppVisibility::Public
}
}

/// Whether the item is virtual.
pub(super) fn get_virtualness(&self) -> Virtualness {
if self.has_attr("pure_virtual") {
Virtualness::PureVirtual
} else if self.has_attr("bindgen_virtual") {
Virtualness::Virtual
} else {
Virtualness::None
}
}

fn parse_if_present<T: Parse>(&self, annotation: &str) -> Option<T> {
self.0
.iter()
.find(|a| a.is_ident(annotation))
.map(|a| a.parse_args().unwrap())
}

fn string_if_present(&self, annotation: &str) -> Option<String> {
let ls: Option<LitStr> = self.parse_if_present(annotation);
ls.map(|ls| ls.value())
}

/// The in-memory layout of the item.
pub(super) fn get_layout(&self) -> Option<Layout> {
self.parse_if_present("layout")
}

/// The original C++ name, which bindgen may have changed.
pub(super) fn get_original_name(&self) -> Option<String> {
self.string_if_present("original_name")
}

fn get_bindgen_special_member_annotation(&self) -> Option<String> {
self.string_if_present("special_member")
}

/// Whether this is a move constructor.
pub(super) fn is_move_constructor(&self) -> bool {
self.get_bindgen_special_member_annotation()
.map_or(false, |val| val == "move_ctor")
}

/// Any reference parameters or return values.
pub(super) fn get_reference_parameters_and_return(&self) -> References {
let mut results = References::default();
for a in &self.0 {
if a.is_ident("ret_type_reference") {
results.ref_return = true;
} else if a.is_ident("ret_type_rvalue_reference") {
results.rvalue_ref_return = true;
} else if a.is_ident("arg_type_reference") {
let r: Result<Ident, syn::Error> = a.parse_args();
if let Ok(ls) = r {
results.ref_params.insert(ls);
}
} else if a.is_ident("arg_type_rvalue_reference") {
let r: Result<Ident, syn::Error> = a.parse_args();
if let Ok(ls) = r {
results.rvalue_ref_params.insert(ls);
}
}
}
results
}
}

#[derive(Debug)]
struct BindgenSemanticAttribute {
annotation_name: Ident,
body: Option<TokenStream>,
}

impl BindgenSemanticAttribute {
fn is_ident(&self, name: &str) -> bool {
self.annotation_name == name
}

fn parse_args<T: Parse>(&self) -> Result<T, syn::Error> {
T::parse.parse2(self.body.as_ref().unwrap().clone())
}
}

impl Parse for BindgenSemanticAttribute {
fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> {
let annotation_name: Ident = input.parse()?;
if input.peek(syn::token::Paren) {
let body_contents;
parenthesized!(body_contents in input);
Ok(Self {
annotation_name,
body: Some(body_contents.parse()?),
})
} else if !input.is_empty() {
Err(input.error("expected nothing"))
} else {
Ok(Self {
annotation_name,
body: None,
})
}
}
}
2 changes: 2 additions & 0 deletions engine/src/conversion/parse/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,9 @@
// See the License for the specific language governing permissions and
// limitations under the License.

mod bindgen_semantic_attributes;
mod parse_bindgen;
mod parse_foreign_mod;

pub(crate) use bindgen_semantic_attributes::BindgenSemanticAttributes;
pub(crate) use parse_bindgen::ParseBindgen;
Loading