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
30use super::context::{BindgenContext, ItemId, TypeId};
31use super::item::{IsOpaque, Item, ItemAncestors};
32use super::traversal::{EdgeKind, Trace, Tracer};
33use 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/// ----+------+-----+----------------------+
101pub(crate) 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.
110 fn self_template_params(&self, ctx: &BindgenContext) -> Vec<TypeId>;
111
112 /// Get the number of free template parameters this template declaration
113 /// has.
114 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.
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`.
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.
166pub(crate) 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.
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?
178 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)]
189pub(crate) 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
197impl TemplateInstantiation {
198 /// Construct a new template instantiation from the given parts.
199 pub(crate) 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.
210 pub(crate) fn template_definition(&self) -> TypeId {
211 self.definition
212 }
213
214 /// Get the concrete template arguments used in this instantiation.
215 pub(crate) fn template_arguments(&self) -> &[TypeId] {
216 &self.args[..]
217 }
218
219 /// Parse a `TemplateInstantiation` from a clang `Type`.
220 pub(crate) 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
292impl IsOpaque for TemplateInstantiation {
293 type Extra = Item;
294
295 /// Is this an opaque template instantiation?
296 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
329impl Trace for TemplateInstantiation {
330 type Extra = ();
331
332 fn trace<T>(&self, _ctx: &BindgenContext, tracer: &mut T, _: &())
333 where
334 T: Tracer,
335 {
336 tracer
337 .visit_kind(self.definition.into(), kind:EdgeKind::TemplateDeclaration);
338 for arg: &TypeId in self.template_arguments() {
339 tracer.visit_kind(item:arg.into(), kind:EdgeKind::TemplateArgument);
340 }
341 }
342}
343