1 //! Template declaration and instantiation related things. 2 //! 3 //! The nomenclature surrounding templates is often confusing, so here are a few 4 //! brief definitions: 5 //! 6 //! * "Template definition": a class/struct/alias/function definition that takes 7 //! generic template parameters. For example: 8 //! 9 //! ```c++ 10 //! template<typename T> 11 //! class List<T> { 12 //! // ... 13 //! }; 14 //! ``` 15 //! 16 //! * "Template instantiation": an instantiation is a use of a template with 17 //! concrete template arguments. For example, `List<int>`. 18 //! 19 //! * "Template specialization": an alternative template definition providing a 20 //! custom definition for instantiations with the matching template 21 //! arguments. This C++ feature is unsupported by bindgen. For example: 22 //! 23 //! ```c++ 24 //! template<> 25 //! class List<int> { 26 //! // Special layout for int lists... 27 //! }; 28 //! ``` 29 30 use super::context::{BindgenContext, ItemId, TypeId}; 31 use super::item::{IsOpaque, Item, ItemAncestors}; 32 use super::traversal::{EdgeKind, Trace, Tracer}; 33 use crate::clang; 34 35 /// Template declaration (and such declaration's template parameters) related 36 /// methods. 37 /// 38 /// This trait's methods distinguish between `None` and `Some([])` for 39 /// declarations that are not templates and template declarations with zero 40 /// parameters, in general. 41 /// 42 /// Consider this example: 43 /// 44 /// ```c++ 45 /// template <typename T, typename U> 46 /// class Foo { 47 /// T use_of_t; 48 /// U use_of_u; 49 /// 50 /// template <typename V> 51 /// using Bar = V*; 52 /// 53 /// class Inner { 54 /// T x; 55 /// U y; 56 /// Bar<int> z; 57 /// }; 58 /// 59 /// template <typename W> 60 /// class Lol { 61 /// // No use of W, but here's a use of T. 62 /// T t; 63 /// }; 64 /// 65 /// template <typename X> 66 /// class Wtf { 67 /// // X is not used because W is not used. 68 /// Lol<X> lololol; 69 /// }; 70 /// }; 71 /// 72 /// class Qux { 73 /// int y; 74 /// }; 75 /// ``` 76 /// 77 /// The following table depicts the results of each trait method when invoked on 78 /// each of the declarations above: 79 /// 80 /// +------+----------------------+--------------------------+------------------------+---- 81 /// |Decl. | self_template_params | num_self_template_params | all_template_parameters| ... 82 /// +------+----------------------+--------------------------+------------------------+---- 83 /// |Foo | [T, U] | 2 | [T, U] | ... 84 /// |Bar | [V] | 1 | [T, U, V] | ... 85 /// |Inner | [] | 0 | [T, U] | ... 86 /// |Lol | [W] | 1 | [T, U, W] | ... 87 /// |Wtf | [X] | 1 | [T, U, X] | ... 88 /// |Qux | [] | 0 | [] | ... 89 /// +------+----------------------+--------------------------+------------------------+---- 90 /// 91 /// ----+------+-----+----------------------+ 92 /// ... |Decl. | ... | used_template_params | 93 /// ----+------+-----+----------------------+ 94 /// ... |Foo | ... | [T, U] | 95 /// ... |Bar | ... | [V] | 96 /// ... |Inner | ... | [] | 97 /// ... |Lol | ... | [T] | 98 /// ... |Wtf | ... | [T] | 99 /// ... |Qux | ... | [] | 100 /// ----+------+-----+----------------------+ 101 pub trait TemplateParameters: Sized { 102 /// Get the set of `ItemId`s that make up this template declaration's free 103 /// template parameters. 104 /// 105 /// Note that these might *not* all be named types: C++ allows 106 /// constant-value template parameters as well as template-template 107 /// parameters. Of course, Rust does not allow generic parameters to be 108 /// anything but types, so we must treat them as opaque, and avoid 109 /// instantiating them. self_template_params(&self, ctx: &BindgenContext) -> Vec<TypeId>110 fn self_template_params(&self, ctx: &BindgenContext) -> Vec<TypeId>; 111 112 /// Get the number of free template parameters this template declaration 113 /// has. num_self_template_params(&self, ctx: &BindgenContext) -> usize114 fn num_self_template_params(&self, ctx: &BindgenContext) -> usize { 115 self.self_template_params(ctx).len() 116 } 117 118 /// Get the complete set of template parameters that can affect this 119 /// declaration. 120 /// 121 /// Note that this item doesn't need to be a template declaration itself for 122 /// `Some` to be returned here (in contrast to `self_template_params`). If 123 /// this item is a member of a template declaration, then the parent's 124 /// template parameters are included here. 125 /// 126 /// In the example above, `Inner` depends on both of the `T` and `U` type 127 /// parameters, even though it is not itself a template declaration and 128 /// therefore has no type parameters itself. Perhaps it helps to think about 129 /// how we would fully reference such a member type in C++: 130 /// `Foo<int,char>::Inner`. `Foo` *must* be instantiated with template 131 /// arguments before we can gain access to the `Inner` member type. all_template_params(&self, ctx: &BindgenContext) -> Vec<TypeId> where Self: ItemAncestors,132 fn all_template_params(&self, ctx: &BindgenContext) -> Vec<TypeId> 133 where 134 Self: ItemAncestors, 135 { 136 let mut ancestors: Vec<_> = self.ancestors(ctx).collect(); 137 ancestors.reverse(); 138 ancestors 139 .into_iter() 140 .flat_map(|id| id.self_template_params(ctx).into_iter()) 141 .collect() 142 } 143 144 /// Get only the set of template parameters that this item uses. This is a 145 /// subset of `all_template_params` and does not necessarily contain any of 146 /// `self_template_params`. used_template_params(&self, ctx: &BindgenContext) -> Vec<TypeId> where Self: AsRef<ItemId>,147 fn used_template_params(&self, ctx: &BindgenContext) -> Vec<TypeId> 148 where 149 Self: AsRef<ItemId>, 150 { 151 assert!( 152 ctx.in_codegen_phase(), 153 "template parameter usage is not computed until codegen" 154 ); 155 156 let id = *self.as_ref(); 157 ctx.resolve_item(id) 158 .all_template_params(ctx) 159 .into_iter() 160 .filter(|p| ctx.uses_template_parameter(id, *p)) 161 .collect() 162 } 163 } 164 165 /// A trait for things which may or may not be a named template type parameter. 166 pub trait AsTemplateParam { 167 /// Any extra information the implementor might need to make this decision. 168 type Extra; 169 170 /// Convert this thing to the item id of a named template type parameter. as_template_param( &self, ctx: &BindgenContext, extra: &Self::Extra, ) -> Option<TypeId>171 fn as_template_param( 172 &self, 173 ctx: &BindgenContext, 174 extra: &Self::Extra, 175 ) -> Option<TypeId>; 176 177 /// Is this a named template type parameter? is_template_param( &self, ctx: &BindgenContext, extra: &Self::Extra, ) -> bool178 fn is_template_param( 179 &self, 180 ctx: &BindgenContext, 181 extra: &Self::Extra, 182 ) -> bool { 183 self.as_template_param(ctx, extra).is_some() 184 } 185 } 186 187 /// A concrete instantiation of a generic template. 188 #[derive(Clone, Debug)] 189 pub struct TemplateInstantiation { 190 /// The template definition which this is instantiating. 191 definition: TypeId, 192 /// The concrete template arguments, which will be substituted in the 193 /// definition for the generic template parameters. 194 args: Vec<TypeId>, 195 } 196 197 impl TemplateInstantiation { 198 /// Construct a new template instantiation from the given parts. new<I>(definition: TypeId, args: I) -> TemplateInstantiation where I: IntoIterator<Item = TypeId>,199 pub fn new<I>(definition: TypeId, args: I) -> TemplateInstantiation 200 where 201 I: IntoIterator<Item = TypeId>, 202 { 203 TemplateInstantiation { 204 definition, 205 args: args.into_iter().collect(), 206 } 207 } 208 209 /// Get the template definition for this instantiation. template_definition(&self) -> TypeId210 pub fn template_definition(&self) -> TypeId { 211 self.definition 212 } 213 214 /// Get the concrete template arguments used in this instantiation. template_arguments(&self) -> &[TypeId]215 pub fn template_arguments(&self) -> &[TypeId] { 216 &self.args[..] 217 } 218 219 /// Parse a `TemplateInstantiation` from a clang `Type`. from_ty( ty: &clang::Type, ctx: &mut BindgenContext, ) -> Option<TemplateInstantiation>220 pub fn from_ty( 221 ty: &clang::Type, 222 ctx: &mut BindgenContext, 223 ) -> Option<TemplateInstantiation> { 224 use clang_sys::*; 225 226 let template_args = ty.template_args().map_or(vec![], |args| match ty 227 .canonical_type() 228 .template_args() 229 { 230 Some(canonical_args) => { 231 let arg_count = args.len(); 232 args.chain(canonical_args.skip(arg_count)) 233 .filter(|t| t.kind() != CXType_Invalid) 234 .map(|t| { 235 Item::from_ty_or_ref(t, t.declaration(), None, ctx) 236 }) 237 .collect() 238 } 239 None => args 240 .filter(|t| t.kind() != CXType_Invalid) 241 .map(|t| Item::from_ty_or_ref(t, t.declaration(), None, ctx)) 242 .collect(), 243 }); 244 245 let declaration = ty.declaration(); 246 let definition = if declaration.kind() == CXCursor_TypeAliasTemplateDecl 247 { 248 Some(declaration) 249 } else { 250 declaration.specialized().or_else(|| { 251 let mut template_ref = None; 252 ty.declaration().visit(|child| { 253 if child.kind() == CXCursor_TemplateRef { 254 template_ref = Some(child); 255 return CXVisit_Break; 256 } 257 258 // Instantiations of template aliases might have the 259 // TemplateRef to the template alias definition arbitrarily 260 // deep, so we need to recurse here and not only visit 261 // direct children. 262 CXChildVisit_Recurse 263 }); 264 265 template_ref.and_then(|cur| cur.referenced()) 266 }) 267 }; 268 269 let definition = match definition { 270 Some(def) => def, 271 None => { 272 if !ty.declaration().is_builtin() { 273 warn!( 274 "Could not find template definition for template \ 275 instantiation" 276 ); 277 } 278 return None; 279 } 280 }; 281 282 let template_definition = 283 Item::from_ty_or_ref(definition.cur_type(), definition, None, ctx); 284 285 Some(TemplateInstantiation::new( 286 template_definition, 287 template_args, 288 )) 289 } 290 } 291 292 impl IsOpaque for TemplateInstantiation { 293 type Extra = Item; 294 295 /// Is this an opaque template instantiation? is_opaque(&self, ctx: &BindgenContext, item: &Item) -> bool296 fn is_opaque(&self, ctx: &BindgenContext, item: &Item) -> bool { 297 if self.template_definition().is_opaque(ctx, &()) { 298 return true; 299 } 300 301 // TODO(#774): This doesn't properly handle opaque instantiations where 302 // an argument is itself an instantiation because `canonical_name` does 303 // not insert the template arguments into the name, ie it for nested 304 // template arguments it creates "Foo" instead of "Foo<int>". The fully 305 // correct fix is to make `canonical_{name,path}` include template 306 // arguments properly. 307 308 let mut path = item.path_for_allowlisting(ctx).clone(); 309 let args: Vec<_> = self 310 .template_arguments() 311 .iter() 312 .map(|arg| { 313 let arg_path = 314 ctx.resolve_item(*arg).path_for_allowlisting(ctx); 315 arg_path[1..].join("::") 316 }) 317 .collect(); 318 { 319 let last = path.last_mut().unwrap(); 320 last.push('<'); 321 last.push_str(&args.join(", ")); 322 last.push('>'); 323 } 324 325 ctx.opaque_by_name(&path) 326 } 327 } 328 329 impl Trace for TemplateInstantiation { 330 type Extra = (); 331 trace<T>(&self, _ctx: &BindgenContext, tracer: &mut T, _: &()) where T: Tracer,332 fn trace<T>(&self, _ctx: &BindgenContext, tracer: &mut T, _: &()) 333 where 334 T: Tracer, 335 { 336 tracer 337 .visit_kind(self.definition.into(), EdgeKind::TemplateDeclaration); 338 for arg in self.template_arguments() { 339 tracer.visit_kind(arg.into(), EdgeKind::TemplateArgument); 340 } 341 } 342 } 343