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