xref: /freebsd-src/contrib/llvm-project/clang/lib/AST/ASTStructuralEquivalence.cpp (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
10b57cec5SDimitry Andric //===- ASTStructuralEquivalence.cpp ---------------------------------------===//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric //
90b57cec5SDimitry Andric //  This file implement StructuralEquivalenceContext class and helper functions
100b57cec5SDimitry Andric //  for layout matching.
110b57cec5SDimitry Andric //
120b57cec5SDimitry Andric // The structural equivalence check could have been implemented as a parallel
130b57cec5SDimitry Andric // BFS on a pair of graphs.  That must have been the original approach at the
140b57cec5SDimitry Andric // beginning.
150b57cec5SDimitry Andric // Let's consider this simple BFS algorithm from the `s` source:
160b57cec5SDimitry Andric // ```
170b57cec5SDimitry Andric // void bfs(Graph G, int s)
180b57cec5SDimitry Andric // {
190b57cec5SDimitry Andric //   Queue<Integer> queue = new Queue<Integer>();
200b57cec5SDimitry Andric //   marked[s] = true; // Mark the source
210b57cec5SDimitry Andric //   queue.enqueue(s); // and put it on the queue.
220b57cec5SDimitry Andric //   while (!q.isEmpty()) {
230b57cec5SDimitry Andric //     int v = queue.dequeue(); // Remove next vertex from the queue.
240b57cec5SDimitry Andric //     for (int w : G.adj(v))
250b57cec5SDimitry Andric //       if (!marked[w]) // For every unmarked adjacent vertex,
260b57cec5SDimitry Andric //       {
270b57cec5SDimitry Andric //         marked[w] = true;
280b57cec5SDimitry Andric //         queue.enqueue(w);
290b57cec5SDimitry Andric //       }
300b57cec5SDimitry Andric //   }
310b57cec5SDimitry Andric // }
320b57cec5SDimitry Andric // ```
330b57cec5SDimitry Andric // Indeed, it has it's queue, which holds pairs of nodes, one from each graph,
345ffd83dbSDimitry Andric // this is the `DeclsToCheck` member. `VisitedDecls` plays the role of the
355ffd83dbSDimitry Andric // marking (`marked`) functionality above, we use it to check whether we've
365ffd83dbSDimitry Andric // already seen a pair of nodes.
370b57cec5SDimitry Andric //
380b57cec5SDimitry Andric // We put in the elements into the queue only in the toplevel decl check
390b57cec5SDimitry Andric // function:
400b57cec5SDimitry Andric // ```
410b57cec5SDimitry Andric // static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
420b57cec5SDimitry Andric //                                      Decl *D1, Decl *D2);
430b57cec5SDimitry Andric // ```
440b57cec5SDimitry Andric // The `while` loop where we iterate over the children is implemented in
450b57cec5SDimitry Andric // `Finish()`.  And `Finish` is called only from the two **member** functions
460b57cec5SDimitry Andric // which check the equivalency of two Decls or two Types. ASTImporter (and
470b57cec5SDimitry Andric // other clients) call only these functions.
480b57cec5SDimitry Andric //
490b57cec5SDimitry Andric // The `static` implementation functions are called from `Finish`, these push
500b57cec5SDimitry Andric // the children nodes to the queue via `static bool
510b57cec5SDimitry Andric // IsStructurallyEquivalent(StructuralEquivalenceContext &Context, Decl *D1,
520b57cec5SDimitry Andric // Decl *D2)`.  So far so good, this is almost like the BFS.  However, if we
530b57cec5SDimitry Andric // let a static implementation function to call `Finish` via another **member**
540b57cec5SDimitry Andric // function that means we end up with two nested while loops each of them
550b57cec5SDimitry Andric // working on the same queue. This is wrong and nobody can reason about it's
560b57cec5SDimitry Andric // doing. Thus, static implementation functions must not call the **member**
570b57cec5SDimitry Andric // functions.
580b57cec5SDimitry Andric //
590b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
600b57cec5SDimitry Andric 
610b57cec5SDimitry Andric #include "clang/AST/ASTStructuralEquivalence.h"
620b57cec5SDimitry Andric #include "clang/AST/ASTContext.h"
630b57cec5SDimitry Andric #include "clang/AST/ASTDiagnostic.h"
640b57cec5SDimitry Andric #include "clang/AST/Decl.h"
650b57cec5SDimitry Andric #include "clang/AST/DeclBase.h"
660b57cec5SDimitry Andric #include "clang/AST/DeclCXX.h"
670b57cec5SDimitry Andric #include "clang/AST/DeclFriend.h"
680b57cec5SDimitry Andric #include "clang/AST/DeclObjC.h"
69e8d8bef9SDimitry Andric #include "clang/AST/DeclOpenMP.h"
700b57cec5SDimitry Andric #include "clang/AST/DeclTemplate.h"
710b57cec5SDimitry Andric #include "clang/AST/ExprCXX.h"
72e8d8bef9SDimitry Andric #include "clang/AST/ExprConcepts.h"
73e8d8bef9SDimitry Andric #include "clang/AST/ExprObjC.h"
74e8d8bef9SDimitry Andric #include "clang/AST/ExprOpenMP.h"
750b57cec5SDimitry Andric #include "clang/AST/NestedNameSpecifier.h"
76e8d8bef9SDimitry Andric #include "clang/AST/StmtObjC.h"
77*0fca6ea1SDimitry Andric #include "clang/AST/StmtOpenACC.h"
78e8d8bef9SDimitry Andric #include "clang/AST/StmtOpenMP.h"
790b57cec5SDimitry Andric #include "clang/AST/TemplateBase.h"
800b57cec5SDimitry Andric #include "clang/AST/TemplateName.h"
810b57cec5SDimitry Andric #include "clang/AST/Type.h"
820b57cec5SDimitry Andric #include "clang/Basic/ExceptionSpecificationType.h"
830b57cec5SDimitry Andric #include "clang/Basic/IdentifierTable.h"
840b57cec5SDimitry Andric #include "clang/Basic/LLVM.h"
850b57cec5SDimitry Andric #include "clang/Basic/SourceLocation.h"
860b57cec5SDimitry Andric #include "llvm/ADT/APInt.h"
870b57cec5SDimitry Andric #include "llvm/ADT/APSInt.h"
88fe6060f1SDimitry Andric #include "llvm/ADT/StringExtras.h"
890b57cec5SDimitry Andric #include "llvm/Support/Casting.h"
900b57cec5SDimitry Andric #include "llvm/Support/Compiler.h"
910b57cec5SDimitry Andric #include "llvm/Support/ErrorHandling.h"
920b57cec5SDimitry Andric #include <cassert>
93bdd1243dSDimitry Andric #include <optional>
940b57cec5SDimitry Andric #include <utility>
950b57cec5SDimitry Andric 
960b57cec5SDimitry Andric using namespace clang;
970b57cec5SDimitry Andric 
980b57cec5SDimitry Andric static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
990b57cec5SDimitry Andric                                      QualType T1, QualType T2);
1000b57cec5SDimitry Andric static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
1010b57cec5SDimitry Andric                                      Decl *D1, Decl *D2);
1020b57cec5SDimitry Andric static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
1037a6dacacSDimitry Andric                                      const Stmt *S1, const Stmt *S2);
1047a6dacacSDimitry Andric static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
1050b57cec5SDimitry Andric                                      const TemplateArgument &Arg1,
1060b57cec5SDimitry Andric                                      const TemplateArgument &Arg2);
1070b57cec5SDimitry Andric static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
108bdd1243dSDimitry Andric                                      const TemplateArgumentLoc &Arg1,
109bdd1243dSDimitry Andric                                      const TemplateArgumentLoc &Arg2);
110bdd1243dSDimitry Andric static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
1110b57cec5SDimitry Andric                                      NestedNameSpecifier *NNS1,
1120b57cec5SDimitry Andric                                      NestedNameSpecifier *NNS2);
1130b57cec5SDimitry Andric static bool IsStructurallyEquivalent(const IdentifierInfo *Name1,
1140b57cec5SDimitry Andric                                      const IdentifierInfo *Name2);
1150b57cec5SDimitry Andric 
1160b57cec5SDimitry Andric static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
1170b57cec5SDimitry Andric                                      const DeclarationName Name1,
1180b57cec5SDimitry Andric                                      const DeclarationName Name2) {
1190b57cec5SDimitry Andric   if (Name1.getNameKind() != Name2.getNameKind())
1200b57cec5SDimitry Andric     return false;
1210b57cec5SDimitry Andric 
1220b57cec5SDimitry Andric   switch (Name1.getNameKind()) {
1230b57cec5SDimitry Andric 
1240b57cec5SDimitry Andric   case DeclarationName::Identifier:
1250b57cec5SDimitry Andric     return IsStructurallyEquivalent(Name1.getAsIdentifierInfo(),
1260b57cec5SDimitry Andric                                     Name2.getAsIdentifierInfo());
1270b57cec5SDimitry Andric 
1280b57cec5SDimitry Andric   case DeclarationName::CXXConstructorName:
1290b57cec5SDimitry Andric   case DeclarationName::CXXDestructorName:
1300b57cec5SDimitry Andric   case DeclarationName::CXXConversionFunctionName:
1310b57cec5SDimitry Andric     return IsStructurallyEquivalent(Context, Name1.getCXXNameType(),
1320b57cec5SDimitry Andric                                     Name2.getCXXNameType());
1330b57cec5SDimitry Andric 
1340b57cec5SDimitry Andric   case DeclarationName::CXXDeductionGuideName: {
1350b57cec5SDimitry Andric     if (!IsStructurallyEquivalent(
1360b57cec5SDimitry Andric             Context, Name1.getCXXDeductionGuideTemplate()->getDeclName(),
1370b57cec5SDimitry Andric             Name2.getCXXDeductionGuideTemplate()->getDeclName()))
1380b57cec5SDimitry Andric       return false;
1390b57cec5SDimitry Andric     return IsStructurallyEquivalent(Context,
1400b57cec5SDimitry Andric                                     Name1.getCXXDeductionGuideTemplate(),
1410b57cec5SDimitry Andric                                     Name2.getCXXDeductionGuideTemplate());
1420b57cec5SDimitry Andric   }
1430b57cec5SDimitry Andric 
1440b57cec5SDimitry Andric   case DeclarationName::CXXOperatorName:
1450b57cec5SDimitry Andric     return Name1.getCXXOverloadedOperator() == Name2.getCXXOverloadedOperator();
1460b57cec5SDimitry Andric 
1470b57cec5SDimitry Andric   case DeclarationName::CXXLiteralOperatorName:
1480b57cec5SDimitry Andric     return IsStructurallyEquivalent(Name1.getCXXLiteralIdentifier(),
1490b57cec5SDimitry Andric                                     Name2.getCXXLiteralIdentifier());
1500b57cec5SDimitry Andric 
1510b57cec5SDimitry Andric   case DeclarationName::CXXUsingDirective:
1520b57cec5SDimitry Andric     return true; // FIXME When do we consider two using directives equal?
1530b57cec5SDimitry Andric 
1540b57cec5SDimitry Andric   case DeclarationName::ObjCZeroArgSelector:
1550b57cec5SDimitry Andric   case DeclarationName::ObjCOneArgSelector:
1560b57cec5SDimitry Andric   case DeclarationName::ObjCMultiArgSelector:
1570b57cec5SDimitry Andric     return true; // FIXME
1580b57cec5SDimitry Andric   }
1590b57cec5SDimitry Andric 
1600b57cec5SDimitry Andric   llvm_unreachable("Unhandled kind of DeclarationName");
1610b57cec5SDimitry Andric   return true;
1620b57cec5SDimitry Andric }
1630b57cec5SDimitry Andric 
164e8d8bef9SDimitry Andric namespace {
165e8d8bef9SDimitry Andric /// Encapsulates Stmt comparison logic.
166e8d8bef9SDimitry Andric class StmtComparer {
167e8d8bef9SDimitry Andric   StructuralEquivalenceContext &Context;
1680b57cec5SDimitry Andric 
169e8d8bef9SDimitry Andric   // IsStmtEquivalent overloads. Each overload compares a specific statement
170e8d8bef9SDimitry Andric   // and only has to compare the data that is specific to the specific statement
171e8d8bef9SDimitry Andric   // class. Should only be called from TraverseStmt.
172e8d8bef9SDimitry Andric 
173e8d8bef9SDimitry Andric   bool IsStmtEquivalent(const AddrLabelExpr *E1, const AddrLabelExpr *E2) {
174e8d8bef9SDimitry Andric     return IsStructurallyEquivalent(Context, E1->getLabel(), E2->getLabel());
175e8d8bef9SDimitry Andric   }
176e8d8bef9SDimitry Andric 
177e8d8bef9SDimitry Andric   bool IsStmtEquivalent(const AtomicExpr *E1, const AtomicExpr *E2) {
178e8d8bef9SDimitry Andric     return E1->getOp() == E2->getOp();
179e8d8bef9SDimitry Andric   }
180e8d8bef9SDimitry Andric 
181e8d8bef9SDimitry Andric   bool IsStmtEquivalent(const BinaryOperator *E1, const BinaryOperator *E2) {
182e8d8bef9SDimitry Andric     return E1->getOpcode() == E2->getOpcode();
183e8d8bef9SDimitry Andric   }
184e8d8bef9SDimitry Andric 
185e8d8bef9SDimitry Andric   bool IsStmtEquivalent(const CallExpr *E1, const CallExpr *E2) {
186e8d8bef9SDimitry Andric     // FIXME: IsStructurallyEquivalent requires non-const Decls.
187e8d8bef9SDimitry Andric     Decl *Callee1 = const_cast<Decl *>(E1->getCalleeDecl());
188e8d8bef9SDimitry Andric     Decl *Callee2 = const_cast<Decl *>(E2->getCalleeDecl());
189e8d8bef9SDimitry Andric 
190e8d8bef9SDimitry Andric     // Compare whether both calls know their callee.
191e8d8bef9SDimitry Andric     if (static_cast<bool>(Callee1) != static_cast<bool>(Callee2))
1920b57cec5SDimitry Andric       return false;
193e8d8bef9SDimitry Andric 
194e8d8bef9SDimitry Andric     // Both calls have no callee, so nothing to do.
195e8d8bef9SDimitry Andric     if (!static_cast<bool>(Callee1))
196e8d8bef9SDimitry Andric       return true;
197e8d8bef9SDimitry Andric 
198e8d8bef9SDimitry Andric     assert(Callee2);
199e8d8bef9SDimitry Andric     return IsStructurallyEquivalent(Context, Callee1, Callee2);
200e8d8bef9SDimitry Andric   }
201e8d8bef9SDimitry Andric 
202e8d8bef9SDimitry Andric   bool IsStmtEquivalent(const CharacterLiteral *E1,
203e8d8bef9SDimitry Andric                         const CharacterLiteral *E2) {
204e8d8bef9SDimitry Andric     return E1->getValue() == E2->getValue() && E1->getKind() == E2->getKind();
205e8d8bef9SDimitry Andric   }
206e8d8bef9SDimitry Andric 
207e8d8bef9SDimitry Andric   bool IsStmtEquivalent(const ChooseExpr *E1, const ChooseExpr *E2) {
208e8d8bef9SDimitry Andric     return true; // Semantics only depend on children.
209e8d8bef9SDimitry Andric   }
210e8d8bef9SDimitry Andric 
211e8d8bef9SDimitry Andric   bool IsStmtEquivalent(const CompoundStmt *E1, const CompoundStmt *E2) {
212e8d8bef9SDimitry Andric     // Number of children is actually checked by the generic children comparison
213e8d8bef9SDimitry Andric     // code, but a CompoundStmt is one of the few statements where the number of
214e8d8bef9SDimitry Andric     // children frequently differs and the number of statements is also always
215e8d8bef9SDimitry Andric     // precomputed. Directly comparing the number of children here is thus
216e8d8bef9SDimitry Andric     // just an optimization.
217e8d8bef9SDimitry Andric     return E1->size() == E2->size();
218e8d8bef9SDimitry Andric   }
219e8d8bef9SDimitry Andric 
2205f757f3fSDimitry Andric   bool IsStmtEquivalent(const DeclRefExpr *DRE1, const DeclRefExpr *DRE2) {
2215f757f3fSDimitry Andric     const ValueDecl *Decl1 = DRE1->getDecl();
2225f757f3fSDimitry Andric     const ValueDecl *Decl2 = DRE2->getDecl();
2235f757f3fSDimitry Andric     if (!Decl1 || !Decl2)
2245f757f3fSDimitry Andric       return false;
2255f757f3fSDimitry Andric     return IsStructurallyEquivalent(Context, const_cast<ValueDecl *>(Decl1),
2265f757f3fSDimitry Andric                                     const_cast<ValueDecl *>(Decl2));
2275f757f3fSDimitry Andric   }
2285f757f3fSDimitry Andric 
229e8d8bef9SDimitry Andric   bool IsStmtEquivalent(const DependentScopeDeclRefExpr *DE1,
230e8d8bef9SDimitry Andric                         const DependentScopeDeclRefExpr *DE2) {
2310b57cec5SDimitry Andric     if (!IsStructurallyEquivalent(Context, DE1->getDeclName(),
2320b57cec5SDimitry Andric                                   DE2->getDeclName()))
2330b57cec5SDimitry Andric       return false;
2340b57cec5SDimitry Andric     return IsStructurallyEquivalent(Context, DE1->getQualifier(),
2350b57cec5SDimitry Andric                                     DE2->getQualifier());
2360b57cec5SDimitry Andric   }
237e8d8bef9SDimitry Andric 
238e8d8bef9SDimitry Andric   bool IsStmtEquivalent(const Expr *E1, const Expr *E2) {
239e8d8bef9SDimitry Andric     return IsStructurallyEquivalent(Context, E1->getType(), E2->getType());
240e8d8bef9SDimitry Andric   }
241e8d8bef9SDimitry Andric 
242e8d8bef9SDimitry Andric   bool IsStmtEquivalent(const ExpressionTraitExpr *E1,
243e8d8bef9SDimitry Andric                         const ExpressionTraitExpr *E2) {
244e8d8bef9SDimitry Andric     return E1->getTrait() == E2->getTrait() && E1->getValue() == E2->getValue();
245e8d8bef9SDimitry Andric   }
246e8d8bef9SDimitry Andric 
247e8d8bef9SDimitry Andric   bool IsStmtEquivalent(const FloatingLiteral *E1, const FloatingLiteral *E2) {
248e8d8bef9SDimitry Andric     return E1->isExact() == E2->isExact() && E1->getValue() == E2->getValue();
249e8d8bef9SDimitry Andric   }
250e8d8bef9SDimitry Andric 
251e8d8bef9SDimitry Andric   bool IsStmtEquivalent(const GenericSelectionExpr *E1,
252e8d8bef9SDimitry Andric                         const GenericSelectionExpr *E2) {
253e8d8bef9SDimitry Andric     for (auto Pair : zip_longest(E1->getAssocTypeSourceInfos(),
254e8d8bef9SDimitry Andric                                  E2->getAssocTypeSourceInfos())) {
255bdd1243dSDimitry Andric       std::optional<TypeSourceInfo *> Child1 = std::get<0>(Pair);
256bdd1243dSDimitry Andric       std::optional<TypeSourceInfo *> Child2 = std::get<1>(Pair);
257e8d8bef9SDimitry Andric       // Skip this case if there are a different number of associated types.
258e8d8bef9SDimitry Andric       if (!Child1 || !Child2)
259e8d8bef9SDimitry Andric         return false;
260e8d8bef9SDimitry Andric 
261e8d8bef9SDimitry Andric       if (!IsStructurallyEquivalent(Context, (*Child1)->getType(),
262e8d8bef9SDimitry Andric                                     (*Child2)->getType()))
263e8d8bef9SDimitry Andric         return false;
264e8d8bef9SDimitry Andric     }
265e8d8bef9SDimitry Andric 
266e8d8bef9SDimitry Andric     return true;
267e8d8bef9SDimitry Andric   }
268e8d8bef9SDimitry Andric 
269e8d8bef9SDimitry Andric   bool IsStmtEquivalent(const ImplicitCastExpr *CastE1,
270e8d8bef9SDimitry Andric                         const ImplicitCastExpr *CastE2) {
271e8d8bef9SDimitry Andric     return IsStructurallyEquivalent(Context, CastE1->getType(),
272e8d8bef9SDimitry Andric                                     CastE2->getType());
273e8d8bef9SDimitry Andric   }
274e8d8bef9SDimitry Andric 
275e8d8bef9SDimitry Andric   bool IsStmtEquivalent(const IntegerLiteral *E1, const IntegerLiteral *E2) {
276e8d8bef9SDimitry Andric     return E1->getValue() == E2->getValue();
277e8d8bef9SDimitry Andric   }
278e8d8bef9SDimitry Andric 
279e8d8bef9SDimitry Andric   bool IsStmtEquivalent(const MemberExpr *E1, const MemberExpr *E2) {
280e8d8bef9SDimitry Andric     return IsStructurallyEquivalent(Context, E1->getFoundDecl(),
281e8d8bef9SDimitry Andric                                     E2->getFoundDecl());
282e8d8bef9SDimitry Andric   }
283e8d8bef9SDimitry Andric 
284e8d8bef9SDimitry Andric   bool IsStmtEquivalent(const ObjCStringLiteral *E1,
285e8d8bef9SDimitry Andric                         const ObjCStringLiteral *E2) {
286e8d8bef9SDimitry Andric     // Just wraps a StringLiteral child.
287e8d8bef9SDimitry Andric     return true;
288e8d8bef9SDimitry Andric   }
289e8d8bef9SDimitry Andric 
290e8d8bef9SDimitry Andric   bool IsStmtEquivalent(const Stmt *S1, const Stmt *S2) { return true; }
291e8d8bef9SDimitry Andric 
2925f757f3fSDimitry Andric   bool IsStmtEquivalent(const GotoStmt *S1, const GotoStmt *S2) {
2935f757f3fSDimitry Andric     LabelDecl *L1 = S1->getLabel();
2945f757f3fSDimitry Andric     LabelDecl *L2 = S2->getLabel();
2955f757f3fSDimitry Andric     if (!L1 || !L2)
2965f757f3fSDimitry Andric       return L1 == L2;
2975f757f3fSDimitry Andric 
2985f757f3fSDimitry Andric     IdentifierInfo *Name1 = L1->getIdentifier();
2995f757f3fSDimitry Andric     IdentifierInfo *Name2 = L2->getIdentifier();
3005f757f3fSDimitry Andric     return ::IsStructurallyEquivalent(Name1, Name2);
3015f757f3fSDimitry Andric   }
3025f757f3fSDimitry Andric 
303e8d8bef9SDimitry Andric   bool IsStmtEquivalent(const SourceLocExpr *E1, const SourceLocExpr *E2) {
304e8d8bef9SDimitry Andric     return E1->getIdentKind() == E2->getIdentKind();
305e8d8bef9SDimitry Andric   }
306e8d8bef9SDimitry Andric 
307e8d8bef9SDimitry Andric   bool IsStmtEquivalent(const StmtExpr *E1, const StmtExpr *E2) {
308e8d8bef9SDimitry Andric     return E1->getTemplateDepth() == E2->getTemplateDepth();
309e8d8bef9SDimitry Andric   }
310e8d8bef9SDimitry Andric 
311e8d8bef9SDimitry Andric   bool IsStmtEquivalent(const StringLiteral *E1, const StringLiteral *E2) {
312e8d8bef9SDimitry Andric     return E1->getBytes() == E2->getBytes();
313e8d8bef9SDimitry Andric   }
314e8d8bef9SDimitry Andric 
315e8d8bef9SDimitry Andric   bool IsStmtEquivalent(const SubstNonTypeTemplateParmExpr *E1,
316e8d8bef9SDimitry Andric                         const SubstNonTypeTemplateParmExpr *E2) {
317bdd1243dSDimitry Andric     if (!IsStructurallyEquivalent(Context, E1->getAssociatedDecl(),
318bdd1243dSDimitry Andric                                   E2->getAssociatedDecl()))
319bdd1243dSDimitry Andric       return false;
320bdd1243dSDimitry Andric     if (E1->getIndex() != E2->getIndex())
321bdd1243dSDimitry Andric       return false;
322bdd1243dSDimitry Andric     if (E1->getPackIndex() != E2->getPackIndex())
323bdd1243dSDimitry Andric       return false;
324bdd1243dSDimitry Andric     return true;
325e8d8bef9SDimitry Andric   }
326e8d8bef9SDimitry Andric 
327e8d8bef9SDimitry Andric   bool IsStmtEquivalent(const SubstNonTypeTemplateParmPackExpr *E1,
328e8d8bef9SDimitry Andric                         const SubstNonTypeTemplateParmPackExpr *E2) {
329e8d8bef9SDimitry Andric     return IsStructurallyEquivalent(Context, E1->getArgumentPack(),
330e8d8bef9SDimitry Andric                                     E2->getArgumentPack());
331e8d8bef9SDimitry Andric   }
332e8d8bef9SDimitry Andric 
333e8d8bef9SDimitry Andric   bool IsStmtEquivalent(const TypeTraitExpr *E1, const TypeTraitExpr *E2) {
334e8d8bef9SDimitry Andric     if (E1->getTrait() != E2->getTrait())
335e8d8bef9SDimitry Andric       return false;
336e8d8bef9SDimitry Andric 
337e8d8bef9SDimitry Andric     for (auto Pair : zip_longest(E1->getArgs(), E2->getArgs())) {
338bdd1243dSDimitry Andric       std::optional<TypeSourceInfo *> Child1 = std::get<0>(Pair);
339bdd1243dSDimitry Andric       std::optional<TypeSourceInfo *> Child2 = std::get<1>(Pair);
340e8d8bef9SDimitry Andric       // Different number of args.
341e8d8bef9SDimitry Andric       if (!Child1 || !Child2)
342e8d8bef9SDimitry Andric         return false;
343e8d8bef9SDimitry Andric 
344e8d8bef9SDimitry Andric       if (!IsStructurallyEquivalent(Context, (*Child1)->getType(),
345e8d8bef9SDimitry Andric                                     (*Child2)->getType()))
346e8d8bef9SDimitry Andric         return false;
347e8d8bef9SDimitry Andric     }
348e8d8bef9SDimitry Andric     return true;
349e8d8bef9SDimitry Andric   }
350e8d8bef9SDimitry Andric 
351*0fca6ea1SDimitry Andric   bool IsStmtEquivalent(const CXXDependentScopeMemberExpr *E1,
352*0fca6ea1SDimitry Andric                         const CXXDependentScopeMemberExpr *E2) {
353*0fca6ea1SDimitry Andric     if (!IsStructurallyEquivalent(Context, E1->getMember(), E2->getMember())) {
354*0fca6ea1SDimitry Andric       return false;
355*0fca6ea1SDimitry Andric     }
356*0fca6ea1SDimitry Andric     return IsStructurallyEquivalent(Context, E1->getBaseType(),
357*0fca6ea1SDimitry Andric                                     E2->getBaseType());
358*0fca6ea1SDimitry Andric   }
359*0fca6ea1SDimitry Andric 
360e8d8bef9SDimitry Andric   bool IsStmtEquivalent(const UnaryExprOrTypeTraitExpr *E1,
361e8d8bef9SDimitry Andric                         const UnaryExprOrTypeTraitExpr *E2) {
362e8d8bef9SDimitry Andric     if (E1->getKind() != E2->getKind())
363e8d8bef9SDimitry Andric       return false;
364e8d8bef9SDimitry Andric     return IsStructurallyEquivalent(Context, E1->getTypeOfArgument(),
365e8d8bef9SDimitry Andric                                     E2->getTypeOfArgument());
366e8d8bef9SDimitry Andric   }
367e8d8bef9SDimitry Andric 
368e8d8bef9SDimitry Andric   bool IsStmtEquivalent(const UnaryOperator *E1, const UnaryOperator *E2) {
369e8d8bef9SDimitry Andric     return E1->getOpcode() == E2->getOpcode();
370e8d8bef9SDimitry Andric   }
371e8d8bef9SDimitry Andric 
372e8d8bef9SDimitry Andric   bool IsStmtEquivalent(const VAArgExpr *E1, const VAArgExpr *E2) {
373e8d8bef9SDimitry Andric     // Semantics only depend on children.
374e8d8bef9SDimitry Andric     return true;
375e8d8bef9SDimitry Andric   }
376e8d8bef9SDimitry Andric 
377bdd1243dSDimitry Andric   bool IsStmtEquivalent(const OverloadExpr *E1, const OverloadExpr *E2) {
378bdd1243dSDimitry Andric     if (!IsStructurallyEquivalent(Context, E1->getName(), E2->getName()))
379bdd1243dSDimitry Andric       return false;
380bdd1243dSDimitry Andric 
381bdd1243dSDimitry Andric     if (static_cast<bool>(E1->getQualifier()) !=
382bdd1243dSDimitry Andric         static_cast<bool>(E2->getQualifier()))
383bdd1243dSDimitry Andric       return false;
384bdd1243dSDimitry Andric     if (E1->getQualifier() &&
385bdd1243dSDimitry Andric         !IsStructurallyEquivalent(Context, E1->getQualifier(),
386bdd1243dSDimitry Andric                                   E2->getQualifier()))
387bdd1243dSDimitry Andric       return false;
388bdd1243dSDimitry Andric 
389bdd1243dSDimitry Andric     if (E1->getNumTemplateArgs() != E2->getNumTemplateArgs())
390bdd1243dSDimitry Andric       return false;
391bdd1243dSDimitry Andric     const TemplateArgumentLoc *Args1 = E1->getTemplateArgs();
392bdd1243dSDimitry Andric     const TemplateArgumentLoc *Args2 = E2->getTemplateArgs();
393bdd1243dSDimitry Andric     for (unsigned int ArgI = 0, ArgN = E1->getNumTemplateArgs(); ArgI < ArgN;
394bdd1243dSDimitry Andric          ++ArgI)
395bdd1243dSDimitry Andric       if (!IsStructurallyEquivalent(Context, Args1[ArgI], Args2[ArgI]))
396bdd1243dSDimitry Andric         return false;
397bdd1243dSDimitry Andric 
398bdd1243dSDimitry Andric     return true;
399bdd1243dSDimitry Andric   }
400bdd1243dSDimitry Andric 
4015f757f3fSDimitry Andric   bool IsStmtEquivalent(const CXXBoolLiteralExpr *E1, const CXXBoolLiteralExpr *E2) {
4025f757f3fSDimitry Andric     return E1->getValue() == E2->getValue();
4035f757f3fSDimitry Andric   }
4045f757f3fSDimitry Andric 
405e8d8bef9SDimitry Andric   /// End point of the traversal chain.
406e8d8bef9SDimitry Andric   bool TraverseStmt(const Stmt *S1, const Stmt *S2) { return true; }
407e8d8bef9SDimitry Andric 
408e8d8bef9SDimitry Andric   // Create traversal methods that traverse the class hierarchy and return
409e8d8bef9SDimitry Andric   // the accumulated result of the comparison. Each TraverseStmt overload
410e8d8bef9SDimitry Andric   // calls the TraverseStmt overload of the parent class. For example,
411e8d8bef9SDimitry Andric   // the TraverseStmt overload for 'BinaryOperator' calls the TraverseStmt
412e8d8bef9SDimitry Andric   // overload of 'Expr' which then calls the overload for 'Stmt'.
413e8d8bef9SDimitry Andric #define STMT(CLASS, PARENT)                                                    \
414e8d8bef9SDimitry Andric   bool TraverseStmt(const CLASS *S1, const CLASS *S2) {                        \
415e8d8bef9SDimitry Andric     if (!TraverseStmt(static_cast<const PARENT *>(S1),                         \
416e8d8bef9SDimitry Andric                       static_cast<const PARENT *>(S2)))                        \
417e8d8bef9SDimitry Andric       return false;                                                            \
418e8d8bef9SDimitry Andric     return IsStmtEquivalent(S1, S2);                                           \
419e8d8bef9SDimitry Andric   }
420e8d8bef9SDimitry Andric #include "clang/AST/StmtNodes.inc"
421e8d8bef9SDimitry Andric 
422e8d8bef9SDimitry Andric public:
423e8d8bef9SDimitry Andric   StmtComparer(StructuralEquivalenceContext &C) : Context(C) {}
424e8d8bef9SDimitry Andric 
425e8d8bef9SDimitry Andric   /// Determine whether two statements are equivalent. The statements have to
426e8d8bef9SDimitry Andric   /// be of the same kind. The children of the statements and their properties
427e8d8bef9SDimitry Andric   /// are not compared by this function.
428e8d8bef9SDimitry Andric   bool IsEquivalent(const Stmt *S1, const Stmt *S2) {
429e8d8bef9SDimitry Andric     if (S1->getStmtClass() != S2->getStmtClass())
430e8d8bef9SDimitry Andric       return false;
431e8d8bef9SDimitry Andric 
432e8d8bef9SDimitry Andric     // Each TraverseStmt walks the class hierarchy from the leaf class to
433e8d8bef9SDimitry Andric     // the root class 'Stmt' (e.g. 'BinaryOperator' -> 'Expr' -> 'Stmt'). Cast
434e8d8bef9SDimitry Andric     // the Stmt we have here to its specific subclass so that we call the
435e8d8bef9SDimitry Andric     // overload that walks the whole class hierarchy from leaf to root (e.g.,
436e8d8bef9SDimitry Andric     // cast to 'BinaryOperator' so that 'Expr' and 'Stmt' is traversed).
437e8d8bef9SDimitry Andric     switch (S1->getStmtClass()) {
438e8d8bef9SDimitry Andric     case Stmt::NoStmtClass:
439e8d8bef9SDimitry Andric       llvm_unreachable("Can't traverse NoStmtClass");
440e8d8bef9SDimitry Andric #define STMT(CLASS, PARENT)                                                    \
441e8d8bef9SDimitry Andric   case Stmt::StmtClass::CLASS##Class:                                          \
442e8d8bef9SDimitry Andric     return TraverseStmt(static_cast<const CLASS *>(S1),                        \
443e8d8bef9SDimitry Andric                         static_cast<const CLASS *>(S2));
444e8d8bef9SDimitry Andric #define ABSTRACT_STMT(S)
445e8d8bef9SDimitry Andric #include "clang/AST/StmtNodes.inc"
446e8d8bef9SDimitry Andric     }
447e8d8bef9SDimitry Andric     llvm_unreachable("Invalid statement kind");
448e8d8bef9SDimitry Andric   }
449e8d8bef9SDimitry Andric };
450e8d8bef9SDimitry Andric } // namespace
451e8d8bef9SDimitry Andric 
4527a6dacacSDimitry Andric static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
4537a6dacacSDimitry Andric                                      const UnaryOperator *E1,
4547a6dacacSDimitry Andric                                      const CXXOperatorCallExpr *E2) {
4557a6dacacSDimitry Andric   return UnaryOperator::getOverloadedOperator(E1->getOpcode()) ==
4567a6dacacSDimitry Andric              E2->getOperator() &&
4577a6dacacSDimitry Andric          IsStructurallyEquivalent(Context, E1->getSubExpr(), E2->getArg(0));
4587a6dacacSDimitry Andric }
4597a6dacacSDimitry Andric 
4607a6dacacSDimitry Andric static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
4617a6dacacSDimitry Andric                                      const CXXOperatorCallExpr *E1,
4627a6dacacSDimitry Andric                                      const UnaryOperator *E2) {
4637a6dacacSDimitry Andric   return E1->getOperator() ==
4647a6dacacSDimitry Andric              UnaryOperator::getOverloadedOperator(E2->getOpcode()) &&
4657a6dacacSDimitry Andric          IsStructurallyEquivalent(Context, E1->getArg(0), E2->getSubExpr());
4667a6dacacSDimitry Andric }
4677a6dacacSDimitry Andric 
4687a6dacacSDimitry Andric static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
4697a6dacacSDimitry Andric                                      const BinaryOperator *E1,
4707a6dacacSDimitry Andric                                      const CXXOperatorCallExpr *E2) {
4717a6dacacSDimitry Andric   return BinaryOperator::getOverloadedOperator(E1->getOpcode()) ==
4727a6dacacSDimitry Andric              E2->getOperator() &&
4737a6dacacSDimitry Andric          IsStructurallyEquivalent(Context, E1->getLHS(), E2->getArg(0)) &&
4747a6dacacSDimitry Andric          IsStructurallyEquivalent(Context, E1->getRHS(), E2->getArg(1));
4757a6dacacSDimitry Andric }
4767a6dacacSDimitry Andric 
4777a6dacacSDimitry Andric static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
4787a6dacacSDimitry Andric                                      const CXXOperatorCallExpr *E1,
4797a6dacacSDimitry Andric                                      const BinaryOperator *E2) {
4807a6dacacSDimitry Andric   return E1->getOperator() ==
4817a6dacacSDimitry Andric              BinaryOperator::getOverloadedOperator(E2->getOpcode()) &&
4827a6dacacSDimitry Andric          IsStructurallyEquivalent(Context, E1->getArg(0), E2->getLHS()) &&
4837a6dacacSDimitry Andric          IsStructurallyEquivalent(Context, E1->getArg(1), E2->getRHS());
4847a6dacacSDimitry Andric }
4857a6dacacSDimitry Andric 
486e8d8bef9SDimitry Andric /// Determine structural equivalence of two statements.
487e8d8bef9SDimitry Andric static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
488e8d8bef9SDimitry Andric                                      const Stmt *S1, const Stmt *S2) {
489e8d8bef9SDimitry Andric   if (!S1 || !S2)
490e8d8bef9SDimitry Andric     return S1 == S2;
491e8d8bef9SDimitry Andric 
4927a6dacacSDimitry Andric   // Check for statements with similar syntax but different AST.
4937a6dacacSDimitry Andric   // A UnaryOperator node is more lightweight than a CXXOperatorCallExpr node.
4947a6dacacSDimitry Andric   // The more heavyweight node is only created if the definition-time name
4957a6dacacSDimitry Andric   // lookup had any results. The lookup results are stored CXXOperatorCallExpr
4967a6dacacSDimitry Andric   // only. The lookup results can be different in a "From" and "To" AST even if
4977a6dacacSDimitry Andric   // the compared structure is otherwise equivalent. For this reason we must
4987a6dacacSDimitry Andric   // treat a similar unary/binary operator node and CXXOperatorCall node as
4997a6dacacSDimitry Andric   // equivalent.
5007a6dacacSDimitry Andric   if (const auto *E2CXXOperatorCall = dyn_cast<CXXOperatorCallExpr>(S2)) {
5017a6dacacSDimitry Andric     if (const auto *E1Unary = dyn_cast<UnaryOperator>(S1))
5027a6dacacSDimitry Andric       return IsStructurallyEquivalent(Context, E1Unary, E2CXXOperatorCall);
5037a6dacacSDimitry Andric     if (const auto *E1Binary = dyn_cast<BinaryOperator>(S1))
5047a6dacacSDimitry Andric       return IsStructurallyEquivalent(Context, E1Binary, E2CXXOperatorCall);
5057a6dacacSDimitry Andric   }
5067a6dacacSDimitry Andric   if (const auto *E1CXXOperatorCall = dyn_cast<CXXOperatorCallExpr>(S1)) {
5077a6dacacSDimitry Andric     if (const auto *E2Unary = dyn_cast<UnaryOperator>(S2))
5087a6dacacSDimitry Andric       return IsStructurallyEquivalent(Context, E1CXXOperatorCall, E2Unary);
5097a6dacacSDimitry Andric     if (const auto *E2Binary = dyn_cast<BinaryOperator>(S2))
5107a6dacacSDimitry Andric       return IsStructurallyEquivalent(Context, E1CXXOperatorCall, E2Binary);
5117a6dacacSDimitry Andric   }
5127a6dacacSDimitry Andric 
513e8d8bef9SDimitry Andric   // Compare the statements itself.
514e8d8bef9SDimitry Andric   StmtComparer Comparer(Context);
515e8d8bef9SDimitry Andric   if (!Comparer.IsEquivalent(S1, S2))
516e8d8bef9SDimitry Andric     return false;
517e8d8bef9SDimitry Andric 
518e8d8bef9SDimitry Andric   // Iterate over the children of both statements and also compare them.
519e8d8bef9SDimitry Andric   for (auto Pair : zip_longest(S1->children(), S2->children())) {
520bdd1243dSDimitry Andric     std::optional<const Stmt *> Child1 = std::get<0>(Pair);
521bdd1243dSDimitry Andric     std::optional<const Stmt *> Child2 = std::get<1>(Pair);
522e8d8bef9SDimitry Andric     // One of the statements has a different amount of children than the other,
523e8d8bef9SDimitry Andric     // so the statements can't be equivalent.
524e8d8bef9SDimitry Andric     if (!Child1 || !Child2)
525e8d8bef9SDimitry Andric       return false;
526e8d8bef9SDimitry Andric     if (!IsStructurallyEquivalent(Context, *Child1, *Child2))
527e8d8bef9SDimitry Andric       return false;
528e8d8bef9SDimitry Andric   }
5290b57cec5SDimitry Andric   return true;
5300b57cec5SDimitry Andric }
5310b57cec5SDimitry Andric 
5320b57cec5SDimitry Andric /// Determine whether two identifiers are equivalent.
5330b57cec5SDimitry Andric static bool IsStructurallyEquivalent(const IdentifierInfo *Name1,
5340b57cec5SDimitry Andric                                      const IdentifierInfo *Name2) {
5350b57cec5SDimitry Andric   if (!Name1 || !Name2)
5360b57cec5SDimitry Andric     return Name1 == Name2;
5370b57cec5SDimitry Andric 
5380b57cec5SDimitry Andric   return Name1->getName() == Name2->getName();
5390b57cec5SDimitry Andric }
5400b57cec5SDimitry Andric 
5410b57cec5SDimitry Andric /// Determine whether two nested-name-specifiers are equivalent.
5420b57cec5SDimitry Andric static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
5430b57cec5SDimitry Andric                                      NestedNameSpecifier *NNS1,
5440b57cec5SDimitry Andric                                      NestedNameSpecifier *NNS2) {
5450b57cec5SDimitry Andric   if (NNS1->getKind() != NNS2->getKind())
5460b57cec5SDimitry Andric     return false;
5470b57cec5SDimitry Andric 
5480b57cec5SDimitry Andric   NestedNameSpecifier *Prefix1 = NNS1->getPrefix(),
5490b57cec5SDimitry Andric                       *Prefix2 = NNS2->getPrefix();
5500b57cec5SDimitry Andric   if ((bool)Prefix1 != (bool)Prefix2)
5510b57cec5SDimitry Andric     return false;
5520b57cec5SDimitry Andric 
5530b57cec5SDimitry Andric   if (Prefix1)
5540b57cec5SDimitry Andric     if (!IsStructurallyEquivalent(Context, Prefix1, Prefix2))
5550b57cec5SDimitry Andric       return false;
5560b57cec5SDimitry Andric 
5570b57cec5SDimitry Andric   switch (NNS1->getKind()) {
5580b57cec5SDimitry Andric   case NestedNameSpecifier::Identifier:
5590b57cec5SDimitry Andric     return IsStructurallyEquivalent(NNS1->getAsIdentifier(),
5600b57cec5SDimitry Andric                                     NNS2->getAsIdentifier());
5610b57cec5SDimitry Andric   case NestedNameSpecifier::Namespace:
5620b57cec5SDimitry Andric     return IsStructurallyEquivalent(Context, NNS1->getAsNamespace(),
5630b57cec5SDimitry Andric                                     NNS2->getAsNamespace());
5640b57cec5SDimitry Andric   case NestedNameSpecifier::NamespaceAlias:
5650b57cec5SDimitry Andric     return IsStructurallyEquivalent(Context, NNS1->getAsNamespaceAlias(),
5660b57cec5SDimitry Andric                                     NNS2->getAsNamespaceAlias());
5670b57cec5SDimitry Andric   case NestedNameSpecifier::TypeSpec:
5680b57cec5SDimitry Andric   case NestedNameSpecifier::TypeSpecWithTemplate:
5690b57cec5SDimitry Andric     return IsStructurallyEquivalent(Context, QualType(NNS1->getAsType(), 0),
5700b57cec5SDimitry Andric                                     QualType(NNS2->getAsType(), 0));
5710b57cec5SDimitry Andric   case NestedNameSpecifier::Global:
5720b57cec5SDimitry Andric     return true;
5730b57cec5SDimitry Andric   case NestedNameSpecifier::Super:
5740b57cec5SDimitry Andric     return IsStructurallyEquivalent(Context, NNS1->getAsRecordDecl(),
5750b57cec5SDimitry Andric                                     NNS2->getAsRecordDecl());
5760b57cec5SDimitry Andric   }
5770b57cec5SDimitry Andric   return false;
5780b57cec5SDimitry Andric }
5790b57cec5SDimitry Andric 
5800b57cec5SDimitry Andric static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
5810b57cec5SDimitry Andric                                      const TemplateName &N1,
5820b57cec5SDimitry Andric                                      const TemplateName &N2) {
583a7dea167SDimitry Andric   TemplateDecl *TemplateDeclN1 = N1.getAsTemplateDecl();
584a7dea167SDimitry Andric   TemplateDecl *TemplateDeclN2 = N2.getAsTemplateDecl();
585a7dea167SDimitry Andric   if (TemplateDeclN1 && TemplateDeclN2) {
586a7dea167SDimitry Andric     if (!IsStructurallyEquivalent(Context, TemplateDeclN1, TemplateDeclN2))
5870b57cec5SDimitry Andric       return false;
588a7dea167SDimitry Andric     // If the kind is different we compare only the template decl.
589a7dea167SDimitry Andric     if (N1.getKind() != N2.getKind())
590a7dea167SDimitry Andric       return true;
591a7dea167SDimitry Andric   } else if (TemplateDeclN1 || TemplateDeclN2)
592a7dea167SDimitry Andric     return false;
593a7dea167SDimitry Andric   else if (N1.getKind() != N2.getKind())
594a7dea167SDimitry Andric     return false;
595a7dea167SDimitry Andric 
596a7dea167SDimitry Andric   // Check for special case incompatibilities.
5970b57cec5SDimitry Andric   switch (N1.getKind()) {
5980b57cec5SDimitry Andric 
5990b57cec5SDimitry Andric   case TemplateName::OverloadedTemplate: {
6000b57cec5SDimitry Andric     OverloadedTemplateStorage *OS1 = N1.getAsOverloadedTemplate(),
6010b57cec5SDimitry Andric                               *OS2 = N2.getAsOverloadedTemplate();
6020b57cec5SDimitry Andric     OverloadedTemplateStorage::iterator I1 = OS1->begin(), I2 = OS2->begin(),
6030b57cec5SDimitry Andric                                         E1 = OS1->end(), E2 = OS2->end();
6040b57cec5SDimitry Andric     for (; I1 != E1 && I2 != E2; ++I1, ++I2)
6050b57cec5SDimitry Andric       if (!IsStructurallyEquivalent(Context, *I1, *I2))
6060b57cec5SDimitry Andric         return false;
6070b57cec5SDimitry Andric     return I1 == E1 && I2 == E2;
6080b57cec5SDimitry Andric   }
6090b57cec5SDimitry Andric 
6100b57cec5SDimitry Andric   case TemplateName::AssumedTemplate: {
6110b57cec5SDimitry Andric     AssumedTemplateStorage *TN1 = N1.getAsAssumedTemplateName(),
6120b57cec5SDimitry Andric                            *TN2 = N1.getAsAssumedTemplateName();
6130b57cec5SDimitry Andric     return TN1->getDeclName() == TN2->getDeclName();
6140b57cec5SDimitry Andric   }
6150b57cec5SDimitry Andric 
6160b57cec5SDimitry Andric   case TemplateName::DependentTemplate: {
6170b57cec5SDimitry Andric     DependentTemplateName *DN1 = N1.getAsDependentTemplateName(),
6180b57cec5SDimitry Andric                           *DN2 = N2.getAsDependentTemplateName();
6190b57cec5SDimitry Andric     if (!IsStructurallyEquivalent(Context, DN1->getQualifier(),
6200b57cec5SDimitry Andric                                   DN2->getQualifier()))
6210b57cec5SDimitry Andric       return false;
6220b57cec5SDimitry Andric     if (DN1->isIdentifier() && DN2->isIdentifier())
6230b57cec5SDimitry Andric       return IsStructurallyEquivalent(DN1->getIdentifier(),
6240b57cec5SDimitry Andric                                       DN2->getIdentifier());
6250b57cec5SDimitry Andric     else if (DN1->isOverloadedOperator() && DN2->isOverloadedOperator())
6260b57cec5SDimitry Andric       return DN1->getOperator() == DN2->getOperator();
6270b57cec5SDimitry Andric     return false;
6280b57cec5SDimitry Andric   }
6290b57cec5SDimitry Andric 
6300b57cec5SDimitry Andric   case TemplateName::SubstTemplateTemplateParmPack: {
6310b57cec5SDimitry Andric     SubstTemplateTemplateParmPackStorage
6320b57cec5SDimitry Andric         *P1 = N1.getAsSubstTemplateTemplateParmPack(),
6330b57cec5SDimitry Andric         *P2 = N2.getAsSubstTemplateTemplateParmPack();
6340b57cec5SDimitry Andric     return IsStructurallyEquivalent(Context, P1->getArgumentPack(),
6350b57cec5SDimitry Andric                                     P2->getArgumentPack()) &&
636bdd1243dSDimitry Andric            IsStructurallyEquivalent(Context, P1->getAssociatedDecl(),
637bdd1243dSDimitry Andric                                     P2->getAssociatedDecl()) &&
638bdd1243dSDimitry Andric            P1->getIndex() == P2->getIndex();
6390b57cec5SDimitry Andric   }
640a7dea167SDimitry Andric 
641a7dea167SDimitry Andric    case TemplateName::Template:
642a7dea167SDimitry Andric    case TemplateName::QualifiedTemplate:
643a7dea167SDimitry Andric    case TemplateName::SubstTemplateTemplateParm:
64481ad6265SDimitry Andric    case TemplateName::UsingTemplate:
645a7dea167SDimitry Andric      // It is sufficient to check value of getAsTemplateDecl.
646a7dea167SDimitry Andric      break;
647a7dea167SDimitry Andric 
6480b57cec5SDimitry Andric   }
649a7dea167SDimitry Andric 
650a7dea167SDimitry Andric   return true;
6510b57cec5SDimitry Andric }
6520b57cec5SDimitry Andric 
653bdd1243dSDimitry Andric static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
654bdd1243dSDimitry Andric                                      ArrayRef<TemplateArgument> Args1,
655bdd1243dSDimitry Andric                                      ArrayRef<TemplateArgument> Args2);
656bdd1243dSDimitry Andric 
6570b57cec5SDimitry Andric /// Determine whether two template arguments are equivalent.
6580b57cec5SDimitry Andric static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
6590b57cec5SDimitry Andric                                      const TemplateArgument &Arg1,
6600b57cec5SDimitry Andric                                      const TemplateArgument &Arg2) {
6610b57cec5SDimitry Andric   if (Arg1.getKind() != Arg2.getKind())
6620b57cec5SDimitry Andric     return false;
6630b57cec5SDimitry Andric 
6640b57cec5SDimitry Andric   switch (Arg1.getKind()) {
6650b57cec5SDimitry Andric   case TemplateArgument::Null:
6660b57cec5SDimitry Andric     return true;
6670b57cec5SDimitry Andric 
6680b57cec5SDimitry Andric   case TemplateArgument::Type:
6690b57cec5SDimitry Andric     return IsStructurallyEquivalent(Context, Arg1.getAsType(), Arg2.getAsType());
6700b57cec5SDimitry Andric 
6710b57cec5SDimitry Andric   case TemplateArgument::Integral:
6720b57cec5SDimitry Andric     if (!IsStructurallyEquivalent(Context, Arg1.getIntegralType(),
6730b57cec5SDimitry Andric                                           Arg2.getIntegralType()))
6740b57cec5SDimitry Andric       return false;
6750b57cec5SDimitry Andric 
6760b57cec5SDimitry Andric     return llvm::APSInt::isSameValue(Arg1.getAsIntegral(),
6770b57cec5SDimitry Andric                                      Arg2.getAsIntegral());
6780b57cec5SDimitry Andric 
6790b57cec5SDimitry Andric   case TemplateArgument::Declaration:
6800b57cec5SDimitry Andric     return IsStructurallyEquivalent(Context, Arg1.getAsDecl(), Arg2.getAsDecl());
6810b57cec5SDimitry Andric 
6820b57cec5SDimitry Andric   case TemplateArgument::NullPtr:
6830b57cec5SDimitry Andric     return true; // FIXME: Is this correct?
6840b57cec5SDimitry Andric 
6850b57cec5SDimitry Andric   case TemplateArgument::Template:
6860b57cec5SDimitry Andric     return IsStructurallyEquivalent(Context, Arg1.getAsTemplate(),
6870b57cec5SDimitry Andric                                     Arg2.getAsTemplate());
6880b57cec5SDimitry Andric 
6890b57cec5SDimitry Andric   case TemplateArgument::TemplateExpansion:
6900b57cec5SDimitry Andric     return IsStructurallyEquivalent(Context,
6910b57cec5SDimitry Andric                                     Arg1.getAsTemplateOrTemplatePattern(),
6920b57cec5SDimitry Andric                                     Arg2.getAsTemplateOrTemplatePattern());
6930b57cec5SDimitry Andric 
6940b57cec5SDimitry Andric   case TemplateArgument::Expression:
6950b57cec5SDimitry Andric     return IsStructurallyEquivalent(Context, Arg1.getAsExpr(),
6960b57cec5SDimitry Andric                                     Arg2.getAsExpr());
6970b57cec5SDimitry Andric 
6987a6dacacSDimitry Andric   case TemplateArgument::StructuralValue:
6997a6dacacSDimitry Andric     return Arg1.structurallyEquals(Arg2);
7007a6dacacSDimitry Andric 
7010b57cec5SDimitry Andric   case TemplateArgument::Pack:
702bdd1243dSDimitry Andric     return IsStructurallyEquivalent(Context, Arg1.pack_elements(),
703bdd1243dSDimitry Andric                                     Arg2.pack_elements());
7040b57cec5SDimitry Andric   }
7050b57cec5SDimitry Andric 
7060b57cec5SDimitry Andric   llvm_unreachable("Invalid template argument kind");
7070b57cec5SDimitry Andric }
7080b57cec5SDimitry Andric 
709bdd1243dSDimitry Andric /// Determine structural equivalence of two template argument lists.
710bdd1243dSDimitry Andric static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
711bdd1243dSDimitry Andric                                      ArrayRef<TemplateArgument> Args1,
712bdd1243dSDimitry Andric                                      ArrayRef<TemplateArgument> Args2) {
713bdd1243dSDimitry Andric   if (Args1.size() != Args2.size())
714bdd1243dSDimitry Andric     return false;
715bdd1243dSDimitry Andric   for (unsigned I = 0, N = Args1.size(); I != N; ++I) {
716bdd1243dSDimitry Andric     if (!IsStructurallyEquivalent(Context, Args1[I], Args2[I]))
717bdd1243dSDimitry Andric       return false;
718bdd1243dSDimitry Andric   }
719bdd1243dSDimitry Andric   return true;
720bdd1243dSDimitry Andric }
721bdd1243dSDimitry Andric 
722bdd1243dSDimitry Andric /// Determine whether two template argument locations are equivalent.
723bdd1243dSDimitry Andric static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
724bdd1243dSDimitry Andric                                      const TemplateArgumentLoc &Arg1,
725bdd1243dSDimitry Andric                                      const TemplateArgumentLoc &Arg2) {
726bdd1243dSDimitry Andric   return IsStructurallyEquivalent(Context, Arg1.getArgument(),
727bdd1243dSDimitry Andric                                   Arg2.getArgument());
728bdd1243dSDimitry Andric }
729bdd1243dSDimitry Andric 
7300b57cec5SDimitry Andric /// Determine structural equivalence for the common part of array
7310b57cec5SDimitry Andric /// types.
7320b57cec5SDimitry Andric static bool IsArrayStructurallyEquivalent(StructuralEquivalenceContext &Context,
7330b57cec5SDimitry Andric                                           const ArrayType *Array1,
7340b57cec5SDimitry Andric                                           const ArrayType *Array2) {
7350b57cec5SDimitry Andric   if (!IsStructurallyEquivalent(Context, Array1->getElementType(),
7360b57cec5SDimitry Andric                                 Array2->getElementType()))
7370b57cec5SDimitry Andric     return false;
7380b57cec5SDimitry Andric   if (Array1->getSizeModifier() != Array2->getSizeModifier())
7390b57cec5SDimitry Andric     return false;
7400b57cec5SDimitry Andric   if (Array1->getIndexTypeQualifiers() != Array2->getIndexTypeQualifiers())
7410b57cec5SDimitry Andric     return false;
7420b57cec5SDimitry Andric 
7430b57cec5SDimitry Andric   return true;
7440b57cec5SDimitry Andric }
7450b57cec5SDimitry Andric 
7460b57cec5SDimitry Andric /// Determine structural equivalence based on the ExtInfo of functions. This
7470b57cec5SDimitry Andric /// is inspired by ASTContext::mergeFunctionTypes(), we compare calling
7480b57cec5SDimitry Andric /// conventions bits but must not compare some other bits.
7490b57cec5SDimitry Andric static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
7500b57cec5SDimitry Andric                                      FunctionType::ExtInfo EI1,
7510b57cec5SDimitry Andric                                      FunctionType::ExtInfo EI2) {
7520b57cec5SDimitry Andric   // Compatible functions must have compatible calling conventions.
7530b57cec5SDimitry Andric   if (EI1.getCC() != EI2.getCC())
7540b57cec5SDimitry Andric     return false;
7550b57cec5SDimitry Andric 
7560b57cec5SDimitry Andric   // Regparm is part of the calling convention.
7570b57cec5SDimitry Andric   if (EI1.getHasRegParm() != EI2.getHasRegParm())
7580b57cec5SDimitry Andric     return false;
7590b57cec5SDimitry Andric   if (EI1.getRegParm() != EI2.getRegParm())
7600b57cec5SDimitry Andric     return false;
7610b57cec5SDimitry Andric 
7620b57cec5SDimitry Andric   if (EI1.getProducesResult() != EI2.getProducesResult())
7630b57cec5SDimitry Andric     return false;
7640b57cec5SDimitry Andric   if (EI1.getNoCallerSavedRegs() != EI2.getNoCallerSavedRegs())
7650b57cec5SDimitry Andric     return false;
7660b57cec5SDimitry Andric   if (EI1.getNoCfCheck() != EI2.getNoCfCheck())
7670b57cec5SDimitry Andric     return false;
7680b57cec5SDimitry Andric 
7690b57cec5SDimitry Andric   return true;
7700b57cec5SDimitry Andric }
7710b57cec5SDimitry Andric 
7720b57cec5SDimitry Andric /// Check the equivalence of exception specifications.
7730b57cec5SDimitry Andric static bool IsEquivalentExceptionSpec(StructuralEquivalenceContext &Context,
7740b57cec5SDimitry Andric                                       const FunctionProtoType *Proto1,
7750b57cec5SDimitry Andric                                       const FunctionProtoType *Proto2) {
7760b57cec5SDimitry Andric 
7770b57cec5SDimitry Andric   auto Spec1 = Proto1->getExceptionSpecType();
7780b57cec5SDimitry Andric   auto Spec2 = Proto2->getExceptionSpecType();
7790b57cec5SDimitry Andric 
7800b57cec5SDimitry Andric   if (isUnresolvedExceptionSpec(Spec1) || isUnresolvedExceptionSpec(Spec2))
7810b57cec5SDimitry Andric     return true;
7820b57cec5SDimitry Andric 
7830b57cec5SDimitry Andric   if (Spec1 != Spec2)
7840b57cec5SDimitry Andric     return false;
7850b57cec5SDimitry Andric   if (Spec1 == EST_Dynamic) {
7860b57cec5SDimitry Andric     if (Proto1->getNumExceptions() != Proto2->getNumExceptions())
7870b57cec5SDimitry Andric       return false;
7880b57cec5SDimitry Andric     for (unsigned I = 0, N = Proto1->getNumExceptions(); I != N; ++I) {
7890b57cec5SDimitry Andric       if (!IsStructurallyEquivalent(Context, Proto1->getExceptionType(I),
7900b57cec5SDimitry Andric                                     Proto2->getExceptionType(I)))
7910b57cec5SDimitry Andric         return false;
7920b57cec5SDimitry Andric     }
7930b57cec5SDimitry Andric   } else if (isComputedNoexcept(Spec1)) {
7940b57cec5SDimitry Andric     if (!IsStructurallyEquivalent(Context, Proto1->getNoexceptExpr(),
7950b57cec5SDimitry Andric                                   Proto2->getNoexceptExpr()))
7960b57cec5SDimitry Andric       return false;
7970b57cec5SDimitry Andric   }
7980b57cec5SDimitry Andric 
7990b57cec5SDimitry Andric   return true;
8000b57cec5SDimitry Andric }
8010b57cec5SDimitry Andric 
8020b57cec5SDimitry Andric /// Determine structural equivalence of two types.
8030b57cec5SDimitry Andric static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
8040b57cec5SDimitry Andric                                      QualType T1, QualType T2) {
8050b57cec5SDimitry Andric   if (T1.isNull() || T2.isNull())
8060b57cec5SDimitry Andric     return T1.isNull() && T2.isNull();
8070b57cec5SDimitry Andric 
8080b57cec5SDimitry Andric   QualType OrigT1 = T1;
8090b57cec5SDimitry Andric   QualType OrigT2 = T2;
8100b57cec5SDimitry Andric 
8110b57cec5SDimitry Andric   if (!Context.StrictTypeSpelling) {
8120b57cec5SDimitry Andric     // We aren't being strict about token-to-token equivalence of types,
8130b57cec5SDimitry Andric     // so map down to the canonical type.
8140b57cec5SDimitry Andric     T1 = Context.FromCtx.getCanonicalType(T1);
8150b57cec5SDimitry Andric     T2 = Context.ToCtx.getCanonicalType(T2);
8160b57cec5SDimitry Andric   }
8170b57cec5SDimitry Andric 
8180b57cec5SDimitry Andric   if (T1.getQualifiers() != T2.getQualifiers())
8190b57cec5SDimitry Andric     return false;
8200b57cec5SDimitry Andric 
8210b57cec5SDimitry Andric   Type::TypeClass TC = T1->getTypeClass();
8220b57cec5SDimitry Andric 
8230b57cec5SDimitry Andric   if (T1->getTypeClass() != T2->getTypeClass()) {
8240b57cec5SDimitry Andric     // Compare function types with prototypes vs. without prototypes as if
8250b57cec5SDimitry Andric     // both did not have prototypes.
8260b57cec5SDimitry Andric     if (T1->getTypeClass() == Type::FunctionProto &&
8270b57cec5SDimitry Andric         T2->getTypeClass() == Type::FunctionNoProto)
8280b57cec5SDimitry Andric       TC = Type::FunctionNoProto;
8290b57cec5SDimitry Andric     else if (T1->getTypeClass() == Type::FunctionNoProto &&
8300b57cec5SDimitry Andric              T2->getTypeClass() == Type::FunctionProto)
8310b57cec5SDimitry Andric       TC = Type::FunctionNoProto;
8320b57cec5SDimitry Andric     else
8330b57cec5SDimitry Andric       return false;
8340b57cec5SDimitry Andric   }
8350b57cec5SDimitry Andric 
8360b57cec5SDimitry Andric   switch (TC) {
8370b57cec5SDimitry Andric   case Type::Builtin:
8380b57cec5SDimitry Andric     // FIXME: Deal with Char_S/Char_U.
8390b57cec5SDimitry Andric     if (cast<BuiltinType>(T1)->getKind() != cast<BuiltinType>(T2)->getKind())
8400b57cec5SDimitry Andric       return false;
8410b57cec5SDimitry Andric     break;
8420b57cec5SDimitry Andric 
8430b57cec5SDimitry Andric   case Type::Complex:
8440b57cec5SDimitry Andric     if (!IsStructurallyEquivalent(Context,
8450b57cec5SDimitry Andric                                   cast<ComplexType>(T1)->getElementType(),
8460b57cec5SDimitry Andric                                   cast<ComplexType>(T2)->getElementType()))
8470b57cec5SDimitry Andric       return false;
8480b57cec5SDimitry Andric     break;
8490b57cec5SDimitry Andric 
8500b57cec5SDimitry Andric   case Type::Adjusted:
8510b57cec5SDimitry Andric   case Type::Decayed:
852*0fca6ea1SDimitry Andric   case Type::ArrayParameter:
8530b57cec5SDimitry Andric     if (!IsStructurallyEquivalent(Context,
8540b57cec5SDimitry Andric                                   cast<AdjustedType>(T1)->getOriginalType(),
8550b57cec5SDimitry Andric                                   cast<AdjustedType>(T2)->getOriginalType()))
8560b57cec5SDimitry Andric       return false;
8570b57cec5SDimitry Andric     break;
8580b57cec5SDimitry Andric 
8590b57cec5SDimitry Andric   case Type::Pointer:
8600b57cec5SDimitry Andric     if (!IsStructurallyEquivalent(Context,
8610b57cec5SDimitry Andric                                   cast<PointerType>(T1)->getPointeeType(),
8620b57cec5SDimitry Andric                                   cast<PointerType>(T2)->getPointeeType()))
8630b57cec5SDimitry Andric       return false;
8640b57cec5SDimitry Andric     break;
8650b57cec5SDimitry Andric 
8660b57cec5SDimitry Andric   case Type::BlockPointer:
8670b57cec5SDimitry Andric     if (!IsStructurallyEquivalent(Context,
8680b57cec5SDimitry Andric                                   cast<BlockPointerType>(T1)->getPointeeType(),
8690b57cec5SDimitry Andric                                   cast<BlockPointerType>(T2)->getPointeeType()))
8700b57cec5SDimitry Andric       return false;
8710b57cec5SDimitry Andric     break;
8720b57cec5SDimitry Andric 
8730b57cec5SDimitry Andric   case Type::LValueReference:
8740b57cec5SDimitry Andric   case Type::RValueReference: {
8750b57cec5SDimitry Andric     const auto *Ref1 = cast<ReferenceType>(T1);
8760b57cec5SDimitry Andric     const auto *Ref2 = cast<ReferenceType>(T2);
8770b57cec5SDimitry Andric     if (Ref1->isSpelledAsLValue() != Ref2->isSpelledAsLValue())
8780b57cec5SDimitry Andric       return false;
8790b57cec5SDimitry Andric     if (Ref1->isInnerRef() != Ref2->isInnerRef())
8800b57cec5SDimitry Andric       return false;
8810b57cec5SDimitry Andric     if (!IsStructurallyEquivalent(Context, Ref1->getPointeeTypeAsWritten(),
8820b57cec5SDimitry Andric                                   Ref2->getPointeeTypeAsWritten()))
8830b57cec5SDimitry Andric       return false;
8840b57cec5SDimitry Andric     break;
8850b57cec5SDimitry Andric   }
8860b57cec5SDimitry Andric 
8870b57cec5SDimitry Andric   case Type::MemberPointer: {
8880b57cec5SDimitry Andric     const auto *MemPtr1 = cast<MemberPointerType>(T1);
8890b57cec5SDimitry Andric     const auto *MemPtr2 = cast<MemberPointerType>(T2);
8900b57cec5SDimitry Andric     if (!IsStructurallyEquivalent(Context, MemPtr1->getPointeeType(),
8910b57cec5SDimitry Andric                                   MemPtr2->getPointeeType()))
8920b57cec5SDimitry Andric       return false;
8930b57cec5SDimitry Andric     if (!IsStructurallyEquivalent(Context, QualType(MemPtr1->getClass(), 0),
8940b57cec5SDimitry Andric                                   QualType(MemPtr2->getClass(), 0)))
8950b57cec5SDimitry Andric       return false;
8960b57cec5SDimitry Andric     break;
8970b57cec5SDimitry Andric   }
8980b57cec5SDimitry Andric 
8990b57cec5SDimitry Andric   case Type::ConstantArray: {
9000b57cec5SDimitry Andric     const auto *Array1 = cast<ConstantArrayType>(T1);
9010b57cec5SDimitry Andric     const auto *Array2 = cast<ConstantArrayType>(T2);
9020b57cec5SDimitry Andric     if (!llvm::APInt::isSameValue(Array1->getSize(), Array2->getSize()))
9030b57cec5SDimitry Andric       return false;
9040b57cec5SDimitry Andric 
9050b57cec5SDimitry Andric     if (!IsArrayStructurallyEquivalent(Context, Array1, Array2))
9060b57cec5SDimitry Andric       return false;
9070b57cec5SDimitry Andric     break;
9080b57cec5SDimitry Andric   }
9090b57cec5SDimitry Andric 
9100b57cec5SDimitry Andric   case Type::IncompleteArray:
9110b57cec5SDimitry Andric     if (!IsArrayStructurallyEquivalent(Context, cast<ArrayType>(T1),
9120b57cec5SDimitry Andric                                        cast<ArrayType>(T2)))
9130b57cec5SDimitry Andric       return false;
9140b57cec5SDimitry Andric     break;
9150b57cec5SDimitry Andric 
9160b57cec5SDimitry Andric   case Type::VariableArray: {
9170b57cec5SDimitry Andric     const auto *Array1 = cast<VariableArrayType>(T1);
9180b57cec5SDimitry Andric     const auto *Array2 = cast<VariableArrayType>(T2);
9190b57cec5SDimitry Andric     if (!IsStructurallyEquivalent(Context, Array1->getSizeExpr(),
9200b57cec5SDimitry Andric                                   Array2->getSizeExpr()))
9210b57cec5SDimitry Andric       return false;
9220b57cec5SDimitry Andric 
9230b57cec5SDimitry Andric     if (!IsArrayStructurallyEquivalent(Context, Array1, Array2))
9240b57cec5SDimitry Andric       return false;
9250b57cec5SDimitry Andric 
9260b57cec5SDimitry Andric     break;
9270b57cec5SDimitry Andric   }
9280b57cec5SDimitry Andric 
9290b57cec5SDimitry Andric   case Type::DependentSizedArray: {
9300b57cec5SDimitry Andric     const auto *Array1 = cast<DependentSizedArrayType>(T1);
9310b57cec5SDimitry Andric     const auto *Array2 = cast<DependentSizedArrayType>(T2);
9320b57cec5SDimitry Andric     if (!IsStructurallyEquivalent(Context, Array1->getSizeExpr(),
9330b57cec5SDimitry Andric                                   Array2->getSizeExpr()))
9340b57cec5SDimitry Andric       return false;
9350b57cec5SDimitry Andric 
9360b57cec5SDimitry Andric     if (!IsArrayStructurallyEquivalent(Context, Array1, Array2))
9370b57cec5SDimitry Andric       return false;
9380b57cec5SDimitry Andric 
9390b57cec5SDimitry Andric     break;
9400b57cec5SDimitry Andric   }
9410b57cec5SDimitry Andric 
9420b57cec5SDimitry Andric   case Type::DependentAddressSpace: {
9430b57cec5SDimitry Andric     const auto *DepAddressSpace1 = cast<DependentAddressSpaceType>(T1);
9440b57cec5SDimitry Andric     const auto *DepAddressSpace2 = cast<DependentAddressSpaceType>(T2);
9450b57cec5SDimitry Andric     if (!IsStructurallyEquivalent(Context, DepAddressSpace1->getAddrSpaceExpr(),
9460b57cec5SDimitry Andric                                   DepAddressSpace2->getAddrSpaceExpr()))
9470b57cec5SDimitry Andric       return false;
9480b57cec5SDimitry Andric     if (!IsStructurallyEquivalent(Context, DepAddressSpace1->getPointeeType(),
9490b57cec5SDimitry Andric                                   DepAddressSpace2->getPointeeType()))
9500b57cec5SDimitry Andric       return false;
9510b57cec5SDimitry Andric 
9520b57cec5SDimitry Andric     break;
9530b57cec5SDimitry Andric   }
9540b57cec5SDimitry Andric 
9550b57cec5SDimitry Andric   case Type::DependentSizedExtVector: {
9560b57cec5SDimitry Andric     const auto *Vec1 = cast<DependentSizedExtVectorType>(T1);
9570b57cec5SDimitry Andric     const auto *Vec2 = cast<DependentSizedExtVectorType>(T2);
9580b57cec5SDimitry Andric     if (!IsStructurallyEquivalent(Context, Vec1->getSizeExpr(),
9590b57cec5SDimitry Andric                                   Vec2->getSizeExpr()))
9600b57cec5SDimitry Andric       return false;
9610b57cec5SDimitry Andric     if (!IsStructurallyEquivalent(Context, Vec1->getElementType(),
9620b57cec5SDimitry Andric                                   Vec2->getElementType()))
9630b57cec5SDimitry Andric       return false;
9640b57cec5SDimitry Andric     break;
9650b57cec5SDimitry Andric   }
9660b57cec5SDimitry Andric 
9670b57cec5SDimitry Andric   case Type::DependentVector: {
9680b57cec5SDimitry Andric     const auto *Vec1 = cast<DependentVectorType>(T1);
9690b57cec5SDimitry Andric     const auto *Vec2 = cast<DependentVectorType>(T2);
9700b57cec5SDimitry Andric     if (Vec1->getVectorKind() != Vec2->getVectorKind())
9710b57cec5SDimitry Andric       return false;
9720b57cec5SDimitry Andric     if (!IsStructurallyEquivalent(Context, Vec1->getSizeExpr(),
9730b57cec5SDimitry Andric                                   Vec2->getSizeExpr()))
9740b57cec5SDimitry Andric       return false;
9750b57cec5SDimitry Andric     if (!IsStructurallyEquivalent(Context, Vec1->getElementType(),
9760b57cec5SDimitry Andric                                   Vec2->getElementType()))
9770b57cec5SDimitry Andric       return false;
9780b57cec5SDimitry Andric     break;
9790b57cec5SDimitry Andric   }
9800b57cec5SDimitry Andric 
9810b57cec5SDimitry Andric   case Type::Vector:
9820b57cec5SDimitry Andric   case Type::ExtVector: {
9830b57cec5SDimitry Andric     const auto *Vec1 = cast<VectorType>(T1);
9840b57cec5SDimitry Andric     const auto *Vec2 = cast<VectorType>(T2);
9850b57cec5SDimitry Andric     if (!IsStructurallyEquivalent(Context, Vec1->getElementType(),
9860b57cec5SDimitry Andric                                   Vec2->getElementType()))
9870b57cec5SDimitry Andric       return false;
9880b57cec5SDimitry Andric     if (Vec1->getNumElements() != Vec2->getNumElements())
9890b57cec5SDimitry Andric       return false;
9900b57cec5SDimitry Andric     if (Vec1->getVectorKind() != Vec2->getVectorKind())
9910b57cec5SDimitry Andric       return false;
9920b57cec5SDimitry Andric     break;
9930b57cec5SDimitry Andric   }
9940b57cec5SDimitry Andric 
9955ffd83dbSDimitry Andric   case Type::DependentSizedMatrix: {
9965ffd83dbSDimitry Andric     const DependentSizedMatrixType *Mat1 = cast<DependentSizedMatrixType>(T1);
9975ffd83dbSDimitry Andric     const DependentSizedMatrixType *Mat2 = cast<DependentSizedMatrixType>(T2);
9985ffd83dbSDimitry Andric     // The element types, row and column expressions must be structurally
9995ffd83dbSDimitry Andric     // equivalent.
10005ffd83dbSDimitry Andric     if (!IsStructurallyEquivalent(Context, Mat1->getRowExpr(),
10015ffd83dbSDimitry Andric                                   Mat2->getRowExpr()) ||
10025ffd83dbSDimitry Andric         !IsStructurallyEquivalent(Context, Mat1->getColumnExpr(),
10035ffd83dbSDimitry Andric                                   Mat2->getColumnExpr()) ||
10045ffd83dbSDimitry Andric         !IsStructurallyEquivalent(Context, Mat1->getElementType(),
10055ffd83dbSDimitry Andric                                   Mat2->getElementType()))
10065ffd83dbSDimitry Andric       return false;
10075ffd83dbSDimitry Andric     break;
10085ffd83dbSDimitry Andric   }
10095ffd83dbSDimitry Andric 
10105ffd83dbSDimitry Andric   case Type::ConstantMatrix: {
10115ffd83dbSDimitry Andric     const ConstantMatrixType *Mat1 = cast<ConstantMatrixType>(T1);
10125ffd83dbSDimitry Andric     const ConstantMatrixType *Mat2 = cast<ConstantMatrixType>(T2);
10135ffd83dbSDimitry Andric     // The element types must be structurally equivalent and the number of rows
10145ffd83dbSDimitry Andric     // and columns must match.
10155ffd83dbSDimitry Andric     if (!IsStructurallyEquivalent(Context, Mat1->getElementType(),
10165ffd83dbSDimitry Andric                                   Mat2->getElementType()) ||
10175ffd83dbSDimitry Andric         Mat1->getNumRows() != Mat2->getNumRows() ||
10185ffd83dbSDimitry Andric         Mat1->getNumColumns() != Mat2->getNumColumns())
10195ffd83dbSDimitry Andric       return false;
10205ffd83dbSDimitry Andric     break;
10215ffd83dbSDimitry Andric   }
10225ffd83dbSDimitry Andric 
10230b57cec5SDimitry Andric   case Type::FunctionProto: {
10240b57cec5SDimitry Andric     const auto *Proto1 = cast<FunctionProtoType>(T1);
10250b57cec5SDimitry Andric     const auto *Proto2 = cast<FunctionProtoType>(T2);
10260b57cec5SDimitry Andric 
10270b57cec5SDimitry Andric     if (Proto1->getNumParams() != Proto2->getNumParams())
10280b57cec5SDimitry Andric       return false;
10290b57cec5SDimitry Andric     for (unsigned I = 0, N = Proto1->getNumParams(); I != N; ++I) {
10300b57cec5SDimitry Andric       if (!IsStructurallyEquivalent(Context, Proto1->getParamType(I),
10310b57cec5SDimitry Andric                                     Proto2->getParamType(I)))
10320b57cec5SDimitry Andric         return false;
10330b57cec5SDimitry Andric     }
10340b57cec5SDimitry Andric     if (Proto1->isVariadic() != Proto2->isVariadic())
10350b57cec5SDimitry Andric       return false;
10360b57cec5SDimitry Andric 
10370b57cec5SDimitry Andric     if (Proto1->getMethodQuals() != Proto2->getMethodQuals())
10380b57cec5SDimitry Andric       return false;
10390b57cec5SDimitry Andric 
10400b57cec5SDimitry Andric     // Check exceptions, this information is lost in canonical type.
10410b57cec5SDimitry Andric     const auto *OrigProto1 =
10420b57cec5SDimitry Andric         cast<FunctionProtoType>(OrigT1.getDesugaredType(Context.FromCtx));
10430b57cec5SDimitry Andric     const auto *OrigProto2 =
10440b57cec5SDimitry Andric         cast<FunctionProtoType>(OrigT2.getDesugaredType(Context.ToCtx));
10450b57cec5SDimitry Andric     if (!IsEquivalentExceptionSpec(Context, OrigProto1, OrigProto2))
10460b57cec5SDimitry Andric       return false;
10470b57cec5SDimitry Andric 
10480b57cec5SDimitry Andric     // Fall through to check the bits common with FunctionNoProtoType.
1049bdd1243dSDimitry Andric     [[fallthrough]];
10500b57cec5SDimitry Andric   }
10510b57cec5SDimitry Andric 
10520b57cec5SDimitry Andric   case Type::FunctionNoProto: {
10530b57cec5SDimitry Andric     const auto *Function1 = cast<FunctionType>(T1);
10540b57cec5SDimitry Andric     const auto *Function2 = cast<FunctionType>(T2);
10550b57cec5SDimitry Andric     if (!IsStructurallyEquivalent(Context, Function1->getReturnType(),
10560b57cec5SDimitry Andric                                   Function2->getReturnType()))
10570b57cec5SDimitry Andric       return false;
10580b57cec5SDimitry Andric     if (!IsStructurallyEquivalent(Context, Function1->getExtInfo(),
10590b57cec5SDimitry Andric                                   Function2->getExtInfo()))
10600b57cec5SDimitry Andric       return false;
10610b57cec5SDimitry Andric     break;
10620b57cec5SDimitry Andric   }
10630b57cec5SDimitry Andric 
10640b57cec5SDimitry Andric   case Type::UnresolvedUsing:
10650b57cec5SDimitry Andric     if (!IsStructurallyEquivalent(Context,
10660b57cec5SDimitry Andric                                   cast<UnresolvedUsingType>(T1)->getDecl(),
10670b57cec5SDimitry Andric                                   cast<UnresolvedUsingType>(T2)->getDecl()))
10680b57cec5SDimitry Andric       return false;
10690b57cec5SDimitry Andric     break;
10700b57cec5SDimitry Andric 
10710b57cec5SDimitry Andric   case Type::Attributed:
10720b57cec5SDimitry Andric     if (!IsStructurallyEquivalent(Context,
10730b57cec5SDimitry Andric                                   cast<AttributedType>(T1)->getModifiedType(),
10740b57cec5SDimitry Andric                                   cast<AttributedType>(T2)->getModifiedType()))
10750b57cec5SDimitry Andric       return false;
10760b57cec5SDimitry Andric     if (!IsStructurallyEquivalent(
10770b57cec5SDimitry Andric             Context, cast<AttributedType>(T1)->getEquivalentType(),
10780b57cec5SDimitry Andric             cast<AttributedType>(T2)->getEquivalentType()))
10790b57cec5SDimitry Andric       return false;
10800b57cec5SDimitry Andric     break;
10810b57cec5SDimitry Andric 
1082*0fca6ea1SDimitry Andric   case Type::CountAttributed:
1083*0fca6ea1SDimitry Andric     if (!IsStructurallyEquivalent(Context,
1084*0fca6ea1SDimitry Andric                                   cast<CountAttributedType>(T1)->desugar(),
1085*0fca6ea1SDimitry Andric                                   cast<CountAttributedType>(T2)->desugar()))
1086*0fca6ea1SDimitry Andric       return false;
1087*0fca6ea1SDimitry Andric     break;
1088*0fca6ea1SDimitry Andric 
108981ad6265SDimitry Andric   case Type::BTFTagAttributed:
109081ad6265SDimitry Andric     if (!IsStructurallyEquivalent(
109181ad6265SDimitry Andric             Context, cast<BTFTagAttributedType>(T1)->getWrappedType(),
109281ad6265SDimitry Andric             cast<BTFTagAttributedType>(T2)->getWrappedType()))
109381ad6265SDimitry Andric       return false;
109481ad6265SDimitry Andric     break;
109581ad6265SDimitry Andric 
10960b57cec5SDimitry Andric   case Type::Paren:
10970b57cec5SDimitry Andric     if (!IsStructurallyEquivalent(Context, cast<ParenType>(T1)->getInnerType(),
10980b57cec5SDimitry Andric                                   cast<ParenType>(T2)->getInnerType()))
10990b57cec5SDimitry Andric       return false;
11000b57cec5SDimitry Andric     break;
11010b57cec5SDimitry Andric 
11020b57cec5SDimitry Andric   case Type::MacroQualified:
11030b57cec5SDimitry Andric     if (!IsStructurallyEquivalent(
11040b57cec5SDimitry Andric             Context, cast<MacroQualifiedType>(T1)->getUnderlyingType(),
11050b57cec5SDimitry Andric             cast<MacroQualifiedType>(T2)->getUnderlyingType()))
11060b57cec5SDimitry Andric       return false;
11070b57cec5SDimitry Andric     break;
11080b57cec5SDimitry Andric 
11090eae32dcSDimitry Andric   case Type::Using:
11100eae32dcSDimitry Andric     if (!IsStructurallyEquivalent(Context, cast<UsingType>(T1)->getFoundDecl(),
11110eae32dcSDimitry Andric                                   cast<UsingType>(T2)->getFoundDecl()))
11120eae32dcSDimitry Andric       return false;
1113bdd1243dSDimitry Andric     if (!IsStructurallyEquivalent(Context,
1114bdd1243dSDimitry Andric                                   cast<UsingType>(T1)->getUnderlyingType(),
1115bdd1243dSDimitry Andric                                   cast<UsingType>(T2)->getUnderlyingType()))
1116bdd1243dSDimitry Andric       return false;
11170eae32dcSDimitry Andric     break;
11180eae32dcSDimitry Andric 
11190b57cec5SDimitry Andric   case Type::Typedef:
11200b57cec5SDimitry Andric     if (!IsStructurallyEquivalent(Context, cast<TypedefType>(T1)->getDecl(),
1121bdd1243dSDimitry Andric                                   cast<TypedefType>(T2)->getDecl()) ||
1122bdd1243dSDimitry Andric         !IsStructurallyEquivalent(Context, cast<TypedefType>(T1)->desugar(),
1123bdd1243dSDimitry Andric                                   cast<TypedefType>(T2)->desugar()))
11240b57cec5SDimitry Andric       return false;
11250b57cec5SDimitry Andric     break;
11260b57cec5SDimitry Andric 
11270b57cec5SDimitry Andric   case Type::TypeOfExpr:
11280b57cec5SDimitry Andric     if (!IsStructurallyEquivalent(
11290b57cec5SDimitry Andric             Context, cast<TypeOfExprType>(T1)->getUnderlyingExpr(),
11300b57cec5SDimitry Andric             cast<TypeOfExprType>(T2)->getUnderlyingExpr()))
11310b57cec5SDimitry Andric       return false;
11320b57cec5SDimitry Andric     break;
11330b57cec5SDimitry Andric 
11340b57cec5SDimitry Andric   case Type::TypeOf:
11350b57cec5SDimitry Andric     if (!IsStructurallyEquivalent(Context,
1136bdd1243dSDimitry Andric                                   cast<TypeOfType>(T1)->getUnmodifiedType(),
1137bdd1243dSDimitry Andric                                   cast<TypeOfType>(T2)->getUnmodifiedType()))
11380b57cec5SDimitry Andric       return false;
11390b57cec5SDimitry Andric     break;
11400b57cec5SDimitry Andric 
11410b57cec5SDimitry Andric   case Type::UnaryTransform:
11420b57cec5SDimitry Andric     if (!IsStructurallyEquivalent(
11430b57cec5SDimitry Andric             Context, cast<UnaryTransformType>(T1)->getUnderlyingType(),
11440b57cec5SDimitry Andric             cast<UnaryTransformType>(T2)->getUnderlyingType()))
11450b57cec5SDimitry Andric       return false;
11460b57cec5SDimitry Andric     break;
11470b57cec5SDimitry Andric 
11480b57cec5SDimitry Andric   case Type::Decltype:
11490b57cec5SDimitry Andric     if (!IsStructurallyEquivalent(Context,
11500b57cec5SDimitry Andric                                   cast<DecltypeType>(T1)->getUnderlyingExpr(),
11510b57cec5SDimitry Andric                                   cast<DecltypeType>(T2)->getUnderlyingExpr()))
11520b57cec5SDimitry Andric       return false;
11530b57cec5SDimitry Andric     break;
11540b57cec5SDimitry Andric 
115555e4f9d5SDimitry Andric   case Type::Auto: {
115655e4f9d5SDimitry Andric     auto *Auto1 = cast<AutoType>(T1);
115755e4f9d5SDimitry Andric     auto *Auto2 = cast<AutoType>(T2);
115855e4f9d5SDimitry Andric     if (!IsStructurallyEquivalent(Context, Auto1->getDeducedType(),
115955e4f9d5SDimitry Andric                                   Auto2->getDeducedType()))
11600b57cec5SDimitry Andric       return false;
116155e4f9d5SDimitry Andric     if (Auto1->isConstrained() != Auto2->isConstrained())
116255e4f9d5SDimitry Andric       return false;
116355e4f9d5SDimitry Andric     if (Auto1->isConstrained()) {
116455e4f9d5SDimitry Andric       if (Auto1->getTypeConstraintConcept() !=
116555e4f9d5SDimitry Andric           Auto2->getTypeConstraintConcept())
116655e4f9d5SDimitry Andric         return false;
1167bdd1243dSDimitry Andric       if (!IsStructurallyEquivalent(Context,
1168bdd1243dSDimitry Andric                                     Auto1->getTypeConstraintArguments(),
1169bdd1243dSDimitry Andric                                     Auto2->getTypeConstraintArguments()))
117055e4f9d5SDimitry Andric         return false;
117155e4f9d5SDimitry Andric     }
11720b57cec5SDimitry Andric     break;
117355e4f9d5SDimitry Andric   }
11740b57cec5SDimitry Andric 
11750b57cec5SDimitry Andric   case Type::DeducedTemplateSpecialization: {
11760b57cec5SDimitry Andric     const auto *DT1 = cast<DeducedTemplateSpecializationType>(T1);
11770b57cec5SDimitry Andric     const auto *DT2 = cast<DeducedTemplateSpecializationType>(T2);
11780b57cec5SDimitry Andric     if (!IsStructurallyEquivalent(Context, DT1->getTemplateName(),
11790b57cec5SDimitry Andric                                   DT2->getTemplateName()))
11800b57cec5SDimitry Andric       return false;
11810b57cec5SDimitry Andric     if (!IsStructurallyEquivalent(Context, DT1->getDeducedType(),
11820b57cec5SDimitry Andric                                   DT2->getDeducedType()))
11830b57cec5SDimitry Andric       return false;
11840b57cec5SDimitry Andric     break;
11850b57cec5SDimitry Andric   }
11860b57cec5SDimitry Andric 
11870b57cec5SDimitry Andric   case Type::Record:
11880b57cec5SDimitry Andric   case Type::Enum:
11890b57cec5SDimitry Andric     if (!IsStructurallyEquivalent(Context, cast<TagType>(T1)->getDecl(),
11900b57cec5SDimitry Andric                                   cast<TagType>(T2)->getDecl()))
11910b57cec5SDimitry Andric       return false;
11920b57cec5SDimitry Andric     break;
11930b57cec5SDimitry Andric 
11940b57cec5SDimitry Andric   case Type::TemplateTypeParm: {
11950b57cec5SDimitry Andric     const auto *Parm1 = cast<TemplateTypeParmType>(T1);
11960b57cec5SDimitry Andric     const auto *Parm2 = cast<TemplateTypeParmType>(T2);
11975f757f3fSDimitry Andric     if (!Context.IgnoreTemplateParmDepth &&
11985f757f3fSDimitry Andric         Parm1->getDepth() != Parm2->getDepth())
11990b57cec5SDimitry Andric       return false;
12000b57cec5SDimitry Andric     if (Parm1->getIndex() != Parm2->getIndex())
12010b57cec5SDimitry Andric       return false;
12020b57cec5SDimitry Andric     if (Parm1->isParameterPack() != Parm2->isParameterPack())
12030b57cec5SDimitry Andric       return false;
12040b57cec5SDimitry Andric 
12050b57cec5SDimitry Andric     // Names of template type parameters are never significant.
12060b57cec5SDimitry Andric     break;
12070b57cec5SDimitry Andric   }
12080b57cec5SDimitry Andric 
12090b57cec5SDimitry Andric   case Type::SubstTemplateTypeParm: {
12100b57cec5SDimitry Andric     const auto *Subst1 = cast<SubstTemplateTypeParmType>(T1);
12110b57cec5SDimitry Andric     const auto *Subst2 = cast<SubstTemplateTypeParmType>(T2);
12120b57cec5SDimitry Andric     if (!IsStructurallyEquivalent(Context, Subst1->getReplacementType(),
12130b57cec5SDimitry Andric                                   Subst2->getReplacementType()))
12140b57cec5SDimitry Andric       return false;
1215bdd1243dSDimitry Andric     if (!IsStructurallyEquivalent(Context, Subst1->getAssociatedDecl(),
1216bdd1243dSDimitry Andric                                   Subst2->getAssociatedDecl()))
1217bdd1243dSDimitry Andric       return false;
1218bdd1243dSDimitry Andric     if (Subst1->getIndex() != Subst2->getIndex())
1219bdd1243dSDimitry Andric       return false;
1220bdd1243dSDimitry Andric     if (Subst1->getPackIndex() != Subst2->getPackIndex())
1221bdd1243dSDimitry Andric       return false;
12220b57cec5SDimitry Andric     break;
12230b57cec5SDimitry Andric   }
12240b57cec5SDimitry Andric 
12250b57cec5SDimitry Andric   case Type::SubstTemplateTypeParmPack: {
12260b57cec5SDimitry Andric     const auto *Subst1 = cast<SubstTemplateTypeParmPackType>(T1);
12270b57cec5SDimitry Andric     const auto *Subst2 = cast<SubstTemplateTypeParmPackType>(T2);
1228bdd1243dSDimitry Andric     if (!IsStructurallyEquivalent(Context, Subst1->getAssociatedDecl(),
1229bdd1243dSDimitry Andric                                   Subst2->getAssociatedDecl()))
1230bdd1243dSDimitry Andric       return false;
1231bdd1243dSDimitry Andric     if (Subst1->getIndex() != Subst2->getIndex())
12320b57cec5SDimitry Andric       return false;
12330b57cec5SDimitry Andric     if (!IsStructurallyEquivalent(Context, Subst1->getArgumentPack(),
12340b57cec5SDimitry Andric                                   Subst2->getArgumentPack()))
12350b57cec5SDimitry Andric       return false;
12360b57cec5SDimitry Andric     break;
12370b57cec5SDimitry Andric   }
12380b57cec5SDimitry Andric 
12390b57cec5SDimitry Andric   case Type::TemplateSpecialization: {
12400b57cec5SDimitry Andric     const auto *Spec1 = cast<TemplateSpecializationType>(T1);
12410b57cec5SDimitry Andric     const auto *Spec2 = cast<TemplateSpecializationType>(T2);
12420b57cec5SDimitry Andric     if (!IsStructurallyEquivalent(Context, Spec1->getTemplateName(),
12430b57cec5SDimitry Andric                                   Spec2->getTemplateName()))
12440b57cec5SDimitry Andric       return false;
1245bdd1243dSDimitry Andric     if (!IsStructurallyEquivalent(Context, Spec1->template_arguments(),
1246bdd1243dSDimitry Andric                                   Spec2->template_arguments()))
12470b57cec5SDimitry Andric       return false;
12480b57cec5SDimitry Andric     break;
12490b57cec5SDimitry Andric   }
12500b57cec5SDimitry Andric 
12510b57cec5SDimitry Andric   case Type::Elaborated: {
12520b57cec5SDimitry Andric     const auto *Elab1 = cast<ElaboratedType>(T1);
12530b57cec5SDimitry Andric     const auto *Elab2 = cast<ElaboratedType>(T2);
12545f757f3fSDimitry Andric     // CHECKME: what if a keyword is ElaboratedTypeKeyword::None or
12555f757f3fSDimitry Andric     // ElaboratedTypeKeyword::Typename
12565f757f3fSDimitry Andric     // ?
12570b57cec5SDimitry Andric     if (Elab1->getKeyword() != Elab2->getKeyword())
12580b57cec5SDimitry Andric       return false;
12590b57cec5SDimitry Andric     if (!IsStructurallyEquivalent(Context, Elab1->getQualifier(),
12600b57cec5SDimitry Andric                                   Elab2->getQualifier()))
12610b57cec5SDimitry Andric       return false;
12620b57cec5SDimitry Andric     if (!IsStructurallyEquivalent(Context, Elab1->getNamedType(),
12630b57cec5SDimitry Andric                                   Elab2->getNamedType()))
12640b57cec5SDimitry Andric       return false;
12650b57cec5SDimitry Andric     break;
12660b57cec5SDimitry Andric   }
12670b57cec5SDimitry Andric 
12680b57cec5SDimitry Andric   case Type::InjectedClassName: {
12690b57cec5SDimitry Andric     const auto *Inj1 = cast<InjectedClassNameType>(T1);
12700b57cec5SDimitry Andric     const auto *Inj2 = cast<InjectedClassNameType>(T2);
12710b57cec5SDimitry Andric     if (!IsStructurallyEquivalent(Context,
12720b57cec5SDimitry Andric                                   Inj1->getInjectedSpecializationType(),
12730b57cec5SDimitry Andric                                   Inj2->getInjectedSpecializationType()))
12740b57cec5SDimitry Andric       return false;
12750b57cec5SDimitry Andric     break;
12760b57cec5SDimitry Andric   }
12770b57cec5SDimitry Andric 
12780b57cec5SDimitry Andric   case Type::DependentName: {
12790b57cec5SDimitry Andric     const auto *Typename1 = cast<DependentNameType>(T1);
12800b57cec5SDimitry Andric     const auto *Typename2 = cast<DependentNameType>(T2);
12810b57cec5SDimitry Andric     if (!IsStructurallyEquivalent(Context, Typename1->getQualifier(),
12820b57cec5SDimitry Andric                                   Typename2->getQualifier()))
12830b57cec5SDimitry Andric       return false;
12840b57cec5SDimitry Andric     if (!IsStructurallyEquivalent(Typename1->getIdentifier(),
12850b57cec5SDimitry Andric                                   Typename2->getIdentifier()))
12860b57cec5SDimitry Andric       return false;
12870b57cec5SDimitry Andric 
12880b57cec5SDimitry Andric     break;
12890b57cec5SDimitry Andric   }
12900b57cec5SDimitry Andric 
12910b57cec5SDimitry Andric   case Type::DependentTemplateSpecialization: {
12920b57cec5SDimitry Andric     const auto *Spec1 = cast<DependentTemplateSpecializationType>(T1);
12930b57cec5SDimitry Andric     const auto *Spec2 = cast<DependentTemplateSpecializationType>(T2);
12940b57cec5SDimitry Andric     if (!IsStructurallyEquivalent(Context, Spec1->getQualifier(),
12950b57cec5SDimitry Andric                                   Spec2->getQualifier()))
12960b57cec5SDimitry Andric       return false;
12970b57cec5SDimitry Andric     if (!IsStructurallyEquivalent(Spec1->getIdentifier(),
12980b57cec5SDimitry Andric                                   Spec2->getIdentifier()))
12990b57cec5SDimitry Andric       return false;
1300bdd1243dSDimitry Andric     if (!IsStructurallyEquivalent(Context, Spec1->template_arguments(),
1301bdd1243dSDimitry Andric                                   Spec2->template_arguments()))
13020b57cec5SDimitry Andric       return false;
13030b57cec5SDimitry Andric     break;
13040b57cec5SDimitry Andric   }
13050b57cec5SDimitry Andric 
13060b57cec5SDimitry Andric   case Type::PackExpansion:
13070b57cec5SDimitry Andric     if (!IsStructurallyEquivalent(Context,
13080b57cec5SDimitry Andric                                   cast<PackExpansionType>(T1)->getPattern(),
13090b57cec5SDimitry Andric                                   cast<PackExpansionType>(T2)->getPattern()))
13100b57cec5SDimitry Andric       return false;
13110b57cec5SDimitry Andric     break;
13120b57cec5SDimitry Andric 
1313*0fca6ea1SDimitry Andric   case Type::PackIndexing:
1314*0fca6ea1SDimitry Andric     if (!IsStructurallyEquivalent(Context,
1315*0fca6ea1SDimitry Andric                                   cast<PackIndexingType>(T1)->getPattern(),
1316*0fca6ea1SDimitry Andric                                   cast<PackIndexingType>(T2)->getPattern()))
1317*0fca6ea1SDimitry Andric       if (!IsStructurallyEquivalent(Context,
1318*0fca6ea1SDimitry Andric                                     cast<PackIndexingType>(T1)->getIndexExpr(),
1319*0fca6ea1SDimitry Andric                                     cast<PackIndexingType>(T2)->getIndexExpr()))
1320*0fca6ea1SDimitry Andric         return false;
1321*0fca6ea1SDimitry Andric     break;
1322*0fca6ea1SDimitry Andric 
13230b57cec5SDimitry Andric   case Type::ObjCInterface: {
13240b57cec5SDimitry Andric     const auto *Iface1 = cast<ObjCInterfaceType>(T1);
13250b57cec5SDimitry Andric     const auto *Iface2 = cast<ObjCInterfaceType>(T2);
13260b57cec5SDimitry Andric     if (!IsStructurallyEquivalent(Context, Iface1->getDecl(),
13270b57cec5SDimitry Andric                                   Iface2->getDecl()))
13280b57cec5SDimitry Andric       return false;
13290b57cec5SDimitry Andric     break;
13300b57cec5SDimitry Andric   }
13310b57cec5SDimitry Andric 
13320b57cec5SDimitry Andric   case Type::ObjCTypeParam: {
13330b57cec5SDimitry Andric     const auto *Obj1 = cast<ObjCTypeParamType>(T1);
13340b57cec5SDimitry Andric     const auto *Obj2 = cast<ObjCTypeParamType>(T2);
13350b57cec5SDimitry Andric     if (!IsStructurallyEquivalent(Context, Obj1->getDecl(), Obj2->getDecl()))
13360b57cec5SDimitry Andric       return false;
13370b57cec5SDimitry Andric 
13380b57cec5SDimitry Andric     if (Obj1->getNumProtocols() != Obj2->getNumProtocols())
13390b57cec5SDimitry Andric       return false;
13400b57cec5SDimitry Andric     for (unsigned I = 0, N = Obj1->getNumProtocols(); I != N; ++I) {
13410b57cec5SDimitry Andric       if (!IsStructurallyEquivalent(Context, Obj1->getProtocol(I),
13420b57cec5SDimitry Andric                                     Obj2->getProtocol(I)))
13430b57cec5SDimitry Andric         return false;
13440b57cec5SDimitry Andric     }
13450b57cec5SDimitry Andric     break;
13460b57cec5SDimitry Andric   }
13470b57cec5SDimitry Andric 
13480b57cec5SDimitry Andric   case Type::ObjCObject: {
13490b57cec5SDimitry Andric     const auto *Obj1 = cast<ObjCObjectType>(T1);
13500b57cec5SDimitry Andric     const auto *Obj2 = cast<ObjCObjectType>(T2);
13510b57cec5SDimitry Andric     if (!IsStructurallyEquivalent(Context, Obj1->getBaseType(),
13520b57cec5SDimitry Andric                                   Obj2->getBaseType()))
13530b57cec5SDimitry Andric       return false;
13540b57cec5SDimitry Andric     if (Obj1->getNumProtocols() != Obj2->getNumProtocols())
13550b57cec5SDimitry Andric       return false;
13560b57cec5SDimitry Andric     for (unsigned I = 0, N = Obj1->getNumProtocols(); I != N; ++I) {
13570b57cec5SDimitry Andric       if (!IsStructurallyEquivalent(Context, Obj1->getProtocol(I),
13580b57cec5SDimitry Andric                                     Obj2->getProtocol(I)))
13590b57cec5SDimitry Andric         return false;
13600b57cec5SDimitry Andric     }
13610b57cec5SDimitry Andric     break;
13620b57cec5SDimitry Andric   }
13630b57cec5SDimitry Andric 
13640b57cec5SDimitry Andric   case Type::ObjCObjectPointer: {
13650b57cec5SDimitry Andric     const auto *Ptr1 = cast<ObjCObjectPointerType>(T1);
13660b57cec5SDimitry Andric     const auto *Ptr2 = cast<ObjCObjectPointerType>(T2);
13670b57cec5SDimitry Andric     if (!IsStructurallyEquivalent(Context, Ptr1->getPointeeType(),
13680b57cec5SDimitry Andric                                   Ptr2->getPointeeType()))
13690b57cec5SDimitry Andric       return false;
13700b57cec5SDimitry Andric     break;
13710b57cec5SDimitry Andric   }
13720b57cec5SDimitry Andric 
13730b57cec5SDimitry Andric   case Type::Atomic:
13740b57cec5SDimitry Andric     if (!IsStructurallyEquivalent(Context, cast<AtomicType>(T1)->getValueType(),
13750b57cec5SDimitry Andric                                   cast<AtomicType>(T2)->getValueType()))
13760b57cec5SDimitry Andric       return false;
13770b57cec5SDimitry Andric     break;
13780b57cec5SDimitry Andric 
13790b57cec5SDimitry Andric   case Type::Pipe:
13800b57cec5SDimitry Andric     if (!IsStructurallyEquivalent(Context, cast<PipeType>(T1)->getElementType(),
13810b57cec5SDimitry Andric                                   cast<PipeType>(T2)->getElementType()))
13820b57cec5SDimitry Andric       return false;
13830b57cec5SDimitry Andric     break;
13840eae32dcSDimitry Andric   case Type::BitInt: {
13850eae32dcSDimitry Andric     const auto *Int1 = cast<BitIntType>(T1);
13860eae32dcSDimitry Andric     const auto *Int2 = cast<BitIntType>(T2);
13875ffd83dbSDimitry Andric 
13885ffd83dbSDimitry Andric     if (Int1->isUnsigned() != Int2->isUnsigned() ||
13895ffd83dbSDimitry Andric         Int1->getNumBits() != Int2->getNumBits())
13905ffd83dbSDimitry Andric       return false;
13915ffd83dbSDimitry Andric     break;
13925ffd83dbSDimitry Andric   }
13930eae32dcSDimitry Andric   case Type::DependentBitInt: {
13940eae32dcSDimitry Andric     const auto *Int1 = cast<DependentBitIntType>(T1);
13950eae32dcSDimitry Andric     const auto *Int2 = cast<DependentBitIntType>(T2);
13965ffd83dbSDimitry Andric 
13975ffd83dbSDimitry Andric     if (Int1->isUnsigned() != Int2->isUnsigned() ||
13985ffd83dbSDimitry Andric         !IsStructurallyEquivalent(Context, Int1->getNumBitsExpr(),
13995ffd83dbSDimitry Andric                                   Int2->getNumBitsExpr()))
14005ffd83dbSDimitry Andric       return false;
140181ad6265SDimitry Andric     break;
14025ffd83dbSDimitry Andric   }
14030b57cec5SDimitry Andric   } // end switch
14040b57cec5SDimitry Andric 
14050b57cec5SDimitry Andric   return true;
14060b57cec5SDimitry Andric }
14070b57cec5SDimitry Andric 
14080b57cec5SDimitry Andric static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
14095f757f3fSDimitry Andric                                      VarDecl *D1, VarDecl *D2) {
14105f757f3fSDimitry Andric   IdentifierInfo *Name1 = D1->getIdentifier();
14115f757f3fSDimitry Andric   IdentifierInfo *Name2 = D2->getIdentifier();
14125f757f3fSDimitry Andric   if (!::IsStructurallyEquivalent(Name1, Name2))
14135f757f3fSDimitry Andric     return false;
14145f757f3fSDimitry Andric 
14155f757f3fSDimitry Andric   if (!IsStructurallyEquivalent(Context, D1->getType(), D2->getType()))
14165f757f3fSDimitry Andric     return false;
14175f757f3fSDimitry Andric 
1418*0fca6ea1SDimitry Andric   // Compare storage class and initializer only if none or both are a
1419*0fca6ea1SDimitry Andric   // definition. Like a forward-declaration matches a class definition, variable
1420*0fca6ea1SDimitry Andric   // declarations that are not definitions should match with the definitions.
1421*0fca6ea1SDimitry Andric   if (D1->isThisDeclarationADefinition() != D2->isThisDeclarationADefinition())
1422*0fca6ea1SDimitry Andric     return true;
1423*0fca6ea1SDimitry Andric 
1424*0fca6ea1SDimitry Andric   if (D1->getStorageClass() != D2->getStorageClass())
1425*0fca6ea1SDimitry Andric     return false;
1426*0fca6ea1SDimitry Andric 
14275f757f3fSDimitry Andric   return IsStructurallyEquivalent(Context, D1->getInit(), D2->getInit());
14285f757f3fSDimitry Andric }
14295f757f3fSDimitry Andric 
14305f757f3fSDimitry Andric static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
143181ad6265SDimitry Andric                                      FieldDecl *Field1, FieldDecl *Field2,
143281ad6265SDimitry Andric                                      QualType Owner2Type) {
143381ad6265SDimitry Andric   const auto *Owner2 = cast<Decl>(Field2->getDeclContext());
14340b57cec5SDimitry Andric 
14350b57cec5SDimitry Andric   // For anonymous structs/unions, match up the anonymous struct/union type
14360b57cec5SDimitry Andric   // declarations directly, so that we don't go off searching for anonymous
14370b57cec5SDimitry Andric   // types
14380b57cec5SDimitry Andric   if (Field1->isAnonymousStructOrUnion() &&
14390b57cec5SDimitry Andric       Field2->isAnonymousStructOrUnion()) {
14400b57cec5SDimitry Andric     RecordDecl *D1 = Field1->getType()->castAs<RecordType>()->getDecl();
14410b57cec5SDimitry Andric     RecordDecl *D2 = Field2->getType()->castAs<RecordType>()->getDecl();
14420b57cec5SDimitry Andric     return IsStructurallyEquivalent(Context, D1, D2);
14430b57cec5SDimitry Andric   }
14440b57cec5SDimitry Andric 
14450b57cec5SDimitry Andric   // Check for equivalent field names.
14460b57cec5SDimitry Andric   IdentifierInfo *Name1 = Field1->getIdentifier();
14470b57cec5SDimitry Andric   IdentifierInfo *Name2 = Field2->getIdentifier();
14480b57cec5SDimitry Andric   if (!::IsStructurallyEquivalent(Name1, Name2)) {
14490b57cec5SDimitry Andric     if (Context.Complain) {
14500b57cec5SDimitry Andric       Context.Diag2(
14510b57cec5SDimitry Andric           Owner2->getLocation(),
14520b57cec5SDimitry Andric           Context.getApplicableDiagnostic(diag::err_odr_tag_type_inconsistent))
145381ad6265SDimitry Andric           << Owner2Type;
14540b57cec5SDimitry Andric       Context.Diag2(Field2->getLocation(), diag::note_odr_field_name)
14550b57cec5SDimitry Andric           << Field2->getDeclName();
14560b57cec5SDimitry Andric       Context.Diag1(Field1->getLocation(), diag::note_odr_field_name)
14570b57cec5SDimitry Andric           << Field1->getDeclName();
14580b57cec5SDimitry Andric     }
14590b57cec5SDimitry Andric     return false;
14600b57cec5SDimitry Andric   }
14610b57cec5SDimitry Andric 
14620b57cec5SDimitry Andric   if (!IsStructurallyEquivalent(Context, Field1->getType(),
14630b57cec5SDimitry Andric                                 Field2->getType())) {
14640b57cec5SDimitry Andric     if (Context.Complain) {
14650b57cec5SDimitry Andric       Context.Diag2(
14660b57cec5SDimitry Andric           Owner2->getLocation(),
14670b57cec5SDimitry Andric           Context.getApplicableDiagnostic(diag::err_odr_tag_type_inconsistent))
146881ad6265SDimitry Andric           << Owner2Type;
14690b57cec5SDimitry Andric       Context.Diag2(Field2->getLocation(), diag::note_odr_field)
14700b57cec5SDimitry Andric           << Field2->getDeclName() << Field2->getType();
14710b57cec5SDimitry Andric       Context.Diag1(Field1->getLocation(), diag::note_odr_field)
14720b57cec5SDimitry Andric           << Field1->getDeclName() << Field1->getType();
14730b57cec5SDimitry Andric     }
14740b57cec5SDimitry Andric     return false;
14750b57cec5SDimitry Andric   }
14760b57cec5SDimitry Andric 
1477e8d8bef9SDimitry Andric   if (Field1->isBitField())
1478e8d8bef9SDimitry Andric     return IsStructurallyEquivalent(Context, Field1->getBitWidth(),
1479e8d8bef9SDimitry Andric                                     Field2->getBitWidth());
14800b57cec5SDimitry Andric 
14810b57cec5SDimitry Andric   return true;
14820b57cec5SDimitry Andric }
14830b57cec5SDimitry Andric 
148481ad6265SDimitry Andric /// Determine structural equivalence of two fields.
148581ad6265SDimitry Andric static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
148681ad6265SDimitry Andric                                      FieldDecl *Field1, FieldDecl *Field2) {
148781ad6265SDimitry Andric   const auto *Owner2 = cast<RecordDecl>(Field2->getDeclContext());
148881ad6265SDimitry Andric   return IsStructurallyEquivalent(Context, Field1, Field2,
148981ad6265SDimitry Andric                                   Context.ToCtx.getTypeDeclType(Owner2));
149081ad6265SDimitry Andric }
149181ad6265SDimitry Andric 
14920b57cec5SDimitry Andric /// Determine structural equivalence of two methods.
14930b57cec5SDimitry Andric static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
14940b57cec5SDimitry Andric                                      CXXMethodDecl *Method1,
14950b57cec5SDimitry Andric                                      CXXMethodDecl *Method2) {
14960b57cec5SDimitry Andric   bool PropertiesEqual =
14970b57cec5SDimitry Andric       Method1->getDeclKind() == Method2->getDeclKind() &&
14980b57cec5SDimitry Andric       Method1->getRefQualifier() == Method2->getRefQualifier() &&
14990b57cec5SDimitry Andric       Method1->getAccess() == Method2->getAccess() &&
15000b57cec5SDimitry Andric       Method1->getOverloadedOperator() == Method2->getOverloadedOperator() &&
15010b57cec5SDimitry Andric       Method1->isStatic() == Method2->isStatic() &&
15025f757f3fSDimitry Andric       Method1->isImplicitObjectMemberFunction() ==
15035f757f3fSDimitry Andric           Method2->isImplicitObjectMemberFunction() &&
15040b57cec5SDimitry Andric       Method1->isConst() == Method2->isConst() &&
15050b57cec5SDimitry Andric       Method1->isVolatile() == Method2->isVolatile() &&
15060b57cec5SDimitry Andric       Method1->isVirtual() == Method2->isVirtual() &&
15077a6dacacSDimitry Andric       Method1->isPureVirtual() == Method2->isPureVirtual() &&
15080b57cec5SDimitry Andric       Method1->isDefaulted() == Method2->isDefaulted() &&
15090b57cec5SDimitry Andric       Method1->isDeleted() == Method2->isDeleted();
15100b57cec5SDimitry Andric   if (!PropertiesEqual)
15110b57cec5SDimitry Andric     return false;
15120b57cec5SDimitry Andric   // FIXME: Check for 'final'.
15130b57cec5SDimitry Andric 
15140b57cec5SDimitry Andric   if (auto *Constructor1 = dyn_cast<CXXConstructorDecl>(Method1)) {
15150b57cec5SDimitry Andric     auto *Constructor2 = cast<CXXConstructorDecl>(Method2);
15160b57cec5SDimitry Andric     if (!Constructor1->getExplicitSpecifier().isEquivalent(
15170b57cec5SDimitry Andric             Constructor2->getExplicitSpecifier()))
15180b57cec5SDimitry Andric       return false;
15190b57cec5SDimitry Andric   }
15200b57cec5SDimitry Andric 
15210b57cec5SDimitry Andric   if (auto *Conversion1 = dyn_cast<CXXConversionDecl>(Method1)) {
15220b57cec5SDimitry Andric     auto *Conversion2 = cast<CXXConversionDecl>(Method2);
15230b57cec5SDimitry Andric     if (!Conversion1->getExplicitSpecifier().isEquivalent(
15240b57cec5SDimitry Andric             Conversion2->getExplicitSpecifier()))
15250b57cec5SDimitry Andric       return false;
15260b57cec5SDimitry Andric     if (!IsStructurallyEquivalent(Context, Conversion1->getConversionType(),
15270b57cec5SDimitry Andric                                   Conversion2->getConversionType()))
15280b57cec5SDimitry Andric       return false;
15290b57cec5SDimitry Andric   }
15300b57cec5SDimitry Andric 
15310b57cec5SDimitry Andric   const IdentifierInfo *Name1 = Method1->getIdentifier();
15320b57cec5SDimitry Andric   const IdentifierInfo *Name2 = Method2->getIdentifier();
15330b57cec5SDimitry Andric   if (!::IsStructurallyEquivalent(Name1, Name2)) {
15340b57cec5SDimitry Andric     return false;
15350b57cec5SDimitry Andric     // TODO: Names do not match, add warning like at check for FieldDecl.
15360b57cec5SDimitry Andric   }
15370b57cec5SDimitry Andric 
15380b57cec5SDimitry Andric   // Check the prototypes.
15390b57cec5SDimitry Andric   if (!::IsStructurallyEquivalent(Context,
15400b57cec5SDimitry Andric                                   Method1->getType(), Method2->getType()))
15410b57cec5SDimitry Andric     return false;
15420b57cec5SDimitry Andric 
15430b57cec5SDimitry Andric   return true;
15440b57cec5SDimitry Andric }
15450b57cec5SDimitry Andric 
15460b57cec5SDimitry Andric /// Determine structural equivalence of two lambda classes.
15470b57cec5SDimitry Andric static bool
15480b57cec5SDimitry Andric IsStructurallyEquivalentLambdas(StructuralEquivalenceContext &Context,
15490b57cec5SDimitry Andric                                 CXXRecordDecl *D1, CXXRecordDecl *D2) {
15500b57cec5SDimitry Andric   assert(D1->isLambda() && D2->isLambda() &&
15510b57cec5SDimitry Andric          "Must be called on lambda classes");
15520b57cec5SDimitry Andric   if (!IsStructurallyEquivalent(Context, D1->getLambdaCallOperator(),
15530b57cec5SDimitry Andric                                 D2->getLambdaCallOperator()))
15540b57cec5SDimitry Andric     return false;
15550b57cec5SDimitry Andric 
15560b57cec5SDimitry Andric   return true;
15570b57cec5SDimitry Andric }
15580b57cec5SDimitry Andric 
15594824e7fdSDimitry Andric /// Determine if context of a class is equivalent.
15601db9f3b2SDimitry Andric static bool
15611db9f3b2SDimitry Andric IsRecordContextStructurallyEquivalent(StructuralEquivalenceContext &Context,
15621db9f3b2SDimitry Andric                                       RecordDecl *D1, RecordDecl *D2) {
15634824e7fdSDimitry Andric   // The context should be completely equal, including anonymous and inline
15644824e7fdSDimitry Andric   // namespaces.
15654824e7fdSDimitry Andric   // We compare objects as part of full translation units, not subtrees of
15664824e7fdSDimitry Andric   // translation units.
15674824e7fdSDimitry Andric   DeclContext *DC1 = D1->getDeclContext()->getNonTransparentContext();
15684824e7fdSDimitry Andric   DeclContext *DC2 = D2->getDeclContext()->getNonTransparentContext();
15694824e7fdSDimitry Andric   while (true) {
15704824e7fdSDimitry Andric     // Special case: We allow a struct defined in a function to be equivalent
15714824e7fdSDimitry Andric     // with a similar struct defined outside of a function.
15724824e7fdSDimitry Andric     if ((DC1->isFunctionOrMethod() && DC2->isTranslationUnit()) ||
15734824e7fdSDimitry Andric         (DC2->isFunctionOrMethod() && DC1->isTranslationUnit()))
15744824e7fdSDimitry Andric       return true;
15754824e7fdSDimitry Andric 
15764824e7fdSDimitry Andric     if (DC1->getDeclKind() != DC2->getDeclKind())
15774824e7fdSDimitry Andric       return false;
15784824e7fdSDimitry Andric     if (DC1->isTranslationUnit())
15794824e7fdSDimitry Andric       break;
15804824e7fdSDimitry Andric     if (DC1->isInlineNamespace() != DC2->isInlineNamespace())
15814824e7fdSDimitry Andric       return false;
15824824e7fdSDimitry Andric     if (const auto *ND1 = dyn_cast<NamedDecl>(DC1)) {
15834824e7fdSDimitry Andric       const auto *ND2 = cast<NamedDecl>(DC2);
15844824e7fdSDimitry Andric       if (!DC1->isInlineNamespace() &&
15854824e7fdSDimitry Andric           !IsStructurallyEquivalent(ND1->getIdentifier(), ND2->getIdentifier()))
15864824e7fdSDimitry Andric         return false;
15874824e7fdSDimitry Andric     }
15884824e7fdSDimitry Andric 
15891db9f3b2SDimitry Andric     if (auto *D1Spec = dyn_cast<ClassTemplateSpecializationDecl>(DC1)) {
15901db9f3b2SDimitry Andric       auto *D2Spec = dyn_cast<ClassTemplateSpecializationDecl>(DC2);
15911db9f3b2SDimitry Andric       if (!IsStructurallyEquivalent(Context, D1Spec, D2Spec))
15921db9f3b2SDimitry Andric         return false;
15931db9f3b2SDimitry Andric     }
15941db9f3b2SDimitry Andric 
15954824e7fdSDimitry Andric     DC1 = DC1->getParent()->getNonTransparentContext();
15964824e7fdSDimitry Andric     DC2 = DC2->getParent()->getNonTransparentContext();
15974824e7fdSDimitry Andric   }
15984824e7fdSDimitry Andric 
15994824e7fdSDimitry Andric   return true;
16004824e7fdSDimitry Andric }
16014824e7fdSDimitry Andric 
160206c3fb27SDimitry Andric static bool NameIsStructurallyEquivalent(const TagDecl &D1, const TagDecl &D2) {
160306c3fb27SDimitry Andric   auto GetName = [](const TagDecl &D) -> const IdentifierInfo * {
160406c3fb27SDimitry Andric     if (const IdentifierInfo *Name = D.getIdentifier())
160506c3fb27SDimitry Andric       return Name;
160606c3fb27SDimitry Andric     if (const TypedefNameDecl *TypedefName = D.getTypedefNameForAnonDecl())
160706c3fb27SDimitry Andric       return TypedefName->getIdentifier();
160806c3fb27SDimitry Andric     return nullptr;
160906c3fb27SDimitry Andric   };
161006c3fb27SDimitry Andric   return IsStructurallyEquivalent(GetName(D1), GetName(D2));
161106c3fb27SDimitry Andric }
161206c3fb27SDimitry Andric 
16130b57cec5SDimitry Andric /// Determine structural equivalence of two records.
16140b57cec5SDimitry Andric static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
16150b57cec5SDimitry Andric                                      RecordDecl *D1, RecordDecl *D2) {
161606c3fb27SDimitry Andric   if (!NameIsStructurallyEquivalent(*D1, *D2)) {
1617e8d8bef9SDimitry Andric     return false;
161806c3fb27SDimitry Andric   }
1619e8d8bef9SDimitry Andric 
16200b57cec5SDimitry Andric   if (D1->isUnion() != D2->isUnion()) {
16210b57cec5SDimitry Andric     if (Context.Complain) {
16220b57cec5SDimitry Andric       Context.Diag2(D2->getLocation(), Context.getApplicableDiagnostic(
16230b57cec5SDimitry Andric                                            diag::err_odr_tag_type_inconsistent))
16240b57cec5SDimitry Andric           << Context.ToCtx.getTypeDeclType(D2);
16250b57cec5SDimitry Andric       Context.Diag1(D1->getLocation(), diag::note_odr_tag_kind_here)
16260b57cec5SDimitry Andric           << D1->getDeclName() << (unsigned)D1->getTagKind();
16270b57cec5SDimitry Andric     }
16280b57cec5SDimitry Andric     return false;
16290b57cec5SDimitry Andric   }
16300b57cec5SDimitry Andric 
16310b57cec5SDimitry Andric   if (!D1->getDeclName() && !D2->getDeclName()) {
16320b57cec5SDimitry Andric     // If both anonymous structs/unions are in a record context, make sure
16330b57cec5SDimitry Andric     // they occur in the same location in the context records.
1634bdd1243dSDimitry Andric     if (std::optional<unsigned> Index1 =
16350b57cec5SDimitry Andric             StructuralEquivalenceContext::findUntaggedStructOrUnionIndex(D1)) {
1636bdd1243dSDimitry Andric       if (std::optional<unsigned> Index2 =
16370b57cec5SDimitry Andric               StructuralEquivalenceContext::findUntaggedStructOrUnionIndex(
16380b57cec5SDimitry Andric                   D2)) {
16390b57cec5SDimitry Andric         if (*Index1 != *Index2)
16400b57cec5SDimitry Andric           return false;
16410b57cec5SDimitry Andric       }
16420b57cec5SDimitry Andric     }
16430b57cec5SDimitry Andric   }
16440b57cec5SDimitry Andric 
16454824e7fdSDimitry Andric   // If the records occur in different context (namespace), these should be
16464824e7fdSDimitry Andric   // different. This is specially important if the definition of one or both
16474824e7fdSDimitry Andric   // records is missing.
16481db9f3b2SDimitry Andric   if (!IsRecordContextStructurallyEquivalent(Context, D1, D2))
16494824e7fdSDimitry Andric     return false;
16504824e7fdSDimitry Andric 
16510b57cec5SDimitry Andric   // If both declarations are class template specializations, we know
16520b57cec5SDimitry Andric   // the ODR applies, so check the template and template arguments.
16530b57cec5SDimitry Andric   const auto *Spec1 = dyn_cast<ClassTemplateSpecializationDecl>(D1);
16540b57cec5SDimitry Andric   const auto *Spec2 = dyn_cast<ClassTemplateSpecializationDecl>(D2);
16550b57cec5SDimitry Andric   if (Spec1 && Spec2) {
16560b57cec5SDimitry Andric     // Check that the specialized templates are the same.
16570b57cec5SDimitry Andric     if (!IsStructurallyEquivalent(Context, Spec1->getSpecializedTemplate(),
16580b57cec5SDimitry Andric                                   Spec2->getSpecializedTemplate()))
16590b57cec5SDimitry Andric       return false;
16600b57cec5SDimitry Andric 
16610b57cec5SDimitry Andric     // Check that the template arguments are the same.
16620b57cec5SDimitry Andric     if (Spec1->getTemplateArgs().size() != Spec2->getTemplateArgs().size())
16630b57cec5SDimitry Andric       return false;
16640b57cec5SDimitry Andric 
16650b57cec5SDimitry Andric     for (unsigned I = 0, N = Spec1->getTemplateArgs().size(); I != N; ++I)
16660b57cec5SDimitry Andric       if (!IsStructurallyEquivalent(Context, Spec1->getTemplateArgs().get(I),
16670b57cec5SDimitry Andric                                     Spec2->getTemplateArgs().get(I)))
16680b57cec5SDimitry Andric         return false;
16690b57cec5SDimitry Andric   }
16700b57cec5SDimitry Andric   // If one is a class template specialization and the other is not, these
16710b57cec5SDimitry Andric   // structures are different.
16720b57cec5SDimitry Andric   else if (Spec1 || Spec2)
16730b57cec5SDimitry Andric     return false;
16740b57cec5SDimitry Andric 
16750b57cec5SDimitry Andric   // Compare the definitions of these two records. If either or both are
16760b57cec5SDimitry Andric   // incomplete (i.e. it is a forward decl), we assume that they are
16770b57cec5SDimitry Andric   // equivalent.
16780b57cec5SDimitry Andric   D1 = D1->getDefinition();
16790b57cec5SDimitry Andric   D2 = D2->getDefinition();
16800b57cec5SDimitry Andric   if (!D1 || !D2)
16810b57cec5SDimitry Andric     return true;
16820b57cec5SDimitry Andric 
16830b57cec5SDimitry Andric   // If any of the records has external storage and we do a minimal check (or
16840b57cec5SDimitry Andric   // AST import) we assume they are equivalent. (If we didn't have this
16850b57cec5SDimitry Andric   // assumption then `RecordDecl::LoadFieldsFromExternalStorage` could trigger
16860b57cec5SDimitry Andric   // another AST import which in turn would call the structural equivalency
16870b57cec5SDimitry Andric   // check again and finally we'd have an improper result.)
16880b57cec5SDimitry Andric   if (Context.EqKind == StructuralEquivalenceKind::Minimal)
16890b57cec5SDimitry Andric     if (D1->hasExternalLexicalStorage() || D2->hasExternalLexicalStorage())
16900b57cec5SDimitry Andric       return true;
16910b57cec5SDimitry Andric 
16920b57cec5SDimitry Andric   // If one definition is currently being defined, we do not compare for
16930b57cec5SDimitry Andric   // equality and we assume that the decls are equal.
16940b57cec5SDimitry Andric   if (D1->isBeingDefined() || D2->isBeingDefined())
16950b57cec5SDimitry Andric     return true;
16960b57cec5SDimitry Andric 
16970b57cec5SDimitry Andric   if (auto *D1CXX = dyn_cast<CXXRecordDecl>(D1)) {
16980b57cec5SDimitry Andric     if (auto *D2CXX = dyn_cast<CXXRecordDecl>(D2)) {
16990b57cec5SDimitry Andric       if (D1CXX->hasExternalLexicalStorage() &&
17000b57cec5SDimitry Andric           !D1CXX->isCompleteDefinition()) {
17010b57cec5SDimitry Andric         D1CXX->getASTContext().getExternalSource()->CompleteType(D1CXX);
17020b57cec5SDimitry Andric       }
17030b57cec5SDimitry Andric 
17040b57cec5SDimitry Andric       if (D1CXX->isLambda() != D2CXX->isLambda())
17050b57cec5SDimitry Andric         return false;
17060b57cec5SDimitry Andric       if (D1CXX->isLambda()) {
17070b57cec5SDimitry Andric         if (!IsStructurallyEquivalentLambdas(Context, D1CXX, D2CXX))
17080b57cec5SDimitry Andric           return false;
17090b57cec5SDimitry Andric       }
17100b57cec5SDimitry Andric 
17110b57cec5SDimitry Andric       if (D1CXX->getNumBases() != D2CXX->getNumBases()) {
17120b57cec5SDimitry Andric         if (Context.Complain) {
17130b57cec5SDimitry Andric           Context.Diag2(D2->getLocation(),
17140b57cec5SDimitry Andric                         Context.getApplicableDiagnostic(
17150b57cec5SDimitry Andric                             diag::err_odr_tag_type_inconsistent))
17160b57cec5SDimitry Andric               << Context.ToCtx.getTypeDeclType(D2);
17170b57cec5SDimitry Andric           Context.Diag2(D2->getLocation(), diag::note_odr_number_of_bases)
17180b57cec5SDimitry Andric               << D2CXX->getNumBases();
17190b57cec5SDimitry Andric           Context.Diag1(D1->getLocation(), diag::note_odr_number_of_bases)
17200b57cec5SDimitry Andric               << D1CXX->getNumBases();
17210b57cec5SDimitry Andric         }
17220b57cec5SDimitry Andric         return false;
17230b57cec5SDimitry Andric       }
17240b57cec5SDimitry Andric 
17250b57cec5SDimitry Andric       // Check the base classes.
17260b57cec5SDimitry Andric       for (CXXRecordDecl::base_class_iterator Base1 = D1CXX->bases_begin(),
17270b57cec5SDimitry Andric                                               BaseEnd1 = D1CXX->bases_end(),
17280b57cec5SDimitry Andric                                               Base2 = D2CXX->bases_begin();
17290b57cec5SDimitry Andric            Base1 != BaseEnd1; ++Base1, ++Base2) {
17300b57cec5SDimitry Andric         if (!IsStructurallyEquivalent(Context, Base1->getType(),
17310b57cec5SDimitry Andric                                       Base2->getType())) {
17320b57cec5SDimitry Andric           if (Context.Complain) {
17330b57cec5SDimitry Andric             Context.Diag2(D2->getLocation(),
17340b57cec5SDimitry Andric                           Context.getApplicableDiagnostic(
17350b57cec5SDimitry Andric                               diag::err_odr_tag_type_inconsistent))
17360b57cec5SDimitry Andric                 << Context.ToCtx.getTypeDeclType(D2);
17370b57cec5SDimitry Andric             Context.Diag2(Base2->getBeginLoc(), diag::note_odr_base)
17380b57cec5SDimitry Andric                 << Base2->getType() << Base2->getSourceRange();
17390b57cec5SDimitry Andric             Context.Diag1(Base1->getBeginLoc(), diag::note_odr_base)
17400b57cec5SDimitry Andric                 << Base1->getType() << Base1->getSourceRange();
17410b57cec5SDimitry Andric           }
17420b57cec5SDimitry Andric           return false;
17430b57cec5SDimitry Andric         }
17440b57cec5SDimitry Andric 
17450b57cec5SDimitry Andric         // Check virtual vs. non-virtual inheritance mismatch.
17460b57cec5SDimitry Andric         if (Base1->isVirtual() != Base2->isVirtual()) {
17470b57cec5SDimitry Andric           if (Context.Complain) {
17480b57cec5SDimitry Andric             Context.Diag2(D2->getLocation(),
17490b57cec5SDimitry Andric                           Context.getApplicableDiagnostic(
17500b57cec5SDimitry Andric                               diag::err_odr_tag_type_inconsistent))
17510b57cec5SDimitry Andric                 << Context.ToCtx.getTypeDeclType(D2);
17520b57cec5SDimitry Andric             Context.Diag2(Base2->getBeginLoc(), diag::note_odr_virtual_base)
17530b57cec5SDimitry Andric                 << Base2->isVirtual() << Base2->getSourceRange();
17540b57cec5SDimitry Andric             Context.Diag1(Base1->getBeginLoc(), diag::note_odr_base)
17550b57cec5SDimitry Andric                 << Base1->isVirtual() << Base1->getSourceRange();
17560b57cec5SDimitry Andric           }
17570b57cec5SDimitry Andric           return false;
17580b57cec5SDimitry Andric         }
17590b57cec5SDimitry Andric       }
17600b57cec5SDimitry Andric 
17610b57cec5SDimitry Andric       // Check the friends for consistency.
17620b57cec5SDimitry Andric       CXXRecordDecl::friend_iterator Friend2 = D2CXX->friend_begin(),
17630b57cec5SDimitry Andric                                      Friend2End = D2CXX->friend_end();
17640b57cec5SDimitry Andric       for (CXXRecordDecl::friend_iterator Friend1 = D1CXX->friend_begin(),
17650b57cec5SDimitry Andric                                           Friend1End = D1CXX->friend_end();
17660b57cec5SDimitry Andric            Friend1 != Friend1End; ++Friend1, ++Friend2) {
17670b57cec5SDimitry Andric         if (Friend2 == Friend2End) {
17680b57cec5SDimitry Andric           if (Context.Complain) {
17690b57cec5SDimitry Andric             Context.Diag2(D2->getLocation(),
17700b57cec5SDimitry Andric                           Context.getApplicableDiagnostic(
17710b57cec5SDimitry Andric                               diag::err_odr_tag_type_inconsistent))
17720b57cec5SDimitry Andric                 << Context.ToCtx.getTypeDeclType(D2CXX);
17730b57cec5SDimitry Andric             Context.Diag1((*Friend1)->getFriendLoc(), diag::note_odr_friend);
17740b57cec5SDimitry Andric             Context.Diag2(D2->getLocation(), diag::note_odr_missing_friend);
17750b57cec5SDimitry Andric           }
17760b57cec5SDimitry Andric           return false;
17770b57cec5SDimitry Andric         }
17780b57cec5SDimitry Andric 
17790b57cec5SDimitry Andric         if (!IsStructurallyEquivalent(Context, *Friend1, *Friend2)) {
17800b57cec5SDimitry Andric           if (Context.Complain) {
17810b57cec5SDimitry Andric             Context.Diag2(D2->getLocation(),
17820b57cec5SDimitry Andric                           Context.getApplicableDiagnostic(
17830b57cec5SDimitry Andric                               diag::err_odr_tag_type_inconsistent))
17840b57cec5SDimitry Andric                 << Context.ToCtx.getTypeDeclType(D2CXX);
17850b57cec5SDimitry Andric             Context.Diag1((*Friend1)->getFriendLoc(), diag::note_odr_friend);
17860b57cec5SDimitry Andric             Context.Diag2((*Friend2)->getFriendLoc(), diag::note_odr_friend);
17870b57cec5SDimitry Andric           }
17880b57cec5SDimitry Andric           return false;
17890b57cec5SDimitry Andric         }
17900b57cec5SDimitry Andric       }
17910b57cec5SDimitry Andric 
17920b57cec5SDimitry Andric       if (Friend2 != Friend2End) {
17930b57cec5SDimitry Andric         if (Context.Complain) {
17940b57cec5SDimitry Andric           Context.Diag2(D2->getLocation(),
17950b57cec5SDimitry Andric                         Context.getApplicableDiagnostic(
17960b57cec5SDimitry Andric                             diag::err_odr_tag_type_inconsistent))
17970b57cec5SDimitry Andric               << Context.ToCtx.getTypeDeclType(D2);
17980b57cec5SDimitry Andric           Context.Diag2((*Friend2)->getFriendLoc(), diag::note_odr_friend);
17990b57cec5SDimitry Andric           Context.Diag1(D1->getLocation(), diag::note_odr_missing_friend);
18000b57cec5SDimitry Andric         }
18010b57cec5SDimitry Andric         return false;
18020b57cec5SDimitry Andric       }
18030b57cec5SDimitry Andric     } else if (D1CXX->getNumBases() > 0) {
18040b57cec5SDimitry Andric       if (Context.Complain) {
18050b57cec5SDimitry Andric         Context.Diag2(D2->getLocation(),
18060b57cec5SDimitry Andric                       Context.getApplicableDiagnostic(
18070b57cec5SDimitry Andric                           diag::err_odr_tag_type_inconsistent))
18080b57cec5SDimitry Andric             << Context.ToCtx.getTypeDeclType(D2);
18090b57cec5SDimitry Andric         const CXXBaseSpecifier *Base1 = D1CXX->bases_begin();
18100b57cec5SDimitry Andric         Context.Diag1(Base1->getBeginLoc(), diag::note_odr_base)
18110b57cec5SDimitry Andric             << Base1->getType() << Base1->getSourceRange();
18120b57cec5SDimitry Andric         Context.Diag2(D2->getLocation(), diag::note_odr_missing_base);
18130b57cec5SDimitry Andric       }
18140b57cec5SDimitry Andric       return false;
18150b57cec5SDimitry Andric     }
18160b57cec5SDimitry Andric   }
18170b57cec5SDimitry Andric 
18180b57cec5SDimitry Andric   // Check the fields for consistency.
181981ad6265SDimitry Andric   QualType D2Type = Context.ToCtx.getTypeDeclType(D2);
18200b57cec5SDimitry Andric   RecordDecl::field_iterator Field2 = D2->field_begin(),
18210b57cec5SDimitry Andric                              Field2End = D2->field_end();
18220b57cec5SDimitry Andric   for (RecordDecl::field_iterator Field1 = D1->field_begin(),
18230b57cec5SDimitry Andric                                   Field1End = D1->field_end();
18240b57cec5SDimitry Andric        Field1 != Field1End; ++Field1, ++Field2) {
18250b57cec5SDimitry Andric     if (Field2 == Field2End) {
18260b57cec5SDimitry Andric       if (Context.Complain) {
18270b57cec5SDimitry Andric         Context.Diag2(D2->getLocation(),
18280b57cec5SDimitry Andric                       Context.getApplicableDiagnostic(
18290b57cec5SDimitry Andric                           diag::err_odr_tag_type_inconsistent))
18300b57cec5SDimitry Andric             << Context.ToCtx.getTypeDeclType(D2);
18310b57cec5SDimitry Andric         Context.Diag1(Field1->getLocation(), diag::note_odr_field)
18320b57cec5SDimitry Andric             << Field1->getDeclName() << Field1->getType();
18330b57cec5SDimitry Andric         Context.Diag2(D2->getLocation(), diag::note_odr_missing_field);
18340b57cec5SDimitry Andric       }
18350b57cec5SDimitry Andric       return false;
18360b57cec5SDimitry Andric     }
18370b57cec5SDimitry Andric 
183881ad6265SDimitry Andric     if (!IsStructurallyEquivalent(Context, *Field1, *Field2, D2Type))
18390b57cec5SDimitry Andric       return false;
18400b57cec5SDimitry Andric   }
18410b57cec5SDimitry Andric 
18420b57cec5SDimitry Andric   if (Field2 != Field2End) {
18430b57cec5SDimitry Andric     if (Context.Complain) {
18440b57cec5SDimitry Andric       Context.Diag2(D2->getLocation(), Context.getApplicableDiagnostic(
18450b57cec5SDimitry Andric                                            diag::err_odr_tag_type_inconsistent))
18460b57cec5SDimitry Andric           << Context.ToCtx.getTypeDeclType(D2);
18470b57cec5SDimitry Andric       Context.Diag2(Field2->getLocation(), diag::note_odr_field)
18480b57cec5SDimitry Andric           << Field2->getDeclName() << Field2->getType();
18490b57cec5SDimitry Andric       Context.Diag1(D1->getLocation(), diag::note_odr_missing_field);
18500b57cec5SDimitry Andric     }
18510b57cec5SDimitry Andric     return false;
18520b57cec5SDimitry Andric   }
18530b57cec5SDimitry Andric 
18540b57cec5SDimitry Andric   return true;
18550b57cec5SDimitry Andric }
18560b57cec5SDimitry Andric 
1857349cc55cSDimitry Andric static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
1858349cc55cSDimitry Andric                                      EnumConstantDecl *D1,
1859349cc55cSDimitry Andric                                      EnumConstantDecl *D2) {
1860349cc55cSDimitry Andric   const llvm::APSInt &FromVal = D1->getInitVal();
1861349cc55cSDimitry Andric   const llvm::APSInt &ToVal = D2->getInitVal();
1862349cc55cSDimitry Andric   if (FromVal.isSigned() != ToVal.isSigned())
1863349cc55cSDimitry Andric     return false;
1864349cc55cSDimitry Andric   if (FromVal.getBitWidth() != ToVal.getBitWidth())
1865349cc55cSDimitry Andric     return false;
1866349cc55cSDimitry Andric   if (FromVal != ToVal)
1867349cc55cSDimitry Andric     return false;
1868349cc55cSDimitry Andric 
1869349cc55cSDimitry Andric   if (!IsStructurallyEquivalent(D1->getIdentifier(), D2->getIdentifier()))
1870349cc55cSDimitry Andric     return false;
1871349cc55cSDimitry Andric 
1872349cc55cSDimitry Andric   // Init expressions are the most expensive check, so do them last.
1873349cc55cSDimitry Andric   return IsStructurallyEquivalent(Context, D1->getInitExpr(),
1874349cc55cSDimitry Andric                                   D2->getInitExpr());
1875349cc55cSDimitry Andric }
1876349cc55cSDimitry Andric 
18770b57cec5SDimitry Andric /// Determine structural equivalence of two enums.
18780b57cec5SDimitry Andric static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
18790b57cec5SDimitry Andric                                      EnumDecl *D1, EnumDecl *D2) {
188006c3fb27SDimitry Andric   if (!NameIsStructurallyEquivalent(*D1, *D2)) {
1881e8d8bef9SDimitry Andric     return false;
188206c3fb27SDimitry Andric   }
1883e8d8bef9SDimitry Andric 
18840b57cec5SDimitry Andric   // Compare the definitions of these two enums. If either or both are
18850b57cec5SDimitry Andric   // incomplete (i.e. forward declared), we assume that they are equivalent.
18860b57cec5SDimitry Andric   D1 = D1->getDefinition();
18870b57cec5SDimitry Andric   D2 = D2->getDefinition();
18880b57cec5SDimitry Andric   if (!D1 || !D2)
18890b57cec5SDimitry Andric     return true;
18900b57cec5SDimitry Andric 
18910b57cec5SDimitry Andric   EnumDecl::enumerator_iterator EC2 = D2->enumerator_begin(),
18920b57cec5SDimitry Andric                                 EC2End = D2->enumerator_end();
18930b57cec5SDimitry Andric   for (EnumDecl::enumerator_iterator EC1 = D1->enumerator_begin(),
18940b57cec5SDimitry Andric                                      EC1End = D1->enumerator_end();
18950b57cec5SDimitry Andric        EC1 != EC1End; ++EC1, ++EC2) {
18960b57cec5SDimitry Andric     if (EC2 == EC2End) {
18970b57cec5SDimitry Andric       if (Context.Complain) {
18980b57cec5SDimitry Andric         Context.Diag2(D2->getLocation(),
18990b57cec5SDimitry Andric                       Context.getApplicableDiagnostic(
19000b57cec5SDimitry Andric                           diag::err_odr_tag_type_inconsistent))
19010b57cec5SDimitry Andric             << Context.ToCtx.getTypeDeclType(D2);
19020b57cec5SDimitry Andric         Context.Diag1(EC1->getLocation(), diag::note_odr_enumerator)
1903fe6060f1SDimitry Andric             << EC1->getDeclName() << toString(EC1->getInitVal(), 10);
19040b57cec5SDimitry Andric         Context.Diag2(D2->getLocation(), diag::note_odr_missing_enumerator);
19050b57cec5SDimitry Andric       }
19060b57cec5SDimitry Andric       return false;
19070b57cec5SDimitry Andric     }
19080b57cec5SDimitry Andric 
19090b57cec5SDimitry Andric     llvm::APSInt Val1 = EC1->getInitVal();
19100b57cec5SDimitry Andric     llvm::APSInt Val2 = EC2->getInitVal();
19110b57cec5SDimitry Andric     if (!llvm::APSInt::isSameValue(Val1, Val2) ||
19120b57cec5SDimitry Andric         !IsStructurallyEquivalent(EC1->getIdentifier(), EC2->getIdentifier())) {
19130b57cec5SDimitry Andric       if (Context.Complain) {
19140b57cec5SDimitry Andric         Context.Diag2(D2->getLocation(),
19150b57cec5SDimitry Andric                       Context.getApplicableDiagnostic(
19160b57cec5SDimitry Andric                           diag::err_odr_tag_type_inconsistent))
19170b57cec5SDimitry Andric             << Context.ToCtx.getTypeDeclType(D2);
19180b57cec5SDimitry Andric         Context.Diag2(EC2->getLocation(), diag::note_odr_enumerator)
1919fe6060f1SDimitry Andric             << EC2->getDeclName() << toString(EC2->getInitVal(), 10);
19200b57cec5SDimitry Andric         Context.Diag1(EC1->getLocation(), diag::note_odr_enumerator)
1921fe6060f1SDimitry Andric             << EC1->getDeclName() << toString(EC1->getInitVal(), 10);
19220b57cec5SDimitry Andric       }
19230b57cec5SDimitry Andric       return false;
19240b57cec5SDimitry Andric     }
19250b57cec5SDimitry Andric   }
19260b57cec5SDimitry Andric 
19270b57cec5SDimitry Andric   if (EC2 != EC2End) {
19280b57cec5SDimitry Andric     if (Context.Complain) {
19290b57cec5SDimitry Andric       Context.Diag2(D2->getLocation(), Context.getApplicableDiagnostic(
19300b57cec5SDimitry Andric                                            diag::err_odr_tag_type_inconsistent))
19310b57cec5SDimitry Andric           << Context.ToCtx.getTypeDeclType(D2);
19320b57cec5SDimitry Andric       Context.Diag2(EC2->getLocation(), diag::note_odr_enumerator)
1933fe6060f1SDimitry Andric           << EC2->getDeclName() << toString(EC2->getInitVal(), 10);
19340b57cec5SDimitry Andric       Context.Diag1(D1->getLocation(), diag::note_odr_missing_enumerator);
19350b57cec5SDimitry Andric     }
19360b57cec5SDimitry Andric     return false;
19370b57cec5SDimitry Andric   }
19380b57cec5SDimitry Andric 
19390b57cec5SDimitry Andric   return true;
19400b57cec5SDimitry Andric }
19410b57cec5SDimitry Andric 
19420b57cec5SDimitry Andric static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
19430b57cec5SDimitry Andric                                      TemplateParameterList *Params1,
19440b57cec5SDimitry Andric                                      TemplateParameterList *Params2) {
19450b57cec5SDimitry Andric   if (Params1->size() != Params2->size()) {
19460b57cec5SDimitry Andric     if (Context.Complain) {
19470b57cec5SDimitry Andric       Context.Diag2(Params2->getTemplateLoc(),
19480b57cec5SDimitry Andric                     Context.getApplicableDiagnostic(
19490b57cec5SDimitry Andric                         diag::err_odr_different_num_template_parameters))
19500b57cec5SDimitry Andric           << Params1->size() << Params2->size();
19510b57cec5SDimitry Andric       Context.Diag1(Params1->getTemplateLoc(),
19520b57cec5SDimitry Andric                     diag::note_odr_template_parameter_list);
19530b57cec5SDimitry Andric     }
19540b57cec5SDimitry Andric     return false;
19550b57cec5SDimitry Andric   }
19560b57cec5SDimitry Andric 
19570b57cec5SDimitry Andric   for (unsigned I = 0, N = Params1->size(); I != N; ++I) {
19580b57cec5SDimitry Andric     if (Params1->getParam(I)->getKind() != Params2->getParam(I)->getKind()) {
19590b57cec5SDimitry Andric       if (Context.Complain) {
19600b57cec5SDimitry Andric         Context.Diag2(Params2->getParam(I)->getLocation(),
19610b57cec5SDimitry Andric                       Context.getApplicableDiagnostic(
19620b57cec5SDimitry Andric                           diag::err_odr_different_template_parameter_kind));
19630b57cec5SDimitry Andric         Context.Diag1(Params1->getParam(I)->getLocation(),
19640b57cec5SDimitry Andric                       diag::note_odr_template_parameter_here);
19650b57cec5SDimitry Andric       }
19660b57cec5SDimitry Andric       return false;
19670b57cec5SDimitry Andric     }
19680b57cec5SDimitry Andric 
19690b57cec5SDimitry Andric     if (!IsStructurallyEquivalent(Context, Params1->getParam(I),
19700b57cec5SDimitry Andric                                   Params2->getParam(I)))
19710b57cec5SDimitry Andric       return false;
19720b57cec5SDimitry Andric   }
19730b57cec5SDimitry Andric 
19740b57cec5SDimitry Andric   return true;
19750b57cec5SDimitry Andric }
19760b57cec5SDimitry Andric 
19770b57cec5SDimitry Andric static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
19780b57cec5SDimitry Andric                                      TemplateTypeParmDecl *D1,
19790b57cec5SDimitry Andric                                      TemplateTypeParmDecl *D2) {
19800b57cec5SDimitry Andric   if (D1->isParameterPack() != D2->isParameterPack()) {
19810b57cec5SDimitry Andric     if (Context.Complain) {
19820b57cec5SDimitry Andric       Context.Diag2(D2->getLocation(),
19830b57cec5SDimitry Andric                     Context.getApplicableDiagnostic(
19840b57cec5SDimitry Andric                         diag::err_odr_parameter_pack_non_pack))
19850b57cec5SDimitry Andric           << D2->isParameterPack();
19860b57cec5SDimitry Andric       Context.Diag1(D1->getLocation(), diag::note_odr_parameter_pack_non_pack)
19870b57cec5SDimitry Andric           << D1->isParameterPack();
19880b57cec5SDimitry Andric     }
19890b57cec5SDimitry Andric     return false;
19900b57cec5SDimitry Andric   }
19910b57cec5SDimitry Andric 
19920b57cec5SDimitry Andric   return true;
19930b57cec5SDimitry Andric }
19940b57cec5SDimitry Andric 
19950b57cec5SDimitry Andric static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
19960b57cec5SDimitry Andric                                      NonTypeTemplateParmDecl *D1,
19970b57cec5SDimitry Andric                                      NonTypeTemplateParmDecl *D2) {
19980b57cec5SDimitry Andric   if (D1->isParameterPack() != D2->isParameterPack()) {
19990b57cec5SDimitry Andric     if (Context.Complain) {
20000b57cec5SDimitry Andric       Context.Diag2(D2->getLocation(),
20010b57cec5SDimitry Andric                     Context.getApplicableDiagnostic(
20020b57cec5SDimitry Andric                         diag::err_odr_parameter_pack_non_pack))
20030b57cec5SDimitry Andric           << D2->isParameterPack();
20040b57cec5SDimitry Andric       Context.Diag1(D1->getLocation(), diag::note_odr_parameter_pack_non_pack)
20050b57cec5SDimitry Andric           << D1->isParameterPack();
20060b57cec5SDimitry Andric     }
20070b57cec5SDimitry Andric     return false;
20080b57cec5SDimitry Andric   }
2009*0fca6ea1SDimitry Andric   if (!Context.IgnoreTemplateParmDepth && D1->getDepth() != D2->getDepth())
2010*0fca6ea1SDimitry Andric     return false;
2011*0fca6ea1SDimitry Andric   if (D1->getIndex() != D2->getIndex())
2012*0fca6ea1SDimitry Andric     return false;
20130b57cec5SDimitry Andric   // Check types.
20140b57cec5SDimitry Andric   if (!IsStructurallyEquivalent(Context, D1->getType(), D2->getType())) {
20150b57cec5SDimitry Andric     if (Context.Complain) {
20160b57cec5SDimitry Andric       Context.Diag2(D2->getLocation(),
20170b57cec5SDimitry Andric                     Context.getApplicableDiagnostic(
20180b57cec5SDimitry Andric                         diag::err_odr_non_type_parameter_type_inconsistent))
20190b57cec5SDimitry Andric           << D2->getType() << D1->getType();
20200b57cec5SDimitry Andric       Context.Diag1(D1->getLocation(), diag::note_odr_value_here)
20210b57cec5SDimitry Andric           << D1->getType();
20220b57cec5SDimitry Andric     }
20230b57cec5SDimitry Andric     return false;
20240b57cec5SDimitry Andric   }
20250b57cec5SDimitry Andric 
20260b57cec5SDimitry Andric   return true;
20270b57cec5SDimitry Andric }
20280b57cec5SDimitry Andric 
20290b57cec5SDimitry Andric static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
20300b57cec5SDimitry Andric                                      TemplateTemplateParmDecl *D1,
20310b57cec5SDimitry Andric                                      TemplateTemplateParmDecl *D2) {
20320b57cec5SDimitry Andric   if (D1->isParameterPack() != D2->isParameterPack()) {
20330b57cec5SDimitry Andric     if (Context.Complain) {
20340b57cec5SDimitry Andric       Context.Diag2(D2->getLocation(),
20350b57cec5SDimitry Andric                     Context.getApplicableDiagnostic(
20360b57cec5SDimitry Andric                         diag::err_odr_parameter_pack_non_pack))
20370b57cec5SDimitry Andric           << D2->isParameterPack();
20380b57cec5SDimitry Andric       Context.Diag1(D1->getLocation(), diag::note_odr_parameter_pack_non_pack)
20390b57cec5SDimitry Andric           << D1->isParameterPack();
20400b57cec5SDimitry Andric     }
20410b57cec5SDimitry Andric     return false;
20420b57cec5SDimitry Andric   }
20430b57cec5SDimitry Andric 
20440b57cec5SDimitry Andric   // Check template parameter lists.
20450b57cec5SDimitry Andric   return IsStructurallyEquivalent(Context, D1->getTemplateParameters(),
20460b57cec5SDimitry Andric                                   D2->getTemplateParameters());
20470b57cec5SDimitry Andric }
20480b57cec5SDimitry Andric 
20490b57cec5SDimitry Andric static bool IsTemplateDeclCommonStructurallyEquivalent(
20500b57cec5SDimitry Andric     StructuralEquivalenceContext &Ctx, TemplateDecl *D1, TemplateDecl *D2) {
20510b57cec5SDimitry Andric   if (!IsStructurallyEquivalent(D1->getIdentifier(), D2->getIdentifier()))
20520b57cec5SDimitry Andric     return false;
20530b57cec5SDimitry Andric   if (!D1->getIdentifier()) // Special name
20540b57cec5SDimitry Andric     if (D1->getNameAsString() != D2->getNameAsString())
20550b57cec5SDimitry Andric       return false;
20560b57cec5SDimitry Andric   return IsStructurallyEquivalent(Ctx, D1->getTemplateParameters(),
20570b57cec5SDimitry Andric                                   D2->getTemplateParameters());
20580b57cec5SDimitry Andric }
20590b57cec5SDimitry Andric 
20600b57cec5SDimitry Andric static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
20610b57cec5SDimitry Andric                                      ClassTemplateDecl *D1,
20620b57cec5SDimitry Andric                                      ClassTemplateDecl *D2) {
20630b57cec5SDimitry Andric   // Check template parameters.
20640b57cec5SDimitry Andric   if (!IsTemplateDeclCommonStructurallyEquivalent(Context, D1, D2))
20650b57cec5SDimitry Andric     return false;
20660b57cec5SDimitry Andric 
20670b57cec5SDimitry Andric   // Check the templated declaration.
20680b57cec5SDimitry Andric   return IsStructurallyEquivalent(Context, D1->getTemplatedDecl(),
20690b57cec5SDimitry Andric                                   D2->getTemplatedDecl());
20700b57cec5SDimitry Andric }
20710b57cec5SDimitry Andric 
20720b57cec5SDimitry Andric static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
20730b57cec5SDimitry Andric                                      FunctionTemplateDecl *D1,
20740b57cec5SDimitry Andric                                      FunctionTemplateDecl *D2) {
20750b57cec5SDimitry Andric   // Check template parameters.
20760b57cec5SDimitry Andric   if (!IsTemplateDeclCommonStructurallyEquivalent(Context, D1, D2))
20770b57cec5SDimitry Andric     return false;
20780b57cec5SDimitry Andric 
20790b57cec5SDimitry Andric   // Check the templated declaration.
20800b57cec5SDimitry Andric   return IsStructurallyEquivalent(Context, D1->getTemplatedDecl()->getType(),
20810b57cec5SDimitry Andric                                   D2->getTemplatedDecl()->getType());
20820b57cec5SDimitry Andric }
20830b57cec5SDimitry Andric 
20840b57cec5SDimitry Andric static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
2085cb14a3feSDimitry Andric                                      TypeAliasTemplateDecl *D1,
2086cb14a3feSDimitry Andric                                      TypeAliasTemplateDecl *D2) {
2087cb14a3feSDimitry Andric   // Check template parameters.
2088cb14a3feSDimitry Andric   if (!IsTemplateDeclCommonStructurallyEquivalent(Context, D1, D2))
2089cb14a3feSDimitry Andric     return false;
2090cb14a3feSDimitry Andric 
2091cb14a3feSDimitry Andric   // Check the templated declaration.
2092cb14a3feSDimitry Andric   return IsStructurallyEquivalent(Context, D1->getTemplatedDecl(),
2093cb14a3feSDimitry Andric                                   D2->getTemplatedDecl());
2094cb14a3feSDimitry Andric }
2095cb14a3feSDimitry Andric 
2096cb14a3feSDimitry Andric static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
20970b57cec5SDimitry Andric                                      ConceptDecl *D1,
20980b57cec5SDimitry Andric                                      ConceptDecl *D2) {
20990b57cec5SDimitry Andric   // Check template parameters.
21000b57cec5SDimitry Andric   if (!IsTemplateDeclCommonStructurallyEquivalent(Context, D1, D2))
21010b57cec5SDimitry Andric     return false;
21020b57cec5SDimitry Andric 
21030b57cec5SDimitry Andric   // Check the constraint expression.
21040b57cec5SDimitry Andric   return IsStructurallyEquivalent(Context, D1->getConstraintExpr(),
21050b57cec5SDimitry Andric                                   D2->getConstraintExpr());
21060b57cec5SDimitry Andric }
21070b57cec5SDimitry Andric 
21080b57cec5SDimitry Andric static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
21090b57cec5SDimitry Andric                                      FriendDecl *D1, FriendDecl *D2) {
21100b57cec5SDimitry Andric   if ((D1->getFriendType() && D2->getFriendDecl()) ||
21110b57cec5SDimitry Andric       (D1->getFriendDecl() && D2->getFriendType())) {
21120b57cec5SDimitry Andric       return false;
21130b57cec5SDimitry Andric   }
21140b57cec5SDimitry Andric   if (D1->getFriendType() && D2->getFriendType())
21150b57cec5SDimitry Andric     return IsStructurallyEquivalent(Context,
21160b57cec5SDimitry Andric                                     D1->getFriendType()->getType(),
21170b57cec5SDimitry Andric                                     D2->getFriendType()->getType());
21180b57cec5SDimitry Andric   if (D1->getFriendDecl() && D2->getFriendDecl())
21190b57cec5SDimitry Andric     return IsStructurallyEquivalent(Context, D1->getFriendDecl(),
21200b57cec5SDimitry Andric                                     D2->getFriendDecl());
21210b57cec5SDimitry Andric   return false;
21220b57cec5SDimitry Andric }
21230b57cec5SDimitry Andric 
21240b57cec5SDimitry Andric static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
2125e8d8bef9SDimitry Andric                                      TypedefNameDecl *D1, TypedefNameDecl *D2) {
2126e8d8bef9SDimitry Andric   if (!IsStructurallyEquivalent(D1->getIdentifier(), D2->getIdentifier()))
2127e8d8bef9SDimitry Andric     return false;
2128e8d8bef9SDimitry Andric 
2129e8d8bef9SDimitry Andric   return IsStructurallyEquivalent(Context, D1->getUnderlyingType(),
2130e8d8bef9SDimitry Andric                                   D2->getUnderlyingType());
2131e8d8bef9SDimitry Andric }
2132e8d8bef9SDimitry Andric 
2133e8d8bef9SDimitry Andric static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
21340b57cec5SDimitry Andric                                      FunctionDecl *D1, FunctionDecl *D2) {
2135e8d8bef9SDimitry Andric   if (!IsStructurallyEquivalent(D1->getIdentifier(), D2->getIdentifier()))
2136e8d8bef9SDimitry Andric     return false;
2137e8d8bef9SDimitry Andric 
2138e8d8bef9SDimitry Andric   if (D1->isOverloadedOperator()) {
2139e8d8bef9SDimitry Andric     if (!D2->isOverloadedOperator())
2140e8d8bef9SDimitry Andric       return false;
2141e8d8bef9SDimitry Andric     if (D1->getOverloadedOperator() != D2->getOverloadedOperator())
2142e8d8bef9SDimitry Andric       return false;
2143e8d8bef9SDimitry Andric   }
2144e8d8bef9SDimitry Andric 
21450b57cec5SDimitry Andric   // FIXME: Consider checking for function attributes as well.
21460b57cec5SDimitry Andric   if (!IsStructurallyEquivalent(Context, D1->getType(), D2->getType()))
21470b57cec5SDimitry Andric     return false;
21480b57cec5SDimitry Andric 
21490b57cec5SDimitry Andric   return true;
21500b57cec5SDimitry Andric }
21510b57cec5SDimitry Andric 
215281ad6265SDimitry Andric static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
215381ad6265SDimitry Andric                                      ObjCIvarDecl *D1, ObjCIvarDecl *D2,
215481ad6265SDimitry Andric                                      QualType Owner2Type) {
215581ad6265SDimitry Andric   if (D1->getAccessControl() != D2->getAccessControl())
215681ad6265SDimitry Andric     return false;
215781ad6265SDimitry Andric 
215881ad6265SDimitry Andric   return IsStructurallyEquivalent(Context, cast<FieldDecl>(D1),
215981ad6265SDimitry Andric                                   cast<FieldDecl>(D2), Owner2Type);
216081ad6265SDimitry Andric }
216181ad6265SDimitry Andric 
216281ad6265SDimitry Andric static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
216381ad6265SDimitry Andric                                      ObjCIvarDecl *D1, ObjCIvarDecl *D2) {
216481ad6265SDimitry Andric   QualType Owner2Type =
216581ad6265SDimitry Andric       Context.ToCtx.getObjCInterfaceType(D2->getContainingInterface());
216681ad6265SDimitry Andric   return IsStructurallyEquivalent(Context, D1, D2, Owner2Type);
216781ad6265SDimitry Andric }
216881ad6265SDimitry Andric 
216981ad6265SDimitry Andric static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
217081ad6265SDimitry Andric                                      ObjCMethodDecl *Method1,
217181ad6265SDimitry Andric                                      ObjCMethodDecl *Method2) {
217281ad6265SDimitry Andric   bool PropertiesEqual =
217381ad6265SDimitry Andric       Method1->isInstanceMethod() == Method2->isInstanceMethod() &&
217481ad6265SDimitry Andric       Method1->isVariadic() == Method2->isVariadic() &&
217581ad6265SDimitry Andric       Method1->isDirectMethod() == Method2->isDirectMethod();
217681ad6265SDimitry Andric   if (!PropertiesEqual)
217781ad6265SDimitry Andric     return false;
217881ad6265SDimitry Andric 
217981ad6265SDimitry Andric   // Compare selector slot names.
218081ad6265SDimitry Andric   Selector Selector1 = Method1->getSelector(),
218181ad6265SDimitry Andric            Selector2 = Method2->getSelector();
218281ad6265SDimitry Andric   unsigned NumArgs = Selector1.getNumArgs();
218381ad6265SDimitry Andric   if (NumArgs != Selector2.getNumArgs())
218481ad6265SDimitry Andric     return false;
218581ad6265SDimitry Andric   // Compare all selector slots. For selectors with arguments it means all arg
218681ad6265SDimitry Andric   // slots. And if there are no arguments, compare the first-and-only slot.
218781ad6265SDimitry Andric   unsigned SlotsToCheck = NumArgs > 0 ? NumArgs : 1;
218881ad6265SDimitry Andric   for (unsigned I = 0; I < SlotsToCheck; ++I) {
218981ad6265SDimitry Andric     if (!IsStructurallyEquivalent(Selector1.getIdentifierInfoForSlot(I),
219081ad6265SDimitry Andric                                   Selector2.getIdentifierInfoForSlot(I)))
219181ad6265SDimitry Andric       return false;
219281ad6265SDimitry Andric   }
219381ad6265SDimitry Andric 
219481ad6265SDimitry Andric   // Compare types.
219581ad6265SDimitry Andric   if (!IsStructurallyEquivalent(Context, Method1->getReturnType(),
219681ad6265SDimitry Andric                                 Method2->getReturnType()))
219781ad6265SDimitry Andric     return false;
219881ad6265SDimitry Andric   assert(
219981ad6265SDimitry Andric       Method1->param_size() == Method2->param_size() &&
220081ad6265SDimitry Andric       "Same number of arguments should be already enforced in Selector checks");
220181ad6265SDimitry Andric   for (ObjCMethodDecl::param_type_iterator
220281ad6265SDimitry Andric            ParamT1 = Method1->param_type_begin(),
220381ad6265SDimitry Andric            ParamT1End = Method1->param_type_end(),
220481ad6265SDimitry Andric            ParamT2 = Method2->param_type_begin(),
220581ad6265SDimitry Andric            ParamT2End = Method2->param_type_end();
220681ad6265SDimitry Andric        (ParamT1 != ParamT1End) && (ParamT2 != ParamT2End);
220781ad6265SDimitry Andric        ++ParamT1, ++ParamT2) {
220881ad6265SDimitry Andric     if (!IsStructurallyEquivalent(Context, *ParamT1, *ParamT2))
220981ad6265SDimitry Andric       return false;
221081ad6265SDimitry Andric   }
221181ad6265SDimitry Andric 
221281ad6265SDimitry Andric   return true;
221381ad6265SDimitry Andric }
221481ad6265SDimitry Andric 
221581ad6265SDimitry Andric static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
221681ad6265SDimitry Andric                                      ObjCCategoryDecl *D1,
221781ad6265SDimitry Andric                                      ObjCCategoryDecl *D2) {
221881ad6265SDimitry Andric   if (!IsStructurallyEquivalent(D1->getIdentifier(), D2->getIdentifier()))
221981ad6265SDimitry Andric     return false;
222081ad6265SDimitry Andric 
222106c3fb27SDimitry Andric   const ObjCInterfaceDecl *Intf1 = D1->getClassInterface(),
222206c3fb27SDimitry Andric                           *Intf2 = D2->getClassInterface();
222306c3fb27SDimitry Andric   if ((!Intf1 || !Intf2) && (Intf1 != Intf2))
222406c3fb27SDimitry Andric     return false;
222506c3fb27SDimitry Andric 
222606c3fb27SDimitry Andric   if (Intf1 &&
222706c3fb27SDimitry Andric       !IsStructurallyEquivalent(Intf1->getIdentifier(), Intf2->getIdentifier()))
222881ad6265SDimitry Andric     return false;
222981ad6265SDimitry Andric 
223081ad6265SDimitry Andric   // Compare protocols.
223181ad6265SDimitry Andric   ObjCCategoryDecl::protocol_iterator Protocol2 = D2->protocol_begin(),
223281ad6265SDimitry Andric                                       Protocol2End = D2->protocol_end();
223381ad6265SDimitry Andric   for (ObjCCategoryDecl::protocol_iterator Protocol1 = D1->protocol_begin(),
223481ad6265SDimitry Andric                                            Protocol1End = D1->protocol_end();
223581ad6265SDimitry Andric        Protocol1 != Protocol1End; ++Protocol1, ++Protocol2) {
223681ad6265SDimitry Andric     if (Protocol2 == Protocol2End)
223781ad6265SDimitry Andric       return false;
223881ad6265SDimitry Andric     if (!IsStructurallyEquivalent((*Protocol1)->getIdentifier(),
223981ad6265SDimitry Andric                                   (*Protocol2)->getIdentifier()))
224081ad6265SDimitry Andric       return false;
224181ad6265SDimitry Andric   }
224281ad6265SDimitry Andric   if (Protocol2 != Protocol2End)
224381ad6265SDimitry Andric     return false;
224481ad6265SDimitry Andric 
224581ad6265SDimitry Andric   // Compare ivars.
224606c3fb27SDimitry Andric   QualType D2Type =
224706c3fb27SDimitry Andric       Intf2 ? Context.ToCtx.getObjCInterfaceType(Intf2) : QualType();
224881ad6265SDimitry Andric   ObjCCategoryDecl::ivar_iterator Ivar2 = D2->ivar_begin(),
224981ad6265SDimitry Andric                                   Ivar2End = D2->ivar_end();
225081ad6265SDimitry Andric   for (ObjCCategoryDecl::ivar_iterator Ivar1 = D1->ivar_begin(),
225181ad6265SDimitry Andric                                        Ivar1End = D1->ivar_end();
225281ad6265SDimitry Andric        Ivar1 != Ivar1End; ++Ivar1, ++Ivar2) {
225381ad6265SDimitry Andric     if (Ivar2 == Ivar2End)
225481ad6265SDimitry Andric       return false;
225581ad6265SDimitry Andric     if (!IsStructurallyEquivalent(Context, *Ivar1, *Ivar2, D2Type))
225681ad6265SDimitry Andric       return false;
225781ad6265SDimitry Andric   }
225881ad6265SDimitry Andric   if (Ivar2 != Ivar2End)
225981ad6265SDimitry Andric     return false;
226081ad6265SDimitry Andric 
226181ad6265SDimitry Andric   // Compare methods.
226281ad6265SDimitry Andric   ObjCCategoryDecl::method_iterator Method2 = D2->meth_begin(),
226381ad6265SDimitry Andric                                     Method2End = D2->meth_end();
226481ad6265SDimitry Andric   for (ObjCCategoryDecl::method_iterator Method1 = D1->meth_begin(),
226581ad6265SDimitry Andric                                          Method1End = D1->meth_end();
226681ad6265SDimitry Andric        Method1 != Method1End; ++Method1, ++Method2) {
226781ad6265SDimitry Andric     if (Method2 == Method2End)
226881ad6265SDimitry Andric       return false;
226981ad6265SDimitry Andric     if (!IsStructurallyEquivalent(Context, *Method1, *Method2))
227081ad6265SDimitry Andric       return false;
227181ad6265SDimitry Andric   }
227281ad6265SDimitry Andric   if (Method2 != Method2End)
227381ad6265SDimitry Andric     return false;
227481ad6265SDimitry Andric 
227581ad6265SDimitry Andric   return true;
227681ad6265SDimitry Andric }
227781ad6265SDimitry Andric 
22780b57cec5SDimitry Andric /// Determine structural equivalence of two declarations.
22790b57cec5SDimitry Andric static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
22800b57cec5SDimitry Andric                                      Decl *D1, Decl *D2) {
22810b57cec5SDimitry Andric   // FIXME: Check for known structural equivalences via a callback of some sort.
22820b57cec5SDimitry Andric 
2283a7dea167SDimitry Andric   D1 = D1->getCanonicalDecl();
2284a7dea167SDimitry Andric   D2 = D2->getCanonicalDecl();
2285a7dea167SDimitry Andric   std::pair<Decl *, Decl *> P{D1, D2};
2286a7dea167SDimitry Andric 
22870b57cec5SDimitry Andric   // Check whether we already know that these two declarations are not
22880b57cec5SDimitry Andric   // structurally equivalent.
2289a7dea167SDimitry Andric   if (Context.NonEquivalentDecls.count(P))
22900b57cec5SDimitry Andric     return false;
22910b57cec5SDimitry Andric 
2292a7dea167SDimitry Andric   // Check if a check for these declarations is already pending.
2293a7dea167SDimitry Andric   // If yes D1 and D2 will be checked later (from DeclsToCheck),
2294a7dea167SDimitry Andric   // or these are already checked (and equivalent).
2295a7dea167SDimitry Andric   bool Inserted = Context.VisitedDecls.insert(P).second;
2296a7dea167SDimitry Andric   if (!Inserted)
2297a7dea167SDimitry Andric     return true;
22980b57cec5SDimitry Andric 
2299a7dea167SDimitry Andric   Context.DeclsToCheck.push(P);
2300a7dea167SDimitry Andric 
23010b57cec5SDimitry Andric   return true;
23020b57cec5SDimitry Andric }
23030b57cec5SDimitry Andric 
23040b57cec5SDimitry Andric DiagnosticBuilder StructuralEquivalenceContext::Diag1(SourceLocation Loc,
23050b57cec5SDimitry Andric                                                       unsigned DiagID) {
23060b57cec5SDimitry Andric   assert(Complain && "Not allowed to complain");
23070b57cec5SDimitry Andric   if (LastDiagFromC2)
23080b57cec5SDimitry Andric     FromCtx.getDiagnostics().notePriorDiagnosticFrom(ToCtx.getDiagnostics());
23090b57cec5SDimitry Andric   LastDiagFromC2 = false;
23100b57cec5SDimitry Andric   return FromCtx.getDiagnostics().Report(Loc, DiagID);
23110b57cec5SDimitry Andric }
23120b57cec5SDimitry Andric 
23130b57cec5SDimitry Andric DiagnosticBuilder StructuralEquivalenceContext::Diag2(SourceLocation Loc,
23140b57cec5SDimitry Andric                                                       unsigned DiagID) {
23150b57cec5SDimitry Andric   assert(Complain && "Not allowed to complain");
23160b57cec5SDimitry Andric   if (!LastDiagFromC2)
23170b57cec5SDimitry Andric     ToCtx.getDiagnostics().notePriorDiagnosticFrom(FromCtx.getDiagnostics());
23180b57cec5SDimitry Andric   LastDiagFromC2 = true;
23190b57cec5SDimitry Andric   return ToCtx.getDiagnostics().Report(Loc, DiagID);
23200b57cec5SDimitry Andric }
23210b57cec5SDimitry Andric 
2322bdd1243dSDimitry Andric std::optional<unsigned>
23230b57cec5SDimitry Andric StructuralEquivalenceContext::findUntaggedStructOrUnionIndex(RecordDecl *Anon) {
23240b57cec5SDimitry Andric   ASTContext &Context = Anon->getASTContext();
23250b57cec5SDimitry Andric   QualType AnonTy = Context.getRecordType(Anon);
23260b57cec5SDimitry Andric 
23270b57cec5SDimitry Andric   const auto *Owner = dyn_cast<RecordDecl>(Anon->getDeclContext());
23280b57cec5SDimitry Andric   if (!Owner)
2329bdd1243dSDimitry Andric     return std::nullopt;
23300b57cec5SDimitry Andric 
23310b57cec5SDimitry Andric   unsigned Index = 0;
23320b57cec5SDimitry Andric   for (const auto *D : Owner->noload_decls()) {
23330b57cec5SDimitry Andric     const auto *F = dyn_cast<FieldDecl>(D);
23340b57cec5SDimitry Andric     if (!F)
23350b57cec5SDimitry Andric       continue;
23360b57cec5SDimitry Andric 
23370b57cec5SDimitry Andric     if (F->isAnonymousStructOrUnion()) {
23380b57cec5SDimitry Andric       if (Context.hasSameType(F->getType(), AnonTy))
23390b57cec5SDimitry Andric         break;
23400b57cec5SDimitry Andric       ++Index;
23410b57cec5SDimitry Andric       continue;
23420b57cec5SDimitry Andric     }
23430b57cec5SDimitry Andric 
23440b57cec5SDimitry Andric     // If the field looks like this:
23450b57cec5SDimitry Andric     // struct { ... } A;
23460b57cec5SDimitry Andric     QualType FieldType = F->getType();
23470b57cec5SDimitry Andric     // In case of nested structs.
23480b57cec5SDimitry Andric     while (const auto *ElabType = dyn_cast<ElaboratedType>(FieldType))
23490b57cec5SDimitry Andric       FieldType = ElabType->getNamedType();
23500b57cec5SDimitry Andric 
23510b57cec5SDimitry Andric     if (const auto *RecType = dyn_cast<RecordType>(FieldType)) {
23520b57cec5SDimitry Andric       const RecordDecl *RecDecl = RecType->getDecl();
23530b57cec5SDimitry Andric       if (RecDecl->getDeclContext() == Owner && !RecDecl->getIdentifier()) {
23540b57cec5SDimitry Andric         if (Context.hasSameType(FieldType, AnonTy))
23550b57cec5SDimitry Andric           break;
23560b57cec5SDimitry Andric         ++Index;
23570b57cec5SDimitry Andric         continue;
23580b57cec5SDimitry Andric       }
23590b57cec5SDimitry Andric     }
23600b57cec5SDimitry Andric   }
23610b57cec5SDimitry Andric 
23620b57cec5SDimitry Andric   return Index;
23630b57cec5SDimitry Andric }
23640b57cec5SDimitry Andric 
23650b57cec5SDimitry Andric unsigned StructuralEquivalenceContext::getApplicableDiagnostic(
23660b57cec5SDimitry Andric     unsigned ErrorDiagnostic) {
23670b57cec5SDimitry Andric   if (ErrorOnTagTypeMismatch)
23680b57cec5SDimitry Andric     return ErrorDiagnostic;
23690b57cec5SDimitry Andric 
23700b57cec5SDimitry Andric   switch (ErrorDiagnostic) {
23710b57cec5SDimitry Andric   case diag::err_odr_variable_type_inconsistent:
23720b57cec5SDimitry Andric     return diag::warn_odr_variable_type_inconsistent;
23730b57cec5SDimitry Andric   case diag::err_odr_variable_multiple_def:
23740b57cec5SDimitry Andric     return diag::warn_odr_variable_multiple_def;
23750b57cec5SDimitry Andric   case diag::err_odr_function_type_inconsistent:
23760b57cec5SDimitry Andric     return diag::warn_odr_function_type_inconsistent;
23770b57cec5SDimitry Andric   case diag::err_odr_tag_type_inconsistent:
23780b57cec5SDimitry Andric     return diag::warn_odr_tag_type_inconsistent;
23790b57cec5SDimitry Andric   case diag::err_odr_field_type_inconsistent:
23800b57cec5SDimitry Andric     return diag::warn_odr_field_type_inconsistent;
23810b57cec5SDimitry Andric   case diag::err_odr_ivar_type_inconsistent:
23820b57cec5SDimitry Andric     return diag::warn_odr_ivar_type_inconsistent;
23830b57cec5SDimitry Andric   case diag::err_odr_objc_superclass_inconsistent:
23840b57cec5SDimitry Andric     return diag::warn_odr_objc_superclass_inconsistent;
23850b57cec5SDimitry Andric   case diag::err_odr_objc_method_result_type_inconsistent:
23860b57cec5SDimitry Andric     return diag::warn_odr_objc_method_result_type_inconsistent;
23870b57cec5SDimitry Andric   case diag::err_odr_objc_method_num_params_inconsistent:
23880b57cec5SDimitry Andric     return diag::warn_odr_objc_method_num_params_inconsistent;
23890b57cec5SDimitry Andric   case diag::err_odr_objc_method_param_type_inconsistent:
23900b57cec5SDimitry Andric     return diag::warn_odr_objc_method_param_type_inconsistent;
23910b57cec5SDimitry Andric   case diag::err_odr_objc_method_variadic_inconsistent:
23920b57cec5SDimitry Andric     return diag::warn_odr_objc_method_variadic_inconsistent;
23930b57cec5SDimitry Andric   case diag::err_odr_objc_property_type_inconsistent:
23940b57cec5SDimitry Andric     return diag::warn_odr_objc_property_type_inconsistent;
23950b57cec5SDimitry Andric   case diag::err_odr_objc_property_impl_kind_inconsistent:
23960b57cec5SDimitry Andric     return diag::warn_odr_objc_property_impl_kind_inconsistent;
23970b57cec5SDimitry Andric   case diag::err_odr_objc_synthesize_ivar_inconsistent:
23980b57cec5SDimitry Andric     return diag::warn_odr_objc_synthesize_ivar_inconsistent;
23990b57cec5SDimitry Andric   case diag::err_odr_different_num_template_parameters:
24000b57cec5SDimitry Andric     return diag::warn_odr_different_num_template_parameters;
24010b57cec5SDimitry Andric   case diag::err_odr_different_template_parameter_kind:
24020b57cec5SDimitry Andric     return diag::warn_odr_different_template_parameter_kind;
24030b57cec5SDimitry Andric   case diag::err_odr_parameter_pack_non_pack:
24040b57cec5SDimitry Andric     return diag::warn_odr_parameter_pack_non_pack;
24050b57cec5SDimitry Andric   case diag::err_odr_non_type_parameter_type_inconsistent:
24060b57cec5SDimitry Andric     return diag::warn_odr_non_type_parameter_type_inconsistent;
24070b57cec5SDimitry Andric   }
24080b57cec5SDimitry Andric   llvm_unreachable("Diagnostic kind not handled in preceding switch");
24090b57cec5SDimitry Andric }
24100b57cec5SDimitry Andric 
24110b57cec5SDimitry Andric bool StructuralEquivalenceContext::IsEquivalent(Decl *D1, Decl *D2) {
24120b57cec5SDimitry Andric 
24130b57cec5SDimitry Andric   // Ensure that the implementation functions (all static functions in this TU)
24140b57cec5SDimitry Andric   // never call the public ASTStructuralEquivalence::IsEquivalent() functions,
24150b57cec5SDimitry Andric   // because that will wreak havoc the internal state (DeclsToCheck and
2416a7dea167SDimitry Andric   // VisitedDecls members) and can cause faulty behaviour.
2417a7dea167SDimitry Andric   // In other words: Do not start a graph search from a new node with the
2418a7dea167SDimitry Andric   // internal data of another search in progress.
2419a7dea167SDimitry Andric   // FIXME: Better encapsulation and separation of internal and public
2420a7dea167SDimitry Andric   // functionality.
24210b57cec5SDimitry Andric   assert(DeclsToCheck.empty());
2422a7dea167SDimitry Andric   assert(VisitedDecls.empty());
24230b57cec5SDimitry Andric 
24240b57cec5SDimitry Andric   if (!::IsStructurallyEquivalent(*this, D1, D2))
24250b57cec5SDimitry Andric     return false;
24260b57cec5SDimitry Andric 
24270b57cec5SDimitry Andric   return !Finish();
24280b57cec5SDimitry Andric }
24290b57cec5SDimitry Andric 
24300b57cec5SDimitry Andric bool StructuralEquivalenceContext::IsEquivalent(QualType T1, QualType T2) {
24310b57cec5SDimitry Andric   assert(DeclsToCheck.empty());
2432a7dea167SDimitry Andric   assert(VisitedDecls.empty());
24330b57cec5SDimitry Andric   if (!::IsStructurallyEquivalent(*this, T1, T2))
24340b57cec5SDimitry Andric     return false;
24350b57cec5SDimitry Andric 
24360b57cec5SDimitry Andric   return !Finish();
24370b57cec5SDimitry Andric }
24380b57cec5SDimitry Andric 
2439e8d8bef9SDimitry Andric bool StructuralEquivalenceContext::IsEquivalent(Stmt *S1, Stmt *S2) {
2440e8d8bef9SDimitry Andric   assert(DeclsToCheck.empty());
2441e8d8bef9SDimitry Andric   assert(VisitedDecls.empty());
2442e8d8bef9SDimitry Andric   if (!::IsStructurallyEquivalent(*this, S1, S2))
2443e8d8bef9SDimitry Andric     return false;
2444e8d8bef9SDimitry Andric 
2445e8d8bef9SDimitry Andric   return !Finish();
2446e8d8bef9SDimitry Andric }
2447e8d8bef9SDimitry Andric 
24480b57cec5SDimitry Andric bool StructuralEquivalenceContext::CheckCommonEquivalence(Decl *D1, Decl *D2) {
24490b57cec5SDimitry Andric   // Check for equivalent described template.
24500b57cec5SDimitry Andric   TemplateDecl *Template1 = D1->getDescribedTemplate();
24510b57cec5SDimitry Andric   TemplateDecl *Template2 = D2->getDescribedTemplate();
24520b57cec5SDimitry Andric   if ((Template1 != nullptr) != (Template2 != nullptr))
24530b57cec5SDimitry Andric     return false;
24540b57cec5SDimitry Andric   if (Template1 && !IsStructurallyEquivalent(*this, Template1, Template2))
24550b57cec5SDimitry Andric     return false;
24560b57cec5SDimitry Andric 
24570b57cec5SDimitry Andric   // FIXME: Move check for identifier names into this function.
24580b57cec5SDimitry Andric 
24590b57cec5SDimitry Andric   return true;
24600b57cec5SDimitry Andric }
24610b57cec5SDimitry Andric 
24620b57cec5SDimitry Andric bool StructuralEquivalenceContext::CheckKindSpecificEquivalence(
24630b57cec5SDimitry Andric     Decl *D1, Decl *D2) {
24640b57cec5SDimitry Andric 
2465e8d8bef9SDimitry Andric   // Kind mismatch.
2466e8d8bef9SDimitry Andric   if (D1->getKind() != D2->getKind())
2467e8d8bef9SDimitry Andric     return false;
2468e8d8bef9SDimitry Andric 
2469e8d8bef9SDimitry Andric   // Cast the Decls to their actual subclass so that the right overload of
2470e8d8bef9SDimitry Andric   // IsStructurallyEquivalent is called.
2471e8d8bef9SDimitry Andric   switch (D1->getKind()) {
2472e8d8bef9SDimitry Andric #define ABSTRACT_DECL(DECL)
2473e8d8bef9SDimitry Andric #define DECL(DERIVED, BASE)                                                    \
2474e8d8bef9SDimitry Andric   case Decl::Kind::DERIVED:                                                    \
2475e8d8bef9SDimitry Andric     return ::IsStructurallyEquivalent(*this, static_cast<DERIVED##Decl *>(D1), \
2476e8d8bef9SDimitry Andric                                       static_cast<DERIVED##Decl *>(D2));
2477e8d8bef9SDimitry Andric #include "clang/AST/DeclNodes.inc"
2478e8d8bef9SDimitry Andric   }
24790b57cec5SDimitry Andric   return true;
24800b57cec5SDimitry Andric }
24810b57cec5SDimitry Andric 
24820b57cec5SDimitry Andric bool StructuralEquivalenceContext::Finish() {
24830b57cec5SDimitry Andric   while (!DeclsToCheck.empty()) {
24840b57cec5SDimitry Andric     // Check the next declaration.
2485a7dea167SDimitry Andric     std::pair<Decl *, Decl *> P = DeclsToCheck.front();
2486a7dea167SDimitry Andric     DeclsToCheck.pop();
24870b57cec5SDimitry Andric 
2488a7dea167SDimitry Andric     Decl *D1 = P.first;
2489a7dea167SDimitry Andric     Decl *D2 = P.second;
24900b57cec5SDimitry Andric 
24910b57cec5SDimitry Andric     bool Equivalent =
24920b57cec5SDimitry Andric         CheckCommonEquivalence(D1, D2) && CheckKindSpecificEquivalence(D1, D2);
24930b57cec5SDimitry Andric 
24940b57cec5SDimitry Andric     if (!Equivalent) {
24950b57cec5SDimitry Andric       // Note that these two declarations are not equivalent (and we already
24960b57cec5SDimitry Andric       // know about it).
2497a7dea167SDimitry Andric       NonEquivalentDecls.insert(P);
2498a7dea167SDimitry Andric 
24990b57cec5SDimitry Andric       return true;
25000b57cec5SDimitry Andric     }
25010b57cec5SDimitry Andric   }
25020b57cec5SDimitry Andric 
25030b57cec5SDimitry Andric   return false;
25040b57cec5SDimitry Andric }
2505