Coverage Report

Created: 2022-05-14 11:35

/Users/buildslave/jenkins/workspace/coverage/llvm-project/clang/lib/AST/ASTStructuralEquivalence.cpp
Line
Count
Source (jump to first uncovered line)
1
//===- ASTStructuralEquivalence.cpp ---------------------------------------===//
2
//
3
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4
// See https://llvm.org/LICENSE.txt for license information.
5
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6
//
7
//===----------------------------------------------------------------------===//
8
//
9
//  This file implement StructuralEquivalenceContext class and helper functions
10
//  for layout matching.
11
//
12
// The structural equivalence check could have been implemented as a parallel
13
// BFS on a pair of graphs.  That must have been the original approach at the
14
// beginning.
15
// Let's consider this simple BFS algorithm from the `s` source:
16
// ```
17
// void bfs(Graph G, int s)
18
// {
19
//   Queue<Integer> queue = new Queue<Integer>();
20
//   marked[s] = true; // Mark the source
21
//   queue.enqueue(s); // and put it on the queue.
22
//   while (!q.isEmpty()) {
23
//     int v = queue.dequeue(); // Remove next vertex from the queue.
24
//     for (int w : G.adj(v))
25
//       if (!marked[w]) // For every unmarked adjacent vertex,
26
//       {
27
//         marked[w] = true;
28
//         queue.enqueue(w);
29
//       }
30
//   }
31
// }
32
// ```
33
// Indeed, it has it's queue, which holds pairs of nodes, one from each graph,
34
// this is the `DeclsToCheck` member. `VisitedDecls` plays the role of the
35
// marking (`marked`) functionality above, we use it to check whether we've
36
// already seen a pair of nodes.
37
//
38
// We put in the elements into the queue only in the toplevel decl check
39
// function:
40
// ```
41
// static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
42
//                                      Decl *D1, Decl *D2);
43
// ```
44
// The `while` loop where we iterate over the children is implemented in
45
// `Finish()`.  And `Finish` is called only from the two **member** functions
46
// which check the equivalency of two Decls or two Types. ASTImporter (and
47
// other clients) call only these functions.
48
//
49
// The `static` implementation functions are called from `Finish`, these push
50
// the children nodes to the queue via `static bool
51
// IsStructurallyEquivalent(StructuralEquivalenceContext &Context, Decl *D1,
52
// Decl *D2)`.  So far so good, this is almost like the BFS.  However, if we
53
// let a static implementation function to call `Finish` via another **member**
54
// function that means we end up with two nested while loops each of them
55
// working on the same queue. This is wrong and nobody can reason about it's
56
// doing. Thus, static implementation functions must not call the **member**
57
// functions.
58
//
59
//===----------------------------------------------------------------------===//
60
61
#include "clang/AST/ASTStructuralEquivalence.h"
62
#include "clang/AST/ASTContext.h"
63
#include "clang/AST/ASTDiagnostic.h"
64
#include "clang/AST/Decl.h"
65
#include "clang/AST/DeclBase.h"
66
#include "clang/AST/DeclCXX.h"
67
#include "clang/AST/DeclFriend.h"
68
#include "clang/AST/DeclObjC.h"
69
#include "clang/AST/DeclOpenMP.h"
70
#include "clang/AST/DeclTemplate.h"
71
#include "clang/AST/ExprCXX.h"
72
#include "clang/AST/ExprConcepts.h"
73
#include "clang/AST/ExprObjC.h"
74
#include "clang/AST/ExprOpenMP.h"
75
#include "clang/AST/NestedNameSpecifier.h"
76
#include "clang/AST/StmtObjC.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/None.h"
88
#include "llvm/ADT/Optional.h"
89
#include "llvm/ADT/StringExtras.h"
90
#include "llvm/Support/Casting.h"
91
#include "llvm/Support/Compiler.h"
92
#include "llvm/Support/ErrorHandling.h"
93
#include <cassert>
94
#include <utility>
95
96
using namespace clang;
97
98
static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
99
                                     QualType T1, QualType T2);
100
static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
101
                                     Decl *D1, Decl *D2);
102
static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
103
                                     const TemplateArgument &Arg1,
104
                                     const TemplateArgument &Arg2);
105
static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
106
                                     NestedNameSpecifier *NNS1,
107
                                     NestedNameSpecifier *NNS2);
108
static bool IsStructurallyEquivalent(const IdentifierInfo *Name1,
109
                                     const IdentifierInfo *Name2);
110
111
static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
112
                                     const DeclarationName Name1,
