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