Skip to content

Commit 1c4332a

Browse files
committed
Completely rework templates
* Find each item's used template parameters when we begin the codegen phase * Add TemplateDeclaration::used_template_params() This method is available during the codegen phase, and uses the information gleaned by the `ir::named::UsedTemplateParameters` analysis. * Remove Item::{applicable_template_args,signature_contains_named_type} They are replaced by the template parameter usage analysis and TemplateDeclaration::used_template_params. * Parse and de-duplicate named template type parameters * Do not attempt to determine template parameter usage when not recursively whitelisting * Add a proper TemplateInstantiation type This makes it so that CompInfo is always either a compound type definition, or a template compound type definition, never an instantiation of a template. It also pulls out TypeKind::TemplateInstantiation(<inline stuff>) to a proper ir::TemplateInstantiation type, and TypeKind::TemplateInstantiation just wraps ir::TemplateInstantiation into TypeKind. * Allow template definitions to lack template parameters because of opaque template definitions * Detect and ignore cycles deriving Copy/Debug and whether a type has a vtable * Bail out early in the face of partial template specialization We don't support it, and shouldn't continue trying to parse a type from this cursor. * Do not consider inner type's parameter usage as our own parameter usage * Do not require a parent_id for template instantiations It is not necessary, and in fact was preventing us from creating template instantiations in some places, resulting in such nonsense as a generic template definition as a base for another type. * Only join if this is NOT a named template type or a template instantiation Otherwise, we'll always consider all of a template instantiation's arguments as used, when they should only be considered used if the template definition uses that template parameter. * Consider function return and parameter types as used Although we should not follow class method edges because we cannot create new monomorphizations of methods, code can create aliases of function pointers whose return or parameter types are template parameters, and those template parameters should be considered used. * Add the AsNamed trait for things which might be a named template type This sees through ResolvedTypeReferences to get at the final named type and its canonical item id. By using this in the named template parameter usage analysis, we ensure we don't have bugs where there are ResolvedTypeReferences in the usage sets rather than the canonical named item id, which could cause template parameters to be ignored accidentally. * Do not consider an inner var's template parameter usage as our own * Make the expectations' tests less noisy * Use opaque blobs for unknown template definition types When we don't know how to generate a Rust type from a template definition (eg because it uses non-type template parameters), then we should fall back to using the instantiation's layout to generate the opaque blob. * Implement CanDeriveDebug for TemplateInstantiation We need the template instantiation's layout to determine if we can derive debug for it when the instantiation's template definition has non-type parameters. * Stop thrashing malloc when unioning ItemSets in UsedTemplateParameters Previously, we were cloning an ItemSet, which requires a malloc for non-empty sets, when taking its union with our current id's set. Now, instead of doing that, we wrap each ItemSet in an Option, and take the set out of the hash map when modifying it. This allows us to side-step the borrow checker and HashMap's lack of an analog to `slice::split_at_mut` and mutate what is logically a value in the hash map while also using immutable references of values that are physically in the hash map. * Add some tests explicitly about template parameter usage * Updated test expectations now that we are inferring template parameter usage * Reinstate the layout tests for template instantiations * Generate opaque blobs for uses of partially specialized templates This adds `TypeKind::Opaque` which signifies that we do not understand anything about the given type and that we should just generate an opaque blob based on the type's layout. It explicitly uses the opaque type kind for partially specialized templates. * Add note about None vs Some([]) in TemplateDeclaration * Do not rely on TypeKind implementing PartialEq * Prefer assert_eq!(lhs, rhs) to assert!(lhs == rhs) * Expand some comments for ir::named::UsedTemplateParameters * Expand Item::is_opaque to consider TypeKind::Opaque * Use opaque types instead of panicking Use opaque types as our last resort when resolving type references after we have collected unresolved type references instead of panicking. * Find template definitions that don't want to be found * Recognize associated template types and make them opaque
1 parent 17275f8 commit 1c4332a

File tree

98 files changed

+2436
-1619
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

98 files changed

+2436
-1619
lines changed

src/clang.rs

Lines changed: 39 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66

77
use cexpr;
88
use clang_sys::*;
9+
use regex;
910
use std::{mem, ptr, slice};
1011
use std::ffi::{CStr, CString};
1112
use std::fmt;
@@ -126,11 +127,11 @@ impl Cursor {
126127
}
127128

128129
/// Return the number of template arguments used by this cursor's referent,
129-
/// if the referent is either a template specialization or declaration.
130-
/// Returns `None` otherwise.
130+
/// if the referent is either a template instantiation. Returns `None`
131+
/// otherwise.
131132
///
132-
/// NOTE: This may not return `Some` for some non-fully specialized
133-
/// templates, see #193 and #194.
133+
/// NOTE: This may not return `Some` for partial template specializations,
134+
/// see #193 and #194.
134135
pub fn num_template_args(&self) -> Option<u32> {
135136
// XXX: `clang_Type_getNumTemplateArguments` is sort of reliable, while
136137
// `clang_Cursor_getNumTemplateArguments` is totally unreliable.
@@ -302,7 +303,11 @@ impl Cursor {
302303
x: clang_getCursorDefinition(self.x),
303304
};
304305

305-
if ret.is_valid() { Some(ret) } else { None }
306+
if ret.is_valid() && ret.kind() != CXCursor_NoDeclFound {
307+
Some(ret)
308+
} else {
309+
None
310+
}
306311
}
307312
}
308313

@@ -331,8 +336,9 @@ impl Cursor {
331336
}
332337
}
333338

334-
/// Given that this cursor points to a template specialization, get a cursor
335-
/// pointing to the template definition that is being specialized.
339+
/// Given that this cursor points to either a template specialization or a
340+
/// template instantiation, get a cursor pointing to the template definition
341+
/// that is being specialized.
336342
pub fn specialized(&self) -> Option<Cursor> {
337343
unsafe {
338344
let ret = Cursor {
@@ -895,8 +901,8 @@ impl Type {
895901
self.is_valid() && self.kind() != CXType_Unexposed
896902
}
897903

898-
/// Is this type a fully specialized template?
899-
pub fn is_fully_specialized_template(&self) -> bool {
904+
/// Is this type a fully instantiated template?
905+
pub fn is_fully_instantiated_template(&self) -> bool {
900906
// Yep, the spelling of this containing type-parameter is extremely
901907
// nasty... But can happen in <type_traits>. Unfortunately I couldn't
902908
// reduce it enough :(
@@ -908,6 +914,30 @@ impl Type {
908914
_ => true,
909915
}
910916
}
917+
918+
/// Is this type an associated template type? Eg `T::Associated` in
919+
/// this example:
920+
///
921+
/// ```c++
922+
/// template <typename T>
923+
/// class Foo {
924+
/// typename T::Associated member;
925+
/// };
926+
/// ```
927+
pub fn is_associated_type(&self) -> bool {
928+
// This is terrible :(
929+
fn hacky_parse_associated_type<S: AsRef<str>>(spelling: S) -> bool {
930+
lazy_static! {
931+
static ref ASSOC_TYPE_RE: regex::Regex =
932+
regex::Regex::new(r"typename type\-parameter\-\d+\-\d+::.+").unwrap();
933+
}
934+
ASSOC_TYPE_RE.is_match(spelling.as_ref())
935+
}
936+
937+
self.kind() == CXType_Unexposed &&
938+
(hacky_parse_associated_type(self.spelling()) ||
939+
hacky_parse_associated_type(self.canonical_type().spelling()))
940+
}
911941
}
912942

913943
/// The `CanonicalTypeDeclaration` type exists as proof-by-construction that its

0 commit comments

Comments
 (0)