@@ -116,16 +116,93 @@ std::string CIRGenTypes::getRecordTypeName(const clang::RecordDecl *recordDecl,
116116 return builder.getUniqueRecordName (std::string (typeName));
117117}
118118
119+ // / Return true if the specified type is already completely laid out.
120+ bool CIRGenTypes::isRecordLayoutComplete (const Type *ty) const {
121+ const auto it = recordDeclTypes.find (ty);
122+ return it != recordDeclTypes.end () && it->second .isComplete ();
123+ }
124+
125+ // We have multiple forms of this function that call each other, so we need to
126+ // declare one in advance.
127+ static bool
128+ isSafeToConvert (QualType qt, CIRGenTypes &cgt,
129+ llvm::SmallPtrSetImpl<const RecordDecl *> &alreadyChecked);
130+
131+ // / Return true if it is safe to convert the specified record decl to CIR and
132+ // / lay it out, false if doing so would cause us to get into a recursive
133+ // / compilation mess.
134+ static bool
135+ isSafeToConvert (const RecordDecl *rd, CIRGenTypes &cgt,
136+ llvm::SmallPtrSetImpl<const RecordDecl *> &alreadyChecked) {
137+ // If we have already checked this type (maybe the same type is used by-value
138+ // multiple times in multiple record fields, don't check again.
139+ if (!alreadyChecked.insert (rd).second )
140+ return true ;
141+
142+ const Type *key = cgt.getASTContext ().getTagDeclType (rd).getTypePtr ();
143+
144+ // If this type is already laid out, converting it is a noop.
145+ if (cgt.isRecordLayoutComplete (key))
146+ return true ;
147+
148+ // If this type is currently being laid out, we can't recursively compile it.
149+ if (cgt.isRecordBeingLaidOut (key))
150+ return false ;
151+
152+ // If this type would require laying out bases that are currently being laid
153+ // out, don't do it. This includes virtual base classes which get laid out
154+ // when a class is translated, even though they aren't embedded by-value into
155+ // the class.
156+ if (const CXXRecordDecl *crd = dyn_cast<CXXRecordDecl>(rd)) {
157+ assert (!cir::MissingFeatures::cxxSupport ());
158+ cgt.getCGModule ().errorNYI (rd->getSourceRange (),
159+ " isSafeToConvert: CXXRecordDecl" );
160+ return false ;
161+ }
162+
163+ // If this type would require laying out members that are currently being laid
164+ // out, don't do it.
165+ for (const FieldDecl *field : rd->fields ())
166+ if (!isSafeToConvert (field->getType (), cgt, alreadyChecked))
167+ return false ;
168+
169+ // If there are no problems, lets do it.
170+ return true ;
171+ }
172+
173+ // / Return true if it is safe to convert this field type, which requires the
174+ // / record elements contained by-value to all be recursively safe to convert.
175+ static bool
176+ isSafeToConvert (QualType qt, CIRGenTypes &cgt,
177+ llvm::SmallPtrSetImpl<const RecordDecl *> &alreadyChecked) {
178+ // Strip off atomic type sugar.
179+ if (const auto *at = qt->getAs <AtomicType>())
180+ qt = at->getValueType ();
181+
182+ // If this is a record, check it.
183+ if (const auto *rt = qt->getAs <RecordType>())
184+ return isSafeToConvert (rt->getDecl (), cgt, alreadyChecked);
185+
186+ // If this is an array, check the elements, which are embedded inline.
187+ if (const auto *at = cgt.getASTContext ().getAsArrayType (qt))
188+ return isSafeToConvert (at->getElementType (), cgt, alreadyChecked);
189+
190+ // Otherwise, there is no concern about transforming this. We only care about
191+ // things that are contained by-value in a record that can have another
192+ // record as a member.
193+ return true ;
194+ }
195+
119196// Return true if it is safe to convert the specified record decl to CIR and lay
120197// it out, false if doing so would cause us to get into a recursive compilation
121198// mess.
122- static bool isSafeToConvert (const RecordDecl *RD , CIRGenTypes &CGT ) {
199+ static bool isSafeToConvert (const RecordDecl *rd , CIRGenTypes &cgt ) {
123200 // If no records are being laid out, we can certainly do this one.
124- if (CGT .noRecordsBeingLaidOut ())
201+ if (cgt .noRecordsBeingLaidOut ())
125202 return true ;
126203
127- assert (! cir::MissingFeatures::recursiveRecordLayout ()) ;
128- return false ;
204+ llvm::SmallPtrSet< const RecordDecl *, 16 > alreadyChecked ;
205+ return isSafeToConvert (rd, cgt, alreadyChecked) ;
129206}
130207
131208// / Lay out a tagged decl type like struct or union.
0 commit comments