@@ -55,29 +55,57 @@ void TopoSorter::visit(Type& type) {
55
55
}
56
56
57
57
void TopoSorter::visit (Class& c) {
58
- for (const auto & param : c.templateParams ) {
59
- visit (param.type );
60
- }
61
58
for (const auto & parent : c.parents ) {
62
59
visit (*parent.type );
63
60
}
64
61
for (const auto & mem : c.members ) {
65
62
visit (*mem.type );
66
63
}
64
+ for (const auto & param : c.templateParams ) {
65
+ visit (param.type );
66
+ }
67
67
sortedTypes_.push_back (c);
68
68
69
- // Same as pointers, child do not create a dependency so are delayed until the
70
- // end
69
+ // Same as pointers, children do not create a dependency so are delayed until
70
+ // the end.
71
71
for (const auto & child : c.children ) {
72
- typesToSort_.push (child);
72
+ visitAfter (child);
73
+ }
74
+ }
75
+
76
+ namespace {
77
+ /*
78
+ * C++17 allows the std::vector, std::list and std::forward_list containers to
79
+ * be instantiated with incomplete types.
80
+ *
81
+ * Other containers are not required to do this, but might still have this
82
+ * behaviour.
83
+ */
84
+ bool containerAllowsIncompleteParams (const Container& c) {
85
+ switch (c.containerInfo_ .ctype ) {
86
+ case SEQ_TYPE:
87
+ case LIST_TYPE:
88
+ // Also std::forward_list, if we ever support that
89
+ // Would be good to have this as an option in the TOML files
90
+ return true ;
91
+ default :
92
+ return false ;
73
93
}
74
94
}
95
+ } // namespace
75
96
76
97
void TopoSorter::visit (Container& c) {
77
- for (const auto & param : c.templateParams ) {
78
- visit (param.type );
98
+ if (!containerAllowsIncompleteParams (c)) {
99
+ for (const auto & param : c.templateParams ) {
100
+ visit (param.type );
101
+ }
79
102
}
80
103
sortedTypes_.push_back (c);
104
+ if (containerAllowsIncompleteParams (c)) {
105
+ for (const auto & param : c.templateParams ) {
106
+ visitAfter (param.type );
107
+ }
108
+ }
81
109
}
82
110
83
111
void TopoSorter::visit (Enum& e) {
@@ -92,7 +120,25 @@ void TopoSorter::visit(Typedef& td) {
92
120
void TopoSorter::visit (Pointer& p) {
93
121
// Pointers do not create a dependency, but we do still care about the types
94
122
// they point to, so delay them until the end.
95
- typesToSort_.push (*p.pointeeType ());
123
+ visitAfter (*p.pointeeType ());
124
+ }
125
+
126
+ /*
127
+ * A type graph may contain cycles, so we need to slightly tweak the standard
128
+ * topological sorting algorithm. Cycles can only be introduced by certain
129
+ * edges, e.g. a pointer's underlying type. However, these edges do not
130
+ * introduce dependencies as these types can be forward declared in a C++
131
+ * program. This means we can delay processing them until after all of the true
132
+ * dependencies have been sorted.
133
+ */
134
+ void TopoSorter::visitAfter (Type& type) {
135
+ typesToSort_.push (type);
136
+ }
137
+
138
+ void TopoSorter::visitAfter (Type* type) {
139
+ if (type) {
140
+ visitAfter (*type);
141
+ }
96
142
}
97
143
98
144
} // namespace type_graph
0 commit comments