summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--README.md2
-rwxr-xr-xsrc/bin/bindgen.rs21
-rwxr-xr-xsrc/clang.rs84
-rw-r--r--src/ir/comp.rs21
-rw-r--r--src/ir/context.rs57
-rw-r--r--src/ir/enum_ty.rs2
-rw-r--r--src/ir/function.rs4
-rw-r--r--src/ir/item.rs38
-rw-r--r--src/ir/module.rs4
-rw-r--r--src/ir/ty.rs6
-rw-r--r--src/ir/var.rs2
-rwxr-xr-xsrc/lib.rs45
-rw-r--r--tests/expectations/replace_template_alias.rs15
-rw-r--r--tests/headers/replace_template_alias.hpp23
14 files changed, 214 insertions, 110 deletions
diff --git a/README.md b/README.md
index 47e7dd53..97488b6b 100644
--- a/README.md
+++ b/README.md
@@ -149,4 +149,4 @@ This mode isn't actively maintained, so no promises are made around it. Check
out the upstream documentation for info about how it *should* work.
[sm-script]: https://github.com/servo/rust-mozjs/blob/master/etc/bindings.sh
-[stylo-scripts]: https://github.com/servo/servo/tree/master/ports/geckolib/gecko_bindings/tools
+[stylo-scripts]: https://github.com/servo/servo/tree/master/components/style/binding_tools
diff --git a/src/bin/bindgen.rs b/src/bin/bindgen.rs
index 17385d85..c906efee 100755
--- a/src/bin/bindgen.rs
+++ b/src/bin/bindgen.rs
@@ -8,7 +8,7 @@ extern crate log;
extern crate clang_sys;
extern crate rustc_serialize;
-use bindgen::{BindgenOptions, Bindings, LinkType};
+use bindgen::{BindgenOptions, Bindings, ClangVersion, LinkType, clang_version};
use std::default::Default;
use std::env;
use std::fs;
@@ -232,6 +232,25 @@ pub fn main() {
let mut bind_args: Vec<_> = env::args().collect();
+ let version = clang_version();
+ let expected_version = if cfg!(feature = "llvm_stable") {
+ (3, 8)
+ } else {
+ (3, 9)
+ };
+
+ info!("Clang Version: {}", version.full);
+
+ match version.parsed {
+ None => warn!("Couldn't parse libclang version"),
+ Some(version) if version != expected_version => {
+ error!("Using clang {:?}, expected {:?}",
+ version,
+ expected_version);
+ }
+ _ => {}
+ }
+
if let Some(clang) = clang_sys::support::Clang::find(None) {
let has_clang_args =
bind_args.iter().rposition(|arg| *arg == "--").is_some();
diff --git a/src/clang.rs b/src/clang.rs
index 7f81c379..94e74d87 100755
--- a/src/clang.rs
+++ b/src/clang.rs
@@ -31,14 +31,6 @@ impl fmt::Debug for Cursor {
}
}
-/// A cursor visitor function.
-///
-/// The first argument is the AST node currently being visited. The second
-/// argument is the parent of the AST node currently being visited. The return
-/// value informs how traversal should proceed.
-pub type CursorVisitor<'s> = for<'a, 'b> FnMut(&'a Cursor, &'b Cursor)
- -> Enum_CXChildVisitResult + 's;
-
impl Cursor {
/// Get the Unified Symbol Resolution for this cursor's referent, if
/// available.
@@ -190,7 +182,7 @@ impl Cursor {
/// Is the referent a template specialization?
pub fn is_template(&self) -> bool {
- self.specialized().is_valid()
+ self.specialized().is_some()
}
/// Is the referent a fully specialized template specialization without any
@@ -257,11 +249,13 @@ impl Cursor {
/// Given that this cursor's referent is a reference to another type, or is
/// a declaration, get the cursor pointing to the referenced type or type of
/// the declared thing.
- pub fn definition(&self) -> Cursor {
+ pub fn definition(&self) -> Option<Cursor> {
unsafe {
- Cursor {
+ let ret = Cursor {
x: clang_getCursorDefinition(self.x),
- }
+ };
+
+ if ret.is_valid() { Some(ret) } else { None }
}
}
@@ -290,11 +284,12 @@ impl Cursor {
/// Given that this cursor points to a template specialization, get a cursor
/// pointing to the template definition that is being specialized.
- pub fn specialized(&self) -> Cursor {
+ pub fn specialized(&self) -> Option<Cursor> {
unsafe {
- Cursor {
+ let ret = Cursor {
x: clang_getSpecializedCursorTemplate(self.x),
- }
+ };
+ if ret.is_valid() { Some(ret) } else { None }
}
}
@@ -306,21 +301,14 @@ impl Cursor {
/// Traverse this cursor's referent and its children.
///
- /// Call the given function on each AST node traversed. See `CursorVisitor`
- /// for details on arguments passed to the function and how its return value
- /// is interpreted.
- pub fn visit<F>(&self, func: F)
- where F: for<'a, 'b> FnMut(&'a Cursor, &'b Cursor)
- -> Enum_CXChildVisitResult,
+ /// Call the given function on each AST node traversed.
+ pub fn visit<Visitor>(&self, mut visitor: Visitor)
+ where Visitor: FnMut(Cursor) -> Enum_CXChildVisitResult,
{
- let mut data: Box<CursorVisitor> = Box::new(func);
- let opt_visit =
- Some(visit_children as extern "C" fn(CXCursor,
- CXCursor,
- CXClientData)
- -> Enum_CXChildVisitResult);
unsafe {
- clang_visitChildren(self.x, opt_visit, mem::transmute(&mut data));
+ clang_visitChildren(self.x,
+ Some(visit_children::<Visitor>),
+ mem::transmute(&mut visitor));
}
}
@@ -415,16 +403,6 @@ impl Cursor {
}
/// Given that this cursor's referent is a function/method call or
- /// declaration, return a cursor to its return type.
- pub fn ret_type(&self) -> Type {
- unsafe {
- Type {
- x: clang_getCursorResultType(self.x),
- }
- }
- }
-
- /// Given that this cursor's referent is a function/method call or
/// declaration, return the number of arguments it takes.
///
/// Returns -1 if the cursor's referent is not a function/method call or
@@ -484,17 +462,18 @@ impl Cursor {
}
}
-extern "C" fn visit_children(cur: CXCursor,
- parent: CXCursor,
- data: CXClientData)
- -> Enum_CXChildVisitResult {
- let func: &mut Box<CursorVisitor> = unsafe { mem::transmute(data) };
- (*func)(&Cursor {
- x: cur,
- },
- &Cursor {
- x: parent,
- })
+extern "C" fn visit_children<Visitor>(cur: CXCursor,
+ _parent: CXCursor,
+ data: CXClientData)
+ -> Enum_CXChildVisitResult
+ where Visitor: FnMut(Cursor) -> Enum_CXChildVisitResult,
+{
+ let func: &mut Visitor = unsafe { mem::transmute(data) };
+ let child = Cursor {
+ x: cur,
+ };
+
+ (*func)(child)
}
impl PartialEq for Cursor {
@@ -1184,7 +1163,12 @@ pub fn ast_dump(c: &Cursor, depth: isize) -> Enum_CXVisitorResult {
kind_to_str(c.kind()),
c.spelling(),
type_to_str(ct)));
- c.visit(|s, _: &Cursor| ast_dump(s, depth + 1));
+ c.visit(|s| ast_dump(&s, depth + 1));
print_indent(depth, ")");
CXChildVisit_Continue
}
+
+/// Try to extract the clang version to a string
+pub fn extract_clang_version() -> String {
+ unsafe { clang_getClangVersion().into() }
+}
diff --git a/src/ir/comp.rs b/src/ir/comp.rs
index d55c24ca..41e5c3d3 100644
--- a/src/ir/comp.rs
+++ b/src/ir/comp.rs
@@ -512,10 +512,11 @@ impl CompInfo {
}
};
- ci.ref_template = Item::parse(cursor.specialized(), None, ctx).ok();
+ ci.ref_template = cursor.specialized()
+ .and_then(|c| Item::parse(c, None, ctx).ok());
let mut maybe_anonymous_struct_field = None;
- cursor.visit(|cur, _other| {
+ cursor.visit(|cur| {
if cur.kind() != CXCursor_FieldDecl {
if let Some((ty, _)) = maybe_anonymous_struct_field {
let field = Field::new(None, ty, None, None, None, false);
@@ -529,7 +530,7 @@ impl CompInfo {
match maybe_anonymous_struct_field.take() {
Some((ty, clang_ty)) => {
let mut used = false;
- cur.visit(|child, _| {
+ cur.visit(|child| {
if child.cur_type() == clang_ty {
used = true;
}
@@ -550,12 +551,12 @@ impl CompInfo {
let bit_width = cur.bit_width();
let field_type = Item::from_ty_or_ref(cur.cur_type(),
- Some(*cur),
+ Some(cur),
Some(potential_id),
ctx);
let comment = cur.raw_comment();
- let annotations = Annotations::new(cur);
+ let annotations = Annotations::new(&cur);
let name = cur.spelling();
let is_mutable = cursor.is_mutable_field();
@@ -575,7 +576,7 @@ impl CompInfo {
ci.fields.push(field);
// No we look for things like attributes and stuff.
- cur.visit(|cur, _| {
+ cur.visit(|cur| {
if cur.kind() == CXCursor_UnexposedAttr {
ci.found_unknown_attr = true;
}
@@ -593,7 +594,7 @@ impl CompInfo {
CXCursor_UnionDecl |
CXCursor_ClassTemplate |
CXCursor_ClassDecl => {
- let inner = Item::parse(*cur, Some(potential_id), ctx)
+ let inner = Item::parse(cur, Some(potential_id), ctx)
.expect("Inner ClassDecl");
if !ci.inner_types.contains(&inner) {
ci.inner_types.push(inner);
@@ -619,7 +620,7 @@ impl CompInfo {
}
let default_type = Item::from_ty(&cur.cur_type(),
- Some(*cur),
+ Some(cur),
Some(potential_id),
ctx)
.ok();
@@ -687,7 +688,7 @@ impl CompInfo {
// NB: This gets us an owned `Function`, not a
// `FunctionSig`.
let method_signature =
- Item::parse(*cur, Some(potential_id), ctx)
+ Item::parse(cur, Some(potential_id), ctx)
.expect("CXXMethod");
let is_const = cur.method_is_const();
@@ -726,7 +727,7 @@ impl CompInfo {
return CXChildVisit_Continue;
}
- let item = Item::parse(*cur, Some(potential_id), ctx)
+ let item = Item::parse(cur, Some(potential_id), ctx)
.expect("VarDecl");
ci.inner_vars.push(item);
}
diff --git a/src/ir/context.rs b/src/ir/context.rs
index beccc514..fc06375c 100644
--- a/src/ir/context.rs
+++ b/src/ir/context.rs
@@ -4,7 +4,7 @@ use BindgenOptions;
use clang::{self, Cursor};
use parse::ClangItemParser;
use std::borrow::{Borrow, Cow};
-use std::collections::{HashMap, HashSet};
+use std::collections::{HashMap, HashSet, hash_map};
use std::collections::btree_map::{self, BTreeMap};
use std::fmt;
use super::int::IntKind;
@@ -308,6 +308,7 @@ impl<'ctx> BindgenContext<'ctx> {
/// `replaces="SomeType"` annotation with the replacement type.
fn process_replacements(&mut self) {
if self.replacements.is_empty() {
+ debug!("No replacements to process");
return;
}
@@ -319,23 +320,27 @@ impl<'ctx> BindgenContext<'ctx> {
let mut replacements = vec![];
for (id, item) in self.items.iter() {
+ // Calls to `canonical_name` are expensive, so eagerly filter out
+ // items that cannot be replaced.
let ty = match item.kind().as_type() {
Some(ty) => ty,
None => continue,
};
- // canonical_name calls are expensive.
- let ci = match ty.as_comp() {
- Some(ci) => ci,
- None => continue,
- };
-
- if ci.is_template_specialization() {
- continue;
+ match *ty.kind() {
+ TypeKind::Comp(ref ci) if !ci.is_template_specialization() => {}
+ TypeKind::TemplateAlias(_, _) |
+ TypeKind::Alias(_, _) => {}
+ _ => continue,
}
- if let Some(replacement) = self.replacements
- .get(&item.canonical_name(self)) {
+ let name = item.real_canonical_name(self,
+ self.options()
+ .enable_cxx_namespaces,
+ true);
+ let replacement = self.replacements.get(&name);
+
+ if let Some(replacement) = replacement {
if replacement != id {
// We set this just after parsing the annotation. It's
// very unlikely, but this can happen.
@@ -347,6 +352,8 @@ impl<'ctx> BindgenContext<'ctx> {
}
for (id, replacement) in replacements {
+ debug!("Replacing {:?} with {:?}", id, replacement);
+
let mut item = self.items.get_mut(&id).unwrap();
*item.kind_mut().as_type_mut().unwrap().kind_mut() =
TypeKind::ResolvedTypeRef(replacement);
@@ -492,15 +499,21 @@ impl<'ctx> BindgenContext<'ctx> {
use clangll::*;
let mut args = vec![];
let mut found_invalid_template_ref = false;
- location.visit(|c, _| {
+ location.visit(|c| {
if c.kind() == CXCursor_TemplateRef &&
c.cur_type().kind() == CXType_Invalid {
found_invalid_template_ref = true;
}
if c.kind() == CXCursor_TypeRef {
+ // The `with_id` id will potentially end up unused if we give up
+ // on this type (for example, its a tricky partial template
+ // specialization), so if we pass `with_id` as the parent, it is
+ // potentially a dangling reference. Instead, use the canonical
+ // template declaration as the parent. It is already parsed and
+ // has a known-resolvable `ItemId`.
let new_ty = Item::from_ty_or_ref(c.cur_type(),
- Some(*c),
- Some(with_id),
+ Some(c),
+ Some(wrapping),
self);
args.push(new_ty);
}
@@ -725,7 +738,21 @@ impl<'ctx> BindgenContext<'ctx> {
/// Replacement types are declared using the `replaces="xxx"` annotation,
/// and implies that the original type is hidden.
pub fn replace(&mut self, name: &str, potential_ty: ItemId) {
- self.replacements.insert(name.into(), potential_ty);
+ match self.replacements.entry(name.into()) {
+ hash_map::Entry::Vacant(entry) => {
+ debug!("Defining replacement for {} as {:?}",
+ name,
+ potential_ty);
+ entry.insert(potential_ty);
+ }
+ hash_map::Entry::Occupied(occupied) => {
+ warn!("Replacement for {} already defined as {:?}; \
+ ignoring duplicate replacement definition as {:?}}}",
+ name,
+ occupied.get(),
+ potential_ty);
+ }
+ }
}
/// Is the item with the given `name` hidden? Or is the item with the given
diff --git a/src/ir/enum_ty.rs b/src/ir/enum_ty.rs
index fd7dbb45..e78184e7 100644
--- a/src/ir/enum_ty.rs
+++ b/src/ir/enum_ty.rs
@@ -70,7 +70,7 @@ impl Enum {
None => true,
};
- declaration.visit(|cursor, _| {
+ declaration.visit(|cursor| {
if cursor.kind() == CXCursor_EnumConstantDecl {
let name = cursor.spelling();
let comment = cursor.raw_comment();
diff --git a/src/ir/function.rs b/src/ir/function.rs
index c2e6ffd0..163e3039 100644
--- a/src/ir/function.rs
+++ b/src/ir/function.rs
@@ -167,10 +167,10 @@ impl FunctionSig {
// For non-CXCursor_FunctionDecl, visiting the cursor's children
// is the only reliable way to get parameter names.
let mut args = vec![];
- cursor.visit(|c, _| {
+ cursor.visit(|c| {
if c.kind() == CXCursor_ParmDecl {
let ty =
- Item::from_ty(&c.cur_type(), Some(*c), None, ctx)
+ Item::from_ty(&c.cur_type(), Some(c), None, ctx)
.expect("ParmDecl?");
let name = c.spelling();
let name =
diff --git a/src/ir/item.rs b/src/ir/item.rs
index 690f4222..a07ee1f3 100644
--- a/src/ir/item.rs
+++ b/src/ir/item.rs
@@ -49,7 +49,9 @@ pub trait ItemCanonicalPath {
/// up to (but not including) the implicit root module.
pub trait ItemAncestors {
/// Get an iterable over this item's ancestors.
- fn ancestors<'a, 'b>(&self, ctx: &'a BindgenContext<'b>) -> ItemAncestorsIter<'a, 'b>;
+ fn ancestors<'a, 'b>(&self,
+ ctx: &'a BindgenContext<'b>)
+ -> ItemAncestorsIter<'a, 'b>;
}
/// An iterator over an item and its ancestors.
@@ -86,7 +88,8 @@ impl ItemId {
/// Allocate the next `ItemId`.
pub fn next() -> Self {
static NEXT_ITEM_ID: AtomicUsize = ATOMIC_USIZE_INIT;
- ItemId(NEXT_ITEM_ID.fetch_add(1, Ordering::Relaxed))
+ let next_id = NEXT_ITEM_ID.fetch_add(1, Ordering::Relaxed);
+ ItemId(next_id)
}
}
@@ -539,11 +542,11 @@ impl Item {
///
/// This name should be derived from the immutable state contained in the
/// type and the parent chain, since it should be consistent.
- fn real_canonical_name(&self,
- ctx: &BindgenContext,
- count_namespaces: bool,
- for_name_checking: bool)
- -> String {
+ pub fn real_canonical_name(&self,
+ ctx: &BindgenContext,
+ count_namespaces: bool,
+ for_name_checking: bool)
+ -> String {
let base_name = match *self.kind() {
ItemKind::Type(ref ty) => {
match *ty.kind() {
@@ -799,12 +802,7 @@ impl ClangItemParser for Item {
// Types are sort of special, so to avoid parsing template classes
// twice, handle them separately.
{
- let definition = cursor.definition();
- let applicable_cursor = if definition.is_valid() {
- definition
- } else {
- cursor
- };
+ let applicable_cursor = cursor.definition().unwrap_or(cursor);
match Self::from_ty(&applicable_cursor.cur_type(),
Some(applicable_cursor),
parent_id,
@@ -823,6 +821,9 @@ impl ClangItemParser for Item {
// too noisy about this.
match cursor.kind() {
CXCursor_MacroDefinition |
+ CXCursor_MacroExpansion |
+ CXCursor_UsingDeclaration |
+ CXCursor_StaticAssert |
CXCursor_InclusionDirective => {
debug!("Unhandled cursor kind {:?}: {:?}",
cursor.kind(),
@@ -935,12 +936,7 @@ impl ClangItemParser for Item {
let decl = {
let decl = ty.declaration();
- let definition = decl.definition();
- if definition.is_valid() {
- definition
- } else {
- decl
- }
+ decl.definition().unwrap_or(decl)
};
let comment = decl.raw_comment()
@@ -1016,11 +1012,11 @@ impl ClangItemParser for Item {
assert_eq!(popped_decl, declaration_to_look_for);
}
- location.visit(|cur, _other| {
+ location.visit(|cur| {
use clangll::*;
result = Item::from_ty_with_id(id,
ty,
- Some(*cur),
+ Some(cur),
parent_id,
ctx);
match result {
diff --git a/src/ir/module.rs b/src/ir/module.rs
index c582d3eb..42175b92 100644
--- a/src/ir/module.rs
+++ b/src/ir/module.rs
@@ -49,8 +49,8 @@ impl ClangSubItemParser for Module {
CXCursor_Namespace => {
let module_id = ctx.module(cursor);
ctx.with_module(module_id, |ctx, children| {
- cursor.visit(|cursor, _| {
- parse_one(ctx, *cursor, Some(module_id), children)
+ cursor.visit(|cursor| {
+ parse_one(ctx, cursor, Some(module_id), children)
})
});
diff --git a/src/ir/ty.rs b/src/ir/ty.rs
index 4d26cdff..81212029 100644
--- a/src/ir/ty.rs
+++ b/src/ir/ty.rs
@@ -547,14 +547,14 @@ impl Type {
let mut inner = Err(ParseError::Continue);
let mut args = vec![];
- location.visit(|cur, _| {
+ location.visit(|cur| {
match cur.kind() {
CXCursor_TypeAliasDecl => {
debug_assert!(cur.cur_type().kind() ==
CXType_Typedef);
inner =
Item::from_ty(&cur.cur_type(),
- Some(*cur),
+ Some(cur),
Some(potential_id),
ctx);
}
@@ -567,7 +567,7 @@ impl Type {
let default_type =
Item::from_ty(&cur.cur_type(),
- Some(*cur),
+ Some(cur),
Some(potential_id),
ctx)
.ok();
diff --git a/src/ir/var.rs b/src/ir/var.rs
index 216d8185..33e56242 100644
--- a/src/ir/var.rs
+++ b/src/ir/var.rs
@@ -203,7 +203,7 @@ fn get_integer_literal_from_cursor(cursor: &clang::Cursor,
-> Option<i64> {
use clangll::*;
let mut value = None;
- cursor.visit(|c, _| {
+ cursor.visit(|c| {
match c.kind() {
CXCursor_IntegerLiteral |
CXCursor_UnaryOperator => {
diff --git a/src/lib.rs b/src/lib.rs
index 1e840246..a0eba4c0 100755
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -461,7 +461,7 @@ pub fn parse_one(ctx: &mut BindgenContext,
Ok(id) => children.push(id),
Err(ParseError::Continue) => {}
Err(ParseError::Recurse) => {
- cursor.visit(|child, _| parse_one(ctx, *child, parent, children));
+ cursor.visit(|child| parse_one(ctx, child, parent, children));
}
}
CXChildVisit_Continue
@@ -480,14 +480,53 @@ fn parse(context: &mut BindgenContext) {
let cursor = context.translation_unit().cursor();
if context.options().emit_ast {
- cursor.visit(|cur, _| clang::ast_dump(cur, 0));
+ cursor.visit(|cur| clang::ast_dump(&cur, 0));
}
let root = context.root_module();
context.with_module(root, |context, children| {
- cursor.visit(|cursor, _| parse_one(context, *cursor, None, children))
+ cursor.visit(|cursor| parse_one(context, cursor, None, children))
});
assert!(context.current_module() == context.root_module(),
"How did this happen?");
}
+
+/// Extracted Clang version data
+#[derive(Debug)]
+pub struct ClangVersion {
+ /// Major and minor semvar, if parsing was successful
+ pub parsed: Option<(u32, u32)>,
+ /// full version string
+ pub full: String,
+}
+
+/// Get the major and the minor semvar numbers of Clang's version
+pub fn clang_version() -> ClangVersion {
+ let raw_v: String = clang::extract_clang_version();
+ let split_v: Option<Vec<&str>> = raw_v.split_whitespace()
+ .nth(2)
+ .map(|v| v.split('.').collect());
+ match split_v {
+ Some(v) => {
+ if v.len() >= 2 {
+ let maybe_major = v[0].parse::<u32>();
+ let maybe_minor = v[1].parse::<u32>();
+ match (maybe_major, maybe_minor) {
+ (Ok(major), Ok(minor)) => {
+ return ClangVersion {
+ parsed: Some((major, minor)),
+ full: raw_v.clone(),
+ }
+ }
+ _ => {}
+ }
+ }
+ }
+ None => {}
+ };
+ ClangVersion {
+ parsed: None,
+ full: raw_v.clone(),
+ }
+}
diff --git a/tests/expectations/replace_template_alias.rs b/tests/expectations/replace_template_alias.rs
new file mode 100644
index 00000000..61a2fbcc
--- /dev/null
+++ b/tests/expectations/replace_template_alias.rs
@@ -0,0 +1,15 @@
+/* automatically generated by rust-bindgen */
+
+
+#![allow(non_snake_case)]
+
+
+#[repr(C)]
+#[derive(Debug, Copy, Clone)]
+pub struct Rooted<T> {
+ pub ptr: MaybeWrapped<T>,
+}
+/// But the replacement type does use T!
+///
+/// <div rustbindgen replaces="MaybeWrapped" />
+pub type MaybeWrapped<T> = T;
diff --git a/tests/headers/replace_template_alias.hpp b/tests/headers/replace_template_alias.hpp
new file mode 100644
index 00000000..6ceae4e5
--- /dev/null
+++ b/tests/headers/replace_template_alias.hpp
@@ -0,0 +1,23 @@
+// bindgen-flags: -- --std=c++14
+
+namespace JS {
+namespace detail {
+
+/// Notice how this doesn't use T.
+template <typename T>
+using MaybeWrapped = int;
+
+}
+
+template <typename T>
+class Rooted {
+ detail::MaybeWrapped<T> ptr;
+};
+
+}
+
+/// But the replacement type does use T!
+///
+/// <div rustbindgen replaces="MaybeWrapped" />
+template <typename T>
+using replaces_MaybeWrapped = T;