113
138k
                                     const DeclarationName Name2) {
114
138k
  if (Name1.getNameKind() != Name2.getNameKind())
115
0
    return false;
116
117
138k
  switch (Name1.getNameKind()) {
118
119
138k
  case DeclarationName::Identifier:
120
138k
    return IsStructurallyEquivalent(Name1.getAsIdentifierInfo(),
121
138k
                                    Name2.getAsIdentifierInfo());
122
123
0
  case DeclarationName::CXXConstructorName:
124
0
  case DeclarationName::CXXDestructorName:
125
0
  case DeclarationName::CXXConversionFunctionName:
126
0
    return IsStructurallyEquivalent(Context, Name1.getCXXNameType(),
127
0
                                    Name2.getCXXNameType());
128
129
0
  case DeclarationName::CXXDeductionGuideName: {
130
0
    if (!IsStructurallyEquivalent(
131
0
            Context, Name1.getCXXDeductionGuideTemplate()->getDeclName(),
132
0
            Name2.getCXXDeductionGuideTemplate()->getDeclName()))
133
0
      return false;
134
0
    return IsStructurallyEquivalent(Context,
135
0
                                    Name1.getCXXDeductionGuideTemplate(),
136
0
                                    Name2.getCXXDeductionGuideTemplate());
137
0
  }
138
139
0
  case DeclarationName::CXXOperatorName:
140
0
    return Name1.getCXXOverloadedOperator() == Name2.getCXXOverloadedOperator();
141
142
0
  case DeclarationName::CXXLiteralOperatorName:
143
0
    return IsStructurallyEquivalent(Name1.getCXXLiteralIdentifier(),
144
0
                                    Name2.getCXXLiteralIdentifier());
145
146
0
  case DeclarationName::CXXUsingDirective:
147
0
    return true; // FIXME When do we consider two using directives equal?
148
149
0
  case DeclarationName::ObjCZeroArgSelector:
150
0
  case DeclarationName::ObjCOneArgSelector:
151
0
  case DeclarationName::ObjCMultiArgSelector:
152
0
    return true; // FIXME
153
138k
  }
154
155
0
  llvm_unreachable("Unhandled kind of DeclarationName");
156
0
  return true;
157
138k
}
158
159
namespace {
160
/// Encapsulates Stmt comparison logic.
161
class StmtComparer {
162
  StructuralEquivalenceContext &Context;
163
164
  // IsStmtEquivalent overloads. Each overload compares a specific statement
165
  // and only has to compare the data that is specific to the specific statement
166
  // class. Should only be called from TraverseStmt.
167
168
4
  bool IsStmtEquivalent(const AddrLabelExpr *E1, const AddrLabelExpr *E2) {
169
4
    return IsStructurallyEquivalent(Context, E1->getLabel(), E2->getLabel());
170
4
  }
171
172
4
  bool IsStmtEquivalent(const AtomicExpr *E1, const AtomicExpr *E2) {
173
4
    return E1->getOp() == E2->getOp();
174
4
  }
175
176
53.2k
  bool IsStmtEquivalent(const BinaryOperator *E1, const BinaryOperator *E2) {
177
53.2k
    return E1->getOpcode() == E2->getOpcode();
178
53.2k
  }
179
180
11.2k
  bool IsStmtEquivalent(const CallExpr *E1, const CallExpr *E2) {
181
    // FIXME: IsStructurallyEquivalent requires non-const Decls.
182
11.2k
    Decl *Callee1 = const_cast<Decl *>(E1->getCalleeDecl());
183
11.2k
    Decl *Callee2 = const_cast<Decl *>(E2->getCalleeDecl());
184
185
    // Compare whether both calls know their callee.
186
11.2k
    if (static_cast<bool>(Callee1) != static_cast<bool>(Callee2))
187
0
      return false;
188
189
    // Both calls have no callee, so nothing to do.
190
11.2k
    if (!static_cast<bool>(Callee1))
191
11.0k
      return true;
192
193
193
    assert(Callee2);
194
0
    return IsStructurallyEquivalent(Context, Callee1, Callee2);
195
11.2k
  }
196
197
  bool IsStmtEquivalent(const CharacterLiteral *E1,
198
4
                        const CharacterLiteral *E2) {
199
4
    return E1->getValue() == E2->getValue() && 
E1->getKind() == E2->getKind()2
;
200
4
  }
201
202
0
  bool IsStmtEquivalent(const ChooseExpr *E1, const ChooseExpr *E2) {
203
0
    return true; // Semantics only depend on children.
204
0
  }
205
206
0
  bool IsStmtEquivalent(const CompoundStmt *E1, const CompoundStmt *E2) {
207
    // Number of children is actually checked by the generic children comparison
208
    // code, but a CompoundStmt is one of the few statements where the number of
209
    // children frequently differs and the number of statements is also always
210
    // precomputed. Directly comparing the number of children here is thus
211
    // just an optimization.
212
0
    return E1->size() == E2->size();
213
0
  }
214
215
  bool IsStmtEquivalent(const DependentScopeDeclRefExpr *DE1,
216
138k
                        const DependentScopeDeclRefExpr *DE2) {
217
138k
    if (!IsStructurallyEquivalent(Context, DE1->getDeclName(),
218
138k
                                  DE2->getDeclName()))
219
947
      return false;
220
137k
    return IsStructurallyEquivalent(Context, DE1->getQualifier(),
221
137k
                                    DE2->getQualifier());
222
138k
  }
223
224
1.09M
  bool IsStmtEquivalent(const Expr *E1, const Expr *E2) {
225
1.09M
    return IsStructurallyEquivalent(Context, E1->getType(), E2->getType());
226
1.09M
  }
227
228
  bool IsStmtEquivalent(const ExpressionTraitExpr *E1,
229
4
                        const ExpressionTraitExpr *E2) {
230
4
    return E1->getTrait() == E2->getTrait() && 
E1->getValue() == E2->getValue()2
;
231
4
  }
232
233
6
  bool IsStmtEquivalent(const FloatingLiteral *E1, const FloatingLiteral *E2) {
234
6
    return E1->isExact() == E2->isExact() && 
E1->getValue() == E2->getValue()4
;
235
6
  }
236
237
  bool IsStmtEquivalent(const GenericSelectionExpr *E1,
238
10
                        const GenericSelectionExpr *E2) {
239
10
    for (auto Pair : zip_longest(E1->getAssocTypeSourceInfos(),
240
14
                                 E2->getAssocTypeSourceInfos())) {
241
14
      Optional<TypeSourceInfo *> Child1 = std::get<0>(Pair);
242
14
      Optional<TypeSourceInfo *> Child2 = std::get<1>(Pair);
243
      // Skip this case if there are a different number of associated types.
244
14
      if (!Child1 || !Child2)
245
0
        return false;
246
247
14
      if (!IsStructurallyEquivalent(Context, (*Child1)->getType(),
248
14
                                    (*Child2)->getType()))
249
6
        return false;
250
14
    }
251
252
4
    return true;
253
10
  }
254
255
  bool IsStmtEquivalent(const ImplicitCastExpr *CastE1,
256
133k
                        const ImplicitCastExpr *CastE2) {
257
133k
    return IsStructurallyEquivalent(Context, CastE1->getType(),
258
133k
                                    CastE2->getType());
259
133k
  }
260
261
50.0k
  bool IsStmtEquivalent(const IntegerLiteral *E1, const IntegerLiteral *E2) {
262
50.0k
    return E1->getValue() == E2->getValue();
263
50.0k
  }
264
265
4
  bool IsStmtEquivalent(const MemberExpr *E1, const MemberExpr *E2) {
266
4
    return IsStructurallyEquivalent(Context, E1->getFoundDecl(),
267
4
                                    E2->getFoundDecl());
268
4
  }
269
270
  bool IsStmtEquivalent(const ObjCStringLiteral *E1,
271
4
                        const ObjCStringLiteral *E2) {
272
    // Just wraps a StringLiteral child.
273
4
    return true;
274
4
  }
275
276
730k
  bool IsStmtEquivalent(const Stmt *S1, const Stmt *S2) { return true; }
277
278
0
  bool IsStmtEquivalent(const SourceLocExpr *E1, const SourceLocExpr *E2) {
279
0
    return E1->getIdentKind() == E2->getIdentKind();
280
0
  }
281
282
0
  bool IsStmtEquivalent(const StmtExpr *E1, const StmtExpr *E2) {
283
0
    return E1->getTemplateDepth() == E2->getTemplateDepth();
284
0
  }
285
286
8
  bool IsStmtEquivalent(const StringLiteral *E1, const StringLiteral *E2) {
287
8
    return E1->getBytes() == E2->getBytes();
288
8
  }
289
290
  bool IsStmtEquivalent(const SubstNonTypeTemplateParmExpr *E1,
291
19.4k
                        const SubstNonTypeTemplateParmExpr *E2) {
292
19.4k
    return IsStructurallyEquivalent(Context, E1->getParameter(),
293
19.4k
                                    E2->getParameter());
294
19.4k
  }
295
296
  bool IsStmtEquivalent(const SubstNonTypeTemplateParmPackExpr *E1,
297
0
                        const SubstNonTypeTemplateParmPackExpr *E2) {
298
0
    return IsStructurallyEquivalent(Context, E1->getArgumentPack(),
299
0
                                    E2->getArgumentPack());
300
0
  }
301
302
42.6k
  bool IsStmtEquivalent(const TypeTraitExpr *E1, const TypeTraitExpr *E2) {
303
42.6k
    if (E1->getTrait() != E2->getTrait())
304
2
      return false;
305
306
44.1k
    
for (auto Pair : zip_longest(E1->getArgs(), E2->getArgs()))42.6k
{
307
44.1k
      Optional<TypeSourceInfo *> Child1 = std::get<0>(Pair);
308
44.1k
      Optional<TypeSourceInfo *> Child2 = std::get<1>(Pair);
309
      // Different number of args.
310
44.1k
      if (!Child1 || 
!Child244.1k
)
311
2
        return false;
312
313
44.1k
      if (!IsStructurallyEquivalent(Context, (*Child1)->getType(),
314
44.1k
                                    (*Child2)->getType()))
315
2
        return false;
316
44.1k
    }
317
42.6k
    return true;
318
42.6k
  }
319
320
  bool IsStmtEquivalent(const UnaryExprOrTypeTraitExpr *E1,
321
1.96k
                        const UnaryExprOrTypeTraitExpr *E2) {
322
1.96k
    if (E1->getKind() != E2->getKind())
323
2
      return false;
324
1.95k
    return IsStructurallyEquivalent(Context, E1->getTypeOfArgument(),
325
1.95k
                                    E2->getTypeOfArgument());
326
1.96k
  }
327
328
53.1k
  bool IsStmtEquivalent(const UnaryOperator *E1, const UnaryOperator *E2) {
329
53.1k
    return E1->getOpcode() == E2->getOpcode();
330
53.1k
  }
331
332
0
  bool IsStmtEquivalent(const VAArgExpr *E1, const VAArgExpr *E2) {
333
    // Semantics only depend on children.
334
0
    return true;
335
0
  }
336
337
  /// End point of the traversal chain.
338
730k
  bool TraverseStmt(const Stmt *S1, const Stmt *S2) { return true; }
339
340
  // Create traversal methods that traverse the class hierarchy and return
341
  // the accumulated result of the comparison. Each TraverseStmt overload
342
  // calls the TraverseStmt overload of the parent class. For example,
343
  // the TraverseStmt overload for 'BinaryOperator' calls the TraverseStmt
344
  // overload of 'Expr' which then calls the overload for 'Stmt'.
345
#define STMT(CLASS, PARENT)                                                    \
346
730k
  bool TraverseStmt(const CLASS *S1, const CLASS *S2) {                        \
347
730k
    if (!TraverseStmt(static_cast<const PARENT *>(S1),                         \
348
730k
                      static_cast<const PARENT *>(S2)))                        \
349
730k
      
return false216
; \
350
730k
    
return IsStmtEquivalent(S1, S2)730k
; \
351
730k
  }
Unexecuted instantiation: ASTStructuralEquivalence.cpp:(anonymous namespace)::StmtComparer::TraverseStmt(clang::GCCAsmStmt const*, clang::GCCAsmStmt const*)
Unexecuted instantiation: ASTStructuralEquivalence.cpp:(anonymous namespace)::StmtComparer::TraverseStmt(clang::MSAsmStmt const*, clang::MSAsmStmt const*)
Unexecuted instantiation: ASTStructuralEquivalence.cpp:(anonymous namespace)::StmtComparer::TraverseStmt(clang::BreakStmt const*, clang::BreakStmt const*)
Unexecuted instantiation: ASTStructuralEquivalence.cpp:(anonymous namespace)::StmtComparer::TraverseStmt(clang::CXXCatchStmt const*, clang::CXXCatchStmt const*)
Unexecuted instantiation: ASTStructuralEquivalence.cpp:(anonymous namespace)::StmtComparer::TraverseStmt(clang::CXXForRangeStmt const*, clang::CXXForRangeStmt const*)
Unexecuted instantiation: ASTStructuralEquivalence.cpp:(anonymous namespace)::StmtComparer::TraverseStmt(clang::CXXTryStmt const*, clang::CXXTryStmt const*)
Unexecuted instantiation: ASTStructuralEquivalence.cpp:(anonymous namespace)::StmtComparer::TraverseStmt(clang::CapturedStmt const*, clang::CapturedStmt const*)
Unexecuted instantiation: ASTStructuralEquivalence.cpp:(anonymous namespace)::StmtComparer::TraverseStmt(clang::CompoundStmt const*, clang::CompoundStmt const*)
Unexecuted instantiation: ASTStructuralEquivalence.cpp:(anonymous namespace)::StmtComparer::TraverseStmt(clang::ContinueStmt const*, clang::ContinueStmt const*)
Unexecuted instantiation: ASTStructuralEquivalence.cpp:(anonymous namespace)::StmtComparer::TraverseStmt(clang::CoreturnStmt const*, clang::CoreturnStmt const*)
Unexecuted instantiation: ASTStructuralEquivalence.cpp:(anonymous namespace)::StmtComparer::TraverseStmt(clang::CoroutineBodyStmt const*, clang::CoroutineBodyStmt const*)
Unexecuted instantiation: ASTStructuralEquivalence.cpp:(anonymous namespace)::StmtComparer::TraverseStmt(clang::DeclStmt const*, clang::DeclStmt const*)
Unexecuted instantiation: ASTStructuralEquivalence.cpp:(anonymous namespace)::StmtComparer::TraverseStmt(clang::DoStmt const*, clang::DoStmt const*)
Unexecuted instantiation: ASTStructuralEquivalence.cpp:(anonymous namespace)::StmtComparer::TraverseStmt(clang::ForStmt const*, clang::ForStmt const*)
Unexecuted instantiation: ASTStructuralEquivalence.cpp:(anonymous namespace)::StmtComparer::TraverseStmt(clang::GotoStmt const*, clang::GotoStmt const*)
Unexecuted instantiation: ASTStructuralEquivalence.cpp:(anonymous namespace)::StmtComparer::TraverseStmt(clang::IfStmt const*, clang::IfStmt const*)
Unexecuted instantiation: ASTStructuralEquivalence.cpp:(anonymous namespace)::StmtComparer::TraverseStmt(clang::IndirectGotoStmt const*, clang::IndirectGotoStmt const*)
Unexecuted instantiation: ASTStructuralEquivalence.cpp:(anonymous namespace)::StmtComparer::TraverseStmt(clang::MSDependentExistsStmt const*, clang::MSDependentExistsStmt const*)
Unexecuted instantiation: ASTStructuralEquivalence.cpp:(anonymous namespace)::StmtComparer::TraverseStmt(clang::NullStmt const*, clang::NullStmt const*)
Unexecuted instantiation: ASTStructuralEquivalence.cpp:(anonymous namespace)::StmtComparer::TraverseStmt(clang::OMPCanonicalLoop const*, clang::OMPCanonicalLoop const*)
Unexecuted instantiation: ASTStructuralEquivalence.cpp:(anonymous namespace)::StmtComparer::TraverseStmt(clang::OMPAtomicDirective const*, clang::OMPAtomicDirective const*)
Unexecuted instantiation: ASTStructuralEquivalence.cpp:(anonymous namespace)::StmtComparer::TraverseStmt(clang::OMPBarrierDirective const*, clang::OMPBarrierDirective const*)
Unexecuted instantiation: ASTStructuralEquivalence.cpp:(anonymous namespace)::StmtComparer::TraverseStmt(clang::OMPCancelDirective const*, clang::OMPCancelDirective const*)
Unexecuted instantiation: ASTStructuralEquivalence.cpp:(anonymous namespace)::StmtComparer::TraverseStmt(clang::OMPCancellationPointDirective const*, clang::OMPCancellationPointDirective const*)
Unexecuted instantiation: ASTStructuralEquivalence.cpp:(anonymous namespace)::StmtComparer::TraverseStmt(clang::OMPCriticalDirective const*, clang::OMPCriticalDirective const*)
Unexecuted instantiation: ASTStructuralEquivalence.cpp:(anonymous namespace)::StmtComparer::TraverseStmt(clang::OMPDepobjDirective const*, clang::OMPDepobjDirective const*)
Unexecuted instantiation: ASTStructuralEquivalence.cpp:(anonymous namespace)::StmtComparer::TraverseStmt(clang::OMPDispatchDirective const*, clang::OMPDispatchDirective const*)
Unexecuted instantiation: ASTStructuralEquivalence.cpp:(anonymous namespace)::StmtComparer::TraverseStmt(clang::OMPFlushDirective const*, clang::OMPFlushDirective const*)
Unexecuted instantiation: ASTStructuralEquivalence.cpp:(anonymous namespace)::StmtComparer::TraverseStmt(clang::OMPInteropDirective const*, clang::OMPInteropDirective const*)
Unexecuted instantiation: ASTStructuralEquivalence.cpp:(anonymous namespace)::StmtComparer::TraverseStmt(clang::OMPDistributeDirective const*, clang::OMPDistributeDirective const*)
Unexecuted instantiation: ASTStructuralEquivalence.cpp:(anonymous namespace)::StmtComparer::TraverseStmt(clang::OMPDistributeParallelForDirective const*, clang::OMPDistributeParallelForDirective const*)
Unexecuted instantiation: ASTStructuralEquivalence.cpp:(anonymous namespace)::StmtComparer::TraverseStmt(clang::OMPDistributeParallelForSimdDirective const*, clang::OMPDistributeParallelForSimdDirective const*)
Unexecuted instantiation: ASTStructuralEquivalence.cpp:(anonymous namespace)::StmtComparer::TraverseStmt(clang::OMPDistributeSimdDirective const*, clang::OMPDistributeSimdDirective const*)
Unexecuted instantiation: ASTStructuralEquivalence.cpp:(anonymous namespace)::StmtComparer::TraverseStmt(clang::OMPForDirective const*, clang::OMPForDirective const*)
Unexecuted instantiation: ASTStructuralEquivalence.cpp:(anonymous namespace)::StmtComparer::TraverseStmt(clang::OMPForSimdDirective const*, clang::OMPForSimdDirective const*)
Unexecuted instantiation: ASTStructuralEquivalence.cpp:(anonymous namespace)::StmtComparer::TraverseStmt(clang::OMPGenericLoopDirective const*, clang::OMPGenericLoopDirective const*)
Unexecuted instantiation: ASTStructuralEquivalence.cpp:(anonymous namespace)::StmtComparer::TraverseStmt(clang::OMPMasterTaskLoopDirective const*, clang::OMPMasterTaskLoopDirective const*)
Unexecuted instantiation: ASTStructuralEquivalence.cpp:(anonymous namespace)::StmtComparer::TraverseStmt(clang::OMPMasterTaskLoopSimdDirective const*, clang::OMPMasterTaskLoopSimdDirective const*)
Unexecuted instantiation: ASTStructuralEquivalence.cpp:(anonymous namespace)::StmtComparer::TraverseStmt(clang::OMPParallelForDirective const*, clang::OMPParallelForDirective const*)
Unexecuted instantiation: ASTStructuralEquivalence.cpp:(anonymous namespace)::StmtComparer::TraverseStmt(clang::OMPParallelForSimdDirective const*, clang::OMPParallelForSimdDirective const*)
Unexecuted instantiation: ASTStructuralEquivalence.cpp:(anonymous namespace)::StmtComparer::TraverseStmt(clang::OMPParallelGenericLoopDirective const*, clang::OMPParallelGenericLoopDirective const*)
Unexecuted instantiation: ASTStructuralEquivalence.cpp:(anonymous namespace)::StmtComparer::TraverseStmt(clang::OMPParallelMasterTaskLoopDirective const*, clang::OMPParallelMasterTaskLoopDirective const*)
Unexecuted instantiation: ASTStructuralEquivalence.cpp:(anonymous namespace)::StmtComparer::TraverseStmt(clang::OMPParallelMasterTaskLoopSimdDirective const*, clang::OMPParallelMasterTaskLoopSimdDirective const*)
Unexecuted instantiation: ASTStructuralEquivalence.cpp:(anonymous namespace)::StmtComparer::TraverseStmt(clang::OMPSimdDirective const*, clang::OMPSimdDirective const*)
Unexecuted instantiation: ASTStructuralEquivalence.cpp:(anonymous namespace)::StmtComparer::TraverseStmt(clang::OMPTargetParallelForSimdDirective const*, clang::OMPTargetParallelForSimdDirective const*)
Unexecuted instantiation: ASTStructuralEquivalence.cpp:(anonymous namespace)::StmtComparer::TraverseStmt(clang::OMPTargetParallelGenericLoopDirective const*, clang::OMPTargetParallelGenericLoopDirective const*)
Unexecuted instantiation: ASTStructuralEquivalence.cpp:(anonymous namespace)::StmtComparer::TraverseStmt(clang::OMPTargetSimdDirective const*, clang::OMPTargetSimdDirective const*)
Unexecuted instantiation: ASTStructuralEquivalence.cpp:(anonymous namespace)::StmtComparer::TraverseStmt(clang::OMPTargetTeamsDistributeDirective const*, clang::OMPTargetTeamsDistributeDirective const*)
Unexecuted instantiation: ASTStructuralEquivalence.cpp:(anonymous namespace)::StmtComparer::TraverseStmt(clang::OMPTargetTeamsDistributeParallelForDirective const*, clang::OMPTargetTeamsDistributeParallelForDirective const*)
Unexecuted instantiation: ASTStructuralEquivalence.cpp:(anonymous namespace)::StmtComparer::TraverseStmt(clang::OMPTargetTeamsDistributeParallelForSimdDirective const*, clang::OMPTargetTeamsDistributeParallelForSimdDirective const*)
Unexecuted instantiation: ASTStructuralEquivalence.cpp:(anonymous namespace)::StmtComparer::TraverseStmt(clang::OMPTargetTeamsDistributeSimdDirective const*, clang::OMPTargetTeamsDistributeSimdDirective const*)
Unexecuted instantiation: ASTStructuralEquivalence.cpp:(anonymous namespace)::StmtComparer::TraverseStmt(clang::OMPTargetTeamsGenericLoopDirective const*, clang::OMPTargetTeamsGenericLoopDirective const*)
Unexecuted instantiation: ASTStructuralEquivalence.cpp:(anonymous namespace)::StmtComparer::TraverseStmt(clang::OMPTaskLoopDirective const*, clang::OMPTaskLoopDirective const*)
Unexecuted instantiation: ASTStructuralEquivalence.cpp:(anonymous namespace)::StmtComparer::TraverseStmt(clang::OMPTaskLoopSimdDirective const*, clang::OMPTaskLoopSimdDirective const*)
Unexecuted instantiation: ASTStructuralEquivalence.cpp:(anonymous namespace)::StmtComparer::TraverseStmt(clang::OMPTeamsDistributeDirective const*, clang::OMPTeamsDistributeDirective const*)
Unexecuted instantiation: ASTStructuralEquivalence.cpp:(anonymous namespace)::StmtComparer::TraverseStmt(clang::OMPTeamsDistributeParallelForDirective const*, clang::OMPTeamsDistributeParallelForDirective const*)
Unexecuted instantiation: ASTStructuralEquivalence.cpp:(anonymous namespace)::StmtComparer::TraverseStmt(clang::OMPTeamsDistributeParallelForSimdDirective const*, clang::OMPTeamsDistributeParallelForSimdDirective const*)
Unexecuted instantiation: ASTStructuralEquivalence.cpp:(anonymous namespace)::StmtComparer::TraverseStmt(clang::OMPTeamsDistributeSimdDirective const*, clang::OMPTeamsDistributeSimdDirective const*)
Unexecuted instantiation: ASTStructuralEquivalence.cpp:(anonymous namespace)::StmtComparer::TraverseStmt(clang::OMPTeamsGenericLoopDirective const*, clang::OMPTeamsGenericLoopDirective const*)
Unexecuted instantiation: ASTStructuralEquivalence.cpp:(anonymous namespace)::StmtComparer::TraverseStmt(clang::OMPTileDirective const*, clang::OMPTileDirective const*)
Unexecuted instantiation: ASTStructuralEquivalence.cpp:(anonymous namespace)::StmtComparer::TraverseStmt(clang::OMPUnrollDirective const*, clang::OMPUnrollDirective const*)
Unexecuted instantiation: ASTStructuralEquivalence.cpp:(anonymous namespace)::StmtComparer::TraverseStmt(clang::OMPMaskedDirective const*, clang::OMPMaskedDirective const*)
Unexecuted instantiation: ASTStructuralEquivalence.cpp:(anonymous namespace)::StmtComparer::TraverseStmt(clang::OMPMasterDirective const*, clang::OMPMasterDirective const*)
Unexecuted instantiation: ASTStructuralEquivalence.cpp:(anonymous namespace)::StmtComparer::TraverseStmt(clang::OMPMetaDirective const*, clang::OMPMetaDirective const*)
Unexecuted instantiation: ASTStructuralEquivalence.cpp:(anonymous namespace)::StmtComparer::TraverseStmt(clang::OMPOrderedDirective const*, clang::OMPOrderedDirective const*)
Unexecuted instantiation: ASTStructuralEquivalence.cpp:(anonymous namespace)::StmtComparer::TraverseStmt(clang::OMPParallelDirective const*, clang::OMPParallelDirective const*)
Unexecuted instantiation: ASTStructuralEquivalence.cpp:(anonymous namespace)::StmtComparer::TraverseStmt(clang::OMPParallelMasterDirective const*, clang::OMPParallelMasterDirective const*)
Unexecuted instantiation: ASTStructuralEquivalence.cpp:(anonymous namespace)::StmtComparer::TraverseStmt(clang::OMPParallelSectionsDirective const*, clang::OMPParallelSectionsDirective const*)
Unexecuted instantiation: ASTStructuralEquivalence.cpp:(anonymous namespace)::StmtComparer::TraverseStmt(clang::OMPScanDirective const*, clang::OMPScanDirective const*)
Unexecuted instantiation: ASTStructuralEquivalence.cpp:(anonymous namespace)::StmtComparer::TraverseStmt(clang::OMPSectionDirective const*, clang::OMPSectionDirective const*)
Unexecuted instantiation: ASTStructuralEquivalence.cpp:(anonymous namespace)::StmtComparer::TraverseStmt(clang::OMPSectionsDirective const*, clang::OMPSectionsDirective const*)
Unexecuted instantiation: ASTStructuralEquivalence.cpp:(anonymous namespace)::StmtComparer::TraverseStmt(clang::OMPSingleDirective const*, clang::OMPSingleDirective const*)
Unexecuted instantiation: ASTStructuralEquivalence.cpp:(anonymous namespace)::StmtComparer::TraverseStmt(clang::OMPTargetDataDirective const*, clang::OMPTargetDataDirective const*)
Unexecuted instantiation: ASTStructuralEquivalence.cpp:(anonymous namespace)::StmtComparer::TraverseStmt(clang::OMPTargetDirective const*, clang::OMPTargetDirective const*)
Unexecuted instantiation: ASTStructuralEquivalence.cpp:(anonymous namespace)::StmtComparer::TraverseStmt(clang::OMPTargetEnterDataDirective const*, clang::OMPTargetEnterDataDirective const*)
Unexecuted instantiation: ASTStructuralEquivalence.cpp:(anonymous namespace)::StmtComparer::TraverseStmt(clang::OMPTargetExitDataDirective const*, clang::OMPTargetExitDataDirective const*)
Unexecuted instantiation: ASTStructuralEquivalence.cpp:(anonymous namespace)::StmtComparer::TraverseStmt(clang::OMPTargetParallelDirective const*, clang::OMPTargetParallelDirective const*)
Unexecuted instantiation: ASTStructuralEquivalence.cpp:(anonymous namespace)::StmtComparer::TraverseStmt(clang::OMPTargetParallelForDirective const*, clang::OMPTargetParallelForDirective const*)
Unexecuted instantiation: ASTStructuralEquivalence.cpp:(anonymous namespace)::StmtComparer::TraverseStmt(clang::OMPTargetTeamsDirective const*, clang::OMPTargetTeamsDirective const*)
Unexecuted instantiation: ASTStructuralEquivalence.cpp:(anonymous namespace)::StmtComparer::TraverseStmt(clang::OMPTargetUpdateDirective const*, clang::OMPTargetUpdateDirective const*)
Unexecuted instantiation: ASTStructuralEquivalence.cpp:(anonymous namespace)::StmtComparer::TraverseStmt(clang::OMPTaskDirective const*, clang::OMPTaskDirective const*)
Unexecuted instantiation: ASTStructuralEquivalence.cpp:(anonymous namespace)::StmtComparer::TraverseStmt(clang::OMPTaskgroupDirective const*, clang::OMPTaskgroupDirective const*)
Unexecuted instantiation: ASTStructuralEquivalence.cpp:(anonymous namespace)::StmtComparer::TraverseStmt(clang::OMPTaskwaitDirective const*, clang::OMPTaskwaitDirective const*)
Unexecuted instantiation: ASTStructuralEquivalence.cpp:(anonymous namespace)::StmtComparer::TraverseStmt(clang::OMPTaskyieldDirective const*, clang::OMPTaskyieldDirective const*)
Unexecuted instantiation: ASTStructuralEquivalence.cpp:(anonymous namespace)::StmtComparer::TraverseStmt(clang::OMPTeamsDirective const*, clang::OMPTeamsDirective const*)
Unexecuted instantiation: ASTStructuralEquivalence.cpp:(anonymous namespace)::StmtComparer::TraverseStmt(clang::ObjCAtCatchStmt const*, clang::ObjCAtCatchStmt const*)
Unexecuted instantiation: ASTStructuralEquivalence.cpp:(anonymous namespace)::StmtComparer::TraverseStmt(clang::ObjCAtFinallyStmt const*, clang::ObjCAtFinallyStmt const*)
Unexecuted instantiation: ASTStructuralEquivalence.cpp:(anonymous namespace)::StmtComparer::TraverseStmt(clang::ObjCAtSynchronizedStmt const*, clang::ObjCAtSynchronizedStmt const*)
Unexecuted instantiation: ASTStructuralEquivalence.cpp:(anonymous namespace)::StmtComparer::TraverseStmt(clang::ObjCAtThrowStmt const*, clang::ObjCAtThrowStmt const*)
Unexecuted instantiation: ASTStructuralEquivalence.cpp:(anonymous namespace)::StmtComparer::TraverseStmt(clang::ObjCAtTryStmt const*, clang::ObjCAtTryStmt const*)
Unexecuted instantiation: ASTStructuralEquivalence.cpp:(anonymous namespace)::StmtComparer::TraverseStmt(clang::ObjCAutoreleasePoolStmt const*, clang::ObjCAutoreleasePoolStmt const*)
Unexecuted instantiation: ASTStructuralEquivalence.cpp:(anonymous namespace)::StmtComparer::TraverseStmt(clang::ObjCForCollectionStmt const*, clang::ObjCForCollectionStmt const*)
Unexecuted instantiation: ASTStructuralEquivalence.cpp:(anonymous namespace)::StmtComparer::TraverseStmt(clang::ReturnStmt const*, clang::ReturnStmt const*)
Unexecuted instantiation: ASTStructuralEquivalence.cpp:(anonymous namespace)::StmtComparer::TraverseStmt(clang::SEHExceptStmt const*, clang::SEHExceptStmt const*)
Unexecuted instantiation: ASTStructuralEquivalence.cpp:(anonymous namespace)::StmtComparer::TraverseStmt(clang::SEHFinallyStmt const*, clang::SEHFinallyStmt const*)
Unexecuted instantiation: ASTStructuralEquivalence.cpp:(anonymous namespace)::StmtComparer::TraverseStmt(clang::SEHLeaveStmt const*, clang::SEHLeaveStmt const*)
Unexecuted instantiation: ASTStructuralEquivalence.cpp:(anonymous namespace)::StmtComparer::TraverseStmt(clang::SEHTryStmt const*, clang::SEHTryStmt const*)
Unexecuted instantiation: ASTStructuralEquivalence.cpp:(anonymous namespace)::StmtComparer::TraverseStmt(clang::CaseStmt const*, clang::CaseStmt const*)
Unexecuted instantiation: ASTStructuralEquivalence.cpp:(anonymous namespace)::StmtComparer::TraverseStmt(clang::DefaultStmt const*, clang::DefaultStmt const*)
Unexecuted instantiation: ASTStructuralEquivalence.cpp:(anonymous namespace)::StmtComparer::TraverseStmt(clang::SwitchStmt const*, clang::SwitchStmt const*)
Unexecuted instantiation: ASTStructuralEquivalence.cpp:(anonymous namespace)::StmtComparer::TraverseStmt(clang::AttributedStmt const*, clang::AttributedStmt const*)
Unexecuted instantiation: ASTStructuralEquivalence.cpp:(anonymous namespace)::StmtComparer::TraverseStmt(clang::BinaryConditionalOperator const*, clang::BinaryConditionalOperator const*)
ASTStructuralEquivalence.cpp:(anonymous namespace)::StmtComparer::TraverseStmt(clang::ConditionalOperator const*, clang::ConditionalOperator const*)
Line
Count
Source
346
165
  bool TraverseStmt(const CLASS *S1, const CLASS *S2) {                        \
347
165
    if (!TraverseStmt(static_cast<const PARENT *>(S1),                         \
348
165
                      static_cast<const PARENT *>(S2)))                        \
349
165
      
return false0
; \
350
165
    return IsStmtEquivalent(S1, S2);                                           \
351
165
  }
ASTStructuralEquivalence.cpp:(anonymous namespace)::StmtComparer::TraverseStmt(clang::AddrLabelExpr const*, clang::AddrLabelExpr const*)
Line
Count
Source
346
4
  bool TraverseStmt(const CLASS *S1, const CLASS *S2) {                        \
347
4
    if (!TraverseStmt(static_cast<const PARENT *>(S1),                         \
348
4
                      static_cast<const PARENT *>(S2)))                        \
349
4
      
return false0
; \
350
4
    return IsStmtEquivalent(S1, S2);                                           \
351
4
  }
Unexecuted instantiation: ASTStructuralEquivalence.cpp:(anonymous namespace)::StmtComparer::TraverseStmt(clang::ArrayInitIndexExpr const*, clang::ArrayInitIndexExpr const*)
Unexecuted instantiation: ASTStructuralEquivalence.cpp:(anonymous namespace)::StmtComparer::TraverseStmt(clang::ArrayInitLoopExpr const*, clang::ArrayInitLoopExpr const*)
Unexecuted instantiation: ASTStructuralEquivalence.cpp:(anonymous namespace)::StmtComparer::TraverseStmt(clang::ArraySubscriptExpr const*, clang::ArraySubscriptExpr const*)
Unexecuted instantiation: ASTStructuralEquivalence.cpp:(anonymous namespace)::StmtComparer::TraverseStmt(clang::ArrayTypeTraitExpr const*, clang::ArrayTypeTraitExpr const*)
Unexecuted instantiation: ASTStructuralEquivalence.cpp:(anonymous namespace)::StmtComparer::TraverseStmt(clang::AsTypeExpr const*, clang::AsTypeExpr const*)
ASTStructuralEquivalence.cpp:(anonymous namespace)::StmtComparer::TraverseStmt(clang::AtomicExpr const*, clang::AtomicExpr const*)
Line
Count
Source
346
4
  bool TraverseStmt(const CLASS *S1, const CLASS *S2) {                        \
347
4
    if (!TraverseStmt(static_cast<const PARENT *>(S1),                         \
348
4
                      static_cast<const PARENT *>(S2)))                        \
349
4
      
return false0
; \
350
4
    return IsStmtEquivalent(S1, S2);                                           \
351
4
  }
ASTStructuralEquivalence.cpp:(anonymous namespace)::StmtComparer::TraverseStmt(clang::BinaryOperator const*, clang::BinaryOperator const*)
Line
Count
Source
346
53.2k
  bool TraverseStmt(const CLASS *S1, const CLASS *S2) {                        \
347
53.2k
    if (!TraverseStmt(static_cast<const PARENT *>(S1),                         \
348
53.2k
                      static_cast<const PARENT *>(S2)))                        \
349
53.2k
      
return false0
; \
350
53.2k
    return IsStmtEquivalent(S1, S2);                                           \
351
53.2k
  }
Unexecuted instantiation: ASTStructuralEquivalence.cpp:(anonymous namespace)::StmtComparer::TraverseStmt(clang::CompoundAssignOperator const*, clang::CompoundAssignOperator const*)
Unexecuted instantiation: ASTStructuralEquivalence.cpp:(anonymous namespace)::StmtComparer::TraverseStmt(clang::BlockExpr const*, clang::BlockExpr const*)
Unexecuted instantiation: ASTStructuralEquivalence.cpp:(anonymous namespace)::StmtComparer::TraverseStmt(clang::CXXBindTemporaryExpr const*, clang::CXXBindTemporaryExpr const*)
ASTStructuralEquivalence.cpp:(anonymous namespace)::StmtComparer::TraverseStmt(clang::CXXBoolLiteralExpr const*, clang::CXXBoolLiteralExpr const*)
Line
Count
Source
346
2
  bool TraverseStmt(const CLASS *S1, const CLASS *S2) {                        \
347
2
    if (!TraverseStmt(static_cast<const PARENT *>(S1),                         \
348
2
                      static_cast<const PARENT *>(S2)))                        \
349
2
      
return false0
; \
350
2
    return IsStmtEquivalent(S1, S2);                                           \
351
2
  }
Unexecuted instantiation: ASTStructuralEquivalence.cpp:(anonymous namespace)::StmtComparer::TraverseStmt(clang::CXXConstructExpr const*, clang::CXXConstructExpr const*)
Unexecuted instantiation: ASTStructuralEquivalence.cpp:(anonymous namespace)::StmtComparer::TraverseStmt(clang::CXXTemporaryObjectExpr const*, clang::CXXTemporaryObjectExpr const*)
Unexecuted instantiation: ASTStructuralEquivalence.cpp:(anonymous namespace)::StmtComparer::TraverseStmt(clang::CXXDefaultArgExpr const*, clang::CXXDefaultArgExpr const*)
Unexecuted instantiation: ASTStructuralEquivalence.cpp:(anonymous namespace)::StmtComparer::TraverseStmt(clang::CXXDefaultInitExpr const*, clang::CXXDefaultInitExpr const*)
Unexecuted instantiation: ASTStructuralEquivalence.cpp:(anonymous namespace)::StmtComparer::TraverseStmt(clang::CXXDeleteExpr const*, clang::CXXDeleteExpr const*)
ASTStructuralEquivalence.cpp:(anonymous namespace)::StmtComparer::TraverseStmt(clang::CXXDependentScopeMemberExpr const*, clang::CXXDependentScopeMemberExpr const*)
Line
Count
Source
346
6.90k
  bool TraverseStmt(const CLASS *S1, const CLASS *S2) {                        \
347
6.90k
    if (!TraverseStmt(static_cast<const PARENT *>(S1),                         \
348
6.90k
                      static_cast<const PARENT *>(S2)))                        \
349
6.90k
      
return false0
; \
350
6.90k
    return IsStmtEquivalent(S1, S2);                                           \
351
6.90k
  }
Unexecuted instantiation: ASTStructuralEquivalence.cpp:(anonymous namespace)::StmtComparer::TraverseStmt(clang::CXXFoldExpr const*, clang::CXXFoldExpr const*)
Unexecuted instantiation: ASTStructuralEquivalence.cpp:(anonymous namespace)::StmtComparer::TraverseStmt(clang::CXXInheritedCtorInitExpr const*, clang::CXXInheritedCtorInitExpr const*)
Unexecuted instantiation: ASTStructuralEquivalence.cpp:(anonymous namespace)::StmtComparer::TraverseStmt(clang::CXXNewExpr const*, clang::CXXNewExpr const*)
ASTStructuralEquivalence.cpp:(anonymous namespace)::StmtComparer::TraverseStmt(clang::CXXNoexceptExpr const*, clang::CXXNoexceptExpr const*)
Line
Count
Source
346
6.09k
  bool TraverseStmt(const CLASS *S1, const CLASS *S2) {                        \
347
6.09k
    if (!TraverseStmt(static_cast<const PARENT *>(S1),                         \
348
6.09k
                      static_cast<const PARENT *>(S2)))                        \
349
6.09k
      
return false0
; \
350
6.09k
    return IsStmtEquivalent(S1, S2);                                           \
351
6.09k
  }
Unexecuted instantiation: ASTStructuralEquivalence.cpp:(anonymous namespace)::StmtComparer::TraverseStmt(clang::CXXNullPtrLiteralExpr const*, clang::CXXNullPtrLiteralExpr const*)
Unexecuted instantiation: ASTStructuralEquivalence.cpp:(anonymous namespace)::StmtComparer::TraverseStmt(clang::CXXPseudoDestructorExpr const*, clang::CXXPseudoDestructorExpr const*)
Unexecuted instantiation: ASTStructuralEquivalence.cpp:(anonymous namespace)::StmtComparer::TraverseStmt(clang::CXXRewrittenBinaryOperator const*, clang::CXXRewrittenBinaryOperator const*)
Unexecuted instantiation: ASTStructuralEquivalence.cpp:(anonymous namespace)::StmtComparer::TraverseStmt(clang::CXXScalarValueInitExpr const*, clang::CXXScalarValueInitExpr const*)
Unexecuted instantiation: ASTStructuralEquivalence.cpp:(anonymous namespace)::StmtComparer::TraverseStmt(clang::CXXStdInitializerListExpr const*, clang::CXXStdInitializerListExpr const*)
Unexecuted instantiation: ASTStructuralEquivalence.cpp:(anonymous namespace)::StmtComparer::TraverseStmt(clang::CXXThisExpr const*, clang::CXXThisExpr const*)
Unexecuted instantiation: ASTStructuralEquivalence.cpp:(anonymous namespace)::StmtComparer::TraverseStmt(clang::CXXThrowExpr const*, clang::CXXThrowExpr const*)
Unexecuted instantiation: ASTStructuralEquivalence.cpp:(anonymous namespace)::StmtComparer::TraverseStmt(clang::CXXTypeidExpr const*, clang::CXXTypeidExpr const*)
Unexecuted instantiation: ASTStructuralEquivalence.cpp:(anonymous namespace)::StmtComparer::TraverseStmt(clang::CXXUnresolvedConstructExpr const*, clang::CXXUnresolvedConstructExpr const*)
Unexecuted instantiation: ASTStructuralEquivalence.cpp:(anonymous namespace)::StmtComparer::TraverseStmt(clang::CXXUuidofExpr const*, clang::CXXUuidofExpr const*)
ASTStructuralEquivalence.cpp:(anonymous namespace)::StmtComparer::TraverseStmt(clang::CallExpr const*, clang::CallExpr const*)
Line
Count
Source
346
10.6k
  bool TraverseStmt(const CLASS *S1, const CLASS *S2) {                        \
347
10.6k
    if (!TraverseStmt(static_cast<const PARENT *>(S1),                         \
348
10.6k
                      static_cast<const PARENT *>(S2)))                        \
349
10.6k
      
return false0
; \
350
10.6k
    return IsStmtEquivalent(S1, S2);                                           \
351
10.6k
  }
Unexecuted instantiation: ASTStructuralEquivalence.cpp:(anonymous namespace)::StmtComparer::TraverseStmt(clang::CUDAKernelCallExpr const*, clang::CUDAKernelCallExpr const*)
Unexecuted instantiation: ASTStructuralEquivalence.cpp:(anonymous namespace)::StmtComparer::TraverseStmt(clang::CXXMemberCallExpr const*, clang::CXXMemberCallExpr const*)
ASTStructuralEquivalence.cpp:(anonymous namespace)::StmtComparer::TraverseStmt(clang::CXXOperatorCallExpr const*, clang::CXXOperatorCallExpr const*)
Line
Count
Source
346
606
  bool TraverseStmt(const CLASS *S1, const CLASS *S2) {                        \
347
606
    if (!TraverseStmt(static_cast<const PARENT *>(S1),                         \
348
606
                      static_cast<const PARENT *>(S2)))                        \
349
606
      
return false0
; \
350
606
    return IsStmtEquivalent(S1, S2);                                           \
351
606
  }
Unexecuted instantiation: ASTStructuralEquivalence.cpp:(anonymous namespace)::StmtComparer::TraverseStmt(clang::UserDefinedLiteral const*, clang::UserDefinedLiteral const*)
Unexecuted instantiation: ASTStructuralEquivalence.cpp:(anonymous namespace)::StmtComparer::TraverseStmt(clang::BuiltinBitCastExpr const*, clang::BuiltinBitCastExpr const*)
Unexecuted instantiation: ASTStructuralEquivalence.cpp:(anonymous namespace)::StmtComparer::TraverseStmt(clang::CStyleCastExpr const*, clang::CStyleCastExpr const*)
Unexecuted instantiation: ASTStructuralEquivalence.cpp:(anonymous namespace)::StmtComparer::TraverseStmt(clang::CXXFunctionalCastExpr const*, clang::CXXFunctionalCastExpr const*)
Unexecuted instantiation: ASTStructuralEquivalence.cpp:(anonymous namespace)::StmtComparer::TraverseStmt(clang::CXXAddrspaceCastExpr const*, clang::CXXAddrspaceCastExpr const*)
Unexecuted instantiation: ASTStructuralEquivalence.cpp:(anonymous namespace)::StmtComparer::TraverseStmt(clang::CXXConstCastExpr const*, clang::CXXConstCastExpr const*)
Unexecuted instantiation: ASTStructuralEquivalence.cpp:(anonymous namespace)::StmtComparer::TraverseStmt(clang::CXXDynamicCastExpr const*, clang::CXXDynamicCastExpr const*)
Unexecuted instantiation: ASTStructuralEquivalence.cpp:(anonymous namespace)::StmtComparer::TraverseStmt(clang::CXXReinterpretCastExpr const*, clang::CXXReinterpretCastExpr const*)
Unexecuted instantiation: ASTStructuralEquivalence.cpp:(anonymous namespace)::StmtComparer::TraverseStmt(clang::CXXStaticCastExpr const*, clang::CXXStaticCastExpr const*)
Unexecuted instantiation: ASTStructuralEquivalence.cpp:(anonymous namespace)::StmtComparer::TraverseStmt(clang::ObjCBridgedCastExpr const*, clang::ObjCBridgedCastExpr const*)
ASTStructuralEquivalence.cpp:(anonymous namespace)::StmtComparer::TraverseStmt(clang::ImplicitCastExpr const*, clang::ImplicitCastExpr const*)
Line
Count
Source
346
133k
  bool TraverseStmt(const CLASS *S1, const CLASS *S2) {                        \
347
133k
    if (!TraverseStmt(static_cast<const PARENT *>(S1),                         \
348
133k
                      static_cast<const PARENT *>(S2)))                        \
349
133k
      
return false0
; \
350
133k
    return IsStmtEquivalent(S1, S2);                                           \
351
133k
  }
ASTStructuralEquivalence.cpp:(anonymous namespace)::StmtComparer::TraverseStmt(clang::CharacterLiteral const*, clang::CharacterLiteral const*)
Line
Count
Source
346
4
  bool TraverseStmt(const CLASS *S1, const CLASS *S2) {                        \
347
4
    if (!TraverseStmt(static_cast<const PARENT *>(S1),                         \
348
4
                      static_cast<const PARENT *>(S2)))                        \
349
4
      
return false0
; \
350
4
    return IsStmtEquivalent(S1, S2);                                           \
351
4
  }
Unexecuted instantiation: ASTStructuralEquivalence.cpp:(anonymous namespace)::StmtComparer::TraverseStmt(clang::ChooseExpr const*, clang::ChooseExpr const*)
Unexecuted instantiation: ASTStructuralEquivalence.cpp:(anonymous namespace)::StmtComparer::TraverseStmt(clang::CompoundLiteralExpr const*, clang::CompoundLiteralExpr const*)
Unexecuted instantiation: ASTStructuralEquivalence.cpp:(anonymous namespace)::StmtComparer::TraverseStmt(clang::ConceptSpecializationExpr const*, clang::ConceptSpecializationExpr const*)
Unexecuted instantiation: ASTStructuralEquivalence.cpp:(anonymous namespace)::StmtComparer::TraverseStmt(clang::ConvertVectorExpr const*, clang::ConvertVectorExpr const*)
Unexecuted instantiation: ASTStructuralEquivalence.cpp:(anonymous namespace)::StmtComparer::TraverseStmt(clang::CoawaitExpr const*, clang::CoawaitExpr const*)
Unexecuted instantiation: ASTStructuralEquivalence.cpp:(anonymous namespace)::StmtComparer::TraverseStmt(clang::CoyieldExpr const*, clang::CoyieldExpr const*)
ASTStructuralEquivalence.cpp:(anonymous namespace)::StmtComparer::TraverseStmt(clang::DeclRefExpr const*, clang::DeclRefExpr const*)
Line
Count
Source
346
203k
  bool TraverseStmt(const CLASS *S1, const CLASS *S2) {                        \
347
203k
    if (!TraverseStmt(static_cast<const PARENT *>(S1),                         \
348
203k
                      static_cast<const PARENT *>(S2)))                        \
349
203k
      
return false210
; \
350
203k
    
return IsStmtEquivalent(S1, S2)202k
; \
351
203k
  }
Unexecuted instantiation: ASTStructuralEquivalence.cpp:(anonymous namespace)::StmtComparer::TraverseStmt(clang::DependentCoawaitExpr const*, clang::DependentCoawaitExpr const*)
ASTStructuralEquivalence.cpp:(anonymous namespace)::StmtComparer::TraverseStmt(clang::DependentScopeDeclRefExpr const*, clang::DependentScopeDeclRefExpr const*)
Line
Count
Source
346
138k
  bool TraverseStmt(const CLASS *S1, const CLASS *S2) {                        \
347
138k
    if (!TraverseStmt(static_cast<const PARENT *>(S1),                         \
348
138k
                      static_cast<const PARENT *>(S2)))                        \
349
138k
      
return false0
; \
350
138k
    return IsStmtEquivalent(S1, S2);                                           \
351
138k
  }
Unexecuted instantiation: ASTStructuralEquivalence.cpp:(anonymous namespace)::StmtComparer::TraverseStmt(clang::DesignatedInitExpr const*, clang::DesignatedInitExpr const*)
Unexecuted instantiation: ASTStructuralEquivalence.cpp:(anonymous namespace)::StmtComparer::TraverseStmt(clang::DesignatedInitUpdateExpr const*, clang::DesignatedInitUpdateExpr const*)
ASTStructuralEquivalence.cpp:(anonymous namespace)::StmtComparer::TraverseStmt(clang::ExpressionTraitExpr const*, clang::ExpressionTraitExpr const*)
Line
Count
Source
346
4
  bool TraverseStmt(const CLASS *S1, const CLASS *S2) {                        \
347
4
    if (!TraverseStmt(static_cast<const PARENT *>(S1),                         \
348
4
                      static_cast<const PARENT *>(S2)))                        \
349
4
      
return false0
; \
350
4
    return IsStmtEquivalent(S1, S2);                                           \
351
4
  }
Unexecuted instantiation: ASTStructuralEquivalence.cpp:(anonymous namespace)::StmtComparer::TraverseStmt(clang::ExtVectorElementExpr const*, clang::ExtVectorElementExpr const*)
Unexecuted instantiation: ASTStructuralEquivalence.cpp:(anonymous namespace)::StmtComparer::TraverseStmt(clang::FixedPointLiteral const*, clang::FixedPointLiteral const*)
ASTStructuralEquivalence.cpp:(anonymous namespace)::StmtComparer::TraverseStmt(clang::FloatingLiteral const*, clang::FloatingLiteral const*)
Line
Count
Source
346
8
  bool TraverseStmt(const CLASS *S1, const CLASS *S2) {                        \
347
8
    if (!TraverseStmt(static_cast<const PARENT *>(S1),                         \
348
8
                      static_cast<const PARENT *>(S2)))                        \
349
8
      
return false2
; \
350
8
    
return IsStmtEquivalent(S1, S2)6
; \
351
8
  }
ASTStructuralEquivalence.cpp:(anonymous namespace)::StmtComparer::TraverseStmt(clang::ConstantExpr const*, clang::ConstantExpr const*)
Line
Count
Source
346
5.18k
  bool TraverseStmt(const CLASS *S1, const CLASS *S2) {                        \
347
5.18k
    if (!TraverseStmt(static_cast<const PARENT *>(S1),                         \
348
5.18k
                      static_cast<const PARENT *>(S2)))                        \
349
5.18k
      
return false0
; \
350
5.18k
    return IsStmtEquivalent(S1, S2);                                           \
351
5.18k
  }
Unexecuted instantiation: ASTStructuralEquivalence.cpp:(anonymous namespace)::StmtComparer::TraverseStmt(clang::ExprWithCleanups const*, clang::ExprWithCleanups const*)
Unexecuted instantiation: ASTStructuralEquivalence.cpp:(anonymous namespace)::StmtComparer::TraverseStmt(clang::FunctionParmPackExpr const*, clang::FunctionParmPackExpr const*)
Unexecuted instantiation: ASTStructuralEquivalence.cpp:(anonymous namespace)::StmtComparer::TraverseStmt(clang::GNUNullExpr const*, clang::GNUNullExpr const*)
ASTStructuralEquivalence.cpp:(anonymous namespace)::StmtComparer::TraverseStmt(clang::GenericSelectionExpr const*, clang::GenericSelectionExpr const*)
Line
Count
Source
346
10
  bool TraverseStmt(const CLASS *S1, const CLASS *S2) {                        \
347
10
    if (!TraverseStmt(static_cast<const PARENT *>(S1),                         \
348
10
                      static_cast<const PARENT *>(S2)))                        \
349
10
      
return false0
; \
350
10
    return IsStmtEquivalent(S1, S2);                                           \
351
10
  }
Unexecuted instantiation: ASTStructuralEquivalence.cpp:(anonymous namespace)::StmtComparer::TraverseStmt(clang::ImaginaryLiteral const*, clang::ImaginaryLiteral const*)
Unexecuted instantiation: ASTStructuralEquivalence.cpp:(anonymous namespace)::StmtComparer::TraverseStmt(clang::ImplicitValueInitExpr const*, clang::ImplicitValueInitExpr const*)
Unexecuted instantiation: ASTStructuralEquivalence.cpp:(anonymous namespace)::StmtComparer::TraverseStmt(clang::InitListExpr const*, clang::InitListExpr const*)
ASTStructuralEquivalence.cpp:(anonymous namespace)::StmtComparer::TraverseStmt(clang::IntegerLiteral const*, clang::IntegerLiteral const*)
Line
Count
Source
346
50.0k
  bool TraverseStmt(const CLASS *S1, const CLASS *S2) {                        \
347
50.0k
    if (!TraverseStmt(static_cast<const PARENT *>(S1),                         \
348
50.0k
                      static_cast<const PARENT *>(S2)))                        \
349
50.0k
      
return false2
; \
350
50.0k
    
return IsStmtEquivalent(S1, S2)50.0k
; \
351
50.0k
  }
Unexecuted instantiation: ASTStructuralEquivalence.cpp:(anonymous namespace)::StmtComparer::TraverseStmt(clang::LambdaExpr const*, clang::LambdaExpr const*)
Unexecuted instantiation: ASTStructuralEquivalence.cpp:(anonymous namespace)::StmtComparer::TraverseStmt(clang::MSPropertyRefExpr const*, clang::MSPropertyRefExpr const*)
Unexecuted instantiation: ASTStructuralEquivalence.cpp:(anonymous namespace)::StmtComparer::TraverseStmt(clang::MSPropertySubscriptExpr const*, clang::MSPropertySubscriptExpr const*)
Unexecuted instantiation: ASTStructuralEquivalence.cpp:(anonymous namespace)::StmtComparer::TraverseStmt(clang::MaterializeTemporaryExpr const*, clang::MaterializeTemporaryExpr const*)
Unexecuted instantiation: ASTStructuralEquivalence.cpp:(anonymous namespace)::StmtComparer::TraverseStmt(clang::MatrixSubscriptExpr const*, clang::MatrixSubscriptExpr const*)
ASTStructuralEquivalence.cpp:(anonymous namespace)::StmtComparer::TraverseStmt(clang::MemberExpr const*, clang::MemberExpr const*)
Line
Count
Source
346
4
  bool TraverseStmt(const CLASS *S1, const CLASS *S2) {                        \
347
4
    if (!TraverseStmt(static_cast<const PARENT *>(S1),                         \
348
4
                      static_cast<const PARENT *>(S2)))                        \
349
4
      
return false0
; \
350
4
    return IsStmtEquivalent(S1, S2);                                           \
351
4
  }
Unexecuted instantiation: ASTStructuralEquivalence.cpp:(anonymous namespace)::StmtComparer::TraverseStmt(clang::NoInitExpr const*, clang::NoInitExpr const*)
Unexecuted instantiation: ASTStructuralEquivalence.cpp:(anonymous namespace)::StmtComparer::TraverseStmt(clang::OMPArraySectionExpr const*, clang::OMPArraySectionExpr const*)
Unexecuted instantiation: ASTStructuralEquivalence.cpp:(anonymous namespace)::StmtComparer::TraverseStmt(clang::OMPArrayShapingExpr const*, clang::OMPArrayShapingExpr const*)
Unexecuted instantiation: ASTStructuralEquivalence.cpp:(anonymous namespace)::StmtComparer::TraverseStmt(clang::OMPIteratorExpr const*, clang::OMPIteratorExpr const*)
Unexecuted instantiation: ASTStructuralEquivalence.cpp:(anonymous namespace)::StmtComparer::TraverseStmt(clang::ObjCArrayLiteral const*, clang::ObjCArrayLiteral const*)
Unexecuted instantiation: ASTStructuralEquivalence.cpp:(anonymous namespace)::StmtComparer::TraverseStmt(clang::ObjCAvailabilityCheckExpr const*, clang::ObjCAvailabilityCheckExpr const*)
Unexecuted instantiation: ASTStructuralEquivalence.cpp:(anonymous namespace)::StmtComparer::TraverseStmt(clang::ObjCBoolLiteralExpr const*, clang::ObjCBoolLiteralExpr const*)
Unexecuted instantiation: ASTStructuralEquivalence.cpp:(anonymous namespace)::StmtComparer::TraverseStmt(clang::ObjCBoxedExpr const*, clang::ObjCBoxedExpr const*)
Unexecuted instantiation: ASTStructuralEquivalence.cpp:(anonymous namespace)::StmtComparer::TraverseStmt(clang::ObjCDictionaryLiteral const*, clang::ObjCDictionaryLiteral const*)
Unexecuted instantiation: ASTStructuralEquivalence.cpp:(anonymous namespace)::StmtComparer::TraverseStmt(clang::ObjCEncodeExpr const*, clang::ObjCEncodeExpr const*)
Unexecuted instantiation: ASTStructuralEquivalence.cpp:(anonymous namespace)::StmtComparer::TraverseStmt(clang::ObjCIndirectCopyRestoreExpr const*, clang::ObjCIndirectCopyRestoreExpr const*)
Unexecuted instantiation: ASTStructuralEquivalence.cpp:(anonymous namespace)::StmtComparer::TraverseStmt(clang::ObjCIsaExpr const*, clang::ObjCIsaExpr const*)
Unexecuted instantiation: ASTStructuralEquivalence.cpp:(anonymous namespace)::StmtComparer::TraverseStmt(clang::ObjCIvarRefExpr const*, clang::ObjCIvarRefExpr const*)
Unexecuted instantiation: ASTStructuralEquivalence.cpp:(anonymous namespace)::StmtComparer::TraverseStmt(clang::ObjCMessageExpr const*, clang::ObjCMessageExpr const*)
Unexecuted instantiation: ASTStructuralEquivalence.cpp:(anonymous namespace)::StmtComparer::TraverseStmt(clang::ObjCPropertyRefExpr const*, clang::ObjCPropertyRefExpr const*)
Unexecuted instantiation: ASTStructuralEquivalence.cpp:(anonymous namespace)::StmtComparer::TraverseStmt(clang::ObjCProtocolExpr const*, clang::ObjCProtocolExpr const*)
Unexecuted instantiation: ASTStructuralEquivalence.cpp:(anonymous namespace)::StmtComparer::TraverseStmt(clang::ObjCSelectorExpr const*, clang::ObjCSelectorExpr const*)
ASTStructuralEquivalence.cpp:(anonymous namespace)::StmtComparer::TraverseStmt(clang::ObjCStringLiteral const*, clang::ObjCStringLiteral const*)
Line
Count
Source
346
4
  bool TraverseStmt(const CLASS *S1, const CLASS *S2) {                        \
347
4
    if (!TraverseStmt(static_cast<const PARENT *>(S1),                         \
348
4
                      static_cast<const PARENT *>(S2)))                        \
349
4
      
return false0
; \
350
4
    return IsStmtEquivalent(S1, S2);                                           \
351
4
  }
Unexecuted instantiation: ASTStructuralEquivalence.cpp:(anonymous namespace)::StmtComparer::TraverseStmt(clang::ObjCSubscriptRefExpr const*, clang::ObjCSubscriptRefExpr const*)
Unexecuted instantiation: ASTStructuralEquivalence.cpp:(anonymous namespace)::StmtComparer::TraverseStmt(clang::OffsetOfExpr const*, clang::OffsetOfExpr const*)
Unexecuted instantiation: ASTStructuralEquivalence.cpp:(anonymous namespace)::StmtComparer::TraverseStmt(clang::OpaqueValueExpr const*, clang::OpaqueValueExpr const*)
ASTStructuralEquivalence.cpp:(anonymous namespace)::StmtComparer::TraverseStmt(clang::UnresolvedLookupExpr const*, clang::UnresolvedLookupExpr const*)
Line
Count
Source
346
2.43k
  bool TraverseStmt(const CLASS *S1, const CLASS *S2) {                        \
347
2.43k
    if (!TraverseStmt(static_cast<const PARENT *>(S1),                         \
348
2.43k
                      static_cast<const PARENT *>(S2)))                        \
349
2.43k
      
return false0
; \
350
2.43k
    return IsStmtEquivalent(S1, S2);                                           \
351
2.43k
  }
Unexecuted instantiation: ASTStructuralEquivalence.cpp:(anonymous namespace)::StmtComparer::TraverseStmt(clang::UnresolvedMemberExpr const*, clang::UnresolvedMemberExpr const*)
ASTStructuralEquivalence.cpp:(anonymous namespace)::StmtComparer::TraverseStmt(clang::PackExpansionExpr const*, clang::PackExpansionExpr const*)
Line
Count
Source
346
783
  bool TraverseStmt(const CLASS *S1, const CLASS *S2) {                        \
347
783
    if (!TraverseStmt(static_cast<const PARENT *>(S1),                         \
348
783
                      static_cast<const PARENT *>(S2)))                        \
349
783
      
return false0
; \
350
783
    return IsStmtEquivalent(S1, S2);                                           \
351
783
  }
ASTStructuralEquivalence.cpp:(anonymous namespace)::StmtComparer::TraverseStmt(clang::ParenExpr const*, clang::ParenExpr const*)
Line
Count
Source
346
2.12k
  bool TraverseStmt(const CLASS *S1, const CLASS *S2) {                        \
347
2.12k
    if (!TraverseStmt(static_cast<const PARENT *>(S1),                         \
348
2.12k
                      static_cast<const PARENT *>(S2)))                        \
349
2.12k
      
return false0
; \
350
2.12k
    return IsStmtEquivalent(S1, S2);                                           \
351
2.12k
  }
Unexecuted instantiation: ASTStructuralEquivalence.cpp:(anonymous namespace)::StmtComparer::TraverseStmt(clang::ParenListExpr const*, clang::ParenListExpr const*)
Unexecuted instantiation: ASTStructuralEquivalence.cpp:(anonymous namespace)::StmtComparer::TraverseStmt(clang::PredefinedExpr const*, clang::PredefinedExpr const*)
Unexecuted instantiation: ASTStructuralEquivalence.cpp:(anonymous namespace)::StmtComparer::TraverseStmt(clang::PseudoObjectExpr const*, clang::PseudoObjectExpr const*)
Unexecuted instantiation: ASTStructuralEquivalence.cpp:(anonymous namespace)::StmtComparer::TraverseStmt(clang::RecoveryExpr const*, clang::RecoveryExpr const*)
Unexecuted instantiation: ASTStructuralEquivalence.cpp:(anonymous namespace)::StmtComparer::TraverseStmt(clang::RequiresExpr const*, clang::RequiresExpr const*)
Unexecuted instantiation: ASTStructuralEquivalence.cpp:(anonymous namespace)::StmtComparer::TraverseStmt(clang::SYCLUniqueStableNameExpr const*, clang::SYCLUniqueStableNameExpr const*)
Unexecuted instantiation: ASTStructuralEquivalence.cpp:(anonymous namespace)::StmtComparer::TraverseStmt(clang::ShuffleVectorExpr const*, clang::ShuffleVectorExpr const*)
ASTStructuralEquivalence.cpp:(anonymous namespace)::StmtComparer::TraverseStmt(clang::SizeOfPackExpr const*, clang::SizeOfPackExpr const*)
Line
Count
Source
346
1.26k
  bool TraverseStmt(const CLASS *S1, const CLASS *S2) {                        \
347
1.26k
    if (!TraverseStmt(static_cast<const PARENT *>(S1),                         \
348
1.26k
                      static_cast<const PARENT *>(S2)))                        \
349
1.26k
      
return false0
; \
350
1.26k
    return IsStmtEquivalent(S1, S2);                                           \
351
1.26k
  }
Unexecuted instantiation: ASTStructuralEquivalence.cpp:(anonymous namespace)::StmtComparer::TraverseStmt(clang::SourceLocExpr const*, clang::SourceLocExpr const*)
Unexecuted instantiation: ASTStructuralEquivalence.cpp:(anonymous namespace)::StmtComparer::TraverseStmt(clang::StmtExpr const*, clang::StmtExpr const*)
ASTStructuralEquivalence.cpp:(anonymous namespace)::StmtComparer::TraverseStmt(clang::StringLiteral const*, clang::StringLiteral const*)
Line
Count
Source
346
10
  bool TraverseStmt(const CLASS *S1, const CLASS *S2) {                        \
347
10
    if (!TraverseStmt(static_cast<const PARENT *>(S1),                         \
348
10
                      static_cast<const PARENT *>(S2)))                        \
349
10
      
return false2
; \
350
10
    
return IsStmtEquivalent(S1, S2)8
; \
351
10
  }
ASTStructuralEquivalence.cpp:(anonymous namespace)::StmtComparer::TraverseStmt(clang::SubstNonTypeTemplateParmExpr const*, clang::SubstNonTypeTemplateParmExpr const*)
Line
Count
Source
346
19.4k
  bool TraverseStmt(const CLASS *S1, const CLASS *S2) {                        \
347
19.4k
    if (!TraverseStmt(static_cast<const PARENT *>(S1),                         \
348
19.4k
                      static_cast<const PARENT *>(S2)))                        \
349
19.4k
      
return false0
; \
350
19.4k
    return IsStmtEquivalent(S1, S2);                                           \
351
19.4k
  }
Unexecuted instantiation: ASTStructuralEquivalence.cpp:(anonymous namespace)::StmtComparer::TraverseStmt(clang::SubstNonTypeTemplateParmPackExpr const*, clang::SubstNonTypeTemplateParmPackExpr const*)
ASTStructuralEquivalence.cpp:(anonymous namespace)::StmtComparer::TraverseStmt(clang::TypeTraitExpr const*, clang::TypeTraitExpr const*)
Line
Count
Source
346
42.6k
  bool TraverseStmt(const CLASS *S1, const CLASS *S2) {                        \
347
42.6k
    if (!TraverseStmt(static_cast<const PARENT *>(S1),                         \
348
42.6k
                      static_cast<const PARENT *>(S2)))                        \
349
42.6k
      
return false0
; \
350
42.6k
    return IsStmtEquivalent(S1, S2);                                           \
351
42.6k
  }
Unexecuted instantiation: ASTStructuralEquivalence.cpp:(anonymous namespace)::StmtComparer::TraverseStmt(clang::TypoExpr const*, clang::TypoExpr const*)
ASTStructuralEquivalence.cpp:(anonymous namespace)::StmtComparer::TraverseStmt(clang::UnaryExprOrTypeTraitExpr const*, clang::UnaryExprOrTypeTraitExpr const*)
Line
Count
Source
346
1.96k
  bool TraverseStmt(const CLASS *S1, const CLASS *S2) {                        \
347
1.96k
    if (!TraverseStmt(static_cast<const PARENT *>(S1),                         \
348
1.96k
                      static_cast<const PARENT *>(S2)))                        \
349
1.96k
      
return false0
; \
350
1.96k
    return IsStmtEquivalent(S1, S2);                                           \
351
1.96k
  }
ASTStructuralEquivalence.cpp:(anonymous namespace)::StmtComparer::TraverseStmt(clang::UnaryOperator const*, clang::UnaryOperator const*)
Line
Count
Source
346
53.1k
  bool TraverseStmt(const CLASS *S1, const CLASS *S2) {                        \
347
53.1k
    if (!TraverseStmt(static_cast<const PARENT *>(S1),                         \
348
53.1k
                      static_cast<const PARENT *>(S2)))                        \
349
53.1k
      
return false0
; \
350
53.1k
    return IsStmtEquivalent(S1, S2);                                           \
351
53.1k
  }
Unexecuted instantiation: ASTStructuralEquivalence.cpp:(anonymous namespace)::StmtComparer::TraverseStmt(clang::VAArgExpr const*, clang::VAArgExpr const*)
Unexecuted instantiation: ASTStructuralEquivalence.cpp:(anonymous namespace)::StmtComparer::TraverseStmt(clang::LabelStmt const*, clang::LabelStmt const*)
Unexecuted instantiation: ASTStructuralEquivalence.cpp:(anonymous namespace)::StmtComparer::TraverseStmt(clang::WhileStmt const*, clang::WhileStmt const*)
352
#include "clang/AST/StmtNodes.inc"
353
354
public:
355
736k
  StmtComparer(StructuralEquivalenceContext &C) : Context(C) {}
356
357
  /// Determine whether two statements are equivalent. The statements have to
358
  /// be of the same kind. The children of the statements and their properties
359
  /// are not compared by this function.
360
736k
  bool IsEquivalent(const Stmt *S1, const Stmt *S2) {
361
736k
    if (S1->getStmtClass() != S2->getStmtClass())
362
6.45k
      return false;
363
364
    // Each TraverseStmt walks the class hierarchy from the leaf class to
365
    // the root class 'Stmt' (e.g. 'BinaryOperator' -> 'Expr' -> 'Stmt'). Cast
366
    // the Stmt we have here to its specific subclass so that we call the
367
    // overload that walks the whole class hierarchy from leaf to root (e.g.,
368
    // cast to 'BinaryOperator' so that 'Expr' and 'Stmt' is traversed).
369
730k
    switch (S1->getStmtClass()) {
370
0
    case Stmt::NoStmtClass:
371
0
      llvm_unreachable("Can't traverse NoStmtClass");
372
0
#define STMT(CLASS, PARENT)                                                    \
373
730k
  case Stmt::StmtClass::CLASS##Class:                                          \
374
730k
    return TraverseStmt(static_cast<const CLASS *>(S1),                        \
375
730k
                        static_cast<const CLASS *>(S2));
376
0
#define ABSTRACT_STMT(S)
377
730k
#include 
"clang/AST/StmtNodes.inc"0
378
730k
    }
379
0
    llvm_unreachable("Invalid statement kind");
380
0
  }
381
};
382
} // namespace
383
384
/// Determine structural equivalence of two statements.
385
static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
386
736k
                                     const Stmt *S1, const Stmt *S2) {
387
736k
  if (!S1 || 
!S2736k
)
388
16
    return S1 == S2;
389
390
  // Compare the statements itself.
391
736k
  StmtComparer Comparer(Context);
392
736k
  if (!Comparer.IsEquivalent(S1, S2))
393
10.1k
    return false;
394
395
  // Iterate over the children of both statements and also compare them.
396
726k
  for (auto Pair : zip_longest(S1->children(), S2->children())) {
397
349k
    Optional<const Stmt *> Child1 = std::get<0>(Pair);
398
349k
    Optional<const Stmt *> Child2 = std::get<1>(Pair);
399
    // One of the statements has a different amount of children than the other,
400
    // so the statements can't be equivalent.
401
349k
    if (!Child1 || !Child2)
402
0
      return false;
403
349k
    if (!IsStructurallyEquivalent(Context, *Child1, *Child2))
404
12.9k
      return false;
405
349k
  }
406
713k
  return true;
407
726k
}
408
409
/// Determine whether two identifiers are equivalent.
410
static bool IsStructurallyEquivalent(const IdentifierInfo *Name1,
411
6.02M
                                     const IdentifierInfo *Name2) {
412
6.02M
  if (!Name1 || 
!Name23.84M
)
413
2.17M
    return Name1 == Name2;
414
415
3.84M
  return Name1->getName() == Name2->getName();
416
6.02M
}
417
418
/// Determine whether two nested-name-specifiers are equivalent.
419
static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
420
                                     NestedNameSpecifier *NNS1,
