12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904 |
- //===- ASTStructuralEquivalence.cpp ---------------------------------------===//
- //
- // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
- // See https://llvm.org/LICENSE.txt for license information.
- // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
- //
- //===----------------------------------------------------------------------===//
- //
- // This file implement StructuralEquivalenceContext class and helper functions
- // for layout matching.
- //
- // The structural equivalence check could have been implemented as a parallel
- // BFS on a pair of graphs. That must have been the original approach at the
- // beginning.
- // Let's consider this simple BFS algorithm from the `s` source:
- // ```
- // void bfs(Graph G, int s)
- // {
- // Queue<Integer> queue = new Queue<Integer>();
- // marked[s] = true; // Mark the source
- // queue.enqueue(s); // and put it on the queue.
- // while (!q.isEmpty()) {
- // int v = queue.dequeue(); // Remove next vertex from the queue.
- // for (int w : G.adj(v))
- // if (!marked[w]) // For every unmarked adjacent vertex,
- // {
- // marked[w] = true;
- // queue.enqueue(w);
- // }
- // }
- // }
- // ```
- // Indeed, it has it's queue, which holds pairs of nodes, one from each graph,
- // this is the `DeclsToCheck` and it's pair is in `TentativeEquivalences`.
- // `TentativeEquivalences` also plays the role of the marking (`marked`)
- // functionality above, we use it to check whether we've already seen a pair of
- // nodes.
- //
- // We put in the elements into the queue only in the toplevel decl check
- // function:
- // ```
- // static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
- // Decl *D1, Decl *D2);
- // ```
- // The `while` loop where we iterate over the children is implemented in
- // `Finish()`. And `Finish` is called only from the two **member** functions
- // which check the equivalency of two Decls or two Types. ASTImporter (and
- // other clients) call only these functions.
- //
- // The `static` implementation functions are called from `Finish`, these push
- // the children nodes to the queue via `static bool
- // IsStructurallyEquivalent(StructuralEquivalenceContext &Context, Decl *D1,
- // Decl *D2)`. So far so good, this is almost like the BFS. However, if we
- // let a static implementation function to call `Finish` via another **member**
- // function that means we end up with two nested while loops each of them
- // working on the same queue. This is wrong and nobody can reason about it's
- // doing. Thus, static implementation functions must not call the **member**
- // functions.
- //
- // So, now `TentativeEquivalences` plays two roles. It is used to store the
- // second half of the decls which we want to compare, plus it plays a role in
- // closing the recursion. On a long term, we could refactor structural
- // equivalency to be more alike to the traditional BFS.
- //
- //===----------------------------------------------------------------------===//
- #include "clang/AST/ASTStructuralEquivalence.h"
- #include "clang/AST/ASTContext.h"
- #include "clang/AST/ASTDiagnostic.h"
- #include "clang/AST/Decl.h"
- #include "clang/AST/DeclBase.h"
- #include "clang/AST/DeclCXX.h"
- #include "clang/AST/DeclFriend.h"
- #include "clang/AST/DeclObjC.h"
- #include "clang/AST/DeclTemplate.h"
- #include "clang/AST/ExprCXX.h"
- #include "clang/AST/NestedNameSpecifier.h"
- #include "clang/AST/TemplateBase.h"
- #include "clang/AST/TemplateName.h"
- #include "clang/AST/Type.h"
- #include "clang/Basic/ExceptionSpecificationType.h"
- #include "clang/Basic/IdentifierTable.h"
- #include "clang/Basic/LLVM.h"
- #include "clang/Basic/SourceLocation.h"
- #include "llvm/ADT/APInt.h"
- #include "llvm/ADT/APSInt.h"
- #include "llvm/ADT/None.h"
- #include "llvm/ADT/Optional.h"
- #include "llvm/Support/Casting.h"
- #include "llvm/Support/Compiler.h"
- #include "llvm/Support/ErrorHandling.h"
- #include <cassert>
- #include <utility>
- using namespace clang;
- static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
- QualType T1, QualType T2);
- static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
- Decl *D1, Decl *D2);
- static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
- const TemplateArgument &Arg1,
- const TemplateArgument &Arg2);
- static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
- NestedNameSpecifier *NNS1,
- NestedNameSpecifier *NNS2);
- static bool IsStructurallyEquivalent(const IdentifierInfo *Name1,
- const IdentifierInfo *Name2);
- static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
- const DeclarationName Name1,
- const DeclarationName Name2) {
- if (Name1.getNameKind() != Name2.getNameKind())
- return false;
- switch (Name1.getNameKind()) {
- case DeclarationName::Identifier:
- return IsStructurallyEquivalent(Name1.getAsIdentifierInfo(),
- Name2.getAsIdentifierInfo());
- case DeclarationName::CXXConstructorName:
- case DeclarationName::CXXDestructorName:
- case DeclarationName::CXXConversionFunctionName:
- return IsStructurallyEquivalent(Context, Name1.getCXXNameType(),
- Name2.getCXXNameType());
- case DeclarationName::CXXDeductionGuideName: {
- if (!IsStructurallyEquivalent(
- Context, Name1.getCXXDeductionGuideTemplate()->getDeclName(),
- Name2.getCXXDeductionGuideTemplate()->getDeclName()))
- return false;
- return IsStructurallyEquivalent(Context,
- Name1.getCXXDeductionGuideTemplate(),
- Name2.getCXXDeductionGuideTemplate());
- }
- case DeclarationName::CXXOperatorName:
- return Name1.getCXXOverloadedOperator() == Name2.getCXXOverloadedOperator();
- case DeclarationName::CXXLiteralOperatorName:
- return IsStructurallyEquivalent(Name1.getCXXLiteralIdentifier(),
- Name2.getCXXLiteralIdentifier());
- case DeclarationName::CXXUsingDirective:
- return true; // FIXME When do we consider two using directives equal?
- case DeclarationName::ObjCZeroArgSelector:
- case DeclarationName::ObjCOneArgSelector:
- case DeclarationName::ObjCMultiArgSelector:
- return true; // FIXME
- }
- llvm_unreachable("Unhandled kind of DeclarationName");
- return true;
- }
- /// Determine structural equivalence of two expressions.
- static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
- const Expr *E1, const Expr *E2) {
- if (!E1 || !E2)
- return E1 == E2;
- if (auto *DE1 = dyn_cast<DependentScopeDeclRefExpr>(E1)) {
- auto *DE2 = dyn_cast<DependentScopeDeclRefExpr>(E2);
- if (!DE2)
- return false;
- if (!IsStructurallyEquivalent(Context, DE1->getDeclName(),
- DE2->getDeclName()))
- return false;
- return IsStructurallyEquivalent(Context, DE1->getQualifier(),
- DE2->getQualifier());
- } else if (auto CastE1 = dyn_cast<ImplicitCastExpr>(E1)) {
- auto *CastE2 = dyn_cast<ImplicitCastExpr>(E2);
- if (!CastE2)
- return false;
- if (!IsStructurallyEquivalent(Context, CastE1->getType(),
- CastE2->getType()))
- return false;
- return IsStructurallyEquivalent(Context, CastE1->getSubExpr(),
- CastE2->getSubExpr());
- }
- // FIXME: Handle other kind of expressions!
- return true;
- }
- /// Determine whether two identifiers are equivalent.
- static bool IsStructurallyEquivalent(const IdentifierInfo *Name1,
- const IdentifierInfo *Name2) {
- if (!Name1 || !Name2)
- return Name1 == Name2;
- return Name1->getName() == Name2->getName();
- }
- /// Determine whether two nested-name-specifiers are equivalent.
- static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
- NestedNameSpecifier *NNS1,
- NestedNameSpecifier *NNS2) {
- if (NNS1->getKind() != NNS2->getKind())
- return false;
- NestedNameSpecifier *Prefix1 = NNS1->getPrefix(),
- *Prefix2 = NNS2->getPrefix();
- if ((bool)Prefix1 != (bool)Prefix2)
- return false;
- if (Prefix1)
- if (!IsStructurallyEquivalent(Context, Prefix1, Prefix2))
- return false;
- switch (NNS1->getKind()) {
- case NestedNameSpecifier::Identifier:
- return IsStructurallyEquivalent(NNS1->getAsIdentifier(),
- NNS2->getAsIdentifier());
- case NestedNameSpecifier::Namespace:
- return IsStructurallyEquivalent(Context, NNS1->getAsNamespace(),
- NNS2->getAsNamespace());
- case NestedNameSpecifier::NamespaceAlias:
- return IsStructurallyEquivalent(Context, NNS1->getAsNamespaceAlias(),
- NNS2->getAsNamespaceAlias());
- case NestedNameSpecifier::TypeSpec:
- case NestedNameSpecifier::TypeSpecWithTemplate:
- return IsStructurallyEquivalent(Context, QualType(NNS1->getAsType(), 0),
- QualType(NNS2->getAsType(), 0));
- case NestedNameSpecifier::Global:
- return true;
- case NestedNameSpecifier::Super:
- return IsStructurallyEquivalent(Context, NNS1->getAsRecordDecl(),
- NNS2->getAsRecordDecl());
- }
- return false;
- }
- static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
- const TemplateName &N1,
- const TemplateName &N2) {
- TemplateDecl *TemplateDeclN1 = N1.getAsTemplateDecl();
- TemplateDecl *TemplateDeclN2 = N2.getAsTemplateDecl();
- if (TemplateDeclN1 && TemplateDeclN2) {
- if (!IsStructurallyEquivalent(Context, TemplateDeclN1, TemplateDeclN2))
- return false;
- // If the kind is different we compare only the template decl.
- if (N1.getKind() != N2.getKind())
- return true;
- } else if (TemplateDeclN1 || TemplateDeclN2)
- return false;
- else if (N1.getKind() != N2.getKind())
- return false;
- // Check for special case incompatibilities.
- switch (N1.getKind()) {
- case TemplateName::OverloadedTemplate: {
- OverloadedTemplateStorage *OS1 = N1.getAsOverloadedTemplate(),
- *OS2 = N2.getAsOverloadedTemplate();
- OverloadedTemplateStorage::iterator I1 = OS1->begin(), I2 = OS2->begin(),
- E1 = OS1->end(), E2 = OS2->end();
- for (; I1 != E1 && I2 != E2; ++I1, ++I2)
- if (!IsStructurallyEquivalent(Context, *I1, *I2))
- return false;
- return I1 == E1 && I2 == E2;
- }
- case TemplateName::AssumedTemplate: {
- AssumedTemplateStorage *TN1 = N1.getAsAssumedTemplateName(),
- *TN2 = N1.getAsAssumedTemplateName();
- return TN1->getDeclName() == TN2->getDeclName();
- }
- case TemplateName::DependentTemplate: {
- DependentTemplateName *DN1 = N1.getAsDependentTemplateName(),
- *DN2 = N2.getAsDependentTemplateName();
- if (!IsStructurallyEquivalent(Context, DN1->getQualifier(),
- DN2->getQualifier()))
- return false;
- if (DN1->isIdentifier() && DN2->isIdentifier())
- return IsStructurallyEquivalent(DN1->getIdentifier(),
- DN2->getIdentifier());
- else if (DN1->isOverloadedOperator() && DN2->isOverloadedOperator())
- return DN1->getOperator() == DN2->getOperator();
- return false;
- }
- case TemplateName::SubstTemplateTemplateParmPack: {
- SubstTemplateTemplateParmPackStorage
- *P1 = N1.getAsSubstTemplateTemplateParmPack(),
- *P2 = N2.getAsSubstTemplateTemplateParmPack();
- return IsStructurallyEquivalent(Context, P1->getArgumentPack(),
- P2->getArgumentPack()) &&
- IsStructurallyEquivalent(Context, P1->getParameterPack(),
- P2->getParameterPack());
- }
- case TemplateName::Template:
- case TemplateName::QualifiedTemplate:
- case TemplateName::SubstTemplateTemplateParm:
- // It is sufficient to check value of getAsTemplateDecl.
- break;
- }
- return true;
- }
- /// Determine whether two template arguments are equivalent.
- static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
- const TemplateArgument &Arg1,
- const TemplateArgument &Arg2) {
- if (Arg1.getKind() != Arg2.getKind())
- return false;
- switch (Arg1.getKind()) {
- case TemplateArgument::Null:
- return true;
- case TemplateArgument::Type:
- return IsStructurallyEquivalent(Context, Arg1.getAsType(), Arg2.getAsType());
- case TemplateArgument::Integral:
- if (!IsStructurallyEquivalent(Context, Arg1.getIntegralType(),
- Arg2.getIntegralType()))
- return false;
- return llvm::APSInt::isSameValue(Arg1.getAsIntegral(),
- Arg2.getAsIntegral());
- case TemplateArgument::Declaration:
- return IsStructurallyEquivalent(Context, Arg1.getAsDecl(), Arg2.getAsDecl());
- case TemplateArgument::NullPtr:
- return true; // FIXME: Is this correct?
- case TemplateArgument::Template:
- return IsStructurallyEquivalent(Context, Arg1.getAsTemplate(),
- Arg2.getAsTemplate());
- case TemplateArgument::TemplateExpansion:
- return IsStructurallyEquivalent(Context,
- Arg1.getAsTemplateOrTemplatePattern(),
- Arg2.getAsTemplateOrTemplatePattern());
- case TemplateArgument::Expression:
- return IsStructurallyEquivalent(Context, Arg1.getAsExpr(),
- Arg2.getAsExpr());
- case TemplateArgument::Pack:
- if (Arg1.pack_size() != Arg2.pack_size())
- return false;
- for (unsigned I = 0, N = Arg1.pack_size(); I != N; ++I)
- if (!IsStructurallyEquivalent(Context, Arg1.pack_begin()[I],
- Arg2.pack_begin()[I]))
- return false;
- return true;
- }
- llvm_unreachable("Invalid template argument kind");
- }
- /// Determine structural equivalence for the common part of array
- /// types.
- static bool IsArrayStructurallyEquivalent(StructuralEquivalenceContext &Context,
- const ArrayType *Array1,
- const ArrayType *Array2) {
- if (!IsStructurallyEquivalent(Context, Array1->getElementType(),
- Array2->getElementType()))
- return false;
- if (Array1->getSizeModifier() != Array2->getSizeModifier())
- return false;
- if (Array1->getIndexTypeQualifiers() != Array2->getIndexTypeQualifiers())
- return false;
- return true;
- }
- /// Determine structural equivalence based on the ExtInfo of functions. This
- /// is inspired by ASTContext::mergeFunctionTypes(), we compare calling
- /// conventions bits but must not compare some other bits.
- static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
- FunctionType::ExtInfo EI1,
- FunctionType::ExtInfo EI2) {
- // Compatible functions must have compatible calling conventions.
- if (EI1.getCC() != EI2.getCC())
- return false;
- // Regparm is part of the calling convention.
- if (EI1.getHasRegParm() != EI2.getHasRegParm())
- return false;
- if (EI1.getRegParm() != EI2.getRegParm())
- return false;
- if (EI1.getProducesResult() != EI2.getProducesResult())
- return false;
- if (EI1.getNoCallerSavedRegs() != EI2.getNoCallerSavedRegs())
- return false;
- if (EI1.getNoCfCheck() != EI2.getNoCfCheck())
- return false;
- return true;
- }
- /// Check the equivalence of exception specifications.
- static bool IsEquivalentExceptionSpec(StructuralEquivalenceContext &Context,
- const FunctionProtoType *Proto1,
- const FunctionProtoType *Proto2) {
- auto Spec1 = Proto1->getExceptionSpecType();
- auto Spec2 = Proto2->getExceptionSpecType();
- if (isUnresolvedExceptionSpec(Spec1) || isUnresolvedExceptionSpec(Spec2))
- return true;
- if (Spec1 != Spec2)
- return false;
- if (Spec1 == EST_Dynamic) {
- if (Proto1->getNumExceptions() != Proto2->getNumExceptions())
- return false;
- for (unsigned I = 0, N = Proto1->getNumExceptions(); I != N; ++I) {
- if (!IsStructurallyEquivalent(Context, Proto1->getExceptionType(I),
- Proto2->getExceptionType(I)))
- return false;
- }
- } else if (isComputedNoexcept(Spec1)) {
- if (!IsStructurallyEquivalent(Context, Proto1->getNoexceptExpr(),
- Proto2->getNoexceptExpr()))
- return false;
- }
- return true;
- }
- /// Determine structural equivalence of two types.
- static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
- QualType T1, QualType T2) {
- if (T1.isNull() || T2.isNull())
- return T1.isNull() && T2.isNull();
- QualType OrigT1 = T1;
- QualType OrigT2 = T2;
- if (!Context.StrictTypeSpelling) {
- // We aren't being strict about token-to-token equivalence of types,
- // so map down to the canonical type.
- T1 = Context.FromCtx.getCanonicalType(T1);
- T2 = Context.ToCtx.getCanonicalType(T2);
- }
- if (T1.getQualifiers() != T2.getQualifiers())
- return false;
- Type::TypeClass TC = T1->getTypeClass();
- if (T1->getTypeClass() != T2->getTypeClass()) {
- // Compare function types with prototypes vs. without prototypes as if
- // both did not have prototypes.
- if (T1->getTypeClass() == Type::FunctionProto &&
- T2->getTypeClass() == Type::FunctionNoProto)
- TC = Type::FunctionNoProto;
- else if (T1->getTypeClass() == Type::FunctionNoProto &&
- T2->getTypeClass() == Type::FunctionProto)
- TC = Type::FunctionNoProto;
- else
- return false;
- }
- switch (TC) {
- case Type::Builtin:
- // FIXME: Deal with Char_S/Char_U.
- if (cast<BuiltinType>(T1)->getKind() != cast<BuiltinType>(T2)->getKind())
- return false;
- break;
- case Type::Complex:
- if (!IsStructurallyEquivalent(Context,
- cast<ComplexType>(T1)->getElementType(),
- cast<ComplexType>(T2)->getElementType()))
- return false;
- break;
- case Type::Adjusted:
- case Type::Decayed:
- if (!IsStructurallyEquivalent(Context,
- cast<AdjustedType>(T1)->getOriginalType(),
- cast<AdjustedType>(T2)->getOriginalType()))
- return false;
- break;
- case Type::Pointer:
- if (!IsStructurallyEquivalent(Context,
- cast<PointerType>(T1)->getPointeeType(),
- cast<PointerType>(T2)->getPointeeType()))
- return false;
- break;
- case Type::BlockPointer:
- if (!IsStructurallyEquivalent(Context,
- cast<BlockPointerType>(T1)->getPointeeType(),
- cast<BlockPointerType>(T2)->getPointeeType()))
- return false;
- break;
- case Type::LValueReference:
- case Type::RValueReference: {
- const auto *Ref1 = cast<ReferenceType>(T1);
- const auto *Ref2 = cast<ReferenceType>(T2);
- if (Ref1->isSpelledAsLValue() != Ref2->isSpelledAsLValue())
- return false;
- if (Ref1->isInnerRef() != Ref2->isInnerRef())
- return false;
- if (!IsStructurallyEquivalent(Context, Ref1->getPointeeTypeAsWritten(),
- Ref2->getPointeeTypeAsWritten()))
- return false;
- break;
- }
- case Type::MemberPointer: {
- const auto *MemPtr1 = cast<MemberPointerType>(T1);
- const auto *MemPtr2 = cast<MemberPointerType>(T2);
- if (!IsStructurallyEquivalent(Context, MemPtr1->getPointeeType(),
- MemPtr2->getPointeeType()))
- return false;
- if (!IsStructurallyEquivalent(Context, QualType(MemPtr1->getClass(), 0),
- QualType(MemPtr2->getClass(), 0)))
- return false;
- break;
- }
- case Type::ConstantArray: {
- const auto *Array1 = cast<ConstantArrayType>(T1);
- const auto *Array2 = cast<ConstantArrayType>(T2);
- if (!llvm::APInt::isSameValue(Array1->getSize(), Array2->getSize()))
- return false;
- if (!IsArrayStructurallyEquivalent(Context, Array1, Array2))
- return false;
- break;
- }
- case Type::IncompleteArray:
- if (!IsArrayStructurallyEquivalent(Context, cast<ArrayType>(T1),
- cast<ArrayType>(T2)))
- return false;
- break;
- case Type::VariableArray: {
- const auto *Array1 = cast<VariableArrayType>(T1);
- const auto *Array2 = cast<VariableArrayType>(T2);
- if (!IsStructurallyEquivalent(Context, Array1->getSizeExpr(),
- Array2->getSizeExpr()))
- return false;
- if (!IsArrayStructurallyEquivalent(Context, Array1, Array2))
- return false;
- break;
- }
- case Type::DependentSizedArray: {
- const auto *Array1 = cast<DependentSizedArrayType>(T1);
- const auto *Array2 = cast<DependentSizedArrayType>(T2);
- if (!IsStructurallyEquivalent(Context, Array1->getSizeExpr(),
- Array2->getSizeExpr()))
- return false;
- if (!IsArrayStructurallyEquivalent(Context, Array1, Array2))
- return false;
- break;
- }
- case Type::DependentAddressSpace: {
- const auto *DepAddressSpace1 = cast<DependentAddressSpaceType>(T1);
- const auto *DepAddressSpace2 = cast<DependentAddressSpaceType>(T2);
- if (!IsStructurallyEquivalent(Context, DepAddressSpace1->getAddrSpaceExpr(),
- DepAddressSpace2->getAddrSpaceExpr()))
- return false;
- if (!IsStructurallyEquivalent(Context, DepAddressSpace1->getPointeeType(),
- DepAddressSpace2->getPointeeType()))
- return false;
- break;
- }
- case Type::DependentSizedExtVector: {
- const auto *Vec1 = cast<DependentSizedExtVectorType>(T1);
- const auto *Vec2 = cast<DependentSizedExtVectorType>(T2);
- if (!IsStructurallyEquivalent(Context, Vec1->getSizeExpr(),
- Vec2->getSizeExpr()))
- return false;
- if (!IsStructurallyEquivalent(Context, Vec1->getElementType(),
- Vec2->getElementType()))
- return false;
- break;
- }
- case Type::DependentVector: {
- const auto *Vec1 = cast<DependentVectorType>(T1);
- const auto *Vec2 = cast<DependentVectorType>(T2);
- if (Vec1->getVectorKind() != Vec2->getVectorKind())
- return false;
- if (!IsStructurallyEquivalent(Context, Vec1->getSizeExpr(),
- Vec2->getSizeExpr()))
- return false;
- if (!IsStructurallyEquivalent(Context, Vec1->getElementType(),
- Vec2->getElementType()))
- return false;
- break;
- }
- case Type::Vector:
- case Type::ExtVector: {
- const auto *Vec1 = cast<VectorType>(T1);
- const auto *Vec2 = cast<VectorType>(T2);
- if (!IsStructurallyEquivalent(Context, Vec1->getElementType(),
- Vec2->getElementType()))
- return false;
- if (Vec1->getNumElements() != Vec2->getNumElements())
- return false;
- if (Vec1->getVectorKind() != Vec2->getVectorKind())
- return false;
- break;
- }
- case Type::FunctionProto: {
- const auto *Proto1 = cast<FunctionProtoType>(T1);
- const auto *Proto2 = cast<FunctionProtoType>(T2);
- if (Proto1->getNumParams() != Proto2->getNumParams())
- return false;
- for (unsigned I = 0, N = Proto1->getNumParams(); I != N; ++I) {
- if (!IsStructurallyEquivalent(Context, Proto1->getParamType(I),
- Proto2->getParamType(I)))
- return false;
- }
- if (Proto1->isVariadic() != Proto2->isVariadic())
- return false;
- if (Proto1->getMethodQuals() != Proto2->getMethodQuals())
- return false;
- // Check exceptions, this information is lost in canonical type.
- const auto *OrigProto1 =
- cast<FunctionProtoType>(OrigT1.getDesugaredType(Context.FromCtx));
- const auto *OrigProto2 =
- cast<FunctionProtoType>(OrigT2.getDesugaredType(Context.ToCtx));
- if (!IsEquivalentExceptionSpec(Context, OrigProto1, OrigProto2))
- return false;
- // Fall through to check the bits common with FunctionNoProtoType.
- LLVM_FALLTHROUGH;
- }
- case Type::FunctionNoProto: {
- const auto *Function1 = cast<FunctionType>(T1);
- const auto *Function2 = cast<FunctionType>(T2);
- if (!IsStructurallyEquivalent(Context, Function1->getReturnType(),
- Function2->getReturnType()))
- return false;
- if (!IsStructurallyEquivalent(Context, Function1->getExtInfo(),
- Function2->getExtInfo()))
- return false;
- break;
- }
- case Type::UnresolvedUsing:
- if (!IsStructurallyEquivalent(Context,
- cast<UnresolvedUsingType>(T1)->getDecl(),
- cast<UnresolvedUsingType>(T2)->getDecl()))
- return false;
- break;
- case Type::Attributed:
- if (!IsStructurallyEquivalent(Context,
- cast<AttributedType>(T1)->getModifiedType(),
- cast<AttributedType>(T2)->getModifiedType()))
- return false;
- if (!IsStructurallyEquivalent(
- Context, cast<AttributedType>(T1)->getEquivalentType(),
- cast<AttributedType>(T2)->getEquivalentType()))
- return false;
- break;
- case Type::Paren:
- if (!IsStructurallyEquivalent(Context, cast<ParenType>(T1)->getInnerType(),
- cast<ParenType>(T2)->getInnerType()))
- return false;
- break;
- case Type::MacroQualified:
- if (!IsStructurallyEquivalent(
- Context, cast<MacroQualifiedType>(T1)->getUnderlyingType(),
- cast<MacroQualifiedType>(T2)->getUnderlyingType()))
- return false;
- break;
- case Type::Typedef:
- if (!IsStructurallyEquivalent(Context, cast<TypedefType>(T1)->getDecl(),
- cast<TypedefType>(T2)->getDecl()))
- return false;
- break;
- case Type::TypeOfExpr:
- if (!IsStructurallyEquivalent(
- Context, cast<TypeOfExprType>(T1)->getUnderlyingExpr(),
- cast<TypeOfExprType>(T2)->getUnderlyingExpr()))
- return false;
- break;
- case Type::TypeOf:
- if (!IsStructurallyEquivalent(Context,
- cast<TypeOfType>(T1)->getUnderlyingType(),
- cast<TypeOfType>(T2)->getUnderlyingType()))
- return false;
- break;
- case Type::UnaryTransform:
- if (!IsStructurallyEquivalent(
- Context, cast<UnaryTransformType>(T1)->getUnderlyingType(),
- cast<UnaryTransformType>(T2)->getUnderlyingType()))
- return false;
- break;
- case Type::Decltype:
- if (!IsStructurallyEquivalent(Context,
- cast<DecltypeType>(T1)->getUnderlyingExpr(),
- cast<DecltypeType>(T2)->getUnderlyingExpr()))
- return false;
- break;
- case Type::Auto:
- if (!IsStructurallyEquivalent(Context, cast<AutoType>(T1)->getDeducedType(),
- cast<AutoType>(T2)->getDeducedType()))
- return false;
- break;
- case Type::DeducedTemplateSpecialization: {
- const auto *DT1 = cast<DeducedTemplateSpecializationType>(T1);
- const auto *DT2 = cast<DeducedTemplateSpecializationType>(T2);
- if (!IsStructurallyEquivalent(Context, DT1->getTemplateName(),
- DT2->getTemplateName()))
- return false;
- if (!IsStructurallyEquivalent(Context, DT1->getDeducedType(),
- DT2->getDeducedType()))
- return false;
- break;
- }
- case Type::Record:
- case Type::Enum:
- if (!IsStructurallyEquivalent(Context, cast<TagType>(T1)->getDecl(),
- cast<TagType>(T2)->getDecl()))
- return false;
- break;
- case Type::TemplateTypeParm: {
- const auto *Parm1 = cast<TemplateTypeParmType>(T1);
- const auto *Parm2 = cast<TemplateTypeParmType>(T2);
- if (Parm1->getDepth() != Parm2->getDepth())
- return false;
- if (Parm1->getIndex() != Parm2->getIndex())
- return false;
- if (Parm1->isParameterPack() != Parm2->isParameterPack())
- return false;
- // Names of template type parameters are never significant.
- break;
- }
- case Type::SubstTemplateTypeParm: {
- const auto *Subst1 = cast<SubstTemplateTypeParmType>(T1);
- const auto *Subst2 = cast<SubstTemplateTypeParmType>(T2);
- if (!IsStructurallyEquivalent(Context,
- QualType(Subst1->getReplacedParameter(), 0),
- QualType(Subst2->getReplacedParameter(), 0)))
- return false;
- if (!IsStructurallyEquivalent(Context, Subst1->getReplacementType(),
- Subst2->getReplacementType()))
- return false;
- break;
- }
- case Type::SubstTemplateTypeParmPack: {
- const auto *Subst1 = cast<SubstTemplateTypeParmPackType>(T1);
- const auto *Subst2 = cast<SubstTemplateTypeParmPackType>(T2);
- if (!IsStructurallyEquivalent(Context,
- QualType(Subst1->getReplacedParameter(), 0),
- QualType(Subst2->getReplacedParameter(), 0)))
- return false;
- if (!IsStructurallyEquivalent(Context, Subst1->getArgumentPack(),
- Subst2->getArgumentPack()))
- return false;
- break;
- }
- case Type::TemplateSpecialization: {
- const auto *Spec1 = cast<TemplateSpecializationType>(T1);
- const auto *Spec2 = cast<TemplateSpecializationType>(T2);
- if (!IsStructurallyEquivalent(Context, Spec1->getTemplateName(),
- Spec2->getTemplateName()))
- return false;
- if (Spec1->getNumArgs() != Spec2->getNumArgs())
- return false;
- for (unsigned I = 0, N = Spec1->getNumArgs(); I != N; ++I) {
- if (!IsStructurallyEquivalent(Context, Spec1->getArg(I),
- Spec2->getArg(I)))
- return false;
- }
- break;
- }
- case Type::Elaborated: {
- const auto *Elab1 = cast<ElaboratedType>(T1);
- const auto *Elab2 = cast<ElaboratedType>(T2);
- // CHECKME: what if a keyword is ETK_None or ETK_typename ?
- if (Elab1->getKeyword() != Elab2->getKeyword())
- return false;
- if (!IsStructurallyEquivalent(Context, Elab1->getQualifier(),
- Elab2->getQualifier()))
- return false;
- if (!IsStructurallyEquivalent(Context, Elab1->getNamedType(),
- Elab2->getNamedType()))
- return false;
- break;
- }
- case Type::InjectedClassName: {
- const auto *Inj1 = cast<InjectedClassNameType>(T1);
- const auto *Inj2 = cast<InjectedClassNameType>(T2);
- if (!IsStructurallyEquivalent(Context,
- Inj1->getInjectedSpecializationType(),
- Inj2->getInjectedSpecializationType()))
- return false;
- break;
- }
- case Type::DependentName: {
- const auto *Typename1 = cast<DependentNameType>(T1);
- const auto *Typename2 = cast<DependentNameType>(T2);
- if (!IsStructurallyEquivalent(Context, Typename1->getQualifier(),
- Typename2->getQualifier()))
- return false;
- if (!IsStructurallyEquivalent(Typename1->getIdentifier(),
- Typename2->getIdentifier()))
- return false;
- break;
- }
- case Type::DependentTemplateSpecialization: {
- const auto *Spec1 = cast<DependentTemplateSpecializationType>(T1);
- const auto *Spec2 = cast<DependentTemplateSpecializationType>(T2);
- if (!IsStructurallyEquivalent(Context, Spec1->getQualifier(),
- Spec2->getQualifier()))
- return false;
- if (!IsStructurallyEquivalent(Spec1->getIdentifier(),
- Spec2->getIdentifier()))
- return false;
- if (Spec1->getNumArgs() != Spec2->getNumArgs())
- return false;
- for (unsigned I = 0, N = Spec1->getNumArgs(); I != N; ++I) {
- if (!IsStructurallyEquivalent(Context, Spec1->getArg(I),
- Spec2->getArg(I)))
- return false;
- }
- break;
- }
- case Type::PackExpansion:
- if (!IsStructurallyEquivalent(Context,
- cast<PackExpansionType>(T1)->getPattern(),
- cast<PackExpansionType>(T2)->getPattern()))
- return false;
- break;
- case Type::ObjCInterface: {
- const auto *Iface1 = cast<ObjCInterfaceType>(T1);
- const auto *Iface2 = cast<ObjCInterfaceType>(T2);
- if (!IsStructurallyEquivalent(Context, Iface1->getDecl(),
- Iface2->getDecl()))
- return false;
- break;
- }
- case Type::ObjCTypeParam: {
- const auto *Obj1 = cast<ObjCTypeParamType>(T1);
- const auto *Obj2 = cast<ObjCTypeParamType>(T2);
- if (!IsStructurallyEquivalent(Context, Obj1->getDecl(), Obj2->getDecl()))
- return false;
- if (Obj1->getNumProtocols() != Obj2->getNumProtocols())
- return false;
- for (unsigned I = 0, N = Obj1->getNumProtocols(); I != N; ++I) {
- if (!IsStructurallyEquivalent(Context, Obj1->getProtocol(I),
- Obj2->getProtocol(I)))
- return false;
- }
- break;
- }
- case Type::ObjCObject: {
- const auto *Obj1 = cast<ObjCObjectType>(T1);
- const auto *Obj2 = cast<ObjCObjectType>(T2);
- if (!IsStructurallyEquivalent(Context, Obj1->getBaseType(),
- Obj2->getBaseType()))
- return false;
- if (Obj1->getNumProtocols() != Obj2->getNumProtocols())
- return false;
- for (unsigned I = 0, N = Obj1->getNumProtocols(); I != N; ++I) {
- if (!IsStructurallyEquivalent(Context, Obj1->getProtocol(I),
- Obj2->getProtocol(I)))
- return false;
- }
- break;
- }
- case Type::ObjCObjectPointer: {
- const auto *Ptr1 = cast<ObjCObjectPointerType>(T1);
- const auto *Ptr2 = cast<ObjCObjectPointerType>(T2);
- if (!IsStructurallyEquivalent(Context, Ptr1->getPointeeType(),
- Ptr2->getPointeeType()))
- return false;
- break;
- }
- case Type::Atomic:
- if (!IsStructurallyEquivalent(Context, cast<AtomicType>(T1)->getValueType(),
- cast<AtomicType>(T2)->getValueType()))
- return false;
- break;
- case Type::Pipe:
- if (!IsStructurallyEquivalent(Context, cast<PipeType>(T1)->getElementType(),
- cast<PipeType>(T2)->getElementType()))
- return false;
- break;
- } // end switch
- return true;
- }
- /// Determine structural equivalence of two fields.
- static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
- FieldDecl *Field1, FieldDecl *Field2) {
- const auto *Owner2 = cast<RecordDecl>(Field2->getDeclContext());
- // For anonymous structs/unions, match up the anonymous struct/union type
- // declarations directly, so that we don't go off searching for anonymous
- // types
- if (Field1->isAnonymousStructOrUnion() &&
- Field2->isAnonymousStructOrUnion()) {
- RecordDecl *D1 = Field1->getType()->castAs<RecordType>()->getDecl();
- RecordDecl *D2 = Field2->getType()->castAs<RecordType>()->getDecl();
- return IsStructurallyEquivalent(Context, D1, D2);
- }
- // Check for equivalent field names.
- IdentifierInfo *Name1 = Field1->getIdentifier();
- IdentifierInfo *Name2 = Field2->getIdentifier();
- if (!::IsStructurallyEquivalent(Name1, Name2)) {
- if (Context.Complain) {
- Context.Diag2(
- Owner2->getLocation(),
- Context.getApplicableDiagnostic(diag::err_odr_tag_type_inconsistent))
- << Context.ToCtx.getTypeDeclType(Owner2);
- Context.Diag2(Field2->getLocation(), diag::note_odr_field_name)
- << Field2->getDeclName();
- Context.Diag1(Field1->getLocation(), diag::note_odr_field_name)
- << Field1->getDeclName();
- }
- return false;
- }
- if (!IsStructurallyEquivalent(Context, Field1->getType(),
- Field2->getType())) {
- if (Context.Complain) {
- Context.Diag2(
- Owner2->getLocation(),
- Context.getApplicableDiagnostic(diag::err_odr_tag_type_inconsistent))
- << Context.ToCtx.getTypeDeclType(Owner2);
- Context.Diag2(Field2->getLocation(), diag::note_odr_field)
- << Field2->getDeclName() << Field2->getType();
- Context.Diag1(Field1->getLocation(), diag::note_odr_field)
- << Field1->getDeclName() << Field1->getType();
- }
- return false;
- }
- if (Field1->isBitField() != Field2->isBitField()) {
- if (Context.Complain) {
- Context.Diag2(
- Owner2->getLocation(),
- Context.getApplicableDiagnostic(diag::err_odr_tag_type_inconsistent))
- << Context.ToCtx.getTypeDeclType(Owner2);
- if (Field1->isBitField()) {
- Context.Diag1(Field1->getLocation(), diag::note_odr_bit_field)
- << Field1->getDeclName() << Field1->getType()
- << Field1->getBitWidthValue(Context.FromCtx);
- Context.Diag2(Field2->getLocation(), diag::note_odr_not_bit_field)
- << Field2->getDeclName();
- } else {
- Context.Diag2(Field2->getLocation(), diag::note_odr_bit_field)
- << Field2->getDeclName() << Field2->getType()
- << Field2->getBitWidthValue(Context.ToCtx);
- Context.Diag1(Field1->getLocation(), diag::note_odr_not_bit_field)
- << Field1->getDeclName();
- }
- }
- return false;
- }
- if (Field1->isBitField()) {
- // Make sure that the bit-fields are the same length.
- unsigned Bits1 = Field1->getBitWidthValue(Context.FromCtx);
- unsigned Bits2 = Field2->getBitWidthValue(Context.ToCtx);
- if (Bits1 != Bits2) {
- if (Context.Complain) {
- Context.Diag2(Owner2->getLocation(),
- Context.getApplicableDiagnostic(
- diag::err_odr_tag_type_inconsistent))
- << Context.ToCtx.getTypeDeclType(Owner2);
- Context.Diag2(Field2->getLocation(), diag::note_odr_bit_field)
- << Field2->getDeclName() << Field2->getType() << Bits2;
- Context.Diag1(Field1->getLocation(), diag::note_odr_bit_field)
- << Field1->getDeclName() << Field1->getType() << Bits1;
- }
- return false;
- }
- }
- return true;
- }
- /// Determine structural equivalence of two methods.
- static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
- CXXMethodDecl *Method1,
- CXXMethodDecl *Method2) {
- bool PropertiesEqual =
- Method1->getDeclKind() == Method2->getDeclKind() &&
- Method1->getRefQualifier() == Method2->getRefQualifier() &&
- Method1->getAccess() == Method2->getAccess() &&
- Method1->getOverloadedOperator() == Method2->getOverloadedOperator() &&
- Method1->isStatic() == Method2->isStatic() &&
- Method1->isConst() == Method2->isConst() &&
- Method1->isVolatile() == Method2->isVolatile() &&
- Method1->isVirtual() == Method2->isVirtual() &&
- Method1->isPure() == Method2->isPure() &&
- Method1->isDefaulted() == Method2->isDefaulted() &&
- Method1->isDeleted() == Method2->isDeleted();
- if (!PropertiesEqual)
- return false;
- // FIXME: Check for 'final'.
- if (auto *Constructor1 = dyn_cast<CXXConstructorDecl>(Method1)) {
- auto *Constructor2 = cast<CXXConstructorDecl>(Method2);
- if (!Constructor1->getExplicitSpecifier().isEquivalent(
- Constructor2->getExplicitSpecifier()))
- return false;
- }
- if (auto *Conversion1 = dyn_cast<CXXConversionDecl>(Method1)) {
- auto *Conversion2 = cast<CXXConversionDecl>(Method2);
- if (!Conversion1->getExplicitSpecifier().isEquivalent(
- Conversion2->getExplicitSpecifier()))
- return false;
- if (!IsStructurallyEquivalent(Context, Conversion1->getConversionType(),
- Conversion2->getConversionType()))
- return false;
- }
- const IdentifierInfo *Name1 = Method1->getIdentifier();
- const IdentifierInfo *Name2 = Method2->getIdentifier();
- if (!::IsStructurallyEquivalent(Name1, Name2)) {
- return false;
- // TODO: Names do not match, add warning like at check for FieldDecl.
- }
- // Check the prototypes.
- if (!::IsStructurallyEquivalent(Context,
- Method1->getType(), Method2->getType()))
- return false;
- return true;
- }
- /// Determine structural equivalence of two lambda classes.
- static bool
- IsStructurallyEquivalentLambdas(StructuralEquivalenceContext &Context,
- CXXRecordDecl *D1, CXXRecordDecl *D2) {
- assert(D1->isLambda() && D2->isLambda() &&
- "Must be called on lambda classes");
- if (!IsStructurallyEquivalent(Context, D1->getLambdaCallOperator(),
- D2->getLambdaCallOperator()))
- return false;
- return true;
- }
- /// Determine structural equivalence of two records.
- static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
- RecordDecl *D1, RecordDecl *D2) {
- if (D1->isUnion() != D2->isUnion()) {
- if (Context.Complain) {
- Context.Diag2(D2->getLocation(), Context.getApplicableDiagnostic(
- diag::err_odr_tag_type_inconsistent))
- << Context.ToCtx.getTypeDeclType(D2);
- Context.Diag1(D1->getLocation(), diag::note_odr_tag_kind_here)
- << D1->getDeclName() << (unsigned)D1->getTagKind();
- }
- return false;
- }
- if (!D1->getDeclName() && !D2->getDeclName()) {
- // If both anonymous structs/unions are in a record context, make sure
- // they occur in the same location in the context records.
- if (Optional<unsigned> Index1 =
- StructuralEquivalenceContext::findUntaggedStructOrUnionIndex(D1)) {
- if (Optional<unsigned> Index2 =
- StructuralEquivalenceContext::findUntaggedStructOrUnionIndex(
- D2)) {
- if (*Index1 != *Index2)
- return false;
- }
- }
- }
- // If both declarations are class template specializations, we know
- // the ODR applies, so check the template and template arguments.
- const auto *Spec1 = dyn_cast<ClassTemplateSpecializationDecl>(D1);
- const auto *Spec2 = dyn_cast<ClassTemplateSpecializationDecl>(D2);
- if (Spec1 && Spec2) {
- // Check that the specialized templates are the same.
- if (!IsStructurallyEquivalent(Context, Spec1->getSpecializedTemplate(),
- Spec2->getSpecializedTemplate()))
- return false;
- // Check that the template arguments are the same.
- if (Spec1->getTemplateArgs().size() != Spec2->getTemplateArgs().size())
- return false;
- for (unsigned I = 0, N = Spec1->getTemplateArgs().size(); I != N; ++I)
- if (!IsStructurallyEquivalent(Context, Spec1->getTemplateArgs().get(I),
- Spec2->getTemplateArgs().get(I)))
- return false;
- }
- // If one is a class template specialization and the other is not, these
- // structures are different.
- else if (Spec1 || Spec2)
- return false;
- // Compare the definitions of these two records. If either or both are
- // incomplete (i.e. it is a forward decl), we assume that they are
- // equivalent.
- D1 = D1->getDefinition();
- D2 = D2->getDefinition();
- if (!D1 || !D2)
- return true;
- // If any of the records has external storage and we do a minimal check (or
- // AST import) we assume they are equivalent. (If we didn't have this
- // assumption then `RecordDecl::LoadFieldsFromExternalStorage` could trigger
- // another AST import which in turn would call the structural equivalency
- // check again and finally we'd have an improper result.)
- if (Context.EqKind == StructuralEquivalenceKind::Minimal)
- if (D1->hasExternalLexicalStorage() || D2->hasExternalLexicalStorage())
- return true;
- // If one definition is currently being defined, we do not compare for
- // equality and we assume that the decls are equal.
- if (D1->isBeingDefined() || D2->isBeingDefined())
- return true;
- if (auto *D1CXX = dyn_cast<CXXRecordDecl>(D1)) {
- if (auto *D2CXX = dyn_cast<CXXRecordDecl>(D2)) {
- if (D1CXX->hasExternalLexicalStorage() &&
- !D1CXX->isCompleteDefinition()) {
- D1CXX->getASTContext().getExternalSource()->CompleteType(D1CXX);
- }
- if (D1CXX->isLambda() != D2CXX->isLambda())
- return false;
- if (D1CXX->isLambda()) {
- if (!IsStructurallyEquivalentLambdas(Context, D1CXX, D2CXX))
- return false;
- }
- if (D1CXX->getNumBases() != D2CXX->getNumBases()) {
- if (Context.Complain) {
- Context.Diag2(D2->getLocation(),
- Context.getApplicableDiagnostic(
- diag::err_odr_tag_type_inconsistent))
- << Context.ToCtx.getTypeDeclType(D2);
- Context.Diag2(D2->getLocation(), diag::note_odr_number_of_bases)
- << D2CXX->getNumBases();
- Context.Diag1(D1->getLocation(), diag::note_odr_number_of_bases)
- << D1CXX->getNumBases();
- }
- return false;
- }
- // Check the base classes.
- for (CXXRecordDecl::base_class_iterator Base1 = D1CXX->bases_begin(),
- BaseEnd1 = D1CXX->bases_end(),
- Base2 = D2CXX->bases_begin();
- Base1 != BaseEnd1; ++Base1, ++Base2) {
- if (!IsStructurallyEquivalent(Context, Base1->getType(),
- Base2->getType())) {
- if (Context.Complain) {
- Context.Diag2(D2->getLocation(),
- Context.getApplicableDiagnostic(
- diag::err_odr_tag_type_inconsistent))
- << Context.ToCtx.getTypeDeclType(D2);
- Context.Diag2(Base2->getBeginLoc(), diag::note_odr_base)
- << Base2->getType() << Base2->getSourceRange();
- Context.Diag1(Base1->getBeginLoc(), diag::note_odr_base)
- << Base1->getType() << Base1->getSourceRange();
- }
- return false;
- }
- // Check virtual vs. non-virtual inheritance mismatch.
- if (Base1->isVirtual() != Base2->isVirtual()) {
- if (Context.Complain) {
- Context.Diag2(D2->getLocation(),
- Context.getApplicableDiagnostic(
- diag::err_odr_tag_type_inconsistent))
- << Context.ToCtx.getTypeDeclType(D2);
- Context.Diag2(Base2->getBeginLoc(), diag::note_odr_virtual_base)
- << Base2->isVirtual() << Base2->getSourceRange();
- Context.Diag1(Base1->getBeginLoc(), diag::note_odr_base)
- << Base1->isVirtual() << Base1->getSourceRange();
- }
- return false;
- }
- }
- // Check the friends for consistency.
- CXXRecordDecl::friend_iterator Friend2 = D2CXX->friend_begin(),
- Friend2End = D2CXX->friend_end();
- for (CXXRecordDecl::friend_iterator Friend1 = D1CXX->friend_begin(),
- Friend1End = D1CXX->friend_end();
- Friend1 != Friend1End; ++Friend1, ++Friend2) {
- if (Friend2 == Friend2End) {
- if (Context.Complain) {
- Context.Diag2(D2->getLocation(),
- Context.getApplicableDiagnostic(
- diag::err_odr_tag_type_inconsistent))
- << Context.ToCtx.getTypeDeclType(D2CXX);
- Context.Diag1((*Friend1)->getFriendLoc(), diag::note_odr_friend);
- Context.Diag2(D2->getLocation(), diag::note_odr_missing_friend);
- }
- return false;
- }
- if (!IsStructurallyEquivalent(Context, *Friend1, *Friend2)) {
- if (Context.Complain) {
- Context.Diag2(D2->getLocation(),
- Context.getApplicableDiagnostic(
- diag::err_odr_tag_type_inconsistent))
- << Context.ToCtx.getTypeDeclType(D2CXX);
- Context.Diag1((*Friend1)->getFriendLoc(), diag::note_odr_friend);
- Context.Diag2((*Friend2)->getFriendLoc(), diag::note_odr_friend);
- }
- return false;
- }
- }
- if (Friend2 != Friend2End) {
- if (Context.Complain) {
- Context.Diag2(D2->getLocation(),
- Context.getApplicableDiagnostic(
- diag::err_odr_tag_type_inconsistent))
- << Context.ToCtx.getTypeDeclType(D2);
- Context.Diag2((*Friend2)->getFriendLoc(), diag::note_odr_friend);
- Context.Diag1(D1->getLocation(), diag::note_odr_missing_friend);
- }
- return false;
- }
- } else if (D1CXX->getNumBases() > 0) {
- if (Context.Complain) {
- Context.Diag2(D2->getLocation(),
- Context.getApplicableDiagnostic(
- diag::err_odr_tag_type_inconsistent))
- << Context.ToCtx.getTypeDeclType(D2);
- const CXXBaseSpecifier *Base1 = D1CXX->bases_begin();
- Context.Diag1(Base1->getBeginLoc(), diag::note_odr_base)
- << Base1->getType() << Base1->getSourceRange();
- Context.Diag2(D2->getLocation(), diag::note_odr_missing_base);
- }
- return false;
- }
- }
- // Check the fields for consistency.
- RecordDecl::field_iterator Field2 = D2->field_begin(),
- Field2End = D2->field_end();
- for (RecordDecl::field_iterator Field1 = D1->field_begin(),
- Field1End = D1->field_end();
- Field1 != Field1End; ++Field1, ++Field2) {
- if (Field2 == Field2End) {
- if (Context.Complain) {
- Context.Diag2(D2->getLocation(),
- Context.getApplicableDiagnostic(
- diag::err_odr_tag_type_inconsistent))
- << Context.ToCtx.getTypeDeclType(D2);
- Context.Diag1(Field1->getLocation(), diag::note_odr_field)
- << Field1->getDeclName() << Field1->getType();
- Context.Diag2(D2->getLocation(), diag::note_odr_missing_field);
- }
- return false;
- }
- if (!IsStructurallyEquivalent(Context, *Field1, *Field2))
- return false;
- }
- if (Field2 != Field2End) {
- if (Context.Complain) {
- Context.Diag2(D2->getLocation(), Context.getApplicableDiagnostic(
- diag::err_odr_tag_type_inconsistent))
- << Context.ToCtx.getTypeDeclType(D2);
- Context.Diag2(Field2->getLocation(), diag::note_odr_field)
- << Field2->getDeclName() << Field2->getType();
- Context.Diag1(D1->getLocation(), diag::note_odr_missing_field);
- }
- return false;
- }
- return true;
- }
- /// Determine structural equivalence of two enums.
- static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
- EnumDecl *D1, EnumDecl *D2) {
- // Compare the definitions of these two enums. If either or both are
- // incomplete (i.e. forward declared), we assume that they are equivalent.
- D1 = D1->getDefinition();
- D2 = D2->getDefinition();
- if (!D1 || !D2)
- return true;
- EnumDecl::enumerator_iterator EC2 = D2->enumerator_begin(),
- EC2End = D2->enumerator_end();
- for (EnumDecl::enumerator_iterator EC1 = D1->enumerator_begin(),
- EC1End = D1->enumerator_end();
- EC1 != EC1End; ++EC1, ++EC2) {
- if (EC2 == EC2End) {
- if (Context.Complain) {
- Context.Diag2(D2->getLocation(),
- Context.getApplicableDiagnostic(
- diag::err_odr_tag_type_inconsistent))
- << Context.ToCtx.getTypeDeclType(D2);
- Context.Diag1(EC1->getLocation(), diag::note_odr_enumerator)
- << EC1->getDeclName() << EC1->getInitVal().toString(10);
- Context.Diag2(D2->getLocation(), diag::note_odr_missing_enumerator);
- }
- return false;
- }
- llvm::APSInt Val1 = EC1->getInitVal();
- llvm::APSInt Val2 = EC2->getInitVal();
- if (!llvm::APSInt::isSameValue(Val1, Val2) ||
- !IsStructurallyEquivalent(EC1->getIdentifier(), EC2->getIdentifier())) {
- if (Context.Complain) {
- Context.Diag2(D2->getLocation(),
- Context.getApplicableDiagnostic(
- diag::err_odr_tag_type_inconsistent))
- << Context.ToCtx.getTypeDeclType(D2);
- Context.Diag2(EC2->getLocation(), diag::note_odr_enumerator)
- << EC2->getDeclName() << EC2->getInitVal().toString(10);
- Context.Diag1(EC1->getLocation(), diag::note_odr_enumerator)
- << EC1->getDeclName() << EC1->getInitVal().toString(10);
- }
- return false;
- }
- }
- if (EC2 != EC2End) {
- if (Context.Complain) {
- Context.Diag2(D2->getLocation(), Context.getApplicableDiagnostic(
- diag::err_odr_tag_type_inconsistent))
- << Context.ToCtx.getTypeDeclType(D2);
- Context.Diag2(EC2->getLocation(), diag::note_odr_enumerator)
- << EC2->getDeclName() << EC2->getInitVal().toString(10);
- Context.Diag1(D1->getLocation(), diag::note_odr_missing_enumerator);
- }
- return false;
- }
- return true;
- }
- static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
- TemplateParameterList *Params1,
- TemplateParameterList *Params2) {
- if (Params1->size() != Params2->size()) {
- if (Context.Complain) {
- Context.Diag2(Params2->getTemplateLoc(),
- Context.getApplicableDiagnostic(
- diag::err_odr_different_num_template_parameters))
- << Params1->size() << Params2->size();
- Context.Diag1(Params1->getTemplateLoc(),
- diag::note_odr_template_parameter_list);
- }
- return false;
- }
- for (unsigned I = 0, N = Params1->size(); I != N; ++I) {
- if (Params1->getParam(I)->getKind() != Params2->getParam(I)->getKind()) {
- if (Context.Complain) {
- Context.Diag2(Params2->getParam(I)->getLocation(),
- Context.getApplicableDiagnostic(
- diag::err_odr_different_template_parameter_kind));
- Context.Diag1(Params1->getParam(I)->getLocation(),
- diag::note_odr_template_parameter_here);
- }
- return false;
- }
- if (!IsStructurallyEquivalent(Context, Params1->getParam(I),
- Params2->getParam(I)))
- return false;
- }
- return true;
- }
- static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
- TemplateTypeParmDecl *D1,
- TemplateTypeParmDecl *D2) {
- if (D1->isParameterPack() != D2->isParameterPack()) {
- if (Context.Complain) {
- Context.Diag2(D2->getLocation(),
- Context.getApplicableDiagnostic(
- diag::err_odr_parameter_pack_non_pack))
- << D2->isParameterPack();
- Context.Diag1(D1->getLocation(), diag::note_odr_parameter_pack_non_pack)
- << D1->isParameterPack();
- }
- return false;
- }
- return true;
- }
- static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
- NonTypeTemplateParmDecl *D1,
- NonTypeTemplateParmDecl *D2) {
- if (D1->isParameterPack() != D2->isParameterPack()) {
- if (Context.Complain) {
- Context.Diag2(D2->getLocation(),
- Context.getApplicableDiagnostic(
- diag::err_odr_parameter_pack_non_pack))
- << D2->isParameterPack();
- Context.Diag1(D1->getLocation(), diag::note_odr_parameter_pack_non_pack)
- << D1->isParameterPack();
- }
- return false;
- }
- // Check types.
- if (!IsStructurallyEquivalent(Context, D1->getType(), D2->getType())) {
- if (Context.Complain) {
- Context.Diag2(D2->getLocation(),
- Context.getApplicableDiagnostic(
- diag::err_odr_non_type_parameter_type_inconsistent))
- << D2->getType() << D1->getType();
- Context.Diag1(D1->getLocation(), diag::note_odr_value_here)
- << D1->getType();
- }
- return false;
- }
- return true;
- }
- static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
- TemplateTemplateParmDecl *D1,
- TemplateTemplateParmDecl *D2) {
- if (D1->isParameterPack() != D2->isParameterPack()) {
- if (Context.Complain) {
- Context.Diag2(D2->getLocation(),
- Context.getApplicableDiagnostic(
- diag::err_odr_parameter_pack_non_pack))
- << D2->isParameterPack();
- Context.Diag1(D1->getLocation(), diag::note_odr_parameter_pack_non_pack)
- << D1->isParameterPack();
- }
- return false;
- }
- // Check template parameter lists.
- return IsStructurallyEquivalent(Context, D1->getTemplateParameters(),
- D2->getTemplateParameters());
- }
- static bool IsTemplateDeclCommonStructurallyEquivalent(
- StructuralEquivalenceContext &Ctx, TemplateDecl *D1, TemplateDecl *D2) {
- if (!IsStructurallyEquivalent(D1->getIdentifier(), D2->getIdentifier()))
- return false;
- if (!D1->getIdentifier()) // Special name
- if (D1->getNameAsString() != D2->getNameAsString())
- return false;
- return IsStructurallyEquivalent(Ctx, D1->getTemplateParameters(),
- D2->getTemplateParameters());
- }
- static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
- ClassTemplateDecl *D1,
- ClassTemplateDecl *D2) {
- // Check template parameters.
- if (!IsTemplateDeclCommonStructurallyEquivalent(Context, D1, D2))
- return false;
- // Check the templated declaration.
- return IsStructurallyEquivalent(Context, D1->getTemplatedDecl(),
- D2->getTemplatedDecl());
- }
- static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
- FunctionTemplateDecl *D1,
- FunctionTemplateDecl *D2) {
- // Check template parameters.
- if (!IsTemplateDeclCommonStructurallyEquivalent(Context, D1, D2))
- return false;
- // Check the templated declaration.
- return IsStructurallyEquivalent(Context, D1->getTemplatedDecl()->getType(),
- D2->getTemplatedDecl()->getType());
- }
- static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
- ConceptDecl *D1,
- ConceptDecl *D2) {
- // Check template parameters.
- if (!IsTemplateDeclCommonStructurallyEquivalent(Context, D1, D2))
- return false;
- // Check the constraint expression.
- return IsStructurallyEquivalent(Context, D1->getConstraintExpr(),
- D2->getConstraintExpr());
- }
- static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
- FriendDecl *D1, FriendDecl *D2) {
- if ((D1->getFriendType() && D2->getFriendDecl()) ||
- (D1->getFriendDecl() && D2->getFriendType())) {
- return false;
- }
- if (D1->getFriendType() && D2->getFriendType())
- return IsStructurallyEquivalent(Context,
- D1->getFriendType()->getType(),
- D2->getFriendType()->getType());
- if (D1->getFriendDecl() && D2->getFriendDecl())
- return IsStructurallyEquivalent(Context, D1->getFriendDecl(),
- D2->getFriendDecl());
- return false;
- }
- static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
- FunctionDecl *D1, FunctionDecl *D2) {
- // FIXME: Consider checking for function attributes as well.
- if (!IsStructurallyEquivalent(Context, D1->getType(), D2->getType()))
- return false;
- return true;
- }
- /// Determine structural equivalence of two declarations.
- static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
- Decl *D1, Decl *D2) {
- // FIXME: Check for known structural equivalences via a callback of some sort.
- D1 = D1->getCanonicalDecl();
- D2 = D2->getCanonicalDecl();
- std::pair<Decl *, Decl *> P{D1, D2};
- // Check whether we already know that these two declarations are not
- // structurally equivalent.
- if (Context.NonEquivalentDecls.count(P))
- return false;
- // Check if a check for these declarations is already pending.
- // If yes D1 and D2 will be checked later (from DeclsToCheck),
- // or these are already checked (and equivalent).
- bool Inserted = Context.VisitedDecls.insert(P).second;
- if (!Inserted)
- return true;
- Context.DeclsToCheck.push(P);
- return true;
- }
- DiagnosticBuilder StructuralEquivalenceContext::Diag1(SourceLocation Loc,
- unsigned DiagID) {
- assert(Complain && "Not allowed to complain");
- if (LastDiagFromC2)
- FromCtx.getDiagnostics().notePriorDiagnosticFrom(ToCtx.getDiagnostics());
- LastDiagFromC2 = false;
- return FromCtx.getDiagnostics().Report(Loc, DiagID);
- }
- DiagnosticBuilder StructuralEquivalenceContext::Diag2(SourceLocation Loc,
- unsigned DiagID) {
- assert(Complain && "Not allowed to complain");
- if (!LastDiagFromC2)
- ToCtx.getDiagnostics().notePriorDiagnosticFrom(FromCtx.getDiagnostics());
- LastDiagFromC2 = true;
- return ToCtx.getDiagnostics().Report(Loc, DiagID);
- }
- Optional<unsigned>
- StructuralEquivalenceContext::findUntaggedStructOrUnionIndex(RecordDecl *Anon) {
- ASTContext &Context = Anon->getASTContext();
- QualType AnonTy = Context.getRecordType(Anon);
- const auto *Owner = dyn_cast<RecordDecl>(Anon->getDeclContext());
- if (!Owner)
- return None;
- unsigned Index = 0;
- for (const auto *D : Owner->noload_decls()) {
- const auto *F = dyn_cast<FieldDecl>(D);
- if (!F)
- continue;
- if (F->isAnonymousStructOrUnion()) {
- if (Context.hasSameType(F->getType(), AnonTy))
- break;
- ++Index;
- continue;
- }
- // If the field looks like this:
- // struct { ... } A;
- QualType FieldType = F->getType();
- // In case of nested structs.
- while (const auto *ElabType = dyn_cast<ElaboratedType>(FieldType))
- FieldType = ElabType->getNamedType();
- if (const auto *RecType = dyn_cast<RecordType>(FieldType)) {
- const RecordDecl *RecDecl = RecType->getDecl();
- if (RecDecl->getDeclContext() == Owner && !RecDecl->getIdentifier()) {
- if (Context.hasSameType(FieldType, AnonTy))
- break;
- ++Index;
- continue;
- }
- }
- }
- return Index;
- }
- unsigned StructuralEquivalenceContext::getApplicableDiagnostic(
- unsigned ErrorDiagnostic) {
- if (ErrorOnTagTypeMismatch)
- return ErrorDiagnostic;
- switch (ErrorDiagnostic) {
- case diag::err_odr_variable_type_inconsistent:
- return diag::warn_odr_variable_type_inconsistent;
- case diag::err_odr_variable_multiple_def:
- return diag::warn_odr_variable_multiple_def;
- case diag::err_odr_function_type_inconsistent:
- return diag::warn_odr_function_type_inconsistent;
- case diag::err_odr_tag_type_inconsistent:
- return diag::warn_odr_tag_type_inconsistent;
- case diag::err_odr_field_type_inconsistent:
- return diag::warn_odr_field_type_inconsistent;
- case diag::err_odr_ivar_type_inconsistent:
- return diag::warn_odr_ivar_type_inconsistent;
- case diag::err_odr_objc_superclass_inconsistent:
- return diag::warn_odr_objc_superclass_inconsistent;
- case diag::err_odr_objc_method_result_type_inconsistent:
- return diag::warn_odr_objc_method_result_type_inconsistent;
- case diag::err_odr_objc_method_num_params_inconsistent:
- return diag::warn_odr_objc_method_num_params_inconsistent;
- case diag::err_odr_objc_method_param_type_inconsistent:
- return diag::warn_odr_objc_method_param_type_inconsistent;
- case diag::err_odr_objc_method_variadic_inconsistent:
- return diag::warn_odr_objc_method_variadic_inconsistent;
- case diag::err_odr_objc_property_type_inconsistent:
- return diag::warn_odr_objc_property_type_inconsistent;
- case diag::err_odr_objc_property_impl_kind_inconsistent:
- return diag::warn_odr_objc_property_impl_kind_inconsistent;
- case diag::err_odr_objc_synthesize_ivar_inconsistent:
- return diag::warn_odr_objc_synthesize_ivar_inconsistent;
- case diag::err_odr_different_num_template_parameters:
- return diag::warn_odr_different_num_template_parameters;
- case diag::err_odr_different_template_parameter_kind:
- return diag::warn_odr_different_template_parameter_kind;
- case diag::err_odr_parameter_pack_non_pack:
- return diag::warn_odr_parameter_pack_non_pack;
- case diag::err_odr_non_type_parameter_type_inconsistent:
- return diag::warn_odr_non_type_parameter_type_inconsistent;
- }
- llvm_unreachable("Diagnostic kind not handled in preceding switch");
- }
- bool StructuralEquivalenceContext::IsEquivalent(Decl *D1, Decl *D2) {
- // Ensure that the implementation functions (all static functions in this TU)
- // never call the public ASTStructuralEquivalence::IsEquivalent() functions,
- // because that will wreak havoc the internal state (DeclsToCheck and
- // VisitedDecls members) and can cause faulty behaviour.
- // In other words: Do not start a graph search from a new node with the
- // internal data of another search in progress.
- // FIXME: Better encapsulation and separation of internal and public
- // functionality.
- assert(DeclsToCheck.empty());
- assert(VisitedDecls.empty());
- if (!::IsStructurallyEquivalent(*this, D1, D2))
- return false;
- return !Finish();
- }
- bool StructuralEquivalenceContext::IsEquivalent(QualType T1, QualType T2) {
- assert(DeclsToCheck.empty());
- assert(VisitedDecls.empty());
- if (!::IsStructurallyEquivalent(*this, T1, T2))
- return false;
- return !Finish();
- }
- bool StructuralEquivalenceContext::CheckCommonEquivalence(Decl *D1, Decl *D2) {
- // Check for equivalent described template.
- TemplateDecl *Template1 = D1->getDescribedTemplate();
- TemplateDecl *Template2 = D2->getDescribedTemplate();
- if ((Template1 != nullptr) != (Template2 != nullptr))
- return false;
- if (Template1 && !IsStructurallyEquivalent(*this, Template1, Template2))
- return false;
- // FIXME: Move check for identifier names into this function.
- return true;
- }
- bool StructuralEquivalenceContext::CheckKindSpecificEquivalence(
- Decl *D1, Decl *D2) {
- // FIXME: Switch on all declaration kinds. For now, we're just going to
- // check the obvious ones.
- if (auto *Record1 = dyn_cast<RecordDecl>(D1)) {
- if (auto *Record2 = dyn_cast<RecordDecl>(D2)) {
- // Check for equivalent structure names.
- IdentifierInfo *Name1 = Record1->getIdentifier();
- if (!Name1 && Record1->getTypedefNameForAnonDecl())
- Name1 = Record1->getTypedefNameForAnonDecl()->getIdentifier();
- IdentifierInfo *Name2 = Record2->getIdentifier();
- if (!Name2 && Record2->getTypedefNameForAnonDecl())
- Name2 = Record2->getTypedefNameForAnonDecl()->getIdentifier();
- if (!::IsStructurallyEquivalent(Name1, Name2) ||
- !::IsStructurallyEquivalent(*this, Record1, Record2))
- return false;
- } else {
- // Record/non-record mismatch.
- return false;
- }
- } else if (auto *Enum1 = dyn_cast<EnumDecl>(D1)) {
- if (auto *Enum2 = dyn_cast<EnumDecl>(D2)) {
- // Check for equivalent enum names.
- IdentifierInfo *Name1 = Enum1->getIdentifier();
- if (!Name1 && Enum1->getTypedefNameForAnonDecl())
- Name1 = Enum1->getTypedefNameForAnonDecl()->getIdentifier();
- IdentifierInfo *Name2 = Enum2->getIdentifier();
- if (!Name2 && Enum2->getTypedefNameForAnonDecl())
- Name2 = Enum2->getTypedefNameForAnonDecl()->getIdentifier();
- if (!::IsStructurallyEquivalent(Name1, Name2) ||
- !::IsStructurallyEquivalent(*this, Enum1, Enum2))
- return false;
- } else {
- // Enum/non-enum mismatch
- return false;
- }
- } else if (const auto *Typedef1 = dyn_cast<TypedefNameDecl>(D1)) {
- if (const auto *Typedef2 = dyn_cast<TypedefNameDecl>(D2)) {
- if (!::IsStructurallyEquivalent(Typedef1->getIdentifier(),
- Typedef2->getIdentifier()) ||
- !::IsStructurallyEquivalent(*this, Typedef1->getUnderlyingType(),
- Typedef2->getUnderlyingType()))
- return false;
- } else {
- // Typedef/non-typedef mismatch.
- return false;
- }
- } else if (auto *ClassTemplate1 = dyn_cast<ClassTemplateDecl>(D1)) {
- if (auto *ClassTemplate2 = dyn_cast<ClassTemplateDecl>(D2)) {
- if (!::IsStructurallyEquivalent(*this, ClassTemplate1,
- ClassTemplate2))
- return false;
- } else {
- // Class template/non-class-template mismatch.
- return false;
- }
- } else if (auto *FunctionTemplate1 = dyn_cast<FunctionTemplateDecl>(D1)) {
- if (auto *FunctionTemplate2 = dyn_cast<FunctionTemplateDecl>(D2)) {
- if (!::IsStructurallyEquivalent(*this, FunctionTemplate1,
- FunctionTemplate2))
- return false;
- } else {
- // Class template/non-class-template mismatch.
- return false;
- }
- } else if (auto *ConceptDecl1 = dyn_cast<ConceptDecl>(D1)) {
- if (auto *ConceptDecl2 = dyn_cast<ConceptDecl>(D2)) {
- if (!::IsStructurallyEquivalent(*this, ConceptDecl1, ConceptDecl2))
- return false;
- } else {
- // Concept/non-concept mismatch.
- return false;
- }
- } else if (auto *TTP1 = dyn_cast<TemplateTypeParmDecl>(D1)) {
- if (auto *TTP2 = dyn_cast<TemplateTypeParmDecl>(D2)) {
- if (!::IsStructurallyEquivalent(*this, TTP1, TTP2))
- return false;
- } else {
- // Kind mismatch.
- return false;
- }
- } else if (auto *NTTP1 = dyn_cast<NonTypeTemplateParmDecl>(D1)) {
- if (auto *NTTP2 = dyn_cast<NonTypeTemplateParmDecl>(D2)) {
- if (!::IsStructurallyEquivalent(*this, NTTP1, NTTP2))
- return false;
- } else {
- // Kind mismatch.
- return false;
- }
- } else if (auto *TTP1 = dyn_cast<TemplateTemplateParmDecl>(D1)) {
- if (auto *TTP2 = dyn_cast<TemplateTemplateParmDecl>(D2)) {
- if (!::IsStructurallyEquivalent(*this, TTP1, TTP2))
- return false;
- } else {
- // Kind mismatch.
- return false;
- }
- } else if (auto *MD1 = dyn_cast<CXXMethodDecl>(D1)) {
- if (auto *MD2 = dyn_cast<CXXMethodDecl>(D2)) {
- if (!::IsStructurallyEquivalent(*this, MD1, MD2))
- return false;
- } else {
- // Kind mismatch.
- return false;
- }
- } else if (FunctionDecl *FD1 = dyn_cast<FunctionDecl>(D1)) {
- if (FunctionDecl *FD2 = dyn_cast<FunctionDecl>(D2)) {
- if (FD1->isOverloadedOperator()) {
- if (!FD2->isOverloadedOperator())
- return false;
- if (FD1->getOverloadedOperator() != FD2->getOverloadedOperator())
- return false;
- }
- if (!::IsStructurallyEquivalent(FD1->getIdentifier(),
- FD2->getIdentifier()))
- return false;
- if (!::IsStructurallyEquivalent(*this, FD1, FD2))
- return false;
- } else {
- // Kind mismatch.
- return false;
- }
- } else if (FriendDecl *FrD1 = dyn_cast<FriendDecl>(D1)) {
- if (FriendDecl *FrD2 = dyn_cast<FriendDecl>(D2)) {
- if (!::IsStructurallyEquivalent(*this, FrD1, FrD2))
- return false;
- } else {
- // Kind mismatch.
- return false;
- }
- }
- return true;
- }
- bool StructuralEquivalenceContext::Finish() {
- while (!DeclsToCheck.empty()) {
- // Check the next declaration.
- std::pair<Decl *, Decl *> P = DeclsToCheck.front();
- DeclsToCheck.pop();
- Decl *D1 = P.first;
- Decl *D2 = P.second;
- bool Equivalent =
- CheckCommonEquivalence(D1, D2) && CheckKindSpecificEquivalence(D1, D2);
- if (!Equivalent) {
- // Note that these two declarations are not equivalent (and we already
- // know about it).
- NonEquivalentDecls.insert(P);
- return true;
- }
- }
- return false;
- }
|