Path: blob/main/contrib/llvm-project/clang/lib/AST/ASTStructuralEquivalence.cpp
35259 views
//===- ASTStructuralEquivalence.cpp ---------------------------------------===//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//7//8// This file implement StructuralEquivalenceContext class and helper functions9// for layout matching.10//11// The structural equivalence check could have been implemented as a parallel12// BFS on a pair of graphs. That must have been the original approach at the13// beginning.14// Let's consider this simple BFS algorithm from the `s` source:15// ```16// void bfs(Graph G, int s)17// {18// Queue<Integer> queue = new Queue<Integer>();19// marked[s] = true; // Mark the source20// queue.enqueue(s); // and put it on the queue.21// while (!q.isEmpty()) {22// int v = queue.dequeue(); // Remove next vertex from the queue.23// for (int w : G.adj(v))24// if (!marked[w]) // For every unmarked adjacent vertex,25// {26// marked[w] = true;27// queue.enqueue(w);28// }29// }30// }31// ```32// Indeed, it has it's queue, which holds pairs of nodes, one from each graph,33// this is the `DeclsToCheck` member. `VisitedDecls` plays the role of the34// marking (`marked`) functionality above, we use it to check whether we've35// already seen a pair of nodes.36//37// We put in the elements into the queue only in the toplevel decl check38// function:39// ```40// static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,41// Decl *D1, Decl *D2);42// ```43// The `while` loop where we iterate over the children is implemented in44// `Finish()`. And `Finish` is called only from the two **member** functions45// which check the equivalency of two Decls or two Types. ASTImporter (and46// other clients) call only these functions.47//48// The `static` implementation functions are called from `Finish`, these push49// the children nodes to the queue via `static bool50// IsStructurallyEquivalent(StructuralEquivalenceContext &Context, Decl *D1,51// Decl *D2)`. So far so good, this is almost like the BFS. However, if we52// let a static implementation function to call `Finish` via another **member**53// function that means we end up with two nested while loops each of them54// working on the same queue. This is wrong and nobody can reason about it's55// doing. Thus, static implementation functions must not call the **member**56// functions.57//58//===----------------------------------------------------------------------===//5960#include "clang/AST/ASTStructuralEquivalence.h"61#include "clang/AST/ASTContext.h"62#include "clang/AST/ASTDiagnostic.h"63#include "clang/AST/Decl.h"64#include "clang/AST/DeclBase.h"65#include "clang/AST/DeclCXX.h"66#include "clang/AST/DeclFriend.h"67#include "clang/AST/DeclObjC.h"68#include "clang/AST/DeclOpenMP.h"69#include "clang/AST/DeclTemplate.h"70#include "clang/AST/ExprCXX.h"71#include "clang/AST/ExprConcepts.h"72#include "clang/AST/ExprObjC.h"73#include "clang/AST/ExprOpenMP.h"74#include "clang/AST/NestedNameSpecifier.h"75#include "clang/AST/StmtObjC.h"76#include "clang/AST/StmtOpenACC.h"77#include "clang/AST/StmtOpenMP.h"78#include "clang/AST/TemplateBase.h"79#include "clang/AST/TemplateName.h"80#include "clang/AST/Type.h"81#include "clang/Basic/ExceptionSpecificationType.h"82#include "clang/Basic/IdentifierTable.h"83#include "clang/Basic/LLVM.h"84#include "clang/Basic/SourceLocation.h"85#include "llvm/ADT/APInt.h"86#include "llvm/ADT/APSInt.h"87#include "llvm/ADT/StringExtras.h"88#include "llvm/Support/Casting.h"89#include "llvm/Support/Compiler.h"90#include "llvm/Support/ErrorHandling.h"91#include <cassert>92#include <optional>93#include <utility>9495using namespace clang;9697static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,98QualType T1, QualType T2);99static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,100Decl *D1, Decl *D2);101static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,102const Stmt *S1, const Stmt *S2);103static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,104const TemplateArgument &Arg1,105const TemplateArgument &Arg2);106static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,107const TemplateArgumentLoc &Arg1,108const TemplateArgumentLoc &Arg2);109static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,110NestedNameSpecifier *NNS1,111NestedNameSpecifier *NNS2);112static bool IsStructurallyEquivalent(const IdentifierInfo *Name1,113const IdentifierInfo *Name2);114115static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,116const DeclarationName Name1,117const DeclarationName Name2) {118if (Name1.getNameKind() != Name2.getNameKind())119return false;120121switch (Name1.getNameKind()) {122123case DeclarationName::Identifier:124return IsStructurallyEquivalent(Name1.getAsIdentifierInfo(),125Name2.getAsIdentifierInfo());126127case DeclarationName::CXXConstructorName:128case DeclarationName::CXXDestructorName:129case DeclarationName::CXXConversionFunctionName:130return IsStructurallyEquivalent(Context, Name1.getCXXNameType(),131Name2.getCXXNameType());132133case DeclarationName::CXXDeductionGuideName: {134if (!IsStructurallyEquivalent(135Context, Name1.getCXXDeductionGuideTemplate()->getDeclName(),136Name2.getCXXDeductionGuideTemplate()->getDeclName()))137return false;138return IsStructurallyEquivalent(Context,139Name1.getCXXDeductionGuideTemplate(),140Name2.getCXXDeductionGuideTemplate());141}142143case DeclarationName::CXXOperatorName:144return Name1.getCXXOverloadedOperator() == Name2.getCXXOverloadedOperator();145146case DeclarationName::CXXLiteralOperatorName:147return IsStructurallyEquivalent(Name1.getCXXLiteralIdentifier(),148Name2.getCXXLiteralIdentifier());149150case DeclarationName::CXXUsingDirective:151return true; // FIXME When do we consider two using directives equal?152153case DeclarationName::ObjCZeroArgSelector:154case DeclarationName::ObjCOneArgSelector:155case DeclarationName::ObjCMultiArgSelector:156return true; // FIXME157}158159llvm_unreachable("Unhandled kind of DeclarationName");160return true;161}162163namespace {164/// Encapsulates Stmt comparison logic.165class StmtComparer {166StructuralEquivalenceContext &Context;167168// IsStmtEquivalent overloads. Each overload compares a specific statement169// and only has to compare the data that is specific to the specific statement170// class. Should only be called from TraverseStmt.171172bool IsStmtEquivalent(const AddrLabelExpr *E1, const AddrLabelExpr *E2) {173return IsStructurallyEquivalent(Context, E1->getLabel(), E2->getLabel());174}175176bool IsStmtEquivalent(const AtomicExpr *E1, const AtomicExpr *E2) {177return E1->getOp() == E2->getOp();178}179180bool IsStmtEquivalent(const BinaryOperator *E1, const BinaryOperator *E2) {181return E1->getOpcode() == E2->getOpcode();182}183184bool IsStmtEquivalent(const CallExpr *E1, const CallExpr *E2) {185// FIXME: IsStructurallyEquivalent requires non-const Decls.186Decl *Callee1 = const_cast<Decl *>(E1->getCalleeDecl());187Decl *Callee2 = const_cast<Decl *>(E2->getCalleeDecl());188189// Compare whether both calls know their callee.190if (static_cast<bool>(Callee1) != static_cast<bool>(Callee2))191return false;192193// Both calls have no callee, so nothing to do.194if (!static_cast<bool>(Callee1))195return true;196197assert(Callee2);198return IsStructurallyEquivalent(Context, Callee1, Callee2);199}200201bool IsStmtEquivalent(const CharacterLiteral *E1,202const CharacterLiteral *E2) {203return E1->getValue() == E2->getValue() && E1->getKind() == E2->getKind();204}205206bool IsStmtEquivalent(const ChooseExpr *E1, const ChooseExpr *E2) {207return true; // Semantics only depend on children.208}209210bool IsStmtEquivalent(const CompoundStmt *E1, const CompoundStmt *E2) {211// Number of children is actually checked by the generic children comparison212// code, but a CompoundStmt is one of the few statements where the number of213// children frequently differs and the number of statements is also always214// precomputed. Directly comparing the number of children here is thus215// just an optimization.216return E1->size() == E2->size();217}218219bool IsStmtEquivalent(const DeclRefExpr *DRE1, const DeclRefExpr *DRE2) {220const ValueDecl *Decl1 = DRE1->getDecl();221const ValueDecl *Decl2 = DRE2->getDecl();222if (!Decl1 || !Decl2)223return false;224return IsStructurallyEquivalent(Context, const_cast<ValueDecl *>(Decl1),225const_cast<ValueDecl *>(Decl2));226}227228bool IsStmtEquivalent(const DependentScopeDeclRefExpr *DE1,229const DependentScopeDeclRefExpr *DE2) {230if (!IsStructurallyEquivalent(Context, DE1->getDeclName(),231DE2->getDeclName()))232return false;233return IsStructurallyEquivalent(Context, DE1->getQualifier(),234DE2->getQualifier());235}236237bool IsStmtEquivalent(const Expr *E1, const Expr *E2) {238return IsStructurallyEquivalent(Context, E1->getType(), E2->getType());239}240241bool IsStmtEquivalent(const ExpressionTraitExpr *E1,242const ExpressionTraitExpr *E2) {243return E1->getTrait() == E2->getTrait() && E1->getValue() == E2->getValue();244}245246bool IsStmtEquivalent(const FloatingLiteral *E1, const FloatingLiteral *E2) {247return E1->isExact() == E2->isExact() && E1->getValue() == E2->getValue();248}249250bool IsStmtEquivalent(const GenericSelectionExpr *E1,251const GenericSelectionExpr *E2) {252for (auto Pair : zip_longest(E1->getAssocTypeSourceInfos(),253E2->getAssocTypeSourceInfos())) {254std::optional<TypeSourceInfo *> Child1 = std::get<0>(Pair);255std::optional<TypeSourceInfo *> Child2 = std::get<1>(Pair);256// Skip this case if there are a different number of associated types.257if (!Child1 || !Child2)258return false;259260if (!IsStructurallyEquivalent(Context, (*Child1)->getType(),261(*Child2)->getType()))262return false;263}264265return true;266}267268bool IsStmtEquivalent(const ImplicitCastExpr *CastE1,269const ImplicitCastExpr *CastE2) {270return IsStructurallyEquivalent(Context, CastE1->getType(),271CastE2->getType());272}273274bool IsStmtEquivalent(const IntegerLiteral *E1, const IntegerLiteral *E2) {275return E1->getValue() == E2->getValue();276}277278bool IsStmtEquivalent(const MemberExpr *E1, const MemberExpr *E2) {279return IsStructurallyEquivalent(Context, E1->getFoundDecl(),280E2->getFoundDecl());281}282283bool IsStmtEquivalent(const ObjCStringLiteral *E1,284const ObjCStringLiteral *E2) {285// Just wraps a StringLiteral child.286return true;287}288289bool IsStmtEquivalent(const Stmt *S1, const Stmt *S2) { return true; }290291bool IsStmtEquivalent(const GotoStmt *S1, const GotoStmt *S2) {292LabelDecl *L1 = S1->getLabel();293LabelDecl *L2 = S2->getLabel();294if (!L1 || !L2)295return L1 == L2;296297IdentifierInfo *Name1 = L1->getIdentifier();298IdentifierInfo *Name2 = L2->getIdentifier();299return ::IsStructurallyEquivalent(Name1, Name2);300}301302bool IsStmtEquivalent(const SourceLocExpr *E1, const SourceLocExpr *E2) {303return E1->getIdentKind() == E2->getIdentKind();304}305306bool IsStmtEquivalent(const StmtExpr *E1, const StmtExpr *E2) {307return E1->getTemplateDepth() == E2->getTemplateDepth();308}309310bool IsStmtEquivalent(const StringLiteral *E1, const StringLiteral *E2) {311return E1->getBytes() == E2->getBytes();312}313314bool IsStmtEquivalent(const SubstNonTypeTemplateParmExpr *E1,315const SubstNonTypeTemplateParmExpr *E2) {316if (!IsStructurallyEquivalent(Context, E1->getAssociatedDecl(),317E2->getAssociatedDecl()))318return false;319if (E1->getIndex() != E2->getIndex())320return false;321if (E1->getPackIndex() != E2->getPackIndex())322return false;323return true;324}325326bool IsStmtEquivalent(const SubstNonTypeTemplateParmPackExpr *E1,327const SubstNonTypeTemplateParmPackExpr *E2) {328return IsStructurallyEquivalent(Context, E1->getArgumentPack(),329E2->getArgumentPack());330}331332bool IsStmtEquivalent(const TypeTraitExpr *E1, const TypeTraitExpr *E2) {333if (E1->getTrait() != E2->getTrait())334return false;335336for (auto Pair : zip_longest(E1->getArgs(), E2->getArgs())) {337std::optional<TypeSourceInfo *> Child1 = std::get<0>(Pair);338std::optional<TypeSourceInfo *> Child2 = std::get<1>(Pair);339// Different number of args.340if (!Child1 || !Child2)341return false;342343if (!IsStructurallyEquivalent(Context, (*Child1)->getType(),344(*Child2)->getType()))345return false;346}347return true;348}349350bool IsStmtEquivalent(const CXXDependentScopeMemberExpr *E1,351const CXXDependentScopeMemberExpr *E2) {352if (!IsStructurallyEquivalent(Context, E1->getMember(), E2->getMember())) {353return false;354}355return IsStructurallyEquivalent(Context, E1->getBaseType(),356E2->getBaseType());357}358359bool IsStmtEquivalent(const UnaryExprOrTypeTraitExpr *E1,360const UnaryExprOrTypeTraitExpr *E2) {361if (E1->getKind() != E2->getKind())362return false;363return IsStructurallyEquivalent(Context, E1->getTypeOfArgument(),364E2->getTypeOfArgument());365}366367bool IsStmtEquivalent(const UnaryOperator *E1, const UnaryOperator *E2) {368return E1->getOpcode() == E2->getOpcode();369}370371bool IsStmtEquivalent(const VAArgExpr *E1, const VAArgExpr *E2) {372// Semantics only depend on children.373return true;374}375376bool IsStmtEquivalent(const OverloadExpr *E1, const OverloadExpr *E2) {377if (!IsStructurallyEquivalent(Context, E1->getName(), E2->getName()))378return false;379380if (static_cast<bool>(E1->getQualifier()) !=381static_cast<bool>(E2->getQualifier()))382return false;383if (E1->getQualifier() &&384!IsStructurallyEquivalent(Context, E1->getQualifier(),385E2->getQualifier()))386return false;387388if (E1->getNumTemplateArgs() != E2->getNumTemplateArgs())389return false;390const TemplateArgumentLoc *Args1 = E1->getTemplateArgs();391const TemplateArgumentLoc *Args2 = E2->getTemplateArgs();392for (unsigned int ArgI = 0, ArgN = E1->getNumTemplateArgs(); ArgI < ArgN;393++ArgI)394if (!IsStructurallyEquivalent(Context, Args1[ArgI], Args2[ArgI]))395return false;396397return true;398}399400bool IsStmtEquivalent(const CXXBoolLiteralExpr *E1, const CXXBoolLiteralExpr *E2) {401return E1->getValue() == E2->getValue();402}403404/// End point of the traversal chain.405bool TraverseStmt(const Stmt *S1, const Stmt *S2) { return true; }406407// Create traversal methods that traverse the class hierarchy and return408// the accumulated result of the comparison. Each TraverseStmt overload409// calls the TraverseStmt overload of the parent class. For example,410// the TraverseStmt overload for 'BinaryOperator' calls the TraverseStmt411// overload of 'Expr' which then calls the overload for 'Stmt'.412#define STMT(CLASS, PARENT) \413bool TraverseStmt(const CLASS *S1, const CLASS *S2) { \414if (!TraverseStmt(static_cast<const PARENT *>(S1), \415static_cast<const PARENT *>(S2))) \416return false; \417return IsStmtEquivalent(S1, S2); \418}419#include "clang/AST/StmtNodes.inc"420421public:422StmtComparer(StructuralEquivalenceContext &C) : Context(C) {}423424/// Determine whether two statements are equivalent. The statements have to425/// be of the same kind. The children of the statements and their properties426/// are not compared by this function.427bool IsEquivalent(const Stmt *S1, const Stmt *S2) {428if (S1->getStmtClass() != S2->getStmtClass())429return false;430431// Each TraverseStmt walks the class hierarchy from the leaf class to432// the root class 'Stmt' (e.g. 'BinaryOperator' -> 'Expr' -> 'Stmt'). Cast433// the Stmt we have here to its specific subclass so that we call the434// overload that walks the whole class hierarchy from leaf to root (e.g.,435// cast to 'BinaryOperator' so that 'Expr' and 'Stmt' is traversed).436switch (S1->getStmtClass()) {437case Stmt::NoStmtClass:438llvm_unreachable("Can't traverse NoStmtClass");439#define STMT(CLASS, PARENT) \440case Stmt::StmtClass::CLASS##Class: \441return TraverseStmt(static_cast<const CLASS *>(S1), \442static_cast<const CLASS *>(S2));443#define ABSTRACT_STMT(S)444#include "clang/AST/StmtNodes.inc"445}446llvm_unreachable("Invalid statement kind");447}448};449} // namespace450451static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,452const UnaryOperator *E1,453const CXXOperatorCallExpr *E2) {454return UnaryOperator::getOverloadedOperator(E1->getOpcode()) ==455E2->getOperator() &&456IsStructurallyEquivalent(Context, E1->getSubExpr(), E2->getArg(0));457}458459static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,460const CXXOperatorCallExpr *E1,461const UnaryOperator *E2) {462return E1->getOperator() ==463UnaryOperator::getOverloadedOperator(E2->getOpcode()) &&464IsStructurallyEquivalent(Context, E1->getArg(0), E2->getSubExpr());465}466467static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,468const BinaryOperator *E1,469const CXXOperatorCallExpr *E2) {470return BinaryOperator::getOverloadedOperator(E1->getOpcode()) ==471E2->getOperator() &&472IsStructurallyEquivalent(Context, E1->getLHS(), E2->getArg(0)) &&473IsStructurallyEquivalent(Context, E1->getRHS(), E2->getArg(1));474}475476static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,477const CXXOperatorCallExpr *E1,478const BinaryOperator *E2) {479return E1->getOperator() ==480BinaryOperator::getOverloadedOperator(E2->getOpcode()) &&481IsStructurallyEquivalent(Context, E1->getArg(0), E2->getLHS()) &&482IsStructurallyEquivalent(Context, E1->getArg(1), E2->getRHS());483}484485/// Determine structural equivalence of two statements.486static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,487const Stmt *S1, const Stmt *S2) {488if (!S1 || !S2)489return S1 == S2;490491// Check for statements with similar syntax but different AST.492// A UnaryOperator node is more lightweight than a CXXOperatorCallExpr node.493// The more heavyweight node is only created if the definition-time name494// lookup had any results. The lookup results are stored CXXOperatorCallExpr495// only. The lookup results can be different in a "From" and "To" AST even if496// the compared structure is otherwise equivalent. For this reason we must497// treat a similar unary/binary operator node and CXXOperatorCall node as498// equivalent.499if (const auto *E2CXXOperatorCall = dyn_cast<CXXOperatorCallExpr>(S2)) {500if (const auto *E1Unary = dyn_cast<UnaryOperator>(S1))501return IsStructurallyEquivalent(Context, E1Unary, E2CXXOperatorCall);502if (const auto *E1Binary = dyn_cast<BinaryOperator>(S1))503return IsStructurallyEquivalent(Context, E1Binary, E2CXXOperatorCall);504}505if (const auto *E1CXXOperatorCall = dyn_cast<CXXOperatorCallExpr>(S1)) {506if (const auto *E2Unary = dyn_cast<UnaryOperator>(S2))507return IsStructurallyEquivalent(Context, E1CXXOperatorCall, E2Unary);508if (const auto *E2Binary = dyn_cast<BinaryOperator>(S2))509return IsStructurallyEquivalent(Context, E1CXXOperatorCall, E2Binary);510}511512// Compare the statements itself.513StmtComparer Comparer(Context);514if (!Comparer.IsEquivalent(S1, S2))515return false;516517// Iterate over the children of both statements and also compare them.518for (auto Pair : zip_longest(S1->children(), S2->children())) {519std::optional<const Stmt *> Child1 = std::get<0>(Pair);520std::optional<const Stmt *> Child2 = std::get<1>(Pair);521// One of the statements has a different amount of children than the other,522// so the statements can't be equivalent.523if (!Child1 || !Child2)524return false;525if (!IsStructurallyEquivalent(Context, *Child1, *Child2))526return false;527}528return true;529}530531/// Determine whether two identifiers are equivalent.532static bool IsStructurallyEquivalent(const IdentifierInfo *Name1,533const IdentifierInfo *Name2) {534if (!Name1 || !Name2)535return Name1 == Name2;536537return Name1->getName() == Name2->getName();538}539540/// Determine whether two nested-name-specifiers are equivalent.541static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,542NestedNameSpecifier *NNS1,543NestedNameSpecifier *NNS2) {544if (NNS1->getKind() != NNS2->getKind())545return false;546547NestedNameSpecifier *Prefix1 = NNS1->getPrefix(),548*Prefix2 = NNS2->getPrefix();549if ((bool)Prefix1 != (bool)Prefix2)550return false;551552if (Prefix1)553if (!IsStructurallyEquivalent(Context, Prefix1, Prefix2))554return false;555556switch (NNS1->getKind()) {557case NestedNameSpecifier::Identifier:558return IsStructurallyEquivalent(NNS1->getAsIdentifier(),559NNS2->getAsIdentifier());560case NestedNameSpecifier::Namespace:561return IsStructurallyEquivalent(Context, NNS1->getAsNamespace(),562NNS2->getAsNamespace());563case NestedNameSpecifier::NamespaceAlias:564return IsStructurallyEquivalent(Context, NNS1->getAsNamespaceAlias(),565NNS2->getAsNamespaceAlias());566case NestedNameSpecifier::TypeSpec:567case NestedNameSpecifier::TypeSpecWithTemplate:568return IsStructurallyEquivalent(Context, QualType(NNS1->getAsType(), 0),569QualType(NNS2->getAsType(), 0));570case NestedNameSpecifier::Global:571return true;572case NestedNameSpecifier::Super:573return IsStructurallyEquivalent(Context, NNS1->getAsRecordDecl(),574NNS2->getAsRecordDecl());575}576return false;577}578579static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,580const TemplateName &N1,581const TemplateName &N2) {582TemplateDecl *TemplateDeclN1 = N1.getAsTemplateDecl();583TemplateDecl *TemplateDeclN2 = N2.getAsTemplateDecl();584if (TemplateDeclN1 && TemplateDeclN2) {585if (!IsStructurallyEquivalent(Context, TemplateDeclN1, TemplateDeclN2))586return false;587// If the kind is different we compare only the template decl.588if (N1.getKind() != N2.getKind())589return true;590} else if (TemplateDeclN1 || TemplateDeclN2)591return false;592else if (N1.getKind() != N2.getKind())593return false;594595// Check for special case incompatibilities.596switch (N1.getKind()) {597598case TemplateName::OverloadedTemplate: {599OverloadedTemplateStorage *OS1 = N1.getAsOverloadedTemplate(),600*OS2 = N2.getAsOverloadedTemplate();601OverloadedTemplateStorage::iterator I1 = OS1->begin(), I2 = OS2->begin(),602E1 = OS1->end(), E2 = OS2->end();603for (; I1 != E1 && I2 != E2; ++I1, ++I2)604if (!IsStructurallyEquivalent(Context, *I1, *I2))605return false;606return I1 == E1 && I2 == E2;607}608609case TemplateName::AssumedTemplate: {610AssumedTemplateStorage *TN1 = N1.getAsAssumedTemplateName(),611*TN2 = N1.getAsAssumedTemplateName();612return TN1->getDeclName() == TN2->getDeclName();613}614615case TemplateName::DependentTemplate: {616DependentTemplateName *DN1 = N1.getAsDependentTemplateName(),617*DN2 = N2.getAsDependentTemplateName();618if (!IsStructurallyEquivalent(Context, DN1->getQualifier(),619DN2->getQualifier()))620return false;621if (DN1->isIdentifier() && DN2->isIdentifier())622return IsStructurallyEquivalent(DN1->getIdentifier(),623DN2->getIdentifier());624else if (DN1->isOverloadedOperator() && DN2->isOverloadedOperator())625return DN1->getOperator() == DN2->getOperator();626return false;627}628629case TemplateName::SubstTemplateTemplateParmPack: {630SubstTemplateTemplateParmPackStorage631*P1 = N1.getAsSubstTemplateTemplateParmPack(),632*P2 = N2.getAsSubstTemplateTemplateParmPack();633return IsStructurallyEquivalent(Context, P1->getArgumentPack(),634P2->getArgumentPack()) &&635IsStructurallyEquivalent(Context, P1->getAssociatedDecl(),636P2->getAssociatedDecl()) &&637P1->getIndex() == P2->getIndex();638}639640case TemplateName::Template:641case TemplateName::QualifiedTemplate:642case TemplateName::SubstTemplateTemplateParm:643case TemplateName::UsingTemplate:644// It is sufficient to check value of getAsTemplateDecl.645break;646647}648649return true;650}651652static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,653ArrayRef<TemplateArgument> Args1,654ArrayRef<TemplateArgument> Args2);655656/// Determine whether two template arguments are equivalent.657static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,658const TemplateArgument &Arg1,659const TemplateArgument &Arg2) {660if (Arg1.getKind() != Arg2.getKind())661return false;662663switch (Arg1.getKind()) {664case TemplateArgument::Null:665return true;666667case TemplateArgument::Type:668return IsStructurallyEquivalent(Context, Arg1.getAsType(), Arg2.getAsType());669670case TemplateArgument::Integral:671if (!IsStructurallyEquivalent(Context, Arg1.getIntegralType(),672Arg2.getIntegralType()))673return false;674675return llvm::APSInt::isSameValue(Arg1.getAsIntegral(),676Arg2.getAsIntegral());677678case TemplateArgument::Declaration:679return IsStructurallyEquivalent(Context, Arg1.getAsDecl(), Arg2.getAsDecl());680681case TemplateArgument::NullPtr:682return true; // FIXME: Is this correct?683684case TemplateArgument::Template:685return IsStructurallyEquivalent(Context, Arg1.getAsTemplate(),686Arg2.getAsTemplate());687688case TemplateArgument::TemplateExpansion:689return IsStructurallyEquivalent(Context,690Arg1.getAsTemplateOrTemplatePattern(),691Arg2.getAsTemplateOrTemplatePattern());692693case TemplateArgument::Expression:694return IsStructurallyEquivalent(Context, Arg1.getAsExpr(),695Arg2.getAsExpr());696697case TemplateArgument::StructuralValue:698return Arg1.structurallyEquals(Arg2);699700case TemplateArgument::Pack:701return IsStructurallyEquivalent(Context, Arg1.pack_elements(),702Arg2.pack_elements());703}704705llvm_unreachable("Invalid template argument kind");706}707708/// Determine structural equivalence of two template argument lists.709static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,710ArrayRef<TemplateArgument> Args1,711ArrayRef<TemplateArgument> Args2) {712if (Args1.size() != Args2.size())713return false;714for (unsigned I = 0, N = Args1.size(); I != N; ++I) {715if (!IsStructurallyEquivalent(Context, Args1[I], Args2[I]))716return false;717}718return true;719}720721/// Determine whether two template argument locations are equivalent.722static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,723const TemplateArgumentLoc &Arg1,724const TemplateArgumentLoc &Arg2) {725return IsStructurallyEquivalent(Context, Arg1.getArgument(),726Arg2.getArgument());727}728729/// Determine structural equivalence for the common part of array730/// types.731static bool IsArrayStructurallyEquivalent(StructuralEquivalenceContext &Context,732const ArrayType *Array1,733const ArrayType *Array2) {734if (!IsStructurallyEquivalent(Context, Array1->getElementType(),735Array2->getElementType()))736return false;737if (Array1->getSizeModifier() != Array2->getSizeModifier())738return false;739if (Array1->getIndexTypeQualifiers() != Array2->getIndexTypeQualifiers())740return false;741742return true;743}744745/// Determine structural equivalence based on the ExtInfo of functions. This746/// is inspired by ASTContext::mergeFunctionTypes(), we compare calling747/// conventions bits but must not compare some other bits.748static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,749FunctionType::ExtInfo EI1,750FunctionType::ExtInfo EI2) {751// Compatible functions must have compatible calling conventions.752if (EI1.getCC() != EI2.getCC())753return false;754755// Regparm is part of the calling convention.756if (EI1.getHasRegParm() != EI2.getHasRegParm())757return false;758if (EI1.getRegParm() != EI2.getRegParm())759return false;760761if (EI1.getProducesResult() != EI2.getProducesResult())762return false;763if (EI1.getNoCallerSavedRegs() != EI2.getNoCallerSavedRegs())764return false;765if (EI1.getNoCfCheck() != EI2.getNoCfCheck())766return false;767768return true;769}770771/// Check the equivalence of exception specifications.772static bool IsEquivalentExceptionSpec(StructuralEquivalenceContext &Context,773const FunctionProtoType *Proto1,774const FunctionProtoType *Proto2) {775776auto Spec1 = Proto1->getExceptionSpecType();777auto Spec2 = Proto2->getExceptionSpecType();778779if (isUnresolvedExceptionSpec(Spec1) || isUnresolvedExceptionSpec(Spec2))780return true;781782if (Spec1 != Spec2)783return false;784if (Spec1 == EST_Dynamic) {785if (Proto1->getNumExceptions() != Proto2->getNumExceptions())786return false;787for (unsigned I = 0, N = Proto1->getNumExceptions(); I != N; ++I) {788if (!IsStructurallyEquivalent(Context, Proto1->getExceptionType(I),789Proto2->getExceptionType(I)))790return false;791}792} else if (isComputedNoexcept(Spec1)) {793if (!IsStructurallyEquivalent(Context, Proto1->getNoexceptExpr(),794Proto2->getNoexceptExpr()))795return false;796}797798return true;799}800801/// Determine structural equivalence of two types.802static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,803QualType T1, QualType T2) {804if (T1.isNull() || T2.isNull())805return T1.isNull() && T2.isNull();806807QualType OrigT1 = T1;808QualType OrigT2 = T2;809810if (!Context.StrictTypeSpelling) {811// We aren't being strict about token-to-token equivalence of types,812// so map down to the canonical type.813T1 = Context.FromCtx.getCanonicalType(T1);814T2 = Context.ToCtx.getCanonicalType(T2);815}816817if (T1.getQualifiers() != T2.getQualifiers())818return false;819820Type::TypeClass TC = T1->getTypeClass();821822if (T1->getTypeClass() != T2->getTypeClass()) {823// Compare function types with prototypes vs. without prototypes as if824// both did not have prototypes.825if (T1->getTypeClass() == Type::FunctionProto &&826T2->getTypeClass() == Type::FunctionNoProto)827TC = Type::FunctionNoProto;828else if (T1->getTypeClass() == Type::FunctionNoProto &&829T2->getTypeClass() == Type::FunctionProto)830TC = Type::FunctionNoProto;831else832return false;833}834835switch (TC) {836case Type::Builtin:837// FIXME: Deal with Char_S/Char_U.838if (cast<BuiltinType>(T1)->getKind() != cast<BuiltinType>(T2)->getKind())839return false;840break;841842case Type::Complex:843if (!IsStructurallyEquivalent(Context,844cast<ComplexType>(T1)->getElementType(),845cast<ComplexType>(T2)->getElementType()))846return false;847break;848849case Type::Adjusted:850case Type::Decayed:851case Type::ArrayParameter:852if (!IsStructurallyEquivalent(Context,853cast<AdjustedType>(T1)->getOriginalType(),854cast<AdjustedType>(T2)->getOriginalType()))855return false;856break;857858case Type::Pointer:859if (!IsStructurallyEquivalent(Context,860cast<PointerType>(T1)->getPointeeType(),861cast<PointerType>(T2)->getPointeeType()))862return false;863break;864865case Type::BlockPointer:866if (!IsStructurallyEquivalent(Context,867cast<BlockPointerType>(T1)->getPointeeType(),868cast<BlockPointerType>(T2)->getPointeeType()))869return false;870break;871872case Type::LValueReference:873case Type::RValueReference: {874const auto *Ref1 = cast<ReferenceType>(T1);875const auto *Ref2 = cast<ReferenceType>(T2);876if (Ref1->isSpelledAsLValue() != Ref2->isSpelledAsLValue())877return false;878if (Ref1->isInnerRef() != Ref2->isInnerRef())879return false;880if (!IsStructurallyEquivalent(Context, Ref1->getPointeeTypeAsWritten(),881Ref2->getPointeeTypeAsWritten()))882return false;883break;884}885886case Type::MemberPointer: {887const auto *MemPtr1 = cast<MemberPointerType>(T1);888const auto *MemPtr2 = cast<MemberPointerType>(T2);889if (!IsStructurallyEquivalent(Context, MemPtr1->getPointeeType(),890MemPtr2->getPointeeType()))891return false;892if (!IsStructurallyEquivalent(Context, QualType(MemPtr1->getClass(), 0),893QualType(MemPtr2->getClass(), 0)))894return false;895break;896}897898case Type::ConstantArray: {899const auto *Array1 = cast<ConstantArrayType>(T1);900const auto *Array2 = cast<ConstantArrayType>(T2);901if (!llvm::APInt::isSameValue(Array1->getSize(), Array2->getSize()))902return false;903904if (!IsArrayStructurallyEquivalent(Context, Array1, Array2))905return false;906break;907}908909case Type::IncompleteArray:910if (!IsArrayStructurallyEquivalent(Context, cast<ArrayType>(T1),911cast<ArrayType>(T2)))912return false;913break;914915case Type::VariableArray: {916const auto *Array1 = cast<VariableArrayType>(T1);917const auto *Array2 = cast<VariableArrayType>(T2);918if (!IsStructurallyEquivalent(Context, Array1->getSizeExpr(),919Array2->getSizeExpr()))920return false;921922if (!IsArrayStructurallyEquivalent(Context, Array1, Array2))923return false;924925break;926}927928case Type::DependentSizedArray: {929const auto *Array1 = cast<DependentSizedArrayType>(T1);930const auto *Array2 = cast<DependentSizedArrayType>(T2);931if (!IsStructurallyEquivalent(Context, Array1->getSizeExpr(),932Array2->getSizeExpr()))933return false;934935if (!IsArrayStructurallyEquivalent(Context, Array1, Array2))936return false;937938break;939}940941case Type::DependentAddressSpace: {942const auto *DepAddressSpace1 = cast<DependentAddressSpaceType>(T1);943const auto *DepAddressSpace2 = cast<DependentAddressSpaceType>(T2);944if (!IsStructurallyEquivalent(Context, DepAddressSpace1->getAddrSpaceExpr(),945DepAddressSpace2->getAddrSpaceExpr()))946return false;947if (!IsStructurallyEquivalent(Context, DepAddressSpace1->getPointeeType(),948DepAddressSpace2->getPointeeType()))949return false;950951break;952}953954case Type::DependentSizedExtVector: {955const auto *Vec1 = cast<DependentSizedExtVectorType>(T1);956const auto *Vec2 = cast<DependentSizedExtVectorType>(T2);957if (!IsStructurallyEquivalent(Context, Vec1->getSizeExpr(),958Vec2->getSizeExpr()))959return false;960if (!IsStructurallyEquivalent(Context, Vec1->getElementType(),961Vec2->getElementType()))962return false;963break;964}965966case Type::DependentVector: {967const auto *Vec1 = cast<DependentVectorType>(T1);968const auto *Vec2 = cast<DependentVectorType>(T2);969if (Vec1->getVectorKind() != Vec2->getVectorKind())970return false;971if (!IsStructurallyEquivalent(Context, Vec1->getSizeExpr(),972Vec2->getSizeExpr()))973return false;974if (!IsStructurallyEquivalent(Context, Vec1->getElementType(),975Vec2->getElementType()))976return false;977break;978}979980case Type::Vector:981case Type::ExtVector: {982const auto *Vec1 = cast<VectorType>(T1);983const auto *Vec2 = cast<VectorType>(T2);984if (!IsStructurallyEquivalent(Context, Vec1->getElementType(),985Vec2->getElementType()))986return false;987if (Vec1->getNumElements() != Vec2->getNumElements())988return false;989if (Vec1->getVectorKind() != Vec2->getVectorKind())990return false;991break;992}993994case Type::DependentSizedMatrix: {995const DependentSizedMatrixType *Mat1 = cast<DependentSizedMatrixType>(T1);996const DependentSizedMatrixType *Mat2 = cast<DependentSizedMatrixType>(T2);997// The element types, row and column expressions must be structurally998// equivalent.999if (!IsStructurallyEquivalent(Context, Mat1->getRowExpr(),1000Mat2->getRowExpr()) ||1001!IsStructurallyEquivalent(Context, Mat1->getColumnExpr(),1002Mat2->getColumnExpr()) ||1003!IsStructurallyEquivalent(Context, Mat1->getElementType(),1004Mat2->getElementType()))1005return false;1006break;1007}10081009case Type::ConstantMatrix: {1010const ConstantMatrixType *Mat1 = cast<ConstantMatrixType>(T1);1011const ConstantMatrixType *Mat2 = cast<ConstantMatrixType>(T2);1012// The element types must be structurally equivalent and the number of rows1013// and columns must match.1014if (!IsStructurallyEquivalent(Context, Mat1->getElementType(),1015Mat2->getElementType()) ||1016Mat1->getNumRows() != Mat2->getNumRows() ||1017Mat1->getNumColumns() != Mat2->getNumColumns())1018return false;1019break;1020}10211022case Type::FunctionProto: {1023const auto *Proto1 = cast<FunctionProtoType>(T1);1024const auto *Proto2 = cast<FunctionProtoType>(T2);10251026if (Proto1->getNumParams() != Proto2->getNumParams())1027return false;1028for (unsigned I = 0, N = Proto1->getNumParams(); I != N; ++I) {1029if (!IsStructurallyEquivalent(Context, Proto1->getParamType(I),1030Proto2->getParamType(I)))1031return false;1032}1033if (Proto1->isVariadic() != Proto2->isVariadic())1034return false;10351036if (Proto1->getMethodQuals() != Proto2->getMethodQuals())1037return false;10381039// Check exceptions, this information is lost in canonical type.1040const auto *OrigProto1 =1041cast<FunctionProtoType>(OrigT1.getDesugaredType(Context.FromCtx));1042const auto *OrigProto2 =1043cast<FunctionProtoType>(OrigT2.getDesugaredType(Context.ToCtx));1044if (!IsEquivalentExceptionSpec(Context, OrigProto1, OrigProto2))1045return false;10461047// Fall through to check the bits common with FunctionNoProtoType.1048[[fallthrough]];1049}10501051case Type::FunctionNoProto: {1052const auto *Function1 = cast<FunctionType>(T1);1053const auto *Function2 = cast<FunctionType>(T2);1054if (!IsStructurallyEquivalent(Context, Function1->getReturnType(),1055Function2->getReturnType()))1056return false;1057if (!IsStructurallyEquivalent(Context, Function1->getExtInfo(),1058Function2->getExtInfo()))1059return false;1060break;1061}10621063case Type::UnresolvedUsing:1064if (!IsStructurallyEquivalent(Context,1065cast<UnresolvedUsingType>(T1)->getDecl(),1066cast<UnresolvedUsingType>(T2)->getDecl()))1067return false;1068break;10691070case Type::Attributed:1071if (!IsStructurallyEquivalent(Context,1072cast<AttributedType>(T1)->getModifiedType(),1073cast<AttributedType>(T2)->getModifiedType()))1074return false;1075if (!IsStructurallyEquivalent(1076Context, cast<AttributedType>(T1)->getEquivalentType(),1077cast<AttributedType>(T2)->getEquivalentType()))1078return false;1079break;10801081case Type::CountAttributed:1082if (!IsStructurallyEquivalent(Context,1083cast<CountAttributedType>(T1)->desugar(),1084cast<CountAttributedType>(T2)->desugar()))1085return false;1086break;10871088case Type::BTFTagAttributed:1089if (!IsStructurallyEquivalent(1090Context, cast<BTFTagAttributedType>(T1)->getWrappedType(),1091cast<BTFTagAttributedType>(T2)->getWrappedType()))1092return false;1093break;10941095case Type::Paren:1096if (!IsStructurallyEquivalent(Context, cast<ParenType>(T1)->getInnerType(),1097cast<ParenType>(T2)->getInnerType()))1098return false;1099break;11001101case Type::MacroQualified:1102if (!IsStructurallyEquivalent(1103Context, cast<MacroQualifiedType>(T1)->getUnderlyingType(),1104cast<MacroQualifiedType>(T2)->getUnderlyingType()))1105return false;1106break;11071108case Type::Using:1109if (!IsStructurallyEquivalent(Context, cast<UsingType>(T1)->getFoundDecl(),1110cast<UsingType>(T2)->getFoundDecl()))1111return false;1112if (!IsStructurallyEquivalent(Context,1113cast<UsingType>(T1)->getUnderlyingType(),1114cast<UsingType>(T2)->getUnderlyingType()))1115return false;1116break;11171118case Type::Typedef:1119if (!IsStructurallyEquivalent(Context, cast<TypedefType>(T1)->getDecl(),1120cast<TypedefType>(T2)->getDecl()) ||1121!IsStructurallyEquivalent(Context, cast<TypedefType>(T1)->desugar(),1122cast<TypedefType>(T2)->desugar()))1123return false;1124break;11251126case Type::TypeOfExpr:1127if (!IsStructurallyEquivalent(1128Context, cast<TypeOfExprType>(T1)->getUnderlyingExpr(),1129cast<TypeOfExprType>(T2)->getUnderlyingExpr()))1130return false;1131break;11321133case Type::TypeOf:1134if (!IsStructurallyEquivalent(Context,1135cast<TypeOfType>(T1)->getUnmodifiedType(),1136cast<TypeOfType>(T2)->getUnmodifiedType()))1137return false;1138break;11391140case Type::UnaryTransform:1141if (!IsStructurallyEquivalent(1142Context, cast<UnaryTransformType>(T1)->getUnderlyingType(),1143cast<UnaryTransformType>(T2)->getUnderlyingType()))1144return false;1145break;11461147case Type::Decltype:1148if (!IsStructurallyEquivalent(Context,1149cast<DecltypeType>(T1)->getUnderlyingExpr(),1150cast<DecltypeType>(T2)->getUnderlyingExpr()))1151return false;1152break;11531154case Type::Auto: {1155auto *Auto1 = cast<AutoType>(T1);1156auto *Auto2 = cast<AutoType>(T2);1157if (!IsStructurallyEquivalent(Context, Auto1->getDeducedType(),1158Auto2->getDeducedType()))1159return false;1160if (Auto1->isConstrained() != Auto2->isConstrained())1161return false;1162if (Auto1->isConstrained()) {1163if (Auto1->getTypeConstraintConcept() !=1164Auto2->getTypeConstraintConcept())1165return false;1166if (!IsStructurallyEquivalent(Context,1167Auto1->getTypeConstraintArguments(),1168Auto2->getTypeConstraintArguments()))1169return false;1170}1171break;1172}11731174case Type::DeducedTemplateSpecialization: {1175const auto *DT1 = cast<DeducedTemplateSpecializationType>(T1);1176const auto *DT2 = cast<DeducedTemplateSpecializationType>(T2);1177if (!IsStructurallyEquivalent(Context, DT1->getTemplateName(),1178DT2->getTemplateName()))1179return false;1180if (!IsStructurallyEquivalent(Context, DT1->getDeducedType(),1181DT2->getDeducedType()))1182return false;1183break;1184}11851186case Type::Record:1187case Type::Enum:1188if (!IsStructurallyEquivalent(Context, cast<TagType>(T1)->getDecl(),1189cast<TagType>(T2)->getDecl()))1190return false;1191break;11921193case Type::TemplateTypeParm: {1194const auto *Parm1 = cast<TemplateTypeParmType>(T1);1195const auto *Parm2 = cast<TemplateTypeParmType>(T2);1196if (!Context.IgnoreTemplateParmDepth &&1197Parm1->getDepth() != Parm2->getDepth())1198return false;1199if (Parm1->getIndex() != Parm2->getIndex())1200return false;1201if (Parm1->isParameterPack() != Parm2->isParameterPack())1202return false;12031204// Names of template type parameters are never significant.1205break;1206}12071208case Type::SubstTemplateTypeParm: {1209const auto *Subst1 = cast<SubstTemplateTypeParmType>(T1);1210const auto *Subst2 = cast<SubstTemplateTypeParmType>(T2);1211if (!IsStructurallyEquivalent(Context, Subst1->getReplacementType(),1212Subst2->getReplacementType()))1213return false;1214if (!IsStructurallyEquivalent(Context, Subst1->getAssociatedDecl(),1215Subst2->getAssociatedDecl()))1216return false;1217if (Subst1->getIndex() != Subst2->getIndex())1218return false;1219if (Subst1->getPackIndex() != Subst2->getPackIndex())1220return false;1221break;1222}12231224case Type::SubstTemplateTypeParmPack: {1225const auto *Subst1 = cast<SubstTemplateTypeParmPackType>(T1);1226const auto *Subst2 = cast<SubstTemplateTypeParmPackType>(T2);1227if (!IsStructurallyEquivalent(Context, Subst1->getAssociatedDecl(),1228Subst2->getAssociatedDecl()))1229return false;1230if (Subst1->getIndex() != Subst2->getIndex())1231return false;1232if (!IsStructurallyEquivalent(Context, Subst1->getArgumentPack(),1233Subst2->getArgumentPack()))1234return false;1235break;1236}12371238case Type::TemplateSpecialization: {1239const auto *Spec1 = cast<TemplateSpecializationType>(T1);1240const auto *Spec2 = cast<TemplateSpecializationType>(T2);1241if (!IsStructurallyEquivalent(Context, Spec1->getTemplateName(),1242Spec2->getTemplateName()))1243return false;1244if (!IsStructurallyEquivalent(Context, Spec1->template_arguments(),1245Spec2->template_arguments()))1246return false;1247break;1248}12491250case Type::Elaborated: {1251const auto *Elab1 = cast<ElaboratedType>(T1);1252const auto *Elab2 = cast<ElaboratedType>(T2);1253// CHECKME: what if a keyword is ElaboratedTypeKeyword::None or1254// ElaboratedTypeKeyword::Typename1255// ?1256if (Elab1->getKeyword() != Elab2->getKeyword())1257return false;1258if (!IsStructurallyEquivalent(Context, Elab1->getQualifier(),1259Elab2->getQualifier()))1260return false;1261if (!IsStructurallyEquivalent(Context, Elab1->getNamedType(),1262Elab2->getNamedType()))1263return false;1264break;1265}12661267case Type::InjectedClassName: {1268const auto *Inj1 = cast<InjectedClassNameType>(T1);1269const auto *Inj2 = cast<InjectedClassNameType>(T2);1270if (!IsStructurallyEquivalent(Context,1271Inj1->getInjectedSpecializationType(),1272Inj2->getInjectedSpecializationType()))1273return false;1274break;1275}12761277case Type::DependentName: {1278const auto *Typename1 = cast<DependentNameType>(T1);1279const auto *Typename2 = cast<DependentNameType>(T2);1280if (!IsStructurallyEquivalent(Context, Typename1->getQualifier(),1281Typename2->getQualifier()))1282return false;1283if (!IsStructurallyEquivalent(Typename1->getIdentifier(),1284Typename2->getIdentifier()))1285return false;12861287break;1288}12891290case Type::DependentTemplateSpecialization: {1291const auto *Spec1 = cast<DependentTemplateSpecializationType>(T1);1292const auto *Spec2 = cast<DependentTemplateSpecializationType>(T2);1293if (!IsStructurallyEquivalent(Context, Spec1->getQualifier(),1294Spec2->getQualifier()))1295return false;1296if (!IsStructurallyEquivalent(Spec1->getIdentifier(),1297Spec2->getIdentifier()))1298return false;1299if (!IsStructurallyEquivalent(Context, Spec1->template_arguments(),1300Spec2->template_arguments()))1301return false;1302break;1303}13041305case Type::PackExpansion:1306if (!IsStructurallyEquivalent(Context,1307cast<PackExpansionType>(T1)->getPattern(),1308cast<PackExpansionType>(T2)->getPattern()))1309return false;1310break;13111312case Type::PackIndexing:1313if (!IsStructurallyEquivalent(Context,1314cast<PackIndexingType>(T1)->getPattern(),1315cast<PackIndexingType>(T2)->getPattern()))1316if (!IsStructurallyEquivalent(Context,1317cast<PackIndexingType>(T1)->getIndexExpr(),1318cast<PackIndexingType>(T2)->getIndexExpr()))1319return false;1320break;13211322case Type::ObjCInterface: {1323const auto *Iface1 = cast<ObjCInterfaceType>(T1);1324const auto *Iface2 = cast<ObjCInterfaceType>(T2);1325if (!IsStructurallyEquivalent(Context, Iface1->getDecl(),1326Iface2->getDecl()))1327return false;1328break;1329}13301331case Type::ObjCTypeParam: {1332const auto *Obj1 = cast<ObjCTypeParamType>(T1);1333const auto *Obj2 = cast<ObjCTypeParamType>(T2);1334if (!IsStructurallyEquivalent(Context, Obj1->getDecl(), Obj2->getDecl()))1335return false;13361337if (Obj1->getNumProtocols() != Obj2->getNumProtocols())1338return false;1339for (unsigned I = 0, N = Obj1->getNumProtocols(); I != N; ++I) {1340if (!IsStructurallyEquivalent(Context, Obj1->getProtocol(I),1341Obj2->getProtocol(I)))1342return false;1343}1344break;1345}13461347case Type::ObjCObject: {1348const auto *Obj1 = cast<ObjCObjectType>(T1);1349const auto *Obj2 = cast<ObjCObjectType>(T2);1350if (!IsStructurallyEquivalent(Context, Obj1->getBaseType(),1351Obj2->getBaseType()))1352return false;1353if (Obj1->getNumProtocols() != Obj2->getNumProtocols())1354return false;1355for (unsigned I = 0, N = Obj1->getNumProtocols(); I != N; ++I) {1356if (!IsStructurallyEquivalent(Context, Obj1->getProtocol(I),1357Obj2->getProtocol(I)))1358return false;1359}1360break;1361}13621363case Type::ObjCObjectPointer: {1364const auto *Ptr1 = cast<ObjCObjectPointerType>(T1);1365const auto *Ptr2 = cast<ObjCObjectPointerType>(T2);1366if (!IsStructurallyEquivalent(Context, Ptr1->getPointeeType(),1367Ptr2->getPointeeType()))1368return false;1369break;1370}13711372case Type::Atomic:1373if (!IsStructurallyEquivalent(Context, cast<AtomicType>(T1)->getValueType(),1374cast<AtomicType>(T2)->getValueType()))1375return false;1376break;13771378case Type::Pipe:1379if (!IsStructurallyEquivalent(Context, cast<PipeType>(T1)->getElementType(),1380cast<PipeType>(T2)->getElementType()))1381return false;1382break;1383case Type::BitInt: {1384const auto *Int1 = cast<BitIntType>(T1);1385const auto *Int2 = cast<BitIntType>(T2);13861387if (Int1->isUnsigned() != Int2->isUnsigned() ||1388Int1->getNumBits() != Int2->getNumBits())1389return false;1390break;1391}1392case Type::DependentBitInt: {1393const auto *Int1 = cast<DependentBitIntType>(T1);1394const auto *Int2 = cast<DependentBitIntType>(T2);13951396if (Int1->isUnsigned() != Int2->isUnsigned() ||1397!IsStructurallyEquivalent(Context, Int1->getNumBitsExpr(),1398Int2->getNumBitsExpr()))1399return false;1400break;1401}1402} // end switch14031404return true;1405}14061407static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,1408VarDecl *D1, VarDecl *D2) {1409IdentifierInfo *Name1 = D1->getIdentifier();1410IdentifierInfo *Name2 = D2->getIdentifier();1411if (!::IsStructurallyEquivalent(Name1, Name2))1412return false;14131414if (!IsStructurallyEquivalent(Context, D1->getType(), D2->getType()))1415return false;14161417// Compare storage class and initializer only if none or both are a1418// definition. Like a forward-declaration matches a class definition, variable1419// declarations that are not definitions should match with the definitions.1420if (D1->isThisDeclarationADefinition() != D2->isThisDeclarationADefinition())1421return true;14221423if (D1->getStorageClass() != D2->getStorageClass())1424return false;14251426return IsStructurallyEquivalent(Context, D1->getInit(), D2->getInit());1427}14281429static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,1430FieldDecl *Field1, FieldDecl *Field2,1431QualType Owner2Type) {1432const auto *Owner2 = cast<Decl>(Field2->getDeclContext());14331434// For anonymous structs/unions, match up the anonymous struct/union type1435// declarations directly, so that we don't go off searching for anonymous1436// types1437if (Field1->isAnonymousStructOrUnion() &&1438Field2->isAnonymousStructOrUnion()) {1439RecordDecl *D1 = Field1->getType()->castAs<RecordType>()->getDecl();1440RecordDecl *D2 = Field2->getType()->castAs<RecordType>()->getDecl();1441return IsStructurallyEquivalent(Context, D1, D2);1442}14431444// Check for equivalent field names.1445IdentifierInfo *Name1 = Field1->getIdentifier();1446IdentifierInfo *Name2 = Field2->getIdentifier();1447if (!::IsStructurallyEquivalent(Name1, Name2)) {1448if (Context.Complain) {1449Context.Diag2(1450Owner2->getLocation(),1451Context.getApplicableDiagnostic(diag::err_odr_tag_type_inconsistent))1452<< Owner2Type;1453Context.Diag2(Field2->getLocation(), diag::note_odr_field_name)1454<< Field2->getDeclName();1455Context.Diag1(Field1->getLocation(), diag::note_odr_field_name)1456<< Field1->getDeclName();1457}1458return false;1459}14601461if (!IsStructurallyEquivalent(Context, Field1->getType(),1462Field2->getType())) {1463if (Context.Complain) {1464Context.Diag2(1465Owner2->getLocation(),1466Context.getApplicableDiagnostic(diag::err_odr_tag_type_inconsistent))1467<< Owner2Type;1468Context.Diag2(Field2->getLocation(), diag::note_odr_field)1469<< Field2->getDeclName() << Field2->getType();1470Context.Diag1(Field1->getLocation(), diag::note_odr_field)1471<< Field1->getDeclName() << Field1->getType();1472}1473return false;1474}14751476if (Field1->isBitField())1477return IsStructurallyEquivalent(Context, Field1->getBitWidth(),1478Field2->getBitWidth());14791480return true;1481}14821483/// Determine structural equivalence of two fields.1484static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,1485FieldDecl *Field1, FieldDecl *Field2) {1486const auto *Owner2 = cast<RecordDecl>(Field2->getDeclContext());1487return IsStructurallyEquivalent(Context, Field1, Field2,1488Context.ToCtx.getTypeDeclType(Owner2));1489}14901491/// Determine structural equivalence of two methods.1492static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,1493CXXMethodDecl *Method1,1494CXXMethodDecl *Method2) {1495bool PropertiesEqual =1496Method1->getDeclKind() == Method2->getDeclKind() &&1497Method1->getRefQualifier() == Method2->getRefQualifier() &&1498Method1->getAccess() == Method2->getAccess() &&1499Method1->getOverloadedOperator() == Method2->getOverloadedOperator() &&1500Method1->isStatic() == Method2->isStatic() &&1501Method1->isImplicitObjectMemberFunction() ==1502Method2->isImplicitObjectMemberFunction() &&1503Method1->isConst() == Method2->isConst() &&1504Method1->isVolatile() == Method2->isVolatile() &&1505Method1->isVirtual() == Method2->isVirtual() &&1506Method1->isPureVirtual() == Method2->isPureVirtual() &&1507Method1->isDefaulted() == Method2->isDefaulted() &&1508Method1->isDeleted() == Method2->isDeleted();1509if (!PropertiesEqual)1510return false;1511// FIXME: Check for 'final'.15121513if (auto *Constructor1 = dyn_cast<CXXConstructorDecl>(Method1)) {1514auto *Constructor2 = cast<CXXConstructorDecl>(Method2);1515if (!Constructor1->getExplicitSpecifier().isEquivalent(1516Constructor2->getExplicitSpecifier()))1517return false;1518}15191520if (auto *Conversion1 = dyn_cast<CXXConversionDecl>(Method1)) {1521auto *Conversion2 = cast<CXXConversionDecl>(Method2);1522if (!Conversion1->getExplicitSpecifier().isEquivalent(1523Conversion2->getExplicitSpecifier()))1524return false;1525if (!IsStructurallyEquivalent(Context, Conversion1->getConversionType(),1526Conversion2->getConversionType()))1527return false;1528}15291530const IdentifierInfo *Name1 = Method1->getIdentifier();1531const IdentifierInfo *Name2 = Method2->getIdentifier();1532if (!::IsStructurallyEquivalent(Name1, Name2)) {1533return false;1534// TODO: Names do not match, add warning like at check for FieldDecl.1535}15361537// Check the prototypes.1538if (!::IsStructurallyEquivalent(Context,1539Method1->getType(), Method2->getType()))1540return false;15411542return true;1543}15441545/// Determine structural equivalence of two lambda classes.1546static bool1547IsStructurallyEquivalentLambdas(StructuralEquivalenceContext &Context,1548CXXRecordDecl *D1, CXXRecordDecl *D2) {1549assert(D1->isLambda() && D2->isLambda() &&1550"Must be called on lambda classes");1551if (!IsStructurallyEquivalent(Context, D1->getLambdaCallOperator(),1552D2->getLambdaCallOperator()))1553return false;15541555return true;1556}15571558/// Determine if context of a class is equivalent.1559static bool1560IsRecordContextStructurallyEquivalent(StructuralEquivalenceContext &Context,1561RecordDecl *D1, RecordDecl *D2) {1562// The context should be completely equal, including anonymous and inline1563// namespaces.1564// We compare objects as part of full translation units, not subtrees of1565// translation units.1566DeclContext *DC1 = D1->getDeclContext()->getNonTransparentContext();1567DeclContext *DC2 = D2->getDeclContext()->getNonTransparentContext();1568while (true) {1569// Special case: We allow a struct defined in a function to be equivalent1570// with a similar struct defined outside of a function.1571if ((DC1->isFunctionOrMethod() && DC2->isTranslationUnit()) ||1572(DC2->isFunctionOrMethod() && DC1->isTranslationUnit()))1573return true;15741575if (DC1->getDeclKind() != DC2->getDeclKind())1576return false;1577if (DC1->isTranslationUnit())1578break;1579if (DC1->isInlineNamespace() != DC2->isInlineNamespace())1580return false;1581if (const auto *ND1 = dyn_cast<NamedDecl>(DC1)) {1582const auto *ND2 = cast<NamedDecl>(DC2);1583if (!DC1->isInlineNamespace() &&1584!IsStructurallyEquivalent(ND1->getIdentifier(), ND2->getIdentifier()))1585return false;1586}15871588if (auto *D1Spec = dyn_cast<ClassTemplateSpecializationDecl>(DC1)) {1589auto *D2Spec = dyn_cast<ClassTemplateSpecializationDecl>(DC2);1590if (!IsStructurallyEquivalent(Context, D1Spec, D2Spec))1591return false;1592}15931594DC1 = DC1->getParent()->getNonTransparentContext();1595DC2 = DC2->getParent()->getNonTransparentContext();1596}15971598return true;1599}16001601static bool NameIsStructurallyEquivalent(const TagDecl &D1, const TagDecl &D2) {1602auto GetName = [](const TagDecl &D) -> const IdentifierInfo * {1603if (const IdentifierInfo *Name = D.getIdentifier())1604return Name;1605if (const TypedefNameDecl *TypedefName = D.getTypedefNameForAnonDecl())1606return TypedefName->getIdentifier();1607return nullptr;1608};1609return IsStructurallyEquivalent(GetName(D1), GetName(D2));1610}16111612/// Determine structural equivalence of two records.1613static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,1614RecordDecl *D1, RecordDecl *D2) {1615if (!NameIsStructurallyEquivalent(*D1, *D2)) {1616return false;1617}16181619if (D1->isUnion() != D2->isUnion()) {1620if (Context.Complain) {1621Context.Diag2(D2->getLocation(), Context.getApplicableDiagnostic(1622diag::err_odr_tag_type_inconsistent))1623<< Context.ToCtx.getTypeDeclType(D2);1624Context.Diag1(D1->getLocation(), diag::note_odr_tag_kind_here)1625<< D1->getDeclName() << (unsigned)D1->getTagKind();1626}1627return false;1628}16291630if (!D1->getDeclName() && !D2->getDeclName()) {1631// If both anonymous structs/unions are in a record context, make sure1632// they occur in the same location in the context records.1633if (std::optional<unsigned> Index1 =1634StructuralEquivalenceContext::findUntaggedStructOrUnionIndex(D1)) {1635if (std::optional<unsigned> Index2 =1636StructuralEquivalenceContext::findUntaggedStructOrUnionIndex(1637D2)) {1638if (*Index1 != *Index2)1639return false;1640}1641}1642}16431644// If the records occur in different context (namespace), these should be1645// different. This is specially important if the definition of one or both1646// records is missing.1647if (!IsRecordContextStructurallyEquivalent(Context, D1, D2))1648return false;16491650// If both declarations are class template specializations, we know1651// the ODR applies, so check the template and template arguments.1652const auto *Spec1 = dyn_cast<ClassTemplateSpecializationDecl>(D1);1653const auto *Spec2 = dyn_cast<ClassTemplateSpecializationDecl>(D2);1654if (Spec1 && Spec2) {1655// Check that the specialized templates are the same.1656if (!IsStructurallyEquivalent(Context, Spec1->getSpecializedTemplate(),1657Spec2->getSpecializedTemplate()))1658return false;16591660// Check that the template arguments are the same.1661if (Spec1->getTemplateArgs().size() != Spec2->getTemplateArgs().size())1662return false;16631664for (unsigned I = 0, N = Spec1->getTemplateArgs().size(); I != N; ++I)1665if (!IsStructurallyEquivalent(Context, Spec1->getTemplateArgs().get(I),1666Spec2->getTemplateArgs().get(I)))1667return false;1668}1669// If one is a class template specialization and the other is not, these1670// structures are different.1671else if (Spec1 || Spec2)1672return false;16731674// Compare the definitions of these two records. If either or both are1675// incomplete (i.e. it is a forward decl), we assume that they are1676// equivalent.1677D1 = D1->getDefinition();1678D2 = D2->getDefinition();1679if (!D1 || !D2)1680return true;16811682// If any of the records has external storage and we do a minimal check (or1683// AST import) we assume they are equivalent. (If we didn't have this1684// assumption then `RecordDecl::LoadFieldsFromExternalStorage` could trigger1685// another AST import which in turn would call the structural equivalency1686// check again and finally we'd have an improper result.)1687if (Context.EqKind == StructuralEquivalenceKind::Minimal)1688if (D1->hasExternalLexicalStorage() || D2->hasExternalLexicalStorage())1689return true;16901691// If one definition is currently being defined, we do not compare for1692// equality and we assume that the decls are equal.1693if (D1->isBeingDefined() || D2->isBeingDefined())1694return true;16951696if (auto *D1CXX = dyn_cast<CXXRecordDecl>(D1)) {1697if (auto *D2CXX = dyn_cast<CXXRecordDecl>(D2)) {1698if (D1CXX->hasExternalLexicalStorage() &&1699!D1CXX->isCompleteDefinition()) {1700D1CXX->getASTContext().getExternalSource()->CompleteType(D1CXX);1701}17021703if (D1CXX->isLambda() != D2CXX->isLambda())1704return false;1705if (D1CXX->isLambda()) {1706if (!IsStructurallyEquivalentLambdas(Context, D1CXX, D2CXX))1707return false;1708}17091710if (D1CXX->getNumBases() != D2CXX->getNumBases()) {1711if (Context.Complain) {1712Context.Diag2(D2->getLocation(),1713Context.getApplicableDiagnostic(1714diag::err_odr_tag_type_inconsistent))1715<< Context.ToCtx.getTypeDeclType(D2);1716Context.Diag2(D2->getLocation(), diag::note_odr_number_of_bases)1717<< D2CXX->getNumBases();1718Context.Diag1(D1->getLocation(), diag::note_odr_number_of_bases)1719<< D1CXX->getNumBases();1720}1721return false;1722}17231724// Check the base classes.1725for (CXXRecordDecl::base_class_iterator Base1 = D1CXX->bases_begin(),1726BaseEnd1 = D1CXX->bases_end(),1727Base2 = D2CXX->bases_begin();1728Base1 != BaseEnd1; ++Base1, ++Base2) {1729if (!IsStructurallyEquivalent(Context, Base1->getType(),1730Base2->getType())) {1731if (Context.Complain) {1732Context.Diag2(D2->getLocation(),1733Context.getApplicableDiagnostic(1734diag::err_odr_tag_type_inconsistent))1735<< Context.ToCtx.getTypeDeclType(D2);1736Context.Diag2(Base2->getBeginLoc(), diag::note_odr_base)1737<< Base2->getType() << Base2->getSourceRange();1738Context.Diag1(Base1->getBeginLoc(), diag::note_odr_base)1739<< Base1->getType() << Base1->getSourceRange();1740}1741return false;1742}17431744// Check virtual vs. non-virtual inheritance mismatch.1745if (Base1->isVirtual() != Base2->isVirtual()) {1746if (Context.Complain) {1747Context.Diag2(D2->getLocation(),1748Context.getApplicableDiagnostic(1749diag::err_odr_tag_type_inconsistent))1750<< Context.ToCtx.getTypeDeclType(D2);1751Context.Diag2(Base2->getBeginLoc(), diag::note_odr_virtual_base)1752<< Base2->isVirtual() << Base2->getSourceRange();1753Context.Diag1(Base1->getBeginLoc(), diag::note_odr_base)1754<< Base1->isVirtual() << Base1->getSourceRange();1755}1756return false;1757}1758}17591760// Check the friends for consistency.1761CXXRecordDecl::friend_iterator Friend2 = D2CXX->friend_begin(),1762Friend2End = D2CXX->friend_end();1763for (CXXRecordDecl::friend_iterator Friend1 = D1CXX->friend_begin(),1764Friend1End = D1CXX->friend_end();1765Friend1 != Friend1End; ++Friend1, ++Friend2) {1766if (Friend2 == Friend2End) {1767if (Context.Complain) {1768Context.Diag2(D2->getLocation(),1769Context.getApplicableDiagnostic(1770diag::err_odr_tag_type_inconsistent))1771<< Context.ToCtx.getTypeDeclType(D2CXX);1772Context.Diag1((*Friend1)->getFriendLoc(), diag::note_odr_friend);1773Context.Diag2(D2->getLocation(), diag::note_odr_missing_friend);1774}1775return false;1776}17771778if (!IsStructurallyEquivalent(Context, *Friend1, *Friend2)) {1779if (Context.Complain) {1780Context.Diag2(D2->getLocation(),1781Context.getApplicableDiagnostic(1782diag::err_odr_tag_type_inconsistent))1783<< Context.ToCtx.getTypeDeclType(D2CXX);1784Context.Diag1((*Friend1)->getFriendLoc(), diag::note_odr_friend);1785Context.Diag2((*Friend2)->getFriendLoc(), diag::note_odr_friend);1786}1787return false;1788}1789}17901791if (Friend2 != Friend2End) {1792if (Context.Complain) {1793Context.Diag2(D2->getLocation(),1794Context.getApplicableDiagnostic(1795diag::err_odr_tag_type_inconsistent))1796<< Context.ToCtx.getTypeDeclType(D2);1797Context.Diag2((*Friend2)->getFriendLoc(), diag::note_odr_friend);1798Context.Diag1(D1->getLocation(), diag::note_odr_missing_friend);1799}1800return false;1801}1802} else if (D1CXX->getNumBases() > 0) {1803if (Context.Complain) {1804Context.Diag2(D2->getLocation(),1805Context.getApplicableDiagnostic(1806diag::err_odr_tag_type_inconsistent))1807<< Context.ToCtx.getTypeDeclType(D2);1808const CXXBaseSpecifier *Base1 = D1CXX->bases_begin();1809Context.Diag1(Base1->getBeginLoc(), diag::note_odr_base)1810<< Base1->getType() << Base1->getSourceRange();1811Context.Diag2(D2->getLocation(), diag::note_odr_missing_base);1812}1813return false;1814}1815}18161817// Check the fields for consistency.1818QualType D2Type = Context.ToCtx.getTypeDeclType(D2);1819RecordDecl::field_iterator Field2 = D2->field_begin(),1820Field2End = D2->field_end();1821for (RecordDecl::field_iterator Field1 = D1->field_begin(),1822Field1End = D1->field_end();1823Field1 != Field1End; ++Field1, ++Field2) {1824if (Field2 == Field2End) {1825if (Context.Complain) {1826Context.Diag2(D2->getLocation(),1827Context.getApplicableDiagnostic(1828diag::err_odr_tag_type_inconsistent))1829<< Context.ToCtx.getTypeDeclType(D2);1830Context.Diag1(Field1->getLocation(), diag::note_odr_field)1831<< Field1->getDeclName() << Field1->getType();1832Context.Diag2(D2->getLocation(), diag::note_odr_missing_field);1833}1834return false;1835}18361837if (!IsStructurallyEquivalent(Context, *Field1, *Field2, D2Type))1838return false;1839}18401841if (Field2 != Field2End) {1842if (Context.Complain) {1843Context.Diag2(D2->getLocation(), Context.getApplicableDiagnostic(1844diag::err_odr_tag_type_inconsistent))1845<< Context.ToCtx.getTypeDeclType(D2);1846Context.Diag2(Field2->getLocation(), diag::note_odr_field)1847<< Field2->getDeclName() << Field2->getType();1848Context.Diag1(D1->getLocation(), diag::note_odr_missing_field);1849}1850return false;1851}18521853return true;1854}18551856static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,1857EnumConstantDecl *D1,1858EnumConstantDecl *D2) {1859const llvm::APSInt &FromVal = D1->getInitVal();1860const llvm::APSInt &ToVal = D2->getInitVal();1861if (FromVal.isSigned() != ToVal.isSigned())1862return false;1863if (FromVal.getBitWidth() != ToVal.getBitWidth())1864return false;1865if (FromVal != ToVal)1866return false;18671868if (!IsStructurallyEquivalent(D1->getIdentifier(), D2->getIdentifier()))1869return false;18701871// Init expressions are the most expensive check, so do them last.1872return IsStructurallyEquivalent(Context, D1->getInitExpr(),1873D2->getInitExpr());1874}18751876/// Determine structural equivalence of two enums.1877static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,1878EnumDecl *D1, EnumDecl *D2) {1879if (!NameIsStructurallyEquivalent(*D1, *D2)) {1880return false;1881}18821883// Compare the definitions of these two enums. If either or both are1884// incomplete (i.e. forward declared), we assume that they are equivalent.1885D1 = D1->getDefinition();1886D2 = D2->getDefinition();1887if (!D1 || !D2)1888return true;18891890EnumDecl::enumerator_iterator EC2 = D2->enumerator_begin(),1891EC2End = D2->enumerator_end();1892for (EnumDecl::enumerator_iterator EC1 = D1->enumerator_begin(),1893EC1End = D1->enumerator_end();1894EC1 != EC1End; ++EC1, ++EC2) {1895if (EC2 == EC2End) {1896if (Context.Complain) {1897Context.Diag2(D2->getLocation(),1898Context.getApplicableDiagnostic(1899diag::err_odr_tag_type_inconsistent))1900<< Context.ToCtx.getTypeDeclType(D2);1901Context.Diag1(EC1->getLocation(), diag::note_odr_enumerator)1902<< EC1->getDeclName() << toString(EC1->getInitVal(), 10);1903Context.Diag2(D2->getLocation(), diag::note_odr_missing_enumerator);1904}1905return false;1906}19071908llvm::APSInt Val1 = EC1->getInitVal();1909llvm::APSInt Val2 = EC2->getInitVal();1910if (!llvm::APSInt::isSameValue(Val1, Val2) ||1911!IsStructurallyEquivalent(EC1->getIdentifier(), EC2->getIdentifier())) {1912if (Context.Complain) {1913Context.Diag2(D2->getLocation(),1914Context.getApplicableDiagnostic(1915diag::err_odr_tag_type_inconsistent))1916<< Context.ToCtx.getTypeDeclType(D2);1917Context.Diag2(EC2->getLocation(), diag::note_odr_enumerator)1918<< EC2->getDeclName() << toString(EC2->getInitVal(), 10);1919Context.Diag1(EC1->getLocation(), diag::note_odr_enumerator)1920<< EC1->getDeclName() << toString(EC1->getInitVal(), 10);1921}1922return false;1923}1924}19251926if (EC2 != EC2End) {1927if (Context.Complain) {1928Context.Diag2(D2->getLocation(), Context.getApplicableDiagnostic(1929diag::err_odr_tag_type_inconsistent))1930<< Context.ToCtx.getTypeDeclType(D2);1931Context.Diag2(EC2->getLocation(), diag::note_odr_enumerator)1932<< EC2->getDeclName() << toString(EC2->getInitVal(), 10);1933Context.Diag1(D1->getLocation(), diag::note_odr_missing_enumerator);1934}1935return false;1936}19371938return true;1939}19401941static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,1942TemplateParameterList *Params1,1943TemplateParameterList *Params2) {1944if (Params1->size() != Params2->size()) {1945if (Context.Complain) {1946Context.Diag2(Params2->getTemplateLoc(),1947Context.getApplicableDiagnostic(1948diag::err_odr_different_num_template_parameters))1949<< Params1->size() << Params2->size();1950Context.Diag1(Params1->getTemplateLoc(),1951diag::note_odr_template_parameter_list);1952}1953return false;1954}19551956for (unsigned I = 0, N = Params1->size(); I != N; ++I) {1957if (Params1->getParam(I)->getKind() != Params2->getParam(I)->getKind()) {1958if (Context.Complain) {1959Context.Diag2(Params2->getParam(I)->getLocation(),1960Context.getApplicableDiagnostic(1961diag::err_odr_different_template_parameter_kind));1962Context.Diag1(Params1->getParam(I)->getLocation(),1963diag::note_odr_template_parameter_here);1964}1965return false;1966}19671968if (!IsStructurallyEquivalent(Context, Params1->getParam(I),1969Params2->getParam(I)))1970return false;1971}19721973return true;1974}19751976static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,1977TemplateTypeParmDecl *D1,1978TemplateTypeParmDecl *D2) {1979if (D1->isParameterPack() != D2->isParameterPack()) {1980if (Context.Complain) {1981Context.Diag2(D2->getLocation(),1982Context.getApplicableDiagnostic(1983diag::err_odr_parameter_pack_non_pack))1984<< D2->isParameterPack();1985Context.Diag1(D1->getLocation(), diag::note_odr_parameter_pack_non_pack)1986<< D1->isParameterPack();1987}1988return false;1989}19901991return true;1992}19931994static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,1995NonTypeTemplateParmDecl *D1,1996NonTypeTemplateParmDecl *D2) {1997if (D1->isParameterPack() != D2->isParameterPack()) {1998if (Context.Complain) {1999Context.Diag2(D2->getLocation(),2000Context.getApplicableDiagnostic(2001diag::err_odr_parameter_pack_non_pack))2002<< D2->isParameterPack();2003Context.Diag1(D1->getLocation(), diag::note_odr_parameter_pack_non_pack)2004<< D1->isParameterPack();2005}2006return false;2007}2008if (!Context.IgnoreTemplateParmDepth && D1->getDepth() != D2->getDepth())2009return false;2010if (D1->getIndex() != D2->getIndex())2011return false;2012// Check types.2013if (!IsStructurallyEquivalent(Context, D1->getType(), D2->getType())) {2014if (Context.Complain) {2015Context.Diag2(D2->getLocation(),2016Context.getApplicableDiagnostic(2017diag::err_odr_non_type_parameter_type_inconsistent))2018<< D2->getType() << D1->getType();2019Context.Diag1(D1->getLocation(), diag::note_odr_value_here)2020<< D1->getType();2021}2022return false;2023}20242025return true;2026}20272028static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,2029TemplateTemplateParmDecl *D1,2030TemplateTemplateParmDecl *D2) {2031if (D1->isParameterPack() != D2->isParameterPack()) {2032if (Context.Complain) {2033Context.Diag2(D2->getLocation(),2034Context.getApplicableDiagnostic(2035diag::err_odr_parameter_pack_non_pack))2036<< D2->isParameterPack();2037Context.Diag1(D1->getLocation(), diag::note_odr_parameter_pack_non_pack)2038<< D1->isParameterPack();2039}2040return false;2041}20422043// Check template parameter lists.2044return IsStructurallyEquivalent(Context, D1->getTemplateParameters(),2045D2->getTemplateParameters());2046}20472048static bool IsTemplateDeclCommonStructurallyEquivalent(2049StructuralEquivalenceContext &Ctx, TemplateDecl *D1, TemplateDecl *D2) {2050if (!IsStructurallyEquivalent(D1->getIdentifier(), D2->getIdentifier()))2051return false;2052if (!D1->getIdentifier()) // Special name2053if (D1->getNameAsString() != D2->getNameAsString())2054return false;2055return IsStructurallyEquivalent(Ctx, D1->getTemplateParameters(),2056D2->getTemplateParameters());2057}20582059static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,2060ClassTemplateDecl *D1,2061ClassTemplateDecl *D2) {2062// Check template parameters.2063if (!IsTemplateDeclCommonStructurallyEquivalent(Context, D1, D2))2064return false;20652066// Check the templated declaration.2067return IsStructurallyEquivalent(Context, D1->getTemplatedDecl(),2068D2->getTemplatedDecl());2069}20702071static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,2072FunctionTemplateDecl *D1,2073FunctionTemplateDecl *D2) {2074// Check template parameters.2075if (!IsTemplateDeclCommonStructurallyEquivalent(Context, D1, D2))2076return false;20772078// Check the templated declaration.2079return IsStructurallyEquivalent(Context, D1->getTemplatedDecl()->getType(),2080D2->getTemplatedDecl()->getType());2081}20822083static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,2084TypeAliasTemplateDecl *D1,2085TypeAliasTemplateDecl *D2) {2086// Check template parameters.2087if (!IsTemplateDeclCommonStructurallyEquivalent(Context, D1, D2))2088return false;20892090// Check the templated declaration.2091return IsStructurallyEquivalent(Context, D1->getTemplatedDecl(),2092D2->getTemplatedDecl());2093}20942095static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,2096ConceptDecl *D1,2097ConceptDecl *D2) {2098// Check template parameters.2099if (!IsTemplateDeclCommonStructurallyEquivalent(Context, D1, D2))2100return false;21012102// Check the constraint expression.2103return IsStructurallyEquivalent(Context, D1->getConstraintExpr(),2104D2->getConstraintExpr());2105}21062107static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,2108FriendDecl *D1, FriendDecl *D2) {2109if ((D1->getFriendType() && D2->getFriendDecl()) ||2110(D1->getFriendDecl() && D2->getFriendType())) {2111return false;2112}2113if (D1->getFriendType() && D2->getFriendType())2114return IsStructurallyEquivalent(Context,2115D1->getFriendType()->getType(),2116D2->getFriendType()->getType());2117if (D1->getFriendDecl() && D2->getFriendDecl())2118return IsStructurallyEquivalent(Context, D1->getFriendDecl(),2119D2->getFriendDecl());2120return false;2121}21222123static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,2124TypedefNameDecl *D1, TypedefNameDecl *D2) {2125if (!IsStructurallyEquivalent(D1->getIdentifier(), D2->getIdentifier()))2126return false;21272128return IsStructurallyEquivalent(Context, D1->getUnderlyingType(),2129D2->getUnderlyingType());2130}21312132static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,2133FunctionDecl *D1, FunctionDecl *D2) {2134if (!IsStructurallyEquivalent(D1->getIdentifier(), D2->getIdentifier()))2135return false;21362137if (D1->isOverloadedOperator()) {2138if (!D2->isOverloadedOperator())2139return false;2140if (D1->getOverloadedOperator() != D2->getOverloadedOperator())2141return false;2142}21432144// FIXME: Consider checking for function attributes as well.2145if (!IsStructurallyEquivalent(Context, D1->getType(), D2->getType()))2146return false;21472148return true;2149}21502151static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,2152ObjCIvarDecl *D1, ObjCIvarDecl *D2,2153QualType Owner2Type) {2154if (D1->getAccessControl() != D2->getAccessControl())2155return false;21562157return IsStructurallyEquivalent(Context, cast<FieldDecl>(D1),2158cast<FieldDecl>(D2), Owner2Type);2159}21602161static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,2162ObjCIvarDecl *D1, ObjCIvarDecl *D2) {2163QualType Owner2Type =2164Context.ToCtx.getObjCInterfaceType(D2->getContainingInterface());2165return IsStructurallyEquivalent(Context, D1, D2, Owner2Type);2166}21672168static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,2169ObjCMethodDecl *Method1,2170ObjCMethodDecl *Method2) {2171bool PropertiesEqual =2172Method1->isInstanceMethod() == Method2->isInstanceMethod() &&2173Method1->isVariadic() == Method2->isVariadic() &&2174Method1->isDirectMethod() == Method2->isDirectMethod();2175if (!PropertiesEqual)2176return false;21772178// Compare selector slot names.2179Selector Selector1 = Method1->getSelector(),2180Selector2 = Method2->getSelector();2181unsigned NumArgs = Selector1.getNumArgs();2182if (NumArgs != Selector2.getNumArgs())2183return false;2184// Compare all selector slots. For selectors with arguments it means all arg2185// slots. And if there are no arguments, compare the first-and-only slot.2186unsigned SlotsToCheck = NumArgs > 0 ? NumArgs : 1;2187for (unsigned I = 0; I < SlotsToCheck; ++I) {2188if (!IsStructurallyEquivalent(Selector1.getIdentifierInfoForSlot(I),2189Selector2.getIdentifierInfoForSlot(I)))2190return false;2191}21922193// Compare types.2194if (!IsStructurallyEquivalent(Context, Method1->getReturnType(),2195Method2->getReturnType()))2196return false;2197assert(2198Method1->param_size() == Method2->param_size() &&2199"Same number of arguments should be already enforced in Selector checks");2200for (ObjCMethodDecl::param_type_iterator2201ParamT1 = Method1->param_type_begin(),2202ParamT1End = Method1->param_type_end(),2203ParamT2 = Method2->param_type_begin(),2204ParamT2End = Method2->param_type_end();2205(ParamT1 != ParamT1End) && (ParamT2 != ParamT2End);2206++ParamT1, ++ParamT2) {2207if (!IsStructurallyEquivalent(Context, *ParamT1, *ParamT2))2208return false;2209}22102211return true;2212}22132214static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,2215ObjCCategoryDecl *D1,2216ObjCCategoryDecl *D2) {2217if (!IsStructurallyEquivalent(D1->getIdentifier(), D2->getIdentifier()))2218return false;22192220const ObjCInterfaceDecl *Intf1 = D1->getClassInterface(),2221*Intf2 = D2->getClassInterface();2222if ((!Intf1 || !Intf2) && (Intf1 != Intf2))2223return false;22242225if (Intf1 &&2226!IsStructurallyEquivalent(Intf1->getIdentifier(), Intf2->getIdentifier()))2227return false;22282229// Compare protocols.2230ObjCCategoryDecl::protocol_iterator Protocol2 = D2->protocol_begin(),2231Protocol2End = D2->protocol_end();2232for (ObjCCategoryDecl::protocol_iterator Protocol1 = D1->protocol_begin(),2233Protocol1End = D1->protocol_end();2234Protocol1 != Protocol1End; ++Protocol1, ++Protocol2) {2235if (Protocol2 == Protocol2End)2236return false;2237if (!IsStructurallyEquivalent((*Protocol1)->getIdentifier(),2238(*Protocol2)->getIdentifier()))2239return false;2240}2241if (Protocol2 != Protocol2End)2242return false;22432244// Compare ivars.2245QualType D2Type =2246Intf2 ? Context.ToCtx.getObjCInterfaceType(Intf2) : QualType();2247ObjCCategoryDecl::ivar_iterator Ivar2 = D2->ivar_begin(),2248Ivar2End = D2->ivar_end();2249for (ObjCCategoryDecl::ivar_iterator Ivar1 = D1->ivar_begin(),2250Ivar1End = D1->ivar_end();2251Ivar1 != Ivar1End; ++Ivar1, ++Ivar2) {2252if (Ivar2 == Ivar2End)2253return false;2254if (!IsStructurallyEquivalent(Context, *Ivar1, *Ivar2, D2Type))2255return false;2256}2257if (Ivar2 != Ivar2End)2258return false;22592260// Compare methods.2261ObjCCategoryDecl::method_iterator Method2 = D2->meth_begin(),2262Method2End = D2->meth_end();2263for (ObjCCategoryDecl::method_iterator Method1 = D1->meth_begin(),2264Method1End = D1->meth_end();2265Method1 != Method1End; ++Method1, ++Method2) {2266if (Method2 == Method2End)2267return false;2268if (!IsStructurallyEquivalent(Context, *Method1, *Method2))2269return false;2270}2271if (Method2 != Method2End)2272return false;22732274return true;2275}22762277/// Determine structural equivalence of two declarations.2278static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,2279Decl *D1, Decl *D2) {2280// FIXME: Check for known structural equivalences via a callback of some sort.22812282D1 = D1->getCanonicalDecl();2283D2 = D2->getCanonicalDecl();2284std::pair<Decl *, Decl *> P{D1, D2};22852286// Check whether we already know that these two declarations are not2287// structurally equivalent.2288if (Context.NonEquivalentDecls.count(P))2289return false;22902291// Check if a check for these declarations is already pending.2292// If yes D1 and D2 will be checked later (from DeclsToCheck),2293// or these are already checked (and equivalent).2294bool Inserted = Context.VisitedDecls.insert(P).second;2295if (!Inserted)2296return true;22972298Context.DeclsToCheck.push(P);22992300return true;2301}23022303DiagnosticBuilder StructuralEquivalenceContext::Diag1(SourceLocation Loc,2304unsigned DiagID) {2305assert(Complain && "Not allowed to complain");2306if (LastDiagFromC2)2307FromCtx.getDiagnostics().notePriorDiagnosticFrom(ToCtx.getDiagnostics());2308LastDiagFromC2 = false;2309return FromCtx.getDiagnostics().Report(Loc, DiagID);2310}23112312DiagnosticBuilder StructuralEquivalenceContext::Diag2(SourceLocation Loc,2313unsigned DiagID) {2314assert(Complain && "Not allowed to complain");2315if (!LastDiagFromC2)2316ToCtx.getDiagnostics().notePriorDiagnosticFrom(FromCtx.getDiagnostics());2317LastDiagFromC2 = true;2318return ToCtx.getDiagnostics().Report(Loc, DiagID);2319}23202321std::optional<unsigned>2322StructuralEquivalenceContext::findUntaggedStructOrUnionIndex(RecordDecl *Anon) {2323ASTContext &Context = Anon->getASTContext();2324QualType AnonTy = Context.getRecordType(Anon);23252326const auto *Owner = dyn_cast<RecordDecl>(Anon->getDeclContext());2327if (!Owner)2328return std::nullopt;23292330unsigned Index = 0;2331for (const auto *D : Owner->noload_decls()) {2332const auto *F = dyn_cast<FieldDecl>(D);2333if (!F)2334continue;23352336if (F->isAnonymousStructOrUnion()) {2337if (Context.hasSameType(F->getType(), AnonTy))2338break;2339++Index;2340continue;2341}23422343// If the field looks like this:2344// struct { ... } A;2345QualType FieldType = F->getType();2346// In case of nested structs.2347while (const auto *ElabType = dyn_cast<ElaboratedType>(FieldType))2348FieldType = ElabType->getNamedType();23492350if (const auto *RecType = dyn_cast<RecordType>(FieldType)) {2351const RecordDecl *RecDecl = RecType->getDecl();2352if (RecDecl->getDeclContext() == Owner && !RecDecl->getIdentifier()) {2353if (Context.hasSameType(FieldType, AnonTy))2354break;2355++Index;2356continue;2357}2358}2359}23602361return Index;2362}23632364unsigned StructuralEquivalenceContext::getApplicableDiagnostic(2365unsigned ErrorDiagnostic) {2366if (ErrorOnTagTypeMismatch)2367return ErrorDiagnostic;23682369switch (ErrorDiagnostic) {2370case diag::err_odr_variable_type_inconsistent:2371return diag::warn_odr_variable_type_inconsistent;2372case diag::err_odr_variable_multiple_def:2373return diag::warn_odr_variable_multiple_def;2374case diag::err_odr_function_type_inconsistent:2375return diag::warn_odr_function_type_inconsistent;2376case diag::err_odr_tag_type_inconsistent:2377return diag::warn_odr_tag_type_inconsistent;2378case diag::err_odr_field_type_inconsistent:2379return diag::warn_odr_field_type_inconsistent;2380case diag::err_odr_ivar_type_inconsistent:2381return diag::warn_odr_ivar_type_inconsistent;2382case diag::err_odr_objc_superclass_inconsistent:2383return diag::warn_odr_objc_superclass_inconsistent;2384case diag::err_odr_objc_method_result_type_inconsistent:2385return diag::warn_odr_objc_method_result_type_inconsistent;2386case diag::err_odr_objc_method_num_params_inconsistent:2387return diag::warn_odr_objc_method_num_params_inconsistent;2388case diag::err_odr_objc_method_param_type_inconsistent:2389return diag::warn_odr_objc_method_param_type_inconsistent;2390case diag::err_odr_objc_method_variadic_inconsistent:2391return diag::warn_odr_objc_method_variadic_inconsistent;2392case diag::err_odr_objc_property_type_inconsistent:2393return diag::warn_odr_objc_property_type_inconsistent;2394case diag::err_odr_objc_property_impl_kind_inconsistent:2395return diag::warn_odr_objc_property_impl_kind_inconsistent;2396case diag::err_odr_objc_synthesize_ivar_inconsistent:2397return diag::warn_odr_objc_synthesize_ivar_inconsistent;2398case diag::err_odr_different_num_template_parameters:2399return diag::warn_odr_different_num_template_parameters;2400case diag::err_odr_different_template_parameter_kind:2401return diag::warn_odr_different_template_parameter_kind;2402case diag::err_odr_parameter_pack_non_pack:2403return diag::warn_odr_parameter_pack_non_pack;2404case diag::err_odr_non_type_parameter_type_inconsistent:2405return diag::warn_odr_non_type_parameter_type_inconsistent;2406}2407llvm_unreachable("Diagnostic kind not handled in preceding switch");2408}24092410bool StructuralEquivalenceContext::IsEquivalent(Decl *D1, Decl *D2) {24112412// Ensure that the implementation functions (all static functions in this TU)2413// never call the public ASTStructuralEquivalence::IsEquivalent() functions,2414// because that will wreak havoc the internal state (DeclsToCheck and2415// VisitedDecls members) and can cause faulty behaviour.2416// In other words: Do not start a graph search from a new node with the2417// internal data of another search in progress.2418// FIXME: Better encapsulation and separation of internal and public2419// functionality.2420assert(DeclsToCheck.empty());2421assert(VisitedDecls.empty());24222423if (!::IsStructurallyEquivalent(*this, D1, D2))2424return false;24252426return !Finish();2427}24282429bool StructuralEquivalenceContext::IsEquivalent(QualType T1, QualType T2) {2430assert(DeclsToCheck.empty());2431assert(VisitedDecls.empty());2432if (!::IsStructurallyEquivalent(*this, T1, T2))2433return false;24342435return !Finish();2436}24372438bool StructuralEquivalenceContext::IsEquivalent(Stmt *S1, Stmt *S2) {2439assert(DeclsToCheck.empty());2440assert(VisitedDecls.empty());2441if (!::IsStructurallyEquivalent(*this, S1, S2))2442return false;24432444return !Finish();2445}24462447bool StructuralEquivalenceContext::CheckCommonEquivalence(Decl *D1, Decl *D2) {2448// Check for equivalent described template.2449TemplateDecl *Template1 = D1->getDescribedTemplate();2450TemplateDecl *Template2 = D2->getDescribedTemplate();2451if ((Template1 != nullptr) != (Template2 != nullptr))2452return false;2453if (Template1 && !IsStructurallyEquivalent(*this, Template1, Template2))2454return false;24552456// FIXME: Move check for identifier names into this function.24572458return true;2459}24602461bool StructuralEquivalenceContext::CheckKindSpecificEquivalence(2462Decl *D1, Decl *D2) {24632464// Kind mismatch.2465if (D1->getKind() != D2->getKind())2466return false;24672468// Cast the Decls to their actual subclass so that the right overload of2469// IsStructurallyEquivalent is called.2470switch (D1->getKind()) {2471#define ABSTRACT_DECL(DECL)2472#define DECL(DERIVED, BASE) \2473case Decl::Kind::DERIVED: \2474return ::IsStructurallyEquivalent(*this, static_cast<DERIVED##Decl *>(D1), \2475static_cast<DERIVED##Decl *>(D2));2476#include "clang/AST/DeclNodes.inc"2477}2478return true;2479}24802481bool StructuralEquivalenceContext::Finish() {2482while (!DeclsToCheck.empty()) {2483// Check the next declaration.2484std::pair<Decl *, Decl *> P = DeclsToCheck.front();2485DeclsToCheck.pop();24862487Decl *D1 = P.first;2488Decl *D2 = P.second;24892490bool Equivalent =2491CheckCommonEquivalence(D1, D2) && CheckKindSpecificEquivalence(D1, D2);24922493if (!Equivalent) {2494// Note that these two declarations are not equivalent (and we already2495// know about it).2496NonEquivalentDecls.insert(P);24972498return true;2499}2500}25012502return false;2503}250425052506