421
556k
                                     NestedNameSpecifier *NNS2) {
422
556k
  if (NNS1->getKind() != NNS2->getKind())
423
108
    return false;
424
425
556k
  NestedNameSpecifier *Prefix1 = NNS1->getPrefix(),
426
556k
                      *Prefix2 = NNS2->getPrefix();
427
556k
  if ((bool)Prefix1 != (bool)Prefix2)
428
0
    return false;
429
430
556k
  if (Prefix1)
431
12.6k
    if (!IsStructurallyEquivalent(Context, Prefix1, Prefix2))
432
0
      return false;
433
434
556k
  switch (NNS1->getKind()) {
435
12.3k
  case NestedNameSpecifier::Identifier:
436
12.3k
    return IsStructurallyEquivalent(NNS1->getAsIdentifier(),
437
12.3k
                                    NNS2->getAsIdentifier());
438
333
  case NestedNameSpecifier::Namespace:
439
333
    return IsStructurallyEquivalent(Context, NNS1->getAsNamespace(),
440
333
                                    NNS2->getAsNamespace());
441
0
  case NestedNameSpecifier::NamespaceAlias:
442
0
    return IsStructurallyEquivalent(Context, NNS1->getAsNamespaceAlias(),
443
0
                                    NNS2->getAsNamespaceAlias());
444
543k
  case NestedNameSpecifier::TypeSpec:
445
543k
  case NestedNameSpecifier::TypeSpecWithTemplate:
446
543k
    return IsStructurallyEquivalent(Context, QualType(NNS1->getAsType(), 0),
447
543k
                                    QualType(NNS2->getAsType(), 0));
448
0
  case NestedNameSpecifier::Global:
449
0
    return true;
450
0
  case NestedNameSpecifier::Super:
451
0
    return IsStructurallyEquivalent(Context, NNS1->getAsRecordDecl(),
452
0
                                    NNS2->getAsRecordDecl());
453
556k
  }
454
0
  return false;
455
556k
}
456
457
static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
458
                                     const TemplateName &N1,
459
1.46M
                                     const TemplateName &N2) {
460
1.46M
  TemplateDecl *TemplateDeclN1 = N1.getAsTemplateDecl();
461
1.46M
  TemplateDecl *TemplateDeclN2 = N2.getAsTemplateDecl();
462
1.46M
  if (TemplateDeclN1 && TemplateDeclN2) {
463
1.46M
    if (!IsStructurallyEquivalent(Context, TemplateDeclN1, TemplateDeclN2))
464
88.2k
      return false;
465
    // If the kind is different we compare only the template decl.
466
1.37M
    if (N1.getKind() != N2.getKind())
467
8
      return true;
468
1.37M
  } else 
if (0
TemplateDeclN10
||
TemplateDeclN20
)
469
0
    return false;
470
0
  else if (N1.getKind() != N2.getKind())
471
0
    return false;
472
473
  // Check for special case incompatibilities.
474
1.37M
  switch (N1.getKind()) {
475
476
0
  case TemplateName::OverloadedTemplate: {
477
0
    OverloadedTemplateStorage *OS1 = N1.getAsOverloadedTemplate(),
478
0
                              *OS2 = N2.getAsOverloadedTemplate();
479
0
    OverloadedTemplateStorage::iterator I1 = OS1->begin(), I2 = OS2->begin(),
480
0
                                        E1 = OS1->end(), E2 = OS2->end();
481
0
    for (; I1 != E1 && I2 != E2; ++I1, ++I2)
482
0
      if (!IsStructurallyEquivalent(Context, *I1, *I2))
483
0
        return false;
484
0
    return I1 == E1 && I2 == E2;
485
0
  }
486
487
0
  case TemplateName::AssumedTemplate: {
488
0
    AssumedTemplateStorage *TN1 = N1.getAsAssumedTemplateName(),
489
0
                           *TN2 = N1.getAsAssumedTemplateName();
490
0
    return TN1->getDeclName() == TN2->getDeclName();
491
0
  }
492
493
0
  case TemplateName::DependentTemplate: {
494
0
    DependentTemplateName *DN1 = N1.getAsDependentTemplateName(),
495
0
                          *DN2 = N2.getAsDependentTemplateName();
496
0
    if (!IsStructurallyEquivalent(Context, DN1->getQualifier(),
497
0
                                  DN2->getQualifier()))
498
0
      return false;
499
0
    if (DN1->isIdentifier() && DN2->isIdentifier())
500
0
      return IsStructurallyEquivalent(DN1->getIdentifier(),
501
0
                                      DN2->getIdentifier());
502
0
    else if (DN1->isOverloadedOperator() && DN2->isOverloadedOperator())
503
0
      return DN1->getOperator() == DN2->getOperator();
504
0
    return false;
505
0
  }
506
507
0
  case TemplateName::SubstTemplateTemplateParmPack: {
508
0
    SubstTemplateTemplateParmPackStorage
509
0
        *P1 = N1.getAsSubstTemplateTemplateParmPack(),
510
0
        *P2 = N2.getAsSubstTemplateTemplateParmPack();
511
0
    return IsStructurallyEquivalent(Context, P1->getArgumentPack(),
512
0
                                    P2->getArgumentPack()) &&
513
0
           IsStructurallyEquivalent(Context, P1->getParameterPack(),
514
0
                                    P2->getParameterPack());
515
0
  }
516
517
1.37M
   case TemplateName::Template:
518
1.37M
   case TemplateName::QualifiedTemplate:
519
1.37M
   case TemplateName::SubstTemplateTemplateParm:
520
1.37M
   case TemplateName::UsingTemplate:
521
     // It is sufficient to check value of getAsTemplateDecl.
522
1.37M
     break;
523
524
1.37M
  }
525
526
1.37M
  return true;
527
1.37M
}
528
529
/// Determine whether two template arguments are equivalent.
530
static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
531
                                     const TemplateArgument &Arg1,
532
2.94M
                                     const TemplateArgument &Arg2) {
533
2.94M
  if (Arg1.getKind() != Arg2.getKind())
534
9.84k
    return false;
535
536
2.93M
  switch (Arg1.getKind()) {
537
0
  case TemplateArgument::Null:
538
0
    return true;
539
540
2.47M
  case TemplateArgument::Type:
541
2.47M
    return IsStructurallyEquivalent(Context, Arg1.getAsType(), Arg2.getAsType());
542
543
93.0k
  case TemplateArgument::Integral:
544
93.0k
    if (!IsStructurallyEquivalent(Context, Arg1.getIntegralType(),
545
93.0k
                                          Arg2.getIntegralType()))
546
0
      return false;
547
548
93.0k
    return llvm::APSInt::isSameValue(Arg1.getAsIntegral(),
549
93.0k
                                     Arg2.getAsIntegral());
550
551
0
  case TemplateArgument::Declaration:
552
0
    return IsStructurallyEquivalent(Context, Arg1.getAsDecl(), Arg2.getAsDecl());
553
554
0
  case TemplateArgument::NullPtr:
555
0
    return true; // FIXME: Is this correct?
556
557
10
  case TemplateArgument::Template:
558
10
    return IsStructurallyEquivalent(Context, Arg1.getAsTemplate(),
559
10
                                    Arg2.getAsTemplate());
560
561
0
  case TemplateArgument::TemplateExpansion:
562
0
    return IsStructurallyEquivalent(Context,
563
0
                                    Arg1.getAsTemplateOrTemplatePattern(),
564
0
                                    Arg2.getAsTemplateOrTemplatePattern());
565
566
356k
  case TemplateArgument::Expression:
567
356k
    return IsStructurallyEquivalent(Context, Arg1.getAsExpr(),
568
356k
                                    Arg2.getAsExpr());
569
570
14.7k
  case TemplateArgument::Pack:
571
14.7k
    if (Arg1.pack_size() != Arg2.pack_size())
572
63
      return false;
573
574
29.3k
    
for (unsigned I = 0, N = Arg1.pack_size(); 14.7k
I != N;
++I14.6k
)
575
15.7k
      if (!IsStructurallyEquivalent(Context, Arg1.pack_begin()[I],
576
15.7k
                                    Arg2.pack_begin()[I]))
577
1.07k
        return false;
578
579
13.6k
    return true;
580
2.93M
  }
581
582
0
  llvm_unreachable("Invalid template argument kind");
583
0
}
584
585
/// Determine structural equivalence for the common part of array
586
/// types.
587
static bool IsArrayStructurallyEquivalent(StructuralEquivalenceContext &Context,
588
                                          const ArrayType *Array1,
589
9.42k
                                          const ArrayType *Array2) {
590
9.42k
  if (!IsStructurallyEquivalent(Context, Array1->getElementType(),
591
9.42k
                                Array2->getElementType()))
592
0
    return false;
593
9.42k
  if (Array1->getSizeModifier() != Array2->getSizeModifier())
594
0
    return false;
595
9.42k
  if (Array1->getIndexTypeQualifiers() != Array2->getIndexTypeQualifiers())
596
0
    return false;
597
598
9.42k
  return true;
599
9.42k
}
600
601
/// Determine structural equivalence based on the ExtInfo of functions. This
602
/// is inspired by ASTContext::mergeFunctionTypes(), we compare calling
603
/// conventions bits but must not compare some other bits.
604
static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
605
                                     FunctionType::ExtInfo EI1,
606
348k
                                     FunctionType::ExtInfo EI2) {
607
  // Compatible functions must have compatible calling conventions.
608
348k
  if (EI1.getCC() != EI2.getCC())
609
38
    return false;
610
611
  // Regparm is part of the calling convention.
612
348k
  if (EI1.getHasRegParm() != EI2.getHasRegParm())
613
0
    return false;
614
348k
  if (EI1.getRegParm() != EI2.getRegParm())
615
0
    return false;
616
617
348k
  if (EI1.getProducesResult() != EI2.getProducesResult())
618
0
    return false;
619
348k
  if (EI1.getNoCallerSavedRegs() != EI2.getNoCallerSavedRegs())
620
2
    return false;
621
348k
  if (EI1.getNoCfCheck() != EI2.getNoCfCheck())
622
0
    return false;
623
624
348k
  return true;
625
348k
}
626
627
/// Check the equivalence of exception specifications.
628
static bool IsEquivalentExceptionSpec(StructuralEquivalenceContext &Context,
629
                                      const FunctionProtoType *Proto1,
630
407k
                                      const FunctionProtoType *Proto2) {
631
632
407k
  auto Spec1 = Proto1->getExceptionSpecType();
633
407k
  auto Spec2 = Proto2->getExceptionSpecType();
634
635
407k
  if (isUnresolvedExceptionSpec(Spec1) || 
isUnresolvedExceptionSpec(Spec2)401k
)
636
5.57k
    return true;
637
638
401k
  if (Spec1 != Spec2)
639
45.8k
    return false;
640
355k
  if (Spec1 == EST_Dynamic) {
641
0
    if (Proto1->getNumExceptions() != Proto2->getNumExceptions())
642
0
      return false;
643
0
    for (unsigned I = 0, N = Proto1->getNumExceptions(); I != N; ++I) {
644
0
      if (!IsStructurallyEquivalent(Context, Proto1->getExceptionType(I),
645
0
                                    Proto2->getExceptionType(I)))
646
0
        return false;
647
0
    }
648
355k
  } else if (isComputedNoexcept(Spec1)) {
649
13.8k
    if (!IsStructurallyEquivalent(Context, Proto1->getNoexceptExpr(),
650
13.8k
                                  Proto2->getNoexceptExpr()))
651
2.81k
      return false;
652
13.8k
  }
653
654
352k
  return true;
655
355k
}
656
657
/// Determine structural equivalence of two types.
658
static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
659
9.62M
                                     QualType T1, QualType T2) {
660
9.62M
  if (T1.isNull() || T2.isNull())
661
0
    return T1.isNull() && T2.isNull();
662
663
9.62M
  QualType OrigT1 = T1;
664
9.62M
  QualType OrigT2 = T2;
665
666
9.62M
  if (!Context.StrictTypeSpelling) {
667
    // We aren't being strict about token-to-token equivalence of types,
668
    // so map down to the canonical type.
669
9.62M
    T1 = Context.FromCtx.getCanonicalType(T1);
670
9.62M
    T2 = Context.ToCtx.getCanonicalType(T2);
671
9.62M
  }
672
673
9.62M
  if (T1.getQualifiers() != T2.getQualifiers())
674
9.40k
    return false;
675
676
9.61M
  Type::TypeClass TC = T1->getTypeClass();
677
678
9.61M
  if (T1->getTypeClass() != T2->getTypeClass()) {
679
    // Compare function types with prototypes vs. without prototypes as if
680
    // both did not have prototypes.
681
369k
    if (T1->getTypeClass() == Type::FunctionProto &&
682
369k
        
T2->getTypeClass() == Type::FunctionNoProto632
)
683
2
      TC = Type::FunctionNoProto;
684
369k
    else if (T1->getTypeClass() == Type::FunctionNoProto &&
685
369k
             
T2->getTypeClass() == Type::FunctionProto0
)
686
0
      TC = Type::FunctionNoProto;
687
369k
    else
688
369k
      return false;
689
369k
  }
690
691
9.24M
  switch (TC) {
692
1.57M
  case Type::Builtin:
693
    // FIXME: Deal with Char_S/Char_U.
694
1.57M
    if (cast<BuiltinType>(T1)->getKind() != cast<BuiltinType>(T2)->getKind())
695
28.8k
      return false;
696
1.54M
    break;
697
698
1.54M
  case Type::Complex:
699
0
    if (!IsStructurallyEquivalent(Context,
700
0
                                  cast<ComplexType>(T1)->getElementType(),
701
0
                                  cast<ComplexType>(T2)->getElementType()))
702
0
      return false;
703
0
    break;
704
705
0
  case Type::Adjusted:
706
0
  case Type::Decayed:
707
0
    if (!IsStructurallyEquivalent(Context,
708
0
                                  cast<AdjustedType>(T1)->getOriginalType(),
709
0
                                  cast<AdjustedType>(T2)->getOriginalType()))
710
0
      return false;
711
0
    break;
712
713
201k
  case Type::Pointer:
714
201k
    if (!IsStructurallyEquivalent(Context,
715
201k
                                  cast<PointerType>(T1)->getPointeeType(),
716
201k
                                  cast<PointerType>(T2)->getPointeeType()))
717
4.78k
      return false;
718
196k
    break;
719
720
196k
  case Type::BlockPointer:
721
0
    if (!IsStructurallyEquivalent(Context,
722
0
                                  cast<BlockPointerType>(T1)->getPointeeType(),
723
0
                                  cast<BlockPointerType>(T2)->getPointeeType()))
724
0
      return false;
725
0
    break;
726
727
858k
  case Type::LValueReference:
728
888k
  case Type::RValueReference: {
729
888k
    const auto *Ref1 = cast<ReferenceType>(T1);
730
888k
    const auto *Ref2 = cast<ReferenceType>(T2);
731
888k
    if (Ref1->isSpelledAsLValue() != Ref2->isSpelledAsLValue())
732
0
      return false;
733
888k
    if (Ref1->isInnerRef() != Ref2->isInnerRef())
734
0
      return false;
735
888k
    if (!IsStructurallyEquivalent(Context, Ref1->getPointeeTypeAsWritten(),
736
888k
                                  Ref2->getPointeeTypeAsWritten()))
737
312k
      return false;
738
575k
    break;
739
888k
  }
740
741
575k
  case Type::MemberPointer: {
742
0
    const auto *MemPtr1 = cast<MemberPointerType>(T1);
743
0
    const auto *MemPtr2 = cast<MemberPointerType>(T2);
744
0
    if (!IsStructurallyEquivalent(Context, MemPtr1->getPointeeType(),
745
0
                                  MemPtr2->getPointeeType()))
746
0
      return false;
747
0
    if (!IsStructurallyEquivalent(Context, QualType(MemPtr1->getClass(), 0),
748
0
                                  QualType(MemPtr2->getClass(), 0)))
749
0
      return false;
750
0
    break;
751
0
  }
752
753
3.43k
  case Type::ConstantArray: {
754
3.43k
    const auto *Array1 = cast<ConstantArrayType>(T1);
755
3.43k
    const auto *Array2 = cast<ConstantArrayType>(T2);
756
3.43k
    if (!llvm::APInt::isSameValue(Array1->getSize(), Array2->getSize()))
757
3
      return false;
758
759
3.43k
    if (!IsArrayStructurallyEquivalent(Context, Array1, Array2))
760
0
      return false;
761
3.43k
    break;
762
3.43k
  }
763
764
3.43k
  case Type::IncompleteArray:
765
567
    if (!IsArrayStructurallyEquivalent(Context, cast<ArrayType>(T1),
766
567
                                       cast<ArrayType>(T2)))
767
0
      return false;
768
567
    break;
769
770
567
  case Type::VariableArray: {
771
0
    const auto *Array1 = cast<VariableArrayType>(T1);
772
0
    const auto *Array2 = cast<VariableArrayType>(T2);
773
0
    if (!IsStructurallyEquivalent(Context, Array1->getSizeExpr(),
774
0
                                  Array2->getSizeExpr()))
775
0
      return false;
776
777
0
    if (!IsArrayStructurallyEquivalent(Context, Array1, Array2))
778
0
      return false;
779
780
0
    break;
781
0
  }
782
783
5.42k
  case Type::DependentSizedArray: {
784
5.42k
    const auto *Array1 = cast<DependentSizedArrayType>(T1);
785
5.42k
    const auto *Array2 = cast<DependentSizedArrayType>(T2);
786
5.42k
    if (!IsStructurallyEquivalent(Context, Array1->getSizeExpr(),
787
5.42k
                                  Array2->getSizeExpr()))
788
0
      return false;
789
790
5.42k
    if (!IsArrayStructurallyEquivalent(Context, Array1, Array2))
791
0
      return false;
792
793
5.42k
    break;
794
5.42k
  }
795
796
5.42k
  case Type::DependentAddressSpace: {
797
0
    const auto *DepAddressSpace1 = cast<DependentAddressSpaceType>(T1);
798
0
    const auto *DepAddressSpace2 = cast<DependentAddressSpaceType>(T2);
799
0
    if (!IsStructurallyEquivalent(Context, DepAddressSpace1->getAddrSpaceExpr(),
800
0
                                  DepAddressSpace2->getAddrSpaceExpr()))
801
0
      return false;
802
0
    if (!IsStructurallyEquivalent(Context, DepAddressSpace1->getPointeeType(),
803
0
                                  DepAddressSpace2->getPointeeType()))
804
0
      return false;
805
806
0
    break;
807
0
  }
808
809
0
  case Type::DependentSizedExtVector: {
810
0
    const auto *Vec1 = cast<DependentSizedExtVectorType>(T1);
811
0
    const auto *Vec2 = cast<DependentSizedExtVectorType>(T2);
812
0
    if (!IsStructurallyEquivalent(Context, Vec1->getSizeExpr(),
813
0
                                  Vec2->getSizeExpr()))
814
0
      return false;
815
0
    if (!IsStructurallyEquivalent(Context, Vec1->getElementType(),
816
0
                                  Vec2->getElementType()))
817
0
      return false;
818
0
    break;
819
0
  }
820
821
0
  case Type::DependentVector: {
822
0
    const auto *Vec1 = cast<DependentVectorType>(T1);
823
0
    const auto *Vec2 = cast<DependentVectorType>(T2);
824
0
    if (Vec1->getVectorKind() != Vec2->getVectorKind())
825
0
      return false;
826
0
    if (!IsStructurallyEquivalent(Context, Vec1->getSizeExpr(),
827
0
                                  Vec2->getSizeExpr()))
828
0
      return false;
829
0
    if (!IsStructurallyEquivalent(Context, Vec1->getElementType(),
830
0
                                  Vec2->getElementType()))
831
0
      return false;
832
0
    break;
833
0
  }
834
835
0
  case Type::Vector:
836
0
  case Type::ExtVector: {
837
0
    const auto *Vec1 = cast<VectorType>(T1);
838
0
    const auto *Vec2 = cast<VectorType>(T2);
839
0
    if (!IsStructurallyEquivalent(Context, Vec1->getElementType(),
840
0
                                  Vec2->getElementType()))
841
0
      return false;
842
0
    if (Vec1->getNumElements() != Vec2->getNumElements())
843
0
      return false;
844
0
    if (Vec1->getVectorKind() != Vec2->getVectorKind())
845
0
      return false;
846
0
    break;
847
0
  }
848
849
0
  case Type::DependentSizedMatrix: {
850
0
    const DependentSizedMatrixType *Mat1 = cast<DependentSizedMatrixType>(T1);
851
0
    const DependentSizedMatrixType *Mat2 = cast<DependentSizedMatrixType>(T2);
852
    // The element types, row and column expressions must be structurally
853
    // equivalent.
854
0
    if (!IsStructurallyEquivalent(Context, Mat1->getRowExpr(),
855
0
                                  Mat2->getRowExpr()) ||
856
0
        !IsStructurallyEquivalent(Context, Mat1->getColumnExpr(),
857
0
                                  Mat2->getColumnExpr()) ||
858
0
        !IsStructurallyEquivalent(Context, Mat1->getElementType(),
859
0
                                  Mat2->getElementType()))
860
0
      return false;
861
0
    break;
862
0
  }
863
864
0
  case Type::ConstantMatrix: {
865
0
    const ConstantMatrixType *Mat1 = cast<ConstantMatrixType>(T1);
866
0
    const ConstantMatrixType *Mat2 = cast<ConstantMatrixType>(T2);
867
    // The element types must be structurally equivalent and the number of rows
868
    // and columns must match.
869
0
    if (!IsStructurallyEquivalent(Context, Mat1->getElementType(),
870
0
                                  Mat2->getElementType()) ||
871
0
        Mat1->getNumRows() != Mat2->getNumRows() ||
872
0
        Mat1->getNumColumns() != Mat2->getNumColumns())
873
0
      return false;
874
0
    break;
875
0
  }
876
877
1.34M
  case Type::FunctionProto: {
878
1.34M
    const auto *Proto1 = cast<FunctionProtoType>(T1);
879
1.34M
    const auto *Proto2 = cast<FunctionProtoType>(T2);
880
881
1.34M
    if (Proto1->getNumParams() != Proto2->getNumParams())
882
274k
      return false;
883
1.98M
    
for (unsigned I = 0, N = Proto1->getNumParams(); 1.06M
I != N;
++I913k
) {
884
1.57M
      if (!IsStructurallyEquivalent(Context, Proto1->getParamType(I),
885
1.57M
                                    Proto2->getParamType(I)))
886
661k
        return false;
887
1.57M
    }
888
408k
    if (Proto1->isVariadic() != Proto2->isVariadic())
889
2
      return false;
890
891
408k
    if (Proto1->getMethodQuals() != Proto2->getMethodQuals())
892
819
      return false;
893
894
    // Check exceptions, this information is lost in canonical type.
895
407k
    const auto *OrigProto1 =
896
407k
        cast<FunctionProtoType>(OrigT1.getDesugaredType(Context.FromCtx));
897
407k
    const auto *OrigProto2 =
898
407k
        cast<FunctionProtoType>(OrigT2.getDesugaredType(Context.ToCtx));
899
407k
    if (!IsEquivalentExceptionSpec(Context, OrigProto1, OrigProto2))
900
48.6k
      return false;
901
902
    // Fall through to check the bits common with FunctionNoProtoType.
903
407k
    
LLVM_FALLTHROUGH358k
;
904
358k
  }
905
906
358k
  case Type::FunctionNoProto: {
907
358k
    const auto *Function1 = cast<FunctionType>(T1);
908
358k
    const auto *Function2 = cast<FunctionType>(T2);
909
358k
    if (!IsStructurallyEquivalent(Context, Function1->getReturnType(),
910
358k
                                  Function2->getReturnType()))
911
10.3k
      return false;
912
348k
    if (!IsStructurallyEquivalent(Context, Function1->getExtInfo(),
913
348k
                                  Function2->getExtInfo()))
914
40
      return false;
915
348k
    break;
916
348k
  }
917
918
348k
  case Type::UnresolvedUsing:
919
0
    if (!IsStructurallyEquivalent(Context,
920
0
                                  cast<UnresolvedUsingType>(T1)->getDecl(),
921
0
                                  cast<UnresolvedUsingType>(T2)->getDecl()))
922
0
      return false;
923
0
    break;
924
925
0
  case Type::Attributed:
926
0
    if (!IsStructurallyEquivalent(Context,
927
0
                                  cast<AttributedType>(T1)->getModifiedType(),
928
0
                                  cast<AttributedType>(T2)->getModifiedType()))
929
0
      return false;
930
0
    if (!IsStructurallyEquivalent(
931
0
            Context, cast<AttributedType>(T1)->getEquivalentType(),
932
0
            cast<AttributedType>(T2)->getEquivalentType()))
933
0
      return false;
934
0
    break;
935
936
0
  case Type::BTFTagAttributed:
937
0
    if (!IsStructurallyEquivalent(
938
0
            Context, cast<BTFTagAttributedType>(T1)->getWrappedType(),
939
0
            cast<BTFTagAttributedType>(T2)->getWrappedType()))
940
0
      return false;
941
0
    break;
942
943
0
  case Type::Paren:
944
0
    if (!IsStructurallyEquivalent(Context, cast<ParenType>(T1)->getInnerType(),
945
0
                                  cast<ParenType>(T2)->getInnerType()))
946
0
      return false;
947
0
    break;
948
949
0
  case Type::MacroQualified:
950
0
    if (!IsStructurallyEquivalent(
951
0
            Context, cast<MacroQualifiedType>(T1)->getUnderlyingType(),
952
0
            cast<MacroQualifiedType>(T2)->getUnderlyingType()))
953
0
      return false;
954
0
    break;
955
956
0
  case Type::Using:
957
0
    if (!IsStructurallyEquivalent(Context, cast<UsingType>(T1)->getFoundDecl(),
958
0
                                  cast<UsingType>(T2)->getFoundDecl()))
959
0
      return false;
960
0
    break;
961
962
0
  case Type::Typedef:
963
0
    if (!IsStructurallyEquivalent(Context, cast<TypedefType>(T1)->getDecl(),
964
0
                                  cast<TypedefType>(T2)->getDecl()))
965
0
      return false;
966
0
    break;
967
968
0
  case Type::TypeOfExpr:
969
0
    if (!IsStructurallyEquivalent(
970
0
            Context, cast<TypeOfExprType>(T1)->getUnderlyingExpr(),
971
0
            cast<TypeOfExprType>(T2)->getUnderlyingExpr()))
972
0
      return false;
973
0
    break;
974
975
0
  case Type::TypeOf:
976
0
    if (!IsStructurallyEquivalent(Context,
977
0
                                  cast<TypeOfType>(T1)->getUnderlyingType(),
978
0
                                  cast<TypeOfType>(T2)->getUnderlyingType()))
979
0
      return false;
980
0
    break;
981
982
0
  case Type::UnaryTransform:
983
0
    if (!IsStructurallyEquivalent(
984
0
            Context, cast<UnaryTransformType>(T1)->getUnderlyingType(),
985
0
            cast<UnaryTransformType>(T2)->getUnderlyingType()))
986
0
      return false;
987
0
    break;
988
989
1.29k
  case Type::Decltype:
990
1.29k
    if (!IsStructurallyEquivalent(Context,
991
1.29k
                                  cast<DecltypeType>(T1)->getUnderlyingExpr(),
992
1.29k
                                  cast<DecltypeType>(T2)->getUnderlyingExpr()))
993
21
      return false;
994
1.27k
    break;
995
996
1.27k
  case Type::Auto: {
997
0
    auto *Auto1 = cast<AutoType>(T1);
998
0
    auto *Auto2 = cast<AutoType>(T2);
999
0
    if (!IsStructurallyEquivalent(Context, Auto1->getDeducedType(),
1000
0
                                  Auto2->getDeducedType()))
1001
0
      return false;
1002
0
    if (Auto1->isConstrained() != Auto2->isConstrained())
1003
0
      return false;
1004
0
    if (Auto1->isConstrained()) {
1005
0
      if (Auto1->getTypeConstraintConcept() !=
1006
0
          Auto2->getTypeConstraintConcept())
1007
0
        return false;
1008
0
      ArrayRef<TemplateArgument> Auto1Args =
1009
0
          Auto1->getTypeConstraintArguments();
1010
0
      ArrayRef<TemplateArgument> Auto2Args =
1011
0
          Auto2->getTypeConstraintArguments();
1012
0
      if (Auto1Args.size() != Auto2Args.size())
1013
0
        return false;
1014
0
      for (unsigned I = 0, N = Auto1Args.size(); I != N; ++I) {
1015
0
        if (!IsStructurallyEquivalent(Context, Auto1Args[I], Auto2Args[I]))
1016
0
          return false;
1017
0
      }
1018
0
    }
1019
0
    break;
1020
0
  }
1021
1022
0
  case Type::DeducedTemplateSpecialization: {
1023
0
    const auto *DT1 = cast<DeducedTemplateSpecializationType>(T1);
1024
0
    const auto *DT2 = cast<DeducedTemplateSpecializationType>(T2);
1025
0
    if (!IsStructurallyEquivalent(Context, DT1->getTemplateName(),
1026
0
                                  DT2->getTemplateName()))
1027
0
      return false;
1028
0
    if (!IsStructurallyEquivalent(Context, DT1->getDeducedType(),
1029
0
                                  DT2->getDeducedType()))
1030
0
      return false;
1031
0
    break;
1032
0
  }
1033
1034
312k
  case Type::Record:
1035
324k
  case Type::Enum:
1036
324k
    if (!IsStructurallyEquivalent(Context, cast<TagType>(T1)->getDecl(),
1037
324k
                                  cast<TagType>(T2)->getDecl()))
1038
28.6k
      return false;
1039
296k
    break;
1040
1041
2.88M
  case Type::TemplateTypeParm: {
1042
2.88M
    const auto *Parm1 = cast<TemplateTypeParmType>(T1);
1043
2.88M
    const auto *Parm2 = cast<TemplateTypeParmType>(T2);
1044
2.88M
    if (Parm1->getDepth() != Parm2->getDepth())
1045
27.5k
      return false;
1046
2.85M
    if (Parm1->getIndex() != Parm2->getIndex())
1047
3.74k
      return false;
1048
2.84M
    if (Parm1->isParameterPack() != Parm2->isParameterPack())
1049
0
      return false;
1050
1051
    // Names of template type parameters are never significant.
1052
2.84M
    break;
1053
2.84M
  }
1054
1055
2.84M
  case Type::SubstTemplateTypeParm: {
1056
0
    const auto *Subst1 = cast<SubstTemplateTypeParmType>(T1);
1057
0
    const auto *Subst2 = cast<SubstTemplateTypeParmType>(T2);
1058
0
    if (!IsStructurallyEquivalent(Context,
1059
0
                                  QualType(Subst1->getReplacedParameter(), 0),
1060
0
                                  QualType(Subst2->getReplacedParameter(), 0)))
1061
0
      return false;
1062
0
    if (!IsStructurallyEquivalent(Context, Subst1->getReplacementType(),
1063
0
                                  Subst2->getReplacementType()))
1064
0
      return false;
1065
0
    break;
1066
0
  }
1067
1068
0
  case Type::SubstTemplateTypeParmPack: {
1069
0
    const auto *Subst1 = cast<SubstTemplateTypeParmPackType>(T1);
1070
0
    const auto *Subst2 = cast<SubstTemplateTypeParmPackType>(T2);
1071
0
    if (!IsStructurallyEquivalent(Context,
1072
0
                                  QualType(Subst1->getReplacedParameter(), 0),
1073
0
                                  QualType(Subst2->getReplacedParameter(), 0)))
1074
0
      return false;
1075
0
    if (!IsStructurallyEquivalent(Context, Subst1->getArgumentPack(),
1076
0
                                  Subst2->getArgumentPack()))
1077
0
      return false;
1078
0
    break;
1079
0
  }
1080
1081
1.46M
  case Type::TemplateSpecialization: {
1082
1.46M
    const auto *Spec1 = cast<TemplateSpecializationType>(T1);
1083
1.46M
    const auto *Spec2 = cast<TemplateSpecializationType>(T2);
1084
1.46M
    if (!IsStructurallyEquivalent(Context, Spec1->getTemplateName(),
1085
1.46M
                                  Spec2->getTemplateName()))
1086
88.2k
      return false;
1087
1.37M
    if (Spec1->getNumArgs() != Spec2->getNumArgs())
1088
103k
      return false;
1089
3.98M
    
for (unsigned I = 0, N = Spec1->getNumArgs(); 1.27M
I != N;
++I2.71M
) {
1090
2.76M
      if (!IsStructurallyEquivalent(Context, Spec1->getArg(I),
1091
2.76M
                                    Spec2->getArg(I)))
1092
53.7k
        return false;
1093
2.76M
    }
1094
1.22M
    break;
1095
1.27M
  }
1096
1097
1.22M
  case Type::Elaborated: {
1098
0
    const auto *Elab1 = cast<ElaboratedType>(T1);
1099
0
    const auto *Elab2 = cast<ElaboratedType>(T2);
1100
    // CHECKME: what if a keyword is ETK_None or ETK_typename ?
1101
0
    if (Elab1->getKeyword() != Elab2->getKeyword())
1102
0
      return false;
1103
0
    if (!IsStructurallyEquivalent(Context, Elab1->getQualifier(),
1104
0
                                  Elab2->getQualifier()))
1105
0
      return false;
1106
0
    if (!IsStructurallyEquivalent(Context, Elab1->getNamedType(),
1107
0
                                  Elab2->getNamedType()))
1108
0
      return false;
1109
0
    break;
1110
0
  }
1111
1112
125k
  case Type::InjectedClassName: {
1113
125k
    const auto *Inj1 = cast<InjectedClassNameType>(T1);
1114
125k
    const auto *Inj2 = cast<InjectedClassNameType>(T2);
1115
125k
    if (!IsStructurallyEquivalent(Context,
1116
125k
                                  Inj1->getInjectedSpecializationType(),
1117
125k
                                  Inj2->getInjectedSpecializationType()))
1118
9.90k
      return false;
1119
115k
    break;
1120
125k
  }
1121
1122
406k
  case Type::DependentName: {
1123
406k
    const auto *Typename1 = cast<DependentNameType>(T1);
1124
406k
    const auto *Typename2 = cast<DependentNameType>(T2);
1125
406k
    if (!IsStructurallyEquivalent(Context, Typename1->getQualifier(),
1126
406k
                                  Typename2->getQualifier()))
1127
8.74k
      return false;
1128
397k
    if (!IsStructurallyEquivalent(Typename1->getIdentifier(),
1129
397k
                                  Typename2->getIdentifier()))
1130
1.95k
      return false;
1131
1132
395k
    break;
1133
397k
  }
1134
1135
395k
  case Type::DependentTemplateSpecialization: {
1136
504
    const auto *Spec1 = cast<DependentTemplateSpecializationType>(T1);
1137
504
    const auto *Spec2 = cast<DependentTemplateSpecializationType>(T2);
1138
504
    if (!IsStructurallyEquivalent(Context, Spec1->getQualifier(),
1139
504
                                  Spec2->getQualifier()))
1140
0
      return false;
1141
504
    if (!IsStructurallyEquivalent(Spec1->getIdentifier(),
1142
504
                                  Spec2->getIdentifier()))
1143
0
      return false;
1144
504
    if (Spec1->getNumArgs() != Spec2->getNumArgs())
1145
0
      return false;
1146
1.00k
    
for (unsigned I = 0, N = Spec1->getNumArgs(); 504
I != N;
++I504
) {
1147
504
      if (!IsStructurallyEquivalent(Context, Spec1->getArg(I),
1148
504
                                    Spec2->getArg(I)))
1149
0
        return false;
1150
504
    }
1151
504
    break;
1152
504
  }
1153
1154
14.3k
  case Type::PackExpansion:
1155
14.3k
    if (!IsStructurallyEquivalent(Context,
1156
14.3k
                                  cast<PackExpansionType>(T1)->getPattern(),
1157
14.3k
                                  cast<PackExpansionType>(T2)->getPattern()))
1158
432
      return false;
1159
13.8k
    break;
1160
1161
13.8k
  case Type::ObjCInterface: {
1162
56
    const auto *Iface1 = cast<ObjCInterfaceType>(T1);
1163
56
    const auto *Iface2 = cast<ObjCInterfaceType>(T2);
1164
56
    if (!IsStructurallyEquivalent(Context, Iface1->getDecl(),
1165
56
                                  Iface2->getDecl()))
1166
0
      return false;
1167
56
    break;
1168
56
  }
1169
1170
56
  case Type::ObjCTypeParam: {
1171
0
    const auto *Obj1 = cast<ObjCTypeParamType>(T1);
1172
0
    const auto *Obj2 = cast<ObjCTypeParamType>(T2);
1173
0
    if (!IsStructurallyEquivalent(Context, Obj1->getDecl(), Obj2->getDecl()))
1174
0
      return false;
1175
1176
0
    if (Obj1->getNumProtocols() != Obj2->getNumProtocols())
1177
0
      return false;
1178
0
    for (unsigned I = 0, N = Obj1->getNumProtocols(); I != N; ++I) {
1179
0
      if (!IsStructurallyEquivalent(Context, Obj1->getProtocol(I),
1180
0
                                    Obj2->getProtocol(I)))
1181
0
        return false;
1182
0
    }
1183
0
    break;
1184
0
  }
1185
1186
949
  case Type::ObjCObject: {
1187
949
    const auto *Obj1 = cast<ObjCObjectType>(T1);
1188
949
    const auto *Obj2 = cast<ObjCObjectType>(T2);
1189
949
    if (!IsStructurallyEquivalent(Context, Obj1->getBaseType(),
1190
949
                                  Obj2->getBaseType()))
1191
0
      return false;
1192
949
    if (Obj1->getNumProtocols() != Obj2->getNumProtocols())
1193
0
      return false;
1194
949
    for (unsigned I = 0, N = Obj1->getNumProtocols(); I != N; 
++I0
) {
1195
0
      if (!IsStructurallyEquivalent(Context, Obj1->getProtocol(I),
1196
0
                                    Obj2->getProtocol(I)))
1197
0
        return false;
1198
0
    }
1199
949
    break;
1200
949
  }
1201
1202
1.00k
  case Type::ObjCObjectPointer: {
1203
1.00k
    const auto *Ptr1 = cast<ObjCObjectPointerType>(T1);
1204
1.00k
    const auto *Ptr2 = cast<ObjCObjectPointerType>(T2);
1205
1.00k
    if (!IsStructurallyEquivalent(Context, Ptr1->getPointeeType(),
1206
1.00k
                                  Ptr2->getPointeeType()))
1207
0
      return false;
1208
1.00k
    break;
1209
1.00k
  }
1210
1211
1.00k
  case Type::Atomic:
1212
0
    if (!IsStructurallyEquivalent(Context, cast<AtomicType>(T1)->getValueType(),
1213
0
                                  cast<AtomicType>(T2)->getValueType()))
1214
0
      return false;
1215
0
    break;
1216
1217
0
  case Type::Pipe:
1218
0
    if (!IsStructurallyEquivalent(Context, cast<PipeType>(T1)->getElementType(),
1219
0
                                  cast<PipeType>(T2)->getElementType()))
1220
0
      return false;
1221
0
    break;
1222
0
  case Type::BitInt: {
1223
0
    const auto *Int1 = cast<BitIntType>(T1);
1224
0
    const auto *Int2 = cast<BitIntType>(T2);
1225
1226
0
    if (Int1->isUnsigned() != Int2->isUnsigned() ||
1227
0
        Int1->getNumBits() != Int2->getNumBits())
1228
0
      return false;
1229
0
    break;
1230
0
  }
1231
0
  case Type::DependentBitInt: {
1232
0
    const auto *Int1 = cast<DependentBitIntType>(T1);
1233
0
    const auto *Int2 = cast<DependentBitIntType>(T2);
1234
1235
0
    if (Int1->isUnsigned() != Int2->isUnsigned() ||
1236
0
        !IsStructurallyEquivalent(Context, Int1->getNumBitsExpr(),
1237
0
                                  Int2->getNumBitsExpr()))
1238
0
      return false;
1239
0
    break;
1240
0
  }
1241
9.24M
  } // end switch
1242
1243
7.57M
  return true;
1244
9.24M
}
1245
1246
static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
1247
                                     FieldDecl *Field1, FieldDecl *Field2,
1248
299k
                                     QualType Owner2Type) {
1249
299k
  const auto *Owner2 = cast<Decl>(Field2->getDeclContext());
1250
1251
  // For anonymous structs/unions, match up the anonymous struct/union type
1252
  // declarations directly, so that we don't go off searching for anonymous
1253
  // types
1254
299k
  if (Field1->isAnonymousStructOrUnion() &&
1255
299k
      
Field2->isAnonymousStructOrUnion()7.25k
) {
1256
7.25k
    RecordDecl *D1 = Field1->getType()->castAs<RecordType>()->getDecl();
1257
7.25k
    RecordDecl *D2 = Field2->getType()->castAs<RecordType>()->getDecl();
1258
7.25k
    return IsStructurallyEquivalent(Context, D1, D2);
1259
7.25k
  }
1260
1261
  // Check for equivalent field names.
1262
292k
  IdentifierInfo *Name1 = Field1->getIdentifier();
1263
292k
  IdentifierInfo *Name2 = Field2->getIdentifier();
1264
292k
  if (!::IsStructurallyEquivalent(Name1, Name2)) {
1265
148
    if (Context.Complain) {
1266
122
      Context.Diag2(
1267
122
          Owner2->getLocation(),
1268
122
          Context.getApplicableDiagnostic(diag::err_odr_tag_type_inconsistent))
1269
122
          << Owner2Type;
1270
122
      Context.Diag2(Field2->getLocation(), diag::note_odr_field_name)
1271
122
          << Field2->getDeclName();
1272
122
      Context.Diag1(Field1->getLocation(), diag::note_odr_field_name)
1273
122
          << Field1->getDeclName();
1274
122
    }
1275
148
    return false;
1276
148
  }
1277
1278
291k
  if (!IsStructurallyEquivalent(Context, Field1->getType(),
1279
291k
                                Field2->getType())) {
1280
817
    if (Context.Complain) {
1281
805
      Context.Diag2(
1282
805
          Owner2->getLocation(),
1283
805
          Context.getApplicableDiagnostic(diag::err_odr_tag_type_inconsistent))
1284
805
          << Owner2Type;
1285
805
      Context.Diag2(Field2->getLocation(), diag::note_odr_field)
1286
805
          << Field2->getDeclName() << Field2->getType();
1287
805
      Context.Diag1(Field1->getLocation(), diag::note_odr_field)
1288
805
          << Field1->getDeclName() << Field1->getType();
1289
805
    }
1290
817
    return false;
1291
817
  }
1292
1293
291k
  if (Field1->isBitField())
1294
9.67k
    return IsStructurallyEquivalent(Context, Field1->getBitWidth(),
1295
9.67k
                                    Field2->getBitWidth());
1296
1297
281k
  return true;
1298
291k
}
1299
1300
/// Determine structural equivalence of two fields.
1301
static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
1302
4
                                     FieldDecl *Field1, FieldDecl *Field2) {
1303
4
  const auto *Owner2 = cast<RecordDecl>(Field2->getDeclContext());
1304
4
  return IsStructurallyEquivalent(Context, Field1, Field2,
1305
4
                                  Context.ToCtx.getTypeDeclType(Owner2));
1306
4
}
1307
1308
/// Determine structural equivalence of two methods.
1309
static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
1310
                                     CXXMethodDecl *Method1,
1311
748k
                                     CXXMethodDecl *Method2) {
1312
748k
  bool PropertiesEqual =
1313
748k
      Method1->getDeclKind() == Method2->getDeclKind() &&
1314
748k
      Method1->getRefQualifier() == Method2->getRefQualifier() &&
1315
748k
      
Method1->getAccess() == Method2->getAccess()748k
&&
1316
748k
      
Method1->getOverloadedOperator() == Method2->getOverloadedOperator()710k
&&
1317
748k
      
Method1->isStatic() == Method2->isStatic()710k
&&
1318
748k
      
Method1->isConst() == Method2->isConst()710k
&&
1319
748k
      
Method1->isVolatile() == Method2->isVolatile()632k
&&
1320
748k
      
Method1->isVirtual() == Method2->isVirtual()630k
&&
1321
748k
      
Method1->isPure() == Method2->isPure()630k
&&
1322
748k
      
Method1->isDefaulted() == Method2->isDefaulted()630k
&&
1323
748k
      
Method1->isDeleted() == Method2->isDeleted()613k
;
1324
748k
  if (!PropertiesEqual)
1325
136k
    return false;
1326
  // FIXME: Check for 'final'.
1327
1328
611k
  if (auto *Constructor1 = dyn_cast<CXXConstructorDecl>(Method1)) {
1329
275k
    auto *Constructor2 = cast<CXXConstructorDecl>(Method2);
1330
275k
    if (!Constructor1->getExplicitSpecifier().isEquivalent(
1331
275k
            Constructor2->getExplicitSpecifier()))
1332
76.2k
      return false;
1333
275k
  }
1334
1335
535k
  if (auto *Conversion1 = dyn_cast<CXXConversionDecl>(Method1)) {
1336
468
    auto *Conversion2 = cast<CXXConversionDecl>(Method2);
1337
468
    if (!Conversion1->getExplicitSpecifier().isEquivalent(
1338
468
            Conversion2->getExplicitSpecifier()))
1339
0
      return false;
1340
468
    if (!IsStructurallyEquivalent(Context, Conversion1->getConversionType(),
1341
468
                                  Conversion2->getConversionType()))
1342
65
      return false;
1343
468
  }
1344
1345
535k
  const IdentifierInfo *Name1 = Method1->getIdentifier();
1346
535k
  const IdentifierInfo *Name2 = Method2->getIdentifier();
1347
535k
  if (!::IsStructurallyEquivalent(Name1, Name2)) {
1348
0
    return false;
1349
    // TODO: Names do not match, add warning like at check for FieldDecl.
1350
0
  }
1351
1352
  // Check the prototypes.
1353
535k
  if (!::IsStructurallyEquivalent(Context,
1354
535k
                                  Method1->getType(), Method2->getType()))
1355
441k
    return false;
1356
1357
93.6k
  return true;
1358
535k
}
1359
1360
/// Determine structural equivalence of two lambda classes.
1361
static bool
1362
IsStructurallyEquivalentLambdas(StructuralEquivalenceContext &Context,
1363
8
                                CXXRecordDecl *D1, CXXRecordDecl *D2) {
1364
8
  assert(D1->isLambda() && D2->isLambda() &&
1365
8
         "Must be called on lambda classes");
1366
8
  if (!IsStructurallyEquivalent(Context, D1->getLambdaCallOperator(),
1367
8
                                D2->getLambdaCallOperator()))
1368
2
    return false;
1369
1370
6
  return true;
1371
8
}
1372
1373
/// Determine if context of a class is equivalent.
1374
static bool IsRecordContextStructurallyEquivalent(RecordDecl *D1,
1375
762k
                                                  RecordDecl *D2) {
1376
  // The context should be completely equal, including anonymous and inline
1377
  // namespaces.
1378
  // We compare objects as part of full translation units, not subtrees of
1379
  // translation units.
1380
762k
  DeclContext *DC1 = D1->getDeclContext()->getNonTransparentContext();
1381
762k
  DeclContext *DC2 = D2->getDeclContext()->getNonTransparentContext();
1382
2.28M
  while (true) {
1383
    // Special case: We allow a struct defined in a function to be equivalent
1384
    // with a similar struct defined outside of a function.
1385
2.28M
    if ((DC1->isFunctionOrMethod() && 
DC2->isTranslationUnit()11
) ||
1386
2.28M
        
(2.28M
DC2->isFunctionOrMethod()2.28M
&&
DC1->isTranslationUnit()10
))
1387
5
      return true;
1388
1389
2.28M
    if (DC1->getDeclKind() != DC2->getDeclKind())
1390
12
      return false;
1391
2.28M
    if (DC1->isTranslationUnit())
1392
762k
      break;
1393
1.52M
    if (DC1->isInlineNamespace() != DC2->isInlineNamespace())
1394
2
      return false;
1395
1.52M
    if (const auto *ND1 = dyn_cast<NamedDecl>(DC1)) {
1396
1.52M
      const auto *ND2 = cast<NamedDecl>(DC2);
1397
1.52M
      if (!DC1->isInlineNamespace() &&
1398
1.52M
          
!IsStructurallyEquivalent(ND1->getIdentifier(), ND2->getIdentifier())783k
)
1399
6
        return false;
1400
1.52M
    }
1401
1402
1.52M
    DC1 = DC1->getParent()->getNonTransparentContext();
1403
1.52M
    DC2 = DC2->getParent()->getNonTransparentContext();
1404
1.52M
  }
1405
1406
762k
  return true;
1407
762k
}
1408
1409
/// Determine structural equivalence of two records.
1410
static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
1411
767k
                                     RecordDecl *D1, RecordDecl *D2) {
1412
1413
  // Check for equivalent structure names.
1414
767k
  IdentifierInfo *Name1 = D1->getIdentifier();
1415
767k
  if (!Name1 && 
D1->getTypedefNameForAnonDecl()7.39k
)
1416
9
    Name1 = D1->getTypedefNameForAnonDecl()->getIdentifier();
1417
767k
  IdentifierInfo *Name2 = D2->getIdentifier();
1418
767k
  if (!Name2 && 
D2->getTypedefNameForAnonDecl()7.39k
)
1419
11
    Name2 = D2->getTypedefNameForAnonDecl()->getIdentifier();
1420
767k
  if (!IsStructurallyEquivalent(Name1, Name2))
1421
5.51k
    return false;
1422
1423
762k
  if (D1->isUnion() != D2->isUnion()) {
1424
3
    if (Context.Complain) {
1425
1
      Context.Diag2(D2->getLocation(), Context.getApplicableDiagnostic(
1426
1
                                           diag::err_odr_tag_type_inconsistent))
1427
1
          << Context.ToCtx.getTypeDeclType(D2);
1428
1
      Context.Diag1(D1->getLocation(), diag::note_odr_tag_kind_here)
1429
1
          << D1->getDeclName() << (unsigned)D1->getTagKind();
1430
1
    }
1431
3
    return false;
1432
3
  }
1433
1434
762k
  if (!D1->getDeclName() && 
!D2->getDeclName()7.39k
) {
1435
    // If both anonymous structs/unions are in a record context, make sure
1436
    // they occur in the same location in the context records.
1437
7.39k
    if (Optional<unsigned> Index1 =
1438
7.39k
            StructuralEquivalenceContext::findUntaggedStructOrUnionIndex(D1)) {
1439
7.36k
      if (Optional<unsigned> Index2 =
1440
7.36k
              StructuralEquivalenceContext::findUntaggedStructOrUnionIndex(
1441
7.36k
                  D2)) {
1442
7.36k
        if (*Index1 != *Index2)
1443
47
          return false;
1444
7.36k
      }
1445
7.36k
    }
1446
7.39k
  }
1447
1448
  // If the records occur in different context (namespace), these should be
1449
  // different. This is specially important if the definition of one or both
1450
  // records is missing.
1451
762k
  if (!IsRecordContextStructurallyEquivalent(D1, D2))
1452
20
    return false;
1453
1454
  // If both declarations are class template specializations, we know
1455
  // the ODR applies, so check the template and template arguments.
1456
762k
  const auto *Spec1 = dyn_cast<ClassTemplateSpecializationDecl>(D1);
1457
762k
  const auto *Spec2 = dyn_cast<ClassTemplateSpecializationDecl>(D2);
1458
762k
  if (Spec1 && 
Spec292.9k
) {
1459
    // Check that the specialized templates are the same.
1460
92.9k
    if (!IsStructurallyEquivalent(Context, Spec1->getSpecializedTemplate(),
1461
92.9k
                                  Spec2->getSpecializedTemplate()))
1462
257
      return false;
1463
1464
    // Check that the template arguments are the same.
1465
92.6k
    if (Spec1->getTemplateArgs().size() != Spec2->getTemplateArgs().size())
1466
18
      return false;
1467
1468
252k
    
for (unsigned I = 0, N = Spec1->getTemplateArgs().size(); 92.6k
I != N;
++I159k
)
1469
163k
      if (!IsStructurallyEquivalent(Context, Spec1->getTemplateArgs().get(I),
1470
163k
                                    Spec2->getTemplateArgs().get(I)))
1471
3.82k
        return false;
1472
92.6k
  }
1473
  // If one is a class template specialization and the other is not, these
1474
  // structures are different.
1475
669k
  else if (Spec1 || Spec2)
1476
0
    return false;
1477
1478
  // Compare the definitions of these two records. If either or both are
1479
  // incomplete (i.e. it is a forward decl), we assume that they are
1480
  // equivalent.
1481
758k
  D1 = D1->getDefinition();
1482
758k
  D2 = D2->getDefinition();
1483
758k
  if (!D1 || 
!D2622k
)
1484
137k
    return true;
1485
1486
  // If any of the records has external storage and we do a minimal check (or
1487
  // AST import) we assume they are equivalent. (If we didn't have this
1488
  // assumption then `RecordDecl::LoadFieldsFromExternalStorage` could trigger
1489
  // another AST import which in turn would call the structural equivalency
1490
  // check again and finally we'd have an improper result.)
1491
620k
  if (Context.EqKind == StructuralEquivalenceKind::Minimal)
1492
619k
    if (D1->hasExternalLexicalStorage() || 
D2->hasExternalLexicalStorage()348k
)
1493
296k
      return true;
1494
1495
  // If one definition is currently being defined, we do not compare for
1496
  // equality and we assume that the decls are equal.
1497
323k
  if (D1->isBeingDefined() || 
D2->isBeingDefined()323k
)
1498
50
    return true;
1499
1500
323k
  if (auto *D1CXX = dyn_cast<CXXRecordDecl>(D1)) {
1501
323k
    if (auto *D2CXX = dyn_cast<CXXRecordDecl>(D2)) {
1502
323k
      if (D1CXX->hasExternalLexicalStorage() &&
1503
323k
          
!D1CXX->isCompleteDefinition()67
) {
1504
0
        D1CXX->getASTContext().getExternalSource()->CompleteType(D1CXX);
1505
0
      }
1506
1507
323k
      if (D1CXX->isLambda() != D2CXX->isLambda())
1508
0
        return false;
1509
323k
      if (D1CXX->isLambda()) {
1510
8
        if (!IsStructurallyEquivalentLambdas(Context, D1CXX, D2CXX))
1511
2
          return false;
1512
8
      }
1513
1514
323k
      if (D1CXX->getNumBases() != D2CXX->getNumBases()) {
1515
0
        if (Context.Complain) {
1516
0
          Context.Diag2(D2->getLocation(),
1517
0
                        Context.getApplicableDiagnostic(
1518
0
                            diag::err_odr_tag_type_inconsistent))
1519
0
              << Context.ToCtx.getTypeDeclType(D2);
1520
0
          Context.Diag2(D2->getLocation(), diag::note_odr_number_of_bases)
1521
0
              << D2CXX->getNumBases();
1522
0
          Context.Diag1(D1->getLocation(), diag::note_odr_number_of_bases)
1523
0
              << D1CXX->getNumBases();
1524
0
        }
1525
0
        return false;
1526
0
      }
1527
1528
      // Check the base classes.
1529
323k
      for (CXXRecordDecl::base_class_iterator Base1 = D1CXX->bases_begin(),
1530
323k
                                              BaseEnd1 = D1CXX->bases_end(),
1531
323k
                                              Base2 = D2CXX->bases_begin();
1532
473k
           Base1 != BaseEnd1; 
++Base1, ++Base2149k
) {
1533
149k
        if (!IsStructurallyEquivalent(Context, Base1->getType(),
1534
149k
                                      Base2->getType())) {
1535
78
          if (Context.Complain) {
1536
78
            Context.Diag2(D2->getLocation(),
1537
78
                          Context.getApplicableDiagnostic(
1538
78
                              diag::err_odr_tag_type_inconsistent))
1539
78
                << Context.ToCtx.getTypeDeclType(D2);
1540
78
            Context.Diag2(Base2->getBeginLoc(), diag::note_odr_base)
1541
78
                << Base2->getType() << Base2->getSourceRange();
1542
78
            Context.Diag1(Base1->getBeginLoc(), diag::note_odr_base)
1543
78
                << Base1->getType() << Base1->getSourceRange();
1544
78
          }
1545
78
          return false;
1546
78
        }
1547
1548
        // Check virtual vs. non-virtual inheritance mismatch.
1549
149k
        if (Base1->isVirtual() != Base2->isVirtual()) {
1550
2
          if (Context.Complain) {
1551
0
            Context.Diag2(D2->getLocation(),
1552
0
                          Context.getApplicableDiagnostic(
1553
0
                              diag::err_odr_tag_type_inconsistent))
1554
0
                << Context.ToCtx.getTypeDeclType(D2);
1555
0
            Context.Diag2(Base2->getBeginLoc(), diag::note_odr_virtual_base)
1556
0
                << Base2->isVirtual() << Base2->getSourceRange();
1557
0
            Context.Diag1(Base1->getBeginLoc(), diag::note_odr_base)
1558
0
                << Base1->isVirtual() << Base1->getSourceRange();
1559
0
          }
1560
2
          return false;
1561
2
        }
1562
149k
      }
1563
1564
      // Check the friends for consistency.
1565
323k
      CXXRecordDecl::friend_iterator Friend2 = D2CXX->friend_begin(),
1566
323k
                                     Friend2End = D2CXX->friend_end();
1567
323k
      for (CXXRecordDecl::friend_iterator Friend1 = D1CXX->friend_begin(),
1568
323k
                                          Friend1End = D1CXX->friend_end();
1569
511k
           Friend1 != Friend1End; 
++Friend1, ++Friend2188k
) {
1570
189k
        if (Friend2 == Friend2End) {
1571
808
          if (Context.Complain) {
1572
807
            Context.Diag2(D2->getLocation(),
1573
807
                          Context.getApplicableDiagnostic(
1574
807
                              diag::err_odr_tag_type_inconsistent))
1575
807
                << Context.ToCtx.getTypeDeclType(D2CXX);
1576
807
            Context.Diag1((*Friend1)->getFriendLoc(), diag::note_odr_friend);
1577
807
            Context.Diag2(D2->getLocation(), diag::note_odr_missing_friend);
1578
807
          }
1579
808
          return false;
1580
808
        }
1581
1582
188k
        if (!IsStructurallyEquivalent(Context, *Friend1, *Friend2)) {
1583
0
          if (Context.Complain) {
1584
0
            Context.Diag2(D2->getLocation(),
1585
0
                          Context.getApplicableDiagnostic(
1586
0
                              diag::err_odr_tag_type_inconsistent))
1587
0
                << Context.ToCtx.getTypeDeclType(D2CXX);
1588
0
            Context.Diag1((*Friend1)->getFriendLoc(), diag::note_odr_friend);
1589
0
            Context.Diag2((*Friend2)->getFriendLoc(), diag::note_odr_friend);
1590
0
          }
1591
0
          return false;
1592
0
        }
1593
188k
      }
1594
1595
322k
      if (Friend2 != Friend2End) {
1596
5
        if (Context.Complain) {
1597
4
          Context.Diag2(D2->getLocation(),
1598
4
                        Context.getApplicableDiagnostic(
1599
4
                            diag::err_odr_tag_type_inconsistent))
1600
4
              << Context.ToCtx.getTypeDeclType(D2);
1601
4
          Context.Diag2((*Friend2)->getFriendLoc(), diag::note_odr_friend);
1602
4
          Context.Diag1(D1->getLocation(), diag::note_odr_missing_friend);
1603
4
        }
1604
5
        return false;
1605
5
      }
1606
322k
    } else 
if (0
D1CXX->getNumBases() > 00
) {
1607
0
      if (Context.Complain) {
1608
0
        Context.Diag2(D2->getLocation(),
1609
0
                      Context.getApplicableDiagnostic(
1610
0
                          diag::err_odr_tag_type_inconsistent))
1611
0
            << Context.ToCtx.getTypeDeclType(D2);
1612
0
        const CXXBaseSpecifier *Base1 = D1CXX->bases_begin();
1613
0
        Context.Diag1(Base1->getBeginLoc(), diag::note_odr_base)
1614
0
            << Base1->getType() << Base1->getSourceRange();
1615
0
        Context.Diag2(D2->getLocation(), diag::note_odr_missing_base);
1616
0
      }
1617
0
      return false;
1618
0
    }
1619
323k
  }
1620
1621
  // Check the fields for consistency.
1622
322k
  QualType D2Type = Context.ToCtx.getTypeDeclType(D2);
1623
322k
  RecordDecl::field_iterator Field2 = D2->field_begin(),
1624
322k
                             Field2End = D2->field_end();
1625
322k
  for (RecordDecl::field_iterator Field1 = D1->field_begin(),
1626
322k
                                  Field1End = D1->field_end();
1627
620k
       Field1 != Field1End; 
++Field1, ++Field2298k
) {
1628
299k
    if (Field2 == Field2End) {
1629
89
      if (Context.Complain) {
1630
88
        Context.Diag2(D2->getLocation(),
1631
88
                      Context.getApplicableDiagnostic(
1632
88
                          diag::err_odr_tag_type_inconsistent))
1633
88
            << Context.ToCtx.getTypeDeclType(D2);
1634
88
        Context.Diag1(Field1->getLocation(), diag::note_odr_field)
1635
88
            << Field1->getDeclName() << Field1->getType();
1636
88
        Context.Diag2(D2->getLocation(), diag::note_odr_missing_field);
1637
88
      }
1638
89
      return false;
1639
89
    }
1640
1641
299k
    if (!IsStructurallyEquivalent(Context, *Field1, *Field2, D2Type))
1642
963
      return false;
1643
299k
  }
1644
1645
321k
  if (Field2 != Field2End) {
1646
16
    if (Context.Complain) {
1647
15
      Context.Diag2(D2->getLocation(), Context.getApplicableDiagnostic(
1648
15
                                           diag::err_odr_tag_type_inconsistent))
1649
15
          << Context.ToCtx.getTypeDeclType(D2);
1650
15
      Context.Diag2(Field2->getLocation(), diag::note_odr_field)
1651
15
          << Field2->getDeclName() << Field2->getType();
1652
15
      Context.Diag1(D1->getLocation(), diag::note_odr_missing_field);
1653
15
    }
1654
16
    return false;
1655
16
  }
1656
1657
321k
  return true;
1658
321k
}
1659
1660
static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
1661
                                     EnumConstantDecl *D1,
1662
30
                                     EnumConstantDecl *D2) {
1663
30
  const llvm::APSInt &FromVal = D1->getInitVal();
1664
30
  const llvm::APSInt &ToVal = D2->getInitVal();
1665
30
  if (FromVal.isSigned() != ToVal.isSigned())
1666
2
    return false;
1667
28
  if (FromVal.getBitWidth() != ToVal.getBitWidth())
1668
2
    return false;
1669
26
  if (FromVal != ToVal)
1670
6
    return false;
1671
1672
20
  if (!IsStructurallyEquivalent(D1->getIdentifier(), D2->getIdentifier()))
1673
2
    return false;
1674
1675
  // Init expressions are the most expensive check, so do them last.
1676
18
  return IsStructurallyEquivalent(Context, D1->getInitExpr(),
1677
18
                                  D2->getInitExpr());
1678
20
}
1679
1680
/// Determine structural equivalence of two enums.
1681
static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
1682
8.40k
                                     EnumDecl *D1, EnumDecl *D2) {
1683
1684
  // Check for equivalent enum names.
1685
8.40k
  IdentifierInfo *Name1 = D1->getIdentifier();
1686
8.40k
  if (!Name1 && 
D1->getTypedefNameForAnonDecl()3.45k
)
1687
15
    Name1 = D1->getTypedefNameForAnonDecl()->getIdentifier();
1688
8.40k
  IdentifierInfo *Name2 = D2->getIdentifier();
1689
8.40k
  if (!Name2 && 
D2->getTypedefNameForAnonDecl()3.45k
)
1690
15
    Name2 = D2->getTypedefNameForAnonDecl()->getIdentifier();
1691
8.40k
  if (!IsStructurallyEquivalent(Name1, Name2))
1692
162
    return false;
1693
1694
  // Compare the definitions of these two enums. If either or both are
1695
  // incomplete (i.e. forward declared), we assume that they are equivalent.
1696
8.24k
  D1 = D1->getDefinition();
1697
8.24k
  D2 = D2->getDefinition();
1698
8.24k
  if (!D1 || 
!D28.20k
)
1699
40
    return true;
1700
1701
8.20k
  EnumDecl::enumerator_iterator EC2 = D2->enumerator_begin(),
1702
8.20k
                                EC2End = D2->enumerator_end();
1703
8.20k
  for (EnumDecl::enumerator_iterator EC1 = D1->enumerator_begin(),
1704
8.20k
                                     EC1End = D1->enumerator_end();
1705
30.0k
       EC1 != EC1End; 
++EC1, ++EC221.8k
) {
1706
21.9k
    if (EC2 == EC2End) {
1707
17
      if (Context.Complain) {
1708
17
        Context.Diag2(D2->getLocation(),
1709
17
                      Context.getApplicableDiagnostic(
1710
17
                          diag::err_odr_tag_type_inconsistent))
1711
17
            << Context.ToCtx.getTypeDeclType(D2);
1712
17
        Context.Diag1(EC1->getLocation(), diag::note_odr_enumerator)
1713
17
            << EC1->getDeclName() << toString(EC1->getInitVal(), 10);
1714
17
        Context.Diag2(D2->getLocation(), diag::note_odr_missing_enumerator);
1715
17
      }
1716
17
      return false;
1717
17
    }
1718
1719
21.9k
    llvm::APSInt Val1 = EC1->getInitVal();
1720
21.9k
    llvm::APSInt Val2 = EC2->getInitVal();
1721
21.9k
    if (!llvm::APSInt::isSameValue(Val1, Val2) ||
1722
21.9k
        
!IsStructurallyEquivalent(EC1->getIdentifier(), EC2->getIdentifier())21.8k
) {
1723
82
      if (Context.Complain) {
1724
80
        Context.Diag2(D2->getLocation(),
1725
80
                      Context.getApplicableDiagnostic(
1726
80
                          diag::err_odr_tag_type_inconsistent))
1727
80
            << Context.ToCtx.getTypeDeclType(D2);
1728
80
        Context.Diag2(EC2->getLocation(), diag::note_odr_enumerator)
1729
80
            << EC2->getDeclName() << toString(EC2->getInitVal(), 10);
1730
80
        Context.Diag1(EC1->getLocation(), diag::note_odr_enumerator)
1731
80
            << EC1->getDeclName() << toString(EC1->getInitVal(), 10);
1732
80
      }
1733
82
      return false;
1734
82
    }
1735
21.9k
  }
1736
1737
8.10k
  if (EC2 != EC2End) {
1738
1
    if (Context.Complain) {
1739
1
      Context.Diag2(D2->getLocation(), Context.getApplicableDiagnostic(
1740
1
                                           diag::err_odr_tag_type_inconsistent))
1741
1
          << Context.ToCtx.getTypeDeclType(D2);
1742
1
      Context.Diag2(EC2->getLocation(), diag::note_odr_enumerator)
1743
1
          << EC2->getDeclName() << toString(EC2->getInitVal(), 10);
1744
1
      Context.Diag1(D1->getLocation(), diag::note_odr_missing_enumerator);
1745
1
    }
1746
1
    return false;
1747
1
  }
1748
1749
8.10k
  return true;
1750
8.10k
}
1751
1752
static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
1753
                                     TemplateParameterList *Params1,
1754
2.87M
                                     TemplateParameterList *Params2) {
1755
2.87M
  if (Params1->size() != Params2->size()) {
1756
1.44M
    if (Context.Complain) {
1757
1.44M
      Context.Diag2(Params2->getTemplateLoc(),
1758
1.44M
                    Context.getApplicableDiagnostic(
1759
1.44M
                        diag::err_odr_different_num_template_parameters))
1760
1.44M
          << Params1->size() << Params2->size();
1761
1.44M
      Context.Diag1(Params1->getTemplateLoc(),
1762
1.44M
                    diag::note_odr_template_parameter_list);
1763
1.44M
    }
1764
1.44M
    return false;
1765
1.44M
  }
1766
1767
4.29M
  
for (unsigned I = 0, N = Params1->size(); 1.42M
I != N;
++I2.86M
) {
1768
2.98M
    if (Params1->getParam(I)->getKind() != Params2->getParam(I)->getKind()) {
1769
111k
      if (Context.Complain) {
1770
110k
        Context.Diag2(Params2->getParam(I)->getLocation(),
1771
110k
                      Context.getApplicableDiagnostic(
1772
110k
                          diag::err_odr_different_template_parameter_kind));
1773
110k
        Context.Diag1(Params1->getParam(I)->getLocation(),
1774
110k
                      diag::note_odr_template_parameter_here);
1775
110k
      }
1776
111k
      return false;
1777
111k
    }
1778
1779
2.87M
    if (!IsStructurallyEquivalent(Context, Params1->getParam(I),
1780
2.87M
                                  Params2->getParam(I)))
1781
1.28k
      return false;
1782
2.87M
  }
1783
1784
1.31M
  return true;
1785
1.42M
}
1786
1787
static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
1788
                                     TemplateTypeParmDecl *D1,
1789
1.42M
                                     TemplateTypeParmDecl *D2) {
1790
1.42M
  if (D1->isParameterPack() != D2->isParameterPack()) {
1791
0
    if (Context.Complain) {
1792
0
      Context.Diag2(D2->getLocation(),
1793
0
                    Context.getApplicableDiagnostic(
1794
0
                        diag::err_odr_parameter_pack_non_pack))
1795
0
          << D2->isParameterPack();
1796
0
      Context.Diag1(D1->getLocation(), diag::note_odr_parameter_pack_non_pack)
1797
0
          << D1->isParameterPack();
1798
0
    }
1799
0
    return false;
1800
0
  }
1801
1802
1.42M
  return true;
1803
1.42M
}
1804
1805
static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
1806
                                     NonTypeTemplateParmDecl *D1,
1807
249k
                                     NonTypeTemplateParmDecl *D2) {
1808
249k
  if (D1->isParameterPack() != D2->isParameterPack()) {
1809
0
    if (Context.Complain) {
1810
0
      Context.Diag2(D2->getLocation(),
1811
0
                    Context.getApplicableDiagnostic(
1812
0
                        diag::err_odr_parameter_pack_non_pack))
1813
0
          << D2->isParameterPack();
1814
0
      Context.Diag1(D1->getLocation(), diag::note_odr_parameter_pack_non_pack)
1815
0
          << D1->isParameterPack();
1816
0
    }
1817
0
    return false;
1818
0
  }
1819
1820
  // Check types.
1821
249k
  if (!IsStructurallyEquivalent(Context, D1->getType(), D2->getType())) {
1822
1.41k
    if (Context.Complain) {
1823
1.41k
      Context.Diag2(D2->getLocation(),
1824
1.41k
                    Context.getApplicableDiagnostic(
1825
1.41k
                        diag::err_odr_non_type_parameter_type_inconsistent))
1826
1.41k
          << D2->getType() << D1->getType();
1827
1.41k
      Context.Diag1(D1->getLocation(), diag::note_odr_value_here)
1828
1.41k
          << D1->getType();
1829
1.41k
    }
1830
1.41k
    return false;
1831
1.41k
  }
1832
1833
248k
  return true;
1834
249k
}
1835
1836
static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
1837
                                     TemplateTemplateParmDecl *D1,
1838
638
                                     TemplateTemplateParmDecl *D2) {
1839
638
  if (D1->isParameterPack() != D2->isParameterPack()) {
1840
0
    if (Context.Complain) {
1841
0
      Context.Diag2(D2->getLocation(),
1842
0
                    Context.getApplicableDiagnostic(
1843
0
                        diag::err_odr_parameter_pack_non_pack))
1844
0
          << D2->isParameterPack();
1845
0
      Context.Diag1(D1->getLocation(), diag::note_odr_parameter_pack_non_pack)
1846
0
          << D1->isParameterPack();
1847
0
    }
1848
0
    return false;
1849
0
  }
1850
1851
  // Check template parameter lists.
1852
638
  return IsStructurallyEquivalent(Context, D1->getTemplateParameters(),
1853
638
                                  D2->getTemplateParameters());
1854
638
}
1855
1856
static bool IsTemplateDeclCommonStructurallyEquivalent(
1857
2.94M
    StructuralEquivalenceContext &Ctx, TemplateDecl *D1, TemplateDecl *D2) {
1858
2.94M
  if (!IsStructurallyEquivalent(D1->getIdentifier(), D2->getIdentifier()))
1859
74.3k
    return false;
1860
2.87M
  if (!D1->getIdentifier()) // Special name
1861
1.77M
    if (D1->getNameAsString() != D2->getNameAsString())
1862
2.73k
      return false;
1863
2.87M
  return IsStructurallyEquivalent(Ctx, D1->getTemplateParameters(),
1864
2.87M
                                  D2->getTemplateParameters());
1865
2.87M
}
1866
1867
static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
1868
                                     ClassTemplateDecl *D1,
1869
664k
                                     ClassTemplateDecl *D2) {
1870
  // Check template parameters.
1871
664k
  if (!IsTemplateDeclCommonStructurallyEquivalent(Context, D1, D2))
1872
48.1k
    return false;
1873
1874
  // Check the templated declaration.
1875
616k
  return IsStructurallyEquivalent(Context, D1->getTemplatedDecl(),
1876
616k
                                  D2->getTemplatedDecl());
1877
664k
}
1878
1879
static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
1880
                                     FunctionTemplateDecl *D1,
1881
2.28M
                                     FunctionTemplateDecl *D2) {
1882
  // Check template parameters.
1883
2.28M
  if (!IsTemplateDeclCommonStructurallyEquivalent(Context, D1, D2))
1884
1.58M
    return false;
1885
1886
  // Check the templated declaration.
1887
699k
  return IsStructurallyEquivalent(Context, D1->getTemplatedDecl()->getType(),
1888
699k
                                  D2->getTemplatedDecl()->getType());
1889
2.28M
}
1890
1891
static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
1892
                                     ConceptDecl *D1,
1893
0
                                     ConceptDecl *D2) {
1894
  // Check template parameters.
1895
0
  if (!IsTemplateDeclCommonStructurallyEquivalent(Context, D1, D2))
1896
0
    return false;
1897
1898
  // Check the constraint expression.
1899
0
  return IsStructurallyEquivalent(Context, D1->getConstraintExpr(),
1900
0
                                  D2->getConstraintExpr());
1901
0
}
1902
1903
static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
1904
186k
                                     FriendDecl *D1, FriendDecl *D2) {
1905
186k
  if ((D1->getFriendType() && 
D2->getFriendDecl()7.09k
) ||
1906
186k
      (D1->getFriendDecl() && 
D2->getFriendType()179k
)) {
1907
0
      return false;
1908
0
  }
1909
186k
  if (D1->getFriendType() && 
D2->getFriendType()7.09k
)
1910
7.09k
    return IsStructurallyEquivalent(Context,
1911
7.09k
                                    D1->getFriendType()->getType(),
1912
7.09k
                                    D2->getFriendType()->getType());
1913
179k
  if (D1->getFriendDecl() && D2->getFriendDecl())
1914
179k
    return IsStructurallyEquivalent(Context, D1->getFriendDecl(),
1915
179k
                                    D2->getFriendDecl());
1916
0
  return false;
1917
179k
}
1918
1919
static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
1920
0
                                     TypedefNameDecl *D1, TypedefNameDecl *D2) {
1921
0
  if (!IsStructurallyEquivalent(D1->getIdentifier(), D2->getIdentifier()))
1922
0
    return false;
1923
1924
0
  return IsStructurallyEquivalent(Context, D1->getUnderlyingType(),
1925
0
                                  D2->getUnderlyingType());
1926
0
}
1927
1928
static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
1929
115k
                                     FunctionDecl *D1, FunctionDecl *D2) {
1930
115k
  if (!IsStructurallyEquivalent(D1->getIdentifier(), D2->getIdentifier()))
1931
697
    return false;
1932
1933
114k
  if (D1->isOverloadedOperator()) {
1934
104k
    if (!D2->isOverloadedOperator())
1935
0
      return false;
1936
104k
    if (D1->getOverloadedOperator() != D2->getOverloadedOperator())
1937
12.5k
      return false;
1938
104k
  }
1939
1940
  // FIXME: Consider checking for function attributes as well.
1941
101k
  if (!IsStructurallyEquivalent(Context, D1->getType(), D2->getType()))
1942
51.1k
    return false;
1943
1944
50.7k
  return true;
1945
101k
}
1946
1947
static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
1948
                                     ObjCIvarDecl *D1, ObjCIvarDecl *D2,
1949
20
                                     QualType Owner2Type) {
1950
20
  if (D1->getAccessControl() != D2->getAccessControl())
1951
2
    return false;
1952
1953
18
  return IsStructurallyEquivalent(Context, cast<FieldDecl>(D1),
1954
18
                                  cast<FieldDecl>(D2), Owner2Type);
1955
20
}
1956
1957
static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
1958
0
                                     ObjCIvarDecl *D1, ObjCIvarDecl *D2) {
1959
0
  QualType Owner2Type =
1960
0
      Context.ToCtx.getObjCInterfaceType(D2->getContainingInterface());
1961
0
  return IsStructurallyEquivalent(Context, D1, D2, Owner2Type);
1962
0
}
1963
1964
static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
1965
                                     ObjCMethodDecl *Method1,
1966
17
                                     ObjCMethodDecl *Method2) {
1967
17
  bool PropertiesEqual =
1968
17
      Method1->isInstanceMethod() == Method2->isInstanceMethod() &&
1969
17
      
Method1->isVariadic() == Method2->isVariadic()15
&&
1970
17
      
Method1->isDirectMethod() == Method2->isDirectMethod()15
;
1971
17
  if (!PropertiesEqual)
1972
2
    return false;
1973
1974
  // Compare selector slot names.
1975
15
  Selector Selector1 = Method1->getSelector(),
1976
15
           Selector2 = Method2->getSelector();
1977
15
  unsigned NumArgs = Selector1.getNumArgs();
1978
15
  if (NumArgs != Selector2.getNumArgs())
1979
0
    return false;
1980
  // Compare all selector slots. For selectors with arguments it means all arg
1981
  // slots. And if there are no arguments, compare the first-and-only slot.
1982
15
  unsigned SlotsToCheck = NumArgs > 0 ? 
NumArgs6
:
19
;
1983
25
  for (unsigned I = 0; I < SlotsToCheck; 
++I10
) {
1984
17
    if (!IsStructurallyEquivalent(Selector1.getIdentifierInfoForSlot(I),
1985
17
                                  Selector2.getIdentifierInfoForSlot(I)))
1986
7
      return false;
1987
17
  }
1988
1989
  // Compare types.
1990
8
  if (!IsStructurallyEquivalent(Context, Method1->getReturnType(),
1991
8
                                Method2->getReturnType()))
1992
2
    return false;
1993
6
  assert(
1994
6
      Method1->param_size() == Method2->param_size() &&
1995
6
      "Same number of arguments should be already enforced in Selector checks");
1996
0
  for (ObjCMethodDecl::param_type_iterator
1997
6
           ParamT1 = Method1->param_type_begin(),
1998
6
           ParamT1End = Method1->param_type_end(),
1999
6
           ParamT2 = Method2->param_type_begin(),
2000
6
           ParamT2End = Method2->param_type_end();
2001
8
       (ParamT1 != ParamT1End) && 
(ParamT2 != ParamT2End)4
;
2002
6
       
++ParamT1, ++ParamT22
) {
2003
4
    if (!IsStructurallyEquivalent(Context, *ParamT1, *ParamT2))
2004
2
      return false;
2005
4
  }
2006
2007
4
  return true;
2008
6
}
2009
2010
static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
2011
                                     ObjCCategoryDecl *D1,
2012
53
                                     ObjCCategoryDecl *D2) {
2013
53
  if (!IsStructurallyEquivalent(D1->getIdentifier(), D2->getIdentifier()))
2014
4
    return false;
2015
2016
49
  if (!IsStructurallyEquivalent(D1->getClassInterface()->getIdentifier(),
2017
49
                                D2->getClassInterface()->getIdentifier()))
2018
2
    return false;
2019
2020
  // Compare protocols.
2021
47
  ObjCCategoryDecl::protocol_iterator Protocol2 = D2->protocol_begin(),
2022
47
                                      Protocol2End = D2->protocol_end();
2023
47
  for (ObjCCategoryDecl::protocol_iterator Protocol1 = D1->protocol_begin(),
2024
47
                                           Protocol1End = D1->protocol_end();
2025
49
       Protocol1 != Protocol1End; 
++Protocol1, ++Protocol22
) {
2026
7
    if (Protocol2 == Protocol2End)
2027
0
      return false;
2028
7
    if (!IsStructurallyEquivalent((*Protocol1)->getIdentifier(),
2029
7
                                  (*Protocol2)->getIdentifier()))
2030
5
      return false;
2031
7
  }
2032
42
  if (Protocol2 != Protocol2End)
2033
0
    return false;
2034
2035
  // Compare ivars.
2036
42
  QualType D2Type = Context.ToCtx.getObjCInterfaceType(D2->getClassInterface());
2037
42
  ObjCCategoryDecl::ivar_iterator Ivar2 = D2->ivar_begin(),
2038
42
                                  Ivar2End = D2->ivar_end();
2039
42
  for (ObjCCategoryDecl::ivar_iterator Ivar1 = D1->ivar_begin(),
2040
42
                                       Ivar1End = D1->ivar_end();
2041
50
       Ivar1 != Ivar1End; 
++Ivar1, ++Ivar28
) {
2042
21
    if (Ivar2 == Ivar2End)
2043
1
      return false;
2044
20
    if (!IsStructurallyEquivalent(Context, *Ivar1, *Ivar2, D2Type))
2045
12
      return false;
2046
20
  }
2047
29
  if (Ivar2 != Ivar2End)
2048
2
    return false;
2049
2050
  // Compare methods.
2051
27
  ObjCCategoryDecl::method_iterator Method2 = D2->meth_begin(),
2052
27
                                    Method2End = D2->meth_end();
2053
27
  for (ObjCCategoryDecl::method_iterator Method1 = D1->meth_begin(),
2054
27
                                         Method1End = D1->meth_end();
2055
31
       Method1 != Method1End; 
++Method1, ++Method24
) {
2056
18
    if (Method2 == Method2End)
2057
1
      return false;
2058
17
    if (!IsStructurallyEquivalent(Context, *Method1, *Method2))
2059
13
      return false;
2060
17
  }
2061
13
  if (Method2 != Method2End)
2062
1
    return false;
2063
2064
12
  return true;
2065
13
}
2066
2067
/// Determine structural equivalence of two declarations.
2068
static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
2069
9.89M
                                     Decl *D1, Decl *D2) {
2070
  // FIXME: Check for known structural equivalences via a callback of some sort.
2071
2072
9.89M
  D1 = D1->getCanonicalDecl();
2073
9.89M
  D2 = D2->getCanonicalDecl();
2074
9.89M
  std::pair<Decl *, Decl *> P{D1, D2};
2075
2076
  // Check whether we already know that these two declarations are not
2077
  // structurally equivalent.
2078
9.89M
  if (Context.NonEquivalentDecls.count(P))
2079
1.47M
    return false;
2080
2081
  // Check if a check for these declarations is already pending.
2082
  // If yes D1 and D2 will be checked later (from DeclsToCheck),
2083
  // or these are already checked (and equivalent).
2084
8.42M
  bool Inserted = Context.VisitedDecls.insert(P).second;
2085
8.42M
  if (!Inserted)
2086
780k
    return true;
2087
2088
7.64M
  Context.DeclsToCheck.push(P);
2089
2090
7.64M
  return true;
2091
8.42M
}
2092
2093
DiagnosticBuilder StructuralEquivalenceContext::Diag1(SourceLocation Loc,
2094
1.55M
                                                      unsigned DiagID) {
2095
1.55M
  assert(Complain && "Not allowed to complain");
2096
1.55M
  if (LastDiagFromC2)
2097
1.55M
    FromCtx.getDiagnostics().notePriorDiagnosticFrom(ToCtx.getDiagnostics());
2098
1.55M
  LastDiagFromC2 = false;
2099
1.55M
  return FromCtx.getDiagnostics().Report(Loc, DiagID);
2100
1.55M
}
2101
2102
DiagnosticBuilder StructuralEquivalenceContext::Diag2(SourceLocation Loc,
2103
1.55M
                                                      unsigned DiagID) {
2104
1.55M
  assert(Complain && "Not allowed to complain");
2105
1.55M
  if (!LastDiagFromC2)
2106
1.55M
    ToCtx.getDiagnostics().notePriorDiagnosticFrom(FromCtx.getDiagnostics());
2107
1.55M
  LastDiagFromC2 = true;
2108
1.55M
  return ToCtx.getDiagnostics().Report(Loc, DiagID);
2109
1.55M
}
2110
2111
Optional<unsigned>
2112
14.7k
StructuralEquivalenceContext::findUntaggedStructOrUnionIndex(RecordDecl *Anon) {
2113
14.7k
  ASTContext &Context = Anon->getASTContext();
2114
14.7k
  QualType AnonTy = Context.getRecordType(Anon);
2115
2116
14.7k
  const auto *Owner = dyn_cast<RecordDecl>(Anon->getDeclContext());
2117
14.7k
  if (!Owner)
2118
32
    return None;
2119
2120
14.7k
  unsigned Index = 0;
2121
36.6k
  for (const auto *D : Owner->noload_decls()) {
2122
36.6k
    const auto *F = dyn_cast<FieldDecl>(D);
2123
36.6k
    if (!F)
2124
21.7k
      continue;
2125
2126
14.8k
    if (F->isAnonymousStructOrUnion()) {
2127
14.5k
      if (Context.hasSameType(F->getType(), AnonTy))
2128
14.5k
        break;
2129
40
      ++Index;
2130
40
      continue;
2131
14.5k
    }
2132
2133
    // If the field looks like this:
2134
    // struct { ... } A;
2135
241
    QualType FieldType = F->getType();
2136
    // In case of nested structs.
2137
452
    while (const auto *ElabType = dyn_cast<ElaboratedType>(FieldType))
2138
211
      FieldType = ElabType->getNamedType();
2139
2140
241
    if (const auto *RecType = dyn_cast<RecordType>(FieldType)) {
2141
241
      const RecordDecl *RecDecl = RecType->getDecl();
2142
241
      if (RecDecl->getDeclContext() == Owner && !RecDecl->getIdentifier()) {
2143
241
        if (Context.hasSameType(FieldType, AnonTy))
2144
168
          break;
2145
73
        ++Index;
2146
73
        continue;
2147
241
      }
2148
241
    }
2149
241
  }
2150
2151
14.7k
  return Index;
2152
14.7k
}
2153
2154
unsigned StructuralEquivalenceContext::getApplicableDiagnostic(
2155
1.55M
    unsigned ErrorDiagnostic) {
2156
1.55M
  if (ErrorOnTagTypeMismatch)
2157
4
    return ErrorDiagnostic;
2158
2159
1.55M
  switch (ErrorDiagnostic) {
2160
0
  case diag::err_odr_variable_type_inconsistent:
2161
0
    return diag::warn_odr_variable_type_inconsistent;
2162
0
  case diag::err_odr_variable_multiple_def:
2163
0
    return diag::warn_odr_variable_multiple_def;
2164
0
  case diag::err_odr_function_type_inconsistent:
2165
0
    return diag::warn_odr_function_type_inconsistent;
2166
2.01k
  case diag::err_odr_tag_type_inconsistent:
2167
2.01k
    return diag::warn_odr_tag_type_inconsistent;
2168
0
  case diag::err_odr_field_type_inconsistent:
2169
0
    return diag::warn_odr_field_type_inconsistent;
2170
0
  case diag::err_odr_ivar_type_inconsistent:
2171
0
    return diag::warn_odr_ivar_type_inconsistent;
2172
0
  case diag::err_odr_objc_superclass_inconsistent:
2173
0
    return diag::warn_odr_objc_superclass_inconsistent;
2174
0
  case diag::err_odr_objc_method_result_type_inconsistent:
2175
0
    return diag::warn_odr_objc_method_result_type_inconsistent;
2176
0
  case diag::err_odr_objc_method_num_params_inconsistent:
2177
0
    return diag::warn_odr_objc_method_num_params_inconsistent;
2178
0
  case diag::err_odr_objc_method_param_type_inconsistent:
2179
0
    return diag::warn_odr_objc_method_param_type_inconsistent;
2180
0
  case diag::err_odr_objc_method_variadic_inconsistent:
2181
0
    return diag::warn_odr_objc_method_variadic_inconsistent;
2182
0
  case diag::err_odr_objc_property_type_inconsistent:
2183
0
    return diag::warn_odr_objc_property_type_inconsistent;
2184
0
  case diag::err_odr_objc_property_impl_kind_inconsistent:
2185
0
    return diag::warn_odr_objc_property_impl_kind_inconsistent;
2186
0
  case diag::err_odr_objc_synthesize_ivar_inconsistent:
2187
0
    return diag::warn_odr_objc_synthesize_ivar_inconsistent;
2188
1.44M
  case diag::err_odr_different_num_template_parameters:
2189
1.44M
    return diag::warn_odr_different_num_template_parameters;
2190
110k
  case diag::err_odr_different_template_parameter_kind:
2191
110k
    return diag::warn_odr_different_template_parameter_kind;
2192
0
  case diag::err_odr_parameter_pack_non_pack:
2193
0
    return diag::warn_odr_parameter_pack_non_pack;
2194
1.41k
  case diag::err_odr_non_type_parameter_type_inconsistent:
2195
1.41k
    return diag::warn_odr_non_type_parameter_type_inconsistent;
2196
1.55M
  }
2197
0
  llvm_unreachable("Diagnostic kind not handled in preceding switch");
2198
0
}
2199
2200
4.74M
bool StructuralEquivalenceContext::IsEquivalent(Decl *D1, Decl *D2) {
2201
2202
  // Ensure that the implementation functions (all static functions in this TU)
2203
  // never call the public ASTStructuralEquivalence::IsEquivalent() functions,
2204
  // because that will wreak havoc the internal state (DeclsToCheck and
2205
  // VisitedDecls members) and can cause faulty behaviour.
2206
  // In other words: Do not start a graph search from a new node with the
2207
  // internal data of another search in progress.
2208
  // FIXME: Better encapsulation and separation of internal and public
2209
  // functionality.
2210
4.74M
  assert(DeclsToCheck.empty());
2211
0
  assert(VisitedDecls.empty());
2212
2213
4.74M
  if (!::IsStructurallyEquivalent(*this, D1, D2))
2214
1.35M
    return false;
2215
2216
3.39M
  return !Finish();
2217
4.74M
}
2218
2219
22.8k
bool StructuralEquivalenceContext::IsEquivalent(QualType T1, QualType T2) {
2220
22.8k
  assert(DeclsToCheck.empty());
2221
0
  assert(VisitedDecls.empty());
2222
22.8k
  if (!::IsStructurallyEquivalent(*this, T1, T2))
2223
2.16k
    return false;
2224
2225
20.7k
  return !Finish();
2226
22.8k
}
2227
2228
82
bool StructuralEquivalenceContext::IsEquivalent(Stmt *S1, Stmt *S2) {
2229
82
  assert(DeclsToCheck.empty());
2230
0
  assert(VisitedDecls.empty());
2231
82
  if (!::IsStructurallyEquivalent(*this, S1, S2))
2232
40
    return false;
2233
2234
42
  return !Finish();
2235
82
}
2236
2237
6.07M
bool StructuralEquivalenceContext::CheckCommonEquivalence(Decl *D1, Decl *D2) {
2238
  // Check for equivalent described template.
2239
6.07M
  TemplateDecl *Template1 = D1->getDescribedTemplate();
2240
6.07M
  TemplateDecl *Template2 = D2->getDescribedTemplate();
2241
6.07M
  if ((Template1 != nullptr) != (Template2 != nullptr))
2242
176k
    return false;
2243
5.89M
  if (Template1 && 
!IsStructurallyEquivalent(*this, Template1, Template2)345
)
2244
48
    return false;
2245
2246
  // FIXME: Move check for identifier names into this function.
2247
2248
5.89M
  return true;
2249
5.89M
}
2250
2251
bool StructuralEquivalenceContext::CheckKindSpecificEquivalence(
2252
5.89M
    Decl *D1, Decl *D2) {
2253
2254
  // Kind mismatch.
2255
5.89M
  if (D1->getKind() != D2->getKind())
2256
63.3k
    return false;
2257
2258
  // Cast the Decls to their actual subclass so that the right overload of
2259
  // IsStructurallyEquivalent is called.
2260
5.83M
  switch (D1->getKind()) {
2261
0
#define ABSTRACT_DECL(DECL)
2262
0
#define DECL(DERIVED, BASE)                                                    \
2263
5.83M
  case Decl::Kind::DERIVED:                                                    \
2264
5.83M
    return ::IsStructurallyEquivalent(*this, static_cast<DERIVED##Decl *>(D1), \
2265
5.83M
                                      static_cast<DERIVED##Decl *>(D2));
2266
5.83M
#include 
"clang/AST/DeclNodes.inc"0
2267
5.83M
  }
2268
0
  return true;
2269
5.83M
}
2270
2271
3.41M
bool StructuralEquivalenceContext::Finish() {
2272
6.38M
  while (!DeclsToCheck.empty()) {
2273
    // Check the next declaration.
2274
6.07M
    std::pair<Decl *, Decl *> P = DeclsToCheck.front();
2275
6.07M
    DeclsToCheck.pop();
2276
2277
6.07M
    Decl *D1 = P.first;
2278
6.07M
    Decl *D2 = P.second;
2279
2280
6.07M
    bool Equivalent =
2281
6.07M
        CheckCommonEquivalence(D1, D2) && 
CheckKindSpecificEquivalence(D1, D2)5.89M
;
2282
2283
6.07M
    if (!Equivalent) {
2284
      // Note that these two declarations are not equivalent (and we already
2285
      // know about it).
2286
3.10M
      NonEquivalentDecls.insert(P);
2287
2288
3.10M
      return true;
2289
3.10M
    }
2290
6.07M
  }
2291
2292
305k
  return false;
2293
3.41M
}