Coverage Report

Created: 2021-09-21 08:58

/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
109k
                                     const DeclarationName Name2) {
114
109k
  if (Name1.getNameKind() != Name2.getNameKind())
115
0
    return false;
116
117
109k
  switch (Name1.getNameKind()) {
118
119
109k
  case DeclarationName::Identifier:
120
109k
    return IsStructurallyEquivalent(Name1.getAsIdentifierInfo(),
121
109k
                                    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
109k
  }
154
155
0
  llvm_unreachable("Unhandled kind of DeclarationName");
156
0
  return true;
157
109k
}
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
39.0k
  bool IsStmtEquivalent(const BinaryOperator *E1, const BinaryOperator *E2) {
177
39.0k
    return E1->getOpcode() == E2->getOpcode();
178
39.0k
  }
179
180
5.23k
  bool IsStmtEquivalent(const CallExpr *E1, const CallExpr *E2) {
181
    // FIXME: IsStructurallyEquivalent requires non-const Decls.
182
5.23k
    Decl *Callee1 = const_cast<Decl *>(E1->getCalleeDecl());
183
5.23k
    Decl *Callee2 = const_cast<Decl *>(E2->getCalleeDecl());
184
185
    // Compare whether both calls know their callee.
186
5.23k
    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
5.23k
    if (!static_cast<bool>(Callee1))
191
5.02k
      return true;
192
193
211
    assert(Callee2);
194
0
    return IsStructurallyEquivalent(Context, Callee1, Callee2);
195
5.23k
  }
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
109k
                        const DependentScopeDeclRefExpr *DE2) {
217
109k
    if (!IsStructurallyEquivalent(Context, DE1->getDeclName(),
218
109k
                                  DE2->getDeclName()))
219
461
      return false;
220
108k
    return IsStructurallyEquivalent(Context, DE1->getQualifier(),
221
108k
                                    DE2->getQualifier());
222
109k
  }
223
224
913k
  bool IsStmtEquivalent(const Expr *E1, const Expr *E2) {
225
913k
    return IsStructurallyEquivalent(Context, E1->getType(), E2->getType());
226
913k
  }
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
121k
                        const ImplicitCastExpr *CastE2) {
257
121k
    return IsStructurallyEquivalent(Context, CastE1->getType(),
258
121k
                                    CastE2->getType());
259
121k
  }
260
261
50.6k
  bool IsStmtEquivalent(const IntegerLiteral *E1, const IntegerLiteral *E2) {
262
50.6k
    return E1->getValue() == E2->getValue();
263
50.6k
  }
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
611k
  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.3k
                        const SubstNonTypeTemplateParmExpr *E2) {
292
19.3k
    return IsStructurallyEquivalent(Context, E1->getParameter(),
293
19.3k
                                    E2->getParameter());
294
19.3k
  }
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
41.9k
  bool IsStmtEquivalent(const TypeTraitExpr *E1, const TypeTraitExpr *E2) {
303
41.9k
    if (E1->getTrait() != E2->getTrait())
304
2
      return false;
305
306
44.0k
    
for (auto Pair : zip_longest(E1->getArgs(), E2->getArgs()))41.9k
{
307
44.0k
      Optional<TypeSourceInfo *> Child1 = std::get<0>(Pair);
308
44.0k
      Optional<TypeSourceInfo *> Child2 = std::get<1>(Pair);
309
      // Different number of args.
310
44.0k
      if (!Child1 || 
!Child244.0k
)
311
2
        return false;
312
313
44.0k
      if (!IsStructurallyEquivalent(Context, (*Child1)->getType(),
314
44.0k
                                    (*Child2)->getType()))
315
2
        return false;
316
44.0k
    }
317
41.9k
    return true;
318
41.9k
  }
319
320
  bool IsStmtEquivalent(const UnaryExprOrTypeTraitExpr *E1,
321
97
                        const UnaryExprOrTypeTraitExpr *E2) {
322
97
    if (E1->getKind() != E2->getKind())
323
2
      return false;
324
95
    return IsStructurallyEquivalent(Context, E1->getTypeOfArgument(),
325
95
                                    E2->getTypeOfArgument());
326
97
  }
327
328
46.1k
  bool IsStmtEquivalent(const UnaryOperator *E1, const UnaryOperator *E2) {
329
46.1k
    return E1->getOpcode() == E2->getOpcode();
330
46.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
611k
  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
611k
  bool TraverseStmt(const CLASS *S1, const CLASS *S2) {                        \
347
611k
    if (!TraverseStmt(static_cast<const PARENT *>(S1),                         \
348
611k
                      static_cast<const PARENT *>(S2)))                        \
349
611k
      
return false6
; \
350
611k
    
return IsStmtEquivalent(S1, S2)611k
; \
351
611k
  }
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::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::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::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::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::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
60
  bool TraverseStmt(const CLASS *S1, const CLASS *S2) {                        \
347
60
    if (!TraverseStmt(static_cast<const PARENT *>(S1),                         \
348
60
                      static_cast<const PARENT *>(S2)))                        \
349
60
      
return false0
; \
350
60
    return IsStmtEquivalent(S1, S2);                                           \
351
60
  }
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
39.0k
  bool TraverseStmt(const CLASS *S1, const CLASS *S2) {                        \
347
39.0k
    if (!TraverseStmt(static_cast<const PARENT *>(S1),                         \
348
39.0k
                      static_cast<const PARENT *>(S2)))                        \
349
39.0k
      
return false0
; \
350
39.0k
    return IsStmtEquivalent(S1, S2);                                           \
351
39.0k
  }
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
290
  bool TraverseStmt(const CLASS *S1, const CLASS *S2) {                        \
347
290
    if (!TraverseStmt(static_cast<const PARENT *>(S1),                         \
348
290
                      static_cast<const PARENT *>(S2)))                        \
349
290
      
return false0
; \
350
290
    return IsStmtEquivalent(S1, S2);                                           \
351
290
  }
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
2.71k
  bool TraverseStmt(const CLASS *S1, const CLASS *S2) {                        \
347
2.71k
    if (!TraverseStmt(static_cast<const PARENT *>(S1),                         \
348
2.71k
                      static_cast<const PARENT *>(S2)))                        \
349
2.71k
      
return false0
; \
350
2.71k
    return IsStmtEquivalent(S1, S2);                                           \
351
2.71k
  }
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
2.18k
  bool TraverseStmt(const CLASS *S1, const CLASS *S2) {                        \
347
2.18k
    if (!TraverseStmt(static_cast<const PARENT *>(S1),                         \
348
2.18k
                      static_cast<const PARENT *>(S2)))                        \
349
2.18k
      
return false0
; \
350
2.18k
    return IsStmtEquivalent(S1, S2);                                           \
351
2.18k
  }
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
4.91k
  bool TraverseStmt(const CLASS *S1, const CLASS *S2) {                        \
347
4.91k
    if (!TraverseStmt(static_cast<const PARENT *>(S1),                         \
348
4.91k
                      static_cast<const PARENT *>(S2)))                        \
349
4.91k
      
return false0
; \
350
4.91k
    return IsStmtEquivalent(S1, S2);                                           \
351
4.91k
  }
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
315
  bool TraverseStmt(const CLASS *S1, const CLASS *S2) {                        \
347
315
    if (!TraverseStmt(static_cast<const PARENT *>(S1),                         \
348
315
                      static_cast<const PARENT *>(S2)))                        \
349
315
      
return false0
; \
350
315
    return IsStmtEquivalent(S1, S2);                                           \
351
315
  }
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*)
ASTStructuralEquivalence.cpp:(anonymous namespace)::StmtComparer::TraverseStmt(clang::CStyleCastExpr const*, clang::CStyleCastExpr const*)
Line
Count
Source
346
288
  bool TraverseStmt(const CLASS *S1, const CLASS *S2) {                        \
347
288
    if (!TraverseStmt(static_cast<const PARENT *>(S1),                         \
348
288
                      static_cast<const PARENT *>(S2)))                        \
349
288
      
return false0
; \
350
288
    return IsStmtEquivalent(S1, S2);                                           \
351
288
  }
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*)
ASTStructuralEquivalence.cpp:(anonymous namespace)::StmtComparer::TraverseStmt(clang::CXXStaticCastExpr const*, clang::CXXStaticCastExpr const*)
Line
Count
Source
346
54
  bool TraverseStmt(const CLASS *S1, const CLASS *S2) {                        \
347
54
    if (!TraverseStmt(static_cast<const PARENT *>(S1),                         \
348
54
                      static_cast<const PARENT *>(S2)))                        \
349
54
      
return false0
; \
350
54
    return IsStmtEquivalent(S1, S2);                                           \
351
54
  }
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
121k
  bool TraverseStmt(const CLASS *S1, const CLASS *S2) {                        \
347
121k
    if (!TraverseStmt(static_cast<const PARENT *>(S1),                         \
348
121k
                      static_cast<const PARENT *>(S2)))                        \
349
121k
      
return false0
; \
350
121k
    return IsStmtEquivalent(S1, S2);                                           \
351
121k
  }
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
167k
  bool TraverseStmt(const CLASS *S1, const CLASS *S2) {                        \
347
167k
    if (!TraverseStmt(static_cast<const PARENT *>(S1),                         \
348
167k
                      static_cast<const PARENT *>(S2)))                        \
349
167k
      
return false0
; \
350
167k
    return IsStmtEquivalent(S1, S2);                                           \
351
167k
  }
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
109k
  bool TraverseStmt(const CLASS *S1, const CLASS *S2) {                        \
347
109k
    if (!TraverseStmt(static_cast<const PARENT *>(S1),                         \
348
109k
                      static_cast<const PARENT *>(S2)))                        \
349
109k
      
return false0
; \
350
109k
    return IsStmtEquivalent(S1, S2);                                           \
351
109k
  }
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
35
  bool TraverseStmt(const CLASS *S1, const CLASS *S2) {                        \
347
35
    if (!TraverseStmt(static_cast<const PARENT *>(S1),                         \
348
35
                      static_cast<const PARENT *>(S2)))                        \
349
35
      
return false0
; \
350
35
    return IsStmtEquivalent(S1, S2);                                           \
351
35
  }
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.6k
  bool TraverseStmt(const CLASS *S1, const CLASS *S2) {                        \
347
50.6k
    if (!TraverseStmt(static_cast<const PARENT *>(S1),                         \
348
50.6k
                      static_cast<const PARENT *>(S2)))                        \
349
50.6k
      
return false2
; \
350
50.6k
    
return IsStmtEquivalent(S1, S2)50.6k
; \
351
50.6k
  }
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
1.41k
  bool TraverseStmt(const CLASS *S1, const CLASS *S2) {                        \
347
1.41k
    if (!TraverseStmt(static_cast<const PARENT *>(S1),                         \
348
1.41k
                      static_cast<const PARENT *>(S2)))                        \
349
1.41k
      
return false0
; \
350
1.41k
    return IsStmtEquivalent(S1, S2);                                           \
351
1.41k
  }
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
822
  bool TraverseStmt(const CLASS *S1, const CLASS *S2) {                        \
347
822
    if (!TraverseStmt(static_cast<const PARENT *>(S1),                         \
348
822
                      static_cast<const PARENT *>(S2)))                        \
349
822
      
return false0
; \
350
822
    return IsStmtEquivalent(S1, S2);                                           \
351
822
  }
ASTStructuralEquivalence.cpp:(anonymous namespace)::StmtComparer::TraverseStmt(clang::ParenExpr const*, clang::ParenExpr const*)
Line
Count
Source
346
2.11k
  bool TraverseStmt(const CLASS *S1, const CLASS *S2) {                        \
347
2.11k
    if (!TraverseStmt(static_cast<const PARENT *>(S1),                         \
348
2.11k
                      static_cast<const PARENT *>(S2)))                        \
349
2.11k
      
return false0
; \
350
2.11k
    return IsStmtEquivalent(S1, S2);                                           \
351
2.11k
  }
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.23k
  bool TraverseStmt(const CLASS *S1, const CLASS *S2) {                        \
347
1.23k
    if (!TraverseStmt(static_cast<const PARENT *>(S1),                         \
348
1.23k
                      static_cast<const PARENT *>(S2)))                        \
349
1.23k
      
return false0
; \
350
1.23k
    return IsStmtEquivalent(S1, S2);                                           \
351
1.23k
  }
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.3k
  bool TraverseStmt(const CLASS *S1, const CLASS *S2) {                        \
347
19.3k
    if (!TraverseStmt(static_cast<const PARENT *>(S1),                         \
348
19.3k
                      static_cast<const PARENT *>(S2)))                        \
349
19.3k
      
return false0
; \
350
19.3k
    return IsStmtEquivalent(S1, S2);                                           \
351
19.3k
  }
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
41.9k
  bool TraverseStmt(const CLASS *S1, const CLASS *S2) {                        \
347
41.9k
    if (!TraverseStmt(static_cast<const PARENT *>(S1),                         \
348
41.9k
                      static_cast<const PARENT *>(S2)))                        \
349
41.9k
      
return false0
; \
350
41.9k
    return IsStmtEquivalent(S1, S2);                                           \
351
41.9k
  }
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
97
  bool TraverseStmt(const CLASS *S1, const CLASS *S2) {                        \
347
97
    if (!TraverseStmt(static_cast<const PARENT *>(S1),                         \
348
97
                      static_cast<const PARENT *>(S2)))                        \
349
97
      
return false0
; \
350
97
    return IsStmtEquivalent(S1, S2);                                           \
351
97
  }
ASTStructuralEquivalence.cpp:(anonymous namespace)::StmtComparer::TraverseStmt(clang::UnaryOperator const*, clang::UnaryOperator const*)
Line
Count
Source
346
46.1k
  bool TraverseStmt(const CLASS *S1, const CLASS *S2) {                        \
347
46.1k
    if (!TraverseStmt(static_cast<const PARENT *>(S1),                         \
348
46.1k
                      static_cast<const PARENT *>(S2)))                        \
349
46.1k
      
return false0
; \
350
46.1k
    return IsStmtEquivalent(S1, S2);                                           \
351
46.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
614k
  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
614k
  bool IsEquivalent(const Stmt *S1, const Stmt *S2) {
361
614k
    if (S1->getStmtClass() != S2->getStmtClass())
362
3.46k
      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
611k
    switch (S1->getStmtClass()) {
370
0
    case Stmt::NoStmtClass:
371
0
      llvm_unreachable("Can't traverse NoStmtClass");
372
0
#define STMT(CLASS, PARENT)                                                    \
373
611k
  case Stmt::StmtClass::CLASS##Class:                                          \
374
611k
    return TraverseStmt(static_cast<const CLASS *>(S1),                        \
375
611k
                        static_cast<const CLASS *>(S2));
376
0
#define ABSTRACT_STMT(S)
377
611k
#include 
"clang/AST/StmtNodes.inc"0
378
611k
    }
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
614k
                                     const Stmt *S1, const Stmt *S2) {
387
614k
  if (!S1 || !S2)
388
0
    return S1 == S2;
389
390
  // Compare the statements itself.
391
614k
  StmtComparer Comparer(Context);
392
614k
  if (!Comparer.IsEquivalent(S1, S2))
393
5.43k
    return false;
394
395
  // Iterate over the children of both statements and also compare them.
396
609k
  for (auto Pair : zip_longest(S1->children(), S2->children())) {
397
280k
    Optional<const Stmt *> Child1 = std::get<0>(Pair);
398
280k
    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
280k
    if (!Child1 || !Child2)
402
0
      return false;
403
280k
    if (!IsStructurallyEquivalent(Context, *Child1, *Child2))
404
7.88k
      return false;
405
280k
  }
406
601k
  return true;
407
609k
}
408
409
/// Determine whether two identifiers are equivalent.
410
static bool IsStructurallyEquivalent(const IdentifierInfo *Name1,
411
2.62M
                                     const IdentifierInfo *Name2) {
412
2.62M
  if (!Name1 || 
!Name21.91M
)
413
713k
    return Name1 == Name2;
414
415
1.90M
  return Name1->getName() == Name2->getName();
416
2.62M
}
417
418
/// Determine whether two nested-name-specifiers are equivalent.
419
static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
420
                                     NestedNameSpecifier *NNS1,
421
477k
                                     NestedNameSpecifier *NNS2) {
422
477k
  if (NNS1->getKind() != NNS2->getKind())
423
42
    return false;
424
425
477k
  NestedNameSpecifier *Prefix1 = NNS1->getPrefix(),
426
477k
                      *Prefix2 = NNS2->getPrefix();
427
477k
  if ((bool)Prefix1 != (bool)Prefix2)
428
0
    return false;
429
430
477k
  if (Prefix1)
431
2.92k
    if (!IsStructurallyEquivalent(Context, Prefix1, Prefix2))
432
0
      return false;
433
434
477k
  switch (NNS1->getKind()) {
435
2.68k
  case NestedNameSpecifier::Identifier:
436
2.68k
    return IsStructurallyEquivalent(NNS1->getAsIdentifier(),
437
2.68k
                                    NNS2->getAsIdentifier());
438
243
  case NestedNameSpecifier::Namespace:
439
243
    return IsStructurallyEquivalent(Context, NNS1->getAsNamespace(),
440
243
                                    NNS2->getAsNamespace());
441
0
  case NestedNameSpecifier::NamespaceAlias:
442
0
    return IsStructurallyEquivalent(Context, NNS1->getAsNamespaceAlias(),
443
0
                                    NNS2->getAsNamespaceAlias());
444
474k
  case NestedNameSpecifier::TypeSpec:
445
474k
  case NestedNameSpecifier::TypeSpecWithTemplate:
446
474k
    return IsStructurallyEquivalent(Context, QualType(NNS1->getAsType(), 0),
447
474k
                                    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
477k
  }
454
0
  return false;
455
477k
}
456
457
static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
458
                                     const TemplateName &N1,
459
856k
                                     const TemplateName &N2) {
460
856k
  TemplateDecl *TemplateDeclN1 = N1.getAsTemplateDecl();
461
856k
  TemplateDecl *TemplateDeclN2 = N2.getAsTemplateDecl();
462
856k
  if (TemplateDeclN1 && TemplateDeclN2) {
463
856k
    if (!IsStructurallyEquivalent(Context, TemplateDeclN1, TemplateDeclN2))
464
24.1k
      return false;
465
    // If the kind is different we compare only the template decl.
466
832k
    if (N1.getKind() != N2.getKind())
467
8
      return true;
468
832k
  } 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
832k
  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
832k
   case TemplateName::Template:
518
832k
   case TemplateName::QualifiedTemplate:
519
832k
   case TemplateName::SubstTemplateTemplateParm:
520
     // It is sufficient to check value of getAsTemplateDecl.
521
832k
     break;
522
523
832k
  }
524
525
832k
  return true;
526
832k
}
527
528
/// Determine whether two template arguments are equivalent.
529
static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
530
                                     const TemplateArgument &Arg1,
531
1.99M
                                     const TemplateArgument &Arg2) {
532
1.99M
  if (Arg1.getKind() != Arg2.getKind())
533
6.53k
    return false;
534
535
1.98M
  switch (Arg1.getKind()) {
536
0
  case TemplateArgument::Null:
537
0
    return true;
538
539
1.54M
  case TemplateArgument::Type:
540
1.54M
    return IsStructurallyEquivalent(Context, Arg1.getAsType(), Arg2.getAsType());
541
542
103k
  case TemplateArgument::Integral:
543
103k
    if (!IsStructurallyEquivalent(Context, Arg1.getIntegralType(),
544
103k
                                          Arg2.getIntegralType()))
545
0
      return false;
546
547
103k
    return llvm::APSInt::isSameValue(Arg1.getAsIntegral(),
548
103k
                                     Arg2.getAsIntegral());
549
550
0
  case TemplateArgument::Declaration:
551
0
    return IsStructurallyEquivalent(Context, Arg1.getAsDecl(), Arg2.getAsDecl());
552
553
0
  case TemplateArgument::NullPtr:
554
0
    return true; // FIXME: Is this correct?
555
556
10
  case TemplateArgument::Template:
557
10
    return IsStructurallyEquivalent(Context, Arg1.getAsTemplate(),
558
10
                                    Arg2.getAsTemplate());
559
560
0
  case TemplateArgument::TemplateExpansion:
561
0
    return IsStructurallyEquivalent(Context,
562
0
                                    Arg1.getAsTemplateOrTemplatePattern(),
563
0
                                    Arg2.getAsTemplateOrTemplatePattern());
564
565
324k
  case TemplateArgument::Expression:
566
324k
    return IsStructurallyEquivalent(Context, Arg1.getAsExpr(),
567
324k
                                    Arg2.getAsExpr());
568
569
12.6k
  case TemplateArgument::Pack:
570
12.6k
    if (Arg1.pack_size() != Arg2.pack_size())
571
0
      return false;
572
573
25.3k
    
for (unsigned I = 0, N = Arg1.pack_size(); 12.6k
I != N;
++I12.7k
)
574
13.5k
      if (!IsStructurallyEquivalent(Context, Arg1.pack_begin()[I],
575
13.5k
                                    Arg2.pack_begin()[I]))
576
768
        return false;
577
578
11.8k
    return true;
579
1.98M
  }
580
581
0
  llvm_unreachable("Invalid template argument kind");
582
0
}
583
584
/// Determine structural equivalence for the common part of array
585
/// types.
586
static bool IsArrayStructurallyEquivalent(StructuralEquivalenceContext &Context,
587
                                          const ArrayType *Array1,
588
2.77k
                                          const ArrayType *Array2) {
589
2.77k
  if (!IsStructurallyEquivalent(Context, Array1->getElementType(),
590
2.77k
                                Array2->getElementType()))
591
0
    return false;
592
2.77k
  if (Array1->getSizeModifier() != Array2->getSizeModifier())
593
0
    return false;
594
2.77k
  if (Array1->getIndexTypeQualifiers() != Array2->getIndexTypeQualifiers())
595
0
    return false;
596
597
2.77k
  return true;
598
2.77k
}
599
600
/// Determine structural equivalence based on the ExtInfo of functions. This
601
/// is inspired by ASTContext::mergeFunctionTypes(), we compare calling
602
/// conventions bits but must not compare some other bits.
603
static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
604
                                     FunctionType::ExtInfo EI1,
605
208k
                                     FunctionType::ExtInfo EI2) {
606
  // Compatible functions must have compatible calling conventions.
607
208k
  if (EI1.getCC() != EI2.getCC())
608
34
    return false;
609
610
  // Regparm is part of the calling convention.
611
208k
  if (EI1.getHasRegParm() != EI2.getHasRegParm())
612
0
    return false;
613
208k
  if (EI1.getRegParm() != EI2.getRegParm())
614
0
    return false;
615
616
208k
  if (EI1.getProducesResult() != EI2.getProducesResult())
617
0
    return false;
618
208k
  if (EI1.getNoCallerSavedRegs() != EI2.getNoCallerSavedRegs())
619
2
    return false;
620
208k
  if (EI1.getNoCfCheck() != EI2.getNoCfCheck())
621
0
    return false;
622
623
208k
  return true;
624
208k
}
625
626
/// Check the equivalence of exception specifications.
627
static bool IsEquivalentExceptionSpec(StructuralEquivalenceContext &Context,
628
                                      const FunctionProtoType *Proto1,
629
231k
                                      const FunctionProtoType *Proto2) {
630
631
231k
  auto Spec1 = Proto1->getExceptionSpecType();
632
231k
  auto Spec2 = Proto2->getExceptionSpecType();
633
634
231k
  if (isUnresolvedExceptionSpec(Spec1) || 
isUnresolvedExceptionSpec(Spec2)226k
)
635
4.53k
    return true;
636
637
226k
  if (Spec1 != Spec2)
638
15.6k
    return false;
639
210k
  if (Spec1 == EST_Dynamic) {
640
0
    if (Proto1->getNumExceptions() != Proto2->getNumExceptions())
641
0
      return false;
642
0
    for (unsigned I = 0, N = Proto1->getNumExceptions(); I != N; ++I) {
643
0
      if (!IsStructurallyEquivalent(Context, Proto1->getExceptionType(I),
644
0
                                    Proto2->getExceptionType(I)))
645
0
        return false;
646
0
    }
647
210k
  } else if (isComputedNoexcept(Spec1)) {
648
7.31k
    if (!IsStructurallyEquivalent(Context, Proto1->getNoexceptExpr(),
649
7.31k
                                  Proto2->getNoexceptExpr()))
650
1.51k
      return false;
651
7.31k
  }
652
653
209k
  return true;
654
210k
}
655
656
/// Determine structural equivalence of two types.
657
static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
658
5.90M
                                     QualType T1, QualType T2) {
659
5.90M
  if (T1.isNull() || T2.isNull())
660
0
    return T1.isNull() && T2.isNull();
661
662
5.90M
  QualType OrigT1 = T1;
663
5.90M
  QualType OrigT2 = T2;
664
665
5.90M
  if (!Context.StrictTypeSpelling) {
666
    // We aren't being strict about token-to-token equivalence of types,
667
    // so map down to the canonical type.
668
5.90M
    T1 = Context.FromCtx.getCanonicalType(T1);
669
5.90M
    T2 = Context.ToCtx.getCanonicalType(T2);
670
5.90M
  }
671
672
5.90M
  if (T1.getQualifiers() != T2.getQualifiers())
673
3.33k
    return false;
674
675
5.90M
  Type::TypeClass TC = T1->getTypeClass();
676
677
5.90M
  if (T1->getTypeClass() != T2->getTypeClass()) {
678
    // Compare function types with prototypes vs. without prototypes as if
679
    // both did not have prototypes.
680
181k
    if (T1->getTypeClass() == Type::FunctionProto &&
681
181k
        
T2->getTypeClass() == Type::FunctionNoProto602
)
682
2
      TC = Type::FunctionNoProto;
683
181k
    else if (T1->getTypeClass() == Type::FunctionNoProto &&
684
181k
             
T2->getTypeClass() == Type::FunctionProto0
)
685
0
      TC = Type::FunctionNoProto;
686
181k
    else
687
181k
      return false;
688
181k
  }
689
690
5.72M
  switch (TC) {
691
1.19M
  case Type::Builtin:
692
    // FIXME: Deal with Char_S/Char_U.
693
1.19M
    if (cast<BuiltinType>(T1)->getKind() != cast<BuiltinType>(T2)->getKind())
694
19.8k
      return false;
695
1.17M
    break;
696
697
1.17M
  case Type::Complex:
698
0
    if (!IsStructurallyEquivalent(Context,
699
0
                                  cast<ComplexType>(T1)->getElementType(),
700
0
                                  cast<ComplexType>(T2)->getElementType()))
701
0
      return false;
702
0
    break;
703
704
0
  case Type::Adjusted:
705
0
  case Type::Decayed:
706
0
    if (!IsStructurallyEquivalent(Context,
707
0
                                  cast<AdjustedType>(T1)->getOriginalType(),
708
0
                                  cast<AdjustedType>(T2)->getOriginalType()))
709
0
      return false;
710
0
    break;
711
712
119k
  case Type::Pointer:
713
119k
    if (!IsStructurallyEquivalent(Context,
714
119k
                                  cast<PointerType>(T1)->getPointeeType(),
715
119k
                                  cast<PointerType>(T2)->getPointeeType()))
716
3.46k
      return false;
717
115k
    break;
718
719
115k
  case Type::BlockPointer:
720
0
    if (!IsStructurallyEquivalent(Context,
721
0
                                  cast<BlockPointerType>(T1)->getPointeeType(),
722
0
                                  cast<BlockPointerType>(T2)->getPointeeType()))
723
0
      return false;
724
0
    break;
725
726
334k
  case Type::LValueReference:
727
355k
  case Type::RValueReference: {
728
355k
    const auto *Ref1 = cast<ReferenceType>(T1);
729
355k
    const auto *Ref2 = cast<ReferenceType>(T2);
730
355k
    if (Ref1->isSpelledAsLValue() != Ref2->isSpelledAsLValue())
731
0
      return false;
732
355k
    if (Ref1->isInnerRef() != Ref2->isInnerRef())
733
0
      return false;
734
355k
    if (!IsStructurallyEquivalent(Context, Ref1->getPointeeTypeAsWritten(),
735
355k
                                  Ref2->getPointeeTypeAsWritten()))
736
101k
      return false;
737
253k
    break;
738
355k
  }
739
740
253k
  case Type::MemberPointer: {
741
0
    const auto *MemPtr1 = cast<MemberPointerType>(T1);
742
0
    const auto *MemPtr2 = cast<MemberPointerType>(T2);
743
0
    if (!IsStructurallyEquivalent(Context, MemPtr1->getPointeeType(),
744
0
                                  MemPtr2->getPointeeType()))
745
0
      return false;
746
0
    if (!IsStructurallyEquivalent(Context, QualType(MemPtr1->getClass(), 0),
747
0
                                  QualType(MemPtr2->getClass(), 0)))
748
0
      return false;
749
0
    break;
750
0
  }
751
752
937
  case Type::ConstantArray: {
753
937
    const auto *Array1 = cast<ConstantArrayType>(T1);
754
937
    const auto *Array2 = cast<ConstantArrayType>(T2);
755
937
    if (!llvm::APInt::isSameValue(Array1->getSize(), Array2->getSize()))
756
3
      return false;
757
758
934
    if (!IsArrayStructurallyEquivalent(Context, Array1, Array2))
759
0
      return false;
760
934
    break;
761
934
  }
762
763
934
  case Type::IncompleteArray:
764
0
    if (!IsArrayStructurallyEquivalent(Context, cast<ArrayType>(T1),
765
0
                                       cast<ArrayType>(T2)))
766
0
      return false;
767
0
    break;
768
769
0
  case Type::VariableArray: {
770
0
    const auto *Array1 = cast<VariableArrayType>(T1);
771
0
    const auto *Array2 = cast<VariableArrayType>(T2);
772
0
    if (!IsStructurallyEquivalent(Context, Array1->getSizeExpr(),
773
0
                                  Array2->getSizeExpr()))
774
0
      return false;
775
776
0
    if (!IsArrayStructurallyEquivalent(Context, Array1, Array2))
777
0
      return false;
778
779
0
    break;
780
0
  }
781
782
1.83k
  case Type::DependentSizedArray: {
783
1.83k
    const auto *Array1 = cast<DependentSizedArrayType>(T1);
784
1.83k
    const auto *Array2 = cast<DependentSizedArrayType>(T2);
785
1.83k
    if (!IsStructurallyEquivalent(Context, Array1->getSizeExpr(),
786
1.83k
                                  Array2->getSizeExpr()))
787
0
      return false;
788
789
1.83k
    if (!IsArrayStructurallyEquivalent(Context, Array1, Array2))
790
0
      return false;
791
792
1.83k
    break;
793
1.83k
  }
794
795
1.83k
  case Type::DependentAddressSpace: {
796
0
    const auto *DepAddressSpace1 = cast<DependentAddressSpaceType>(T1);
797
0
    const auto *DepAddressSpace2 = cast<DependentAddressSpaceType>(T2);
798
0
    if (!IsStructurallyEquivalent(Context, DepAddressSpace1->getAddrSpaceExpr(),
799
0
                                  DepAddressSpace2->getAddrSpaceExpr()))
800
0
      return false;
801
0
    if (!IsStructurallyEquivalent(Context, DepAddressSpace1->getPointeeType(),
802
0
                                  DepAddressSpace2->getPointeeType()))
803
0
      return false;
804
805
0
    break;
806
0
  }
807
808
0
  case Type::DependentSizedExtVector: {
809
0
    const auto *Vec1 = cast<DependentSizedExtVectorType>(T1);
810
0
    const auto *Vec2 = cast<DependentSizedExtVectorType>(T2);
811
0
    if (!IsStructurallyEquivalent(Context, Vec1->getSizeExpr(),
812
0
                                  Vec2->getSizeExpr()))
813
0
      return false;
814
0
    if (!IsStructurallyEquivalent(Context, Vec1->getElementType(),
815
0
                                  Vec2->getElementType()))
816
0
      return false;
817
0
    break;
818
0
  }
819
820
0
  case Type::DependentVector: {
821
0
    const auto *Vec1 = cast<DependentVectorType>(T1);
822
0
    const auto *Vec2 = cast<DependentVectorType>(T2);
823
0
    if (Vec1->getVectorKind() != Vec2->getVectorKind())
824
0
      return false;
825
0
    if (!IsStructurallyEquivalent(Context, Vec1->getSizeExpr(),
826
0
                                  Vec2->getSizeExpr()))
827
0
      return false;
828
0
    if (!IsStructurallyEquivalent(Context, Vec1->getElementType(),
829
0
                                  Vec2->getElementType()))
830
0
      return false;
831
0
    break;
832
0
  }
833
834
0
  case Type::Vector:
835
0
  case Type::ExtVector: {
836
0
    const auto *Vec1 = cast<VectorType>(T1);
837
0
    const auto *Vec2 = cast<VectorType>(T2);
838
0
    if (!IsStructurallyEquivalent(Context, Vec1->getElementType(),
839
0
                                  Vec2->getElementType()))
840
0
      return false;
841
0
    if (Vec1->getNumElements() != Vec2->getNumElements())
842
0
      return false;
843
0
    if (Vec1->getVectorKind() != Vec2->getVectorKind())
844
0
      return false;
845
0
    break;
846
0
  }
847
848
0
  case Type::DependentSizedMatrix: {
849
0
    const DependentSizedMatrixType *Mat1 = cast<DependentSizedMatrixType>(T1);
850
0
    const DependentSizedMatrixType *Mat2 = cast<DependentSizedMatrixType>(T2);
851
    // The element types, row and column expressions must be structurally
852
    // equivalent.
853
0
    if (!IsStructurallyEquivalent(Context, Mat1->getRowExpr(),
854
0
                                  Mat2->getRowExpr()) ||
855
0
        !IsStructurallyEquivalent(Context, Mat1->getColumnExpr(),
856
0
                                  Mat2->getColumnExpr()) ||
857
0
        !IsStructurallyEquivalent(Context, Mat1->getElementType(),
858
0
                                  Mat2->getElementType()))
859
0
      return false;
860
0
    break;
861
0
  }
862
863
0
  case Type::ConstantMatrix: {
864
0
    const ConstantMatrixType *Mat1 = cast<ConstantMatrixType>(T1);
865
0
    const ConstantMatrixType *Mat2 = cast<ConstantMatrixType>(T2);
866
    // The element types must be structurally equivalent and the number of rows
867
    // and columns must match.
868
0
    if (!IsStructurallyEquivalent(Context, Mat1->getElementType(),
869
0
                                  Mat2->getElementType()) ||
870
0
        Mat1->getNumRows() != Mat2->getNumRows() ||
871
0
        Mat1->getNumColumns() != Mat2->getNumColumns())
872
0
      return false;
873
0
    break;
874
0
  }
875
876
617k
  case Type::FunctionProto: {
877
617k
    const auto *Proto1 = cast<FunctionProtoType>(T1);
878
617k
    const auto *Proto2 = cast<FunctionProtoType>(T2);
879
880
617k
    if (Proto1->getNumParams() != Proto2->getNumParams())
881
97.3k
      return false;
882
1.02M
    
for (unsigned I = 0, N = Proto1->getNumParams(); 519k
I != N;
++I507k
) {
883
796k
      if (!IsStructurallyEquivalent(Context, Proto1->getParamType(I),
884
796k
                                    Proto2->getParamType(I)))
885
288k
        return false;
886
796k
    }
887
231k
    if (Proto1->isVariadic() != Proto2->isVariadic())
888
2
      return false;
889
890
231k
    if (Proto1->getMethodQuals() != Proto2->getMethodQuals())
891
168
      return false;
892
893
    // Check exceptions, this information is lost in canonical type.
894
231k
    const auto *OrigProto1 =
895
231k
        cast<FunctionProtoType>(OrigT1.getDesugaredType(Context.FromCtx));
896
231k
    const auto *OrigProto2 =
897
231k
        cast<FunctionProtoType>(OrigT2.getDesugaredType(Context.ToCtx));
898
231k
    if (!IsEquivalentExceptionSpec(Context, OrigProto1, OrigProto2))
899
17.1k
      return false;
900
901
    // Fall through to check the bits common with FunctionNoProtoType.
902
231k
    
LLVM_FALLTHROUGH213k
;
903
213k
  }
904
905
213k
  case Type::FunctionNoProto: {
906
213k
    const auto *Function1 = cast<FunctionType>(T1);
907
213k
    const auto *Function2 = cast<FunctionType>(T2);
908
213k
    if (!IsStructurallyEquivalent(Context, Function1->getReturnType(),
909
213k
                                  Function2->getReturnType()))
910
5.40k
      return false;
911
208k
    if (!IsStructurallyEquivalent(Context, Function1->getExtInfo(),
912
208k
                                  Function2->getExtInfo()))
913
36
      return false;
914
208k
    break;
915
208k
  }
916
917
208k
  case Type::UnresolvedUsing:
918
0
    if (!IsStructurallyEquivalent(Context,
919
0
                                  cast<UnresolvedUsingType>(T1)->getDecl(),
920
0
                                  cast<UnresolvedUsingType>(T2)->getDecl()))
921
0
      return false;
922
0
    break;
923
924
0
  case Type::Attributed:
925
0
    if (!IsStructurallyEquivalent(Context,
926
0
                                  cast<AttributedType>(T1)->getModifiedType(),
927
0
                                  cast<AttributedType>(T2)->getModifiedType()))
928
0
      return false;
929
0
    if (!IsStructurallyEquivalent(
930
0
            Context, cast<AttributedType>(T1)->getEquivalentType(),
931
0
            cast<AttributedType>(T2)->getEquivalentType()))
932
0
      return false;
933
0
    break;
934
935
0
  case Type::Paren:
936
0
    if (!IsStructurallyEquivalent(Context, cast<ParenType>(T1)->getInnerType(),
937
0
                                  cast<ParenType>(T2)->getInnerType()))
938
0
      return false;
939
0
    break;
940
941
0
  case Type::MacroQualified:
942
0
    if (!IsStructurallyEquivalent(
943
0
            Context, cast<MacroQualifiedType>(T1)->getUnderlyingType(),
944
0
            cast<MacroQualifiedType>(T2)->getUnderlyingType()))
945
0
      return false;
946
0
    break;
947
948
0
  case Type::Typedef:
949
0
    if (!IsStructurallyEquivalent(Context, cast<TypedefType>(T1)->getDecl(),
950
0
                                  cast<TypedefType>(T2)->getDecl()))
951
0
      return false;
952
0
    break;
953
954
0
  case Type::TypeOfExpr:
955
0
    if (!IsStructurallyEquivalent(
956
0
            Context, cast<TypeOfExprType>(T1)->getUnderlyingExpr(),
957
0
            cast<TypeOfExprType>(T2)->getUnderlyingExpr()))
958
0
      return false;
959
0
    break;
960
961
0
  case Type::TypeOf:
962
0
    if (!IsStructurallyEquivalent(Context,
963
0
                                  cast<TypeOfType>(T1)->getUnderlyingType(),
964
0
                                  cast<TypeOfType>(T2)->getUnderlyingType()))
965
0
      return false;
966
0
    break;
967
968
0
  case Type::UnaryTransform:
969
0
    if (!IsStructurallyEquivalent(
970
0
            Context, cast<UnaryTransformType>(T1)->getUnderlyingType(),
971
0
            cast<UnaryTransformType>(T2)->getUnderlyingType()))
972
0
      return false;
973
0
    break;
974
975
1.33k
  case Type::Decltype:
976
1.33k
    if (!IsStructurallyEquivalent(Context,
977
1.33k
                                  cast<DecltypeType>(T1)->getUnderlyingExpr(),
978
1.33k
                                  cast<DecltypeType>(T2)->getUnderlyingExpr()))
979
24
      return false;
980
1.30k
    break;
981
982
1.30k
  case Type::Auto: {
983
0
    auto *Auto1 = cast<AutoType>(T1);
984
0
    auto *Auto2 = cast<AutoType>(T2);
985
0
    if (!IsStructurallyEquivalent(Context, Auto1->getDeducedType(),
986
0
                                  Auto2->getDeducedType()))
987
0
      return false;
988
0
    if (Auto1->isConstrained() != Auto2->isConstrained())
989
0
      return false;
990
0
    if (Auto1->isConstrained()) {
991
0
      if (Auto1->getTypeConstraintConcept() !=
992
0
          Auto2->getTypeConstraintConcept())
993
0
        return false;
994
0
      ArrayRef<TemplateArgument> Auto1Args =
995
0
          Auto1->getTypeConstraintArguments();
996
0
      ArrayRef<TemplateArgument> Auto2Args =
997
0
          Auto2->getTypeConstraintArguments();
998
0
      if (Auto1Args.size() != Auto2Args.size())
999
0
        return false;
1000
0
      for (unsigned I = 0, N = Auto1Args.size(); I != N; ++I) {
1001
0
        if (!IsStructurallyEquivalent(Context, Auto1Args[I], Auto2Args[I]))
1002
0
          return false;
1003
0
      }
1004
0
    }
1005
0
    break;
1006
0
  }
1007
1008
0
  case Type::DeducedTemplateSpecialization: {
1009
0
    const auto *DT1 = cast<DeducedTemplateSpecializationType>(T1);
1010
0
    const auto *DT2 = cast<DeducedTemplateSpecializationType>(T2);
1011
0
    if (!IsStructurallyEquivalent(Context, DT1->getTemplateName(),
1012
0
                                  DT2->getTemplateName()))
1013
0
      return false;
1014
0
    if (!IsStructurallyEquivalent(Context, DT1->getDeducedType(),
1015
0
                                  DT2->getDeducedType()))
1016
0
      return false;
1017
0
    break;
1018
0
  }
1019
1020
212k
  case Type::Record:
1021
214k
  case Type::Enum:
1022
214k
    if (!IsStructurallyEquivalent(Context, cast<TagType>(T1)->getDecl(),
1023
214k
                                  cast<TagType>(T2)->getDecl()))
1024
9.74k
      return false;
1025
205k
    break;
1026
1027
1.90M
  case Type::TemplateTypeParm: {
1028
1.90M
    const auto *Parm1 = cast<TemplateTypeParmType>(T1);
1029
1.90M
    const auto *Parm2 = cast<TemplateTypeParmType>(T2);
1030
1.90M
    if (Parm1->getDepth() != Parm2->getDepth())
1031
5.17k
      return false;
1032
1.89M
    if (Parm1->getIndex() != Parm2->getIndex())
1033
959
      return false;
1034
1.89M
    if (Parm1->isParameterPack() != Parm2->isParameterPack())
1035
0
      return false;
1036
1037
    // Names of template type parameters are never significant.
1038
1.89M
    break;
1039
1.89M
  }
1040
1041
1.89M
  case Type::SubstTemplateTypeParm: {
1042
0
    const auto *Subst1 = cast<SubstTemplateTypeParmType>(T1);
1043
0
    const auto *Subst2 = cast<SubstTemplateTypeParmType>(T2);
1044
0
    if (!IsStructurallyEquivalent(Context,
1045
0
                                  QualType(Subst1->getReplacedParameter(), 0),
1046
0
                                  QualType(Subst2->getReplacedParameter(), 0)))
1047
0
      return false;
1048
0
    if (!IsStructurallyEquivalent(Context, Subst1->getReplacementType(),
1049
0
                                  Subst2->getReplacementType()))
1050
0
      return false;
1051
0
    break;
1052
0
  }
1053
1054
0
  case Type::SubstTemplateTypeParmPack: {
1055
0
    const auto *Subst1 = cast<SubstTemplateTypeParmPackType>(T1);
1056
0
    const auto *Subst2 = cast<SubstTemplateTypeParmPackType>(T2);
1057
0
    if (!IsStructurallyEquivalent(Context,
1058
0
                                  QualType(Subst1->getReplacedParameter(), 0),
1059
0
                                  QualType(Subst2->getReplacedParameter(), 0)))
1060
0
      return false;
1061
0
    if (!IsStructurallyEquivalent(Context, Subst1->getArgumentPack(),
1062
0
                                  Subst2->getArgumentPack()))
1063
0
      return false;
1064
0
    break;
1065
0
  }
1066
1067
856k
  case Type::TemplateSpecialization: {
1068
856k
    const auto *Spec1 = cast<TemplateSpecializationType>(T1);
1069
856k
    const auto *Spec2 = cast<TemplateSpecializationType>(T2);
1070
856k
    if (!IsStructurallyEquivalent(Context, Spec1->getTemplateName(),
1071
856k
                                  Spec2->getTemplateName()))
1072
24.1k
      return false;
1073
832k
    if (Spec1->getNumArgs() != Spec2->getNumArgs())
1074
41.9k
      return false;
1075
2.58M
    
for (unsigned I = 0, N = Spec1->getNumArgs(); 790k
I != N;
++I1.79M
) {
1076
1.81M
      if (!IsStructurallyEquivalent(Context, Spec1->getArg(I),
1077
1.81M
                                    Spec2->getArg(I)))
1078
19.1k
        return false;
1079
1.81M
    }
1080
771k
    break;
1081
790k
  }
1082
1083
771k
  case Type::Elaborated: {
1084
0
    const auto *Elab1 = cast<ElaboratedType>(T1);
1085
0
    const auto *Elab2 = cast<ElaboratedType>(T2);
1086
    // CHECKME: what if a keyword is ETK_None or ETK_typename ?
1087
0
    if (Elab1->getKeyword() != Elab2->getKeyword())
1088
0
      return false;
1089
0
    if (!IsStructurallyEquivalent(Context, Elab1->getQualifier(),
1090
0
                                  Elab2->getQualifier()))
1091
0
      return false;
1092
0
    if (!IsStructurallyEquivalent(Context, Elab1->getNamedType(),
1093
0
                                  Elab2->getNamedType()))
1094
0
      return false;
1095
0
    break;
1096
0
  }
1097
1098
73.6k
  case Type::InjectedClassName: {
1099
73.6k
    const auto *Inj1 = cast<InjectedClassNameType>(T1);
1100
73.6k
    const auto *Inj2 = cast<InjectedClassNameType>(T2);
1101
73.6k
    if (!IsStructurallyEquivalent(Context,
1102
73.6k
                                  Inj1->getInjectedSpecializationType(),
1103
73.6k
                                  Inj2->getInjectedSpecializationType()))
1104
6.39k
      return false;
1105
67.2k
    break;
1106
73.6k
  }
1107
1108
365k
  case Type::DependentName: {
1109
365k
    const auto *Typename1 = cast<DependentNameType>(T1);
1110
365k
    const auto *Typename2 = cast<DependentNameType>(T2);
1111
365k
    if (!IsStructurallyEquivalent(Context, Typename1->getQualifier(),
1112
365k
                                  Typename2->getQualifier()))
1113
4.97k
      return false;
1114
360k
    if (!IsStructurallyEquivalent(Typename1->getIdentifier(),
1115
360k
                                  Typename2->getIdentifier()))
1116
1.12k
      return false;
1117
1118
359k
    break;
1119
360k
  }
1120
1121
359k
  case Type::DependentTemplateSpecialization: {
1122
480
    const auto *Spec1 = cast<DependentTemplateSpecializationType>(T1);
1123
480
    const auto *Spec2 = cast<DependentTemplateSpecializationType>(T2);
1124
480
    if (!IsStructurallyEquivalent(Context, Spec1->getQualifier(),
1125
480
                                  Spec2->getQualifier()))
1126
0
      return false;
1127
480
    if (!IsStructurallyEquivalent(Spec1->getIdentifier(),
1128
480
                                  Spec2->getIdentifier()))
1129
0
      return false;
1130
480
    if (Spec1->getNumArgs() != Spec2->getNumArgs())
1131
0
      return false;
1132
960
    
for (unsigned I = 0, N = Spec1->getNumArgs(); 480
I != N;
++I480
) {
1133
480
      if (!IsStructurallyEquivalent(Context, Spec1->getArg(I),
1134
480
                                    Spec2->getArg(I)))
1135
0
        return false;
1136
480
    }
1137
480
    break;
1138
480
  }
1139
1140
12.3k
  case Type::PackExpansion:
1141
12.3k
    if (!IsStructurallyEquivalent(Context,
1142
12.3k
                                  cast<PackExpansionType>(T1)->getPattern(),
1143
12.3k
                                  cast<PackExpansionType>(T2)->getPattern()))
1144
408
      return false;
1145
11.9k
    break;
1146
1147
11.9k
  case Type::ObjCInterface: {
1148
65
    const auto *Iface1 = cast<ObjCInterfaceType>(T1);
1149
65
    const auto *Iface2 = cast<ObjCInterfaceType>(T2);
1150
65
    if (!IsStructurallyEquivalent(Context, Iface1->getDecl(),
1151
65
                                  Iface2->getDecl()))
1152
0
      return false;
1153
65
    break;
1154
65
  }
1155
1156
65
  case Type::ObjCTypeParam: {
1157
0
    const auto *Obj1 = cast<ObjCTypeParamType>(T1);
1158
0
    const auto *Obj2 = cast<ObjCTypeParamType>(T2);
1159
0
    if (!IsStructurallyEquivalent(Context, Obj1->getDecl(), Obj2->getDecl()))
1160
0
      return false;
1161
1162
0
    if (Obj1->getNumProtocols() != Obj2->getNumProtocols())
1163
0
      return false;
1164
0
    for (unsigned I = 0, N = Obj1->getNumProtocols(); I != N; ++I) {
1165
0
      if (!IsStructurallyEquivalent(Context, Obj1->getProtocol(I),
1166
0
                                    Obj2->getProtocol(I)))
1167
0
        return false;
1168
0
    }
1169
0
    break;
1170
0
  }
1171
1172
947
  case Type::ObjCObject: {
1173
947
    const auto *Obj1 = cast<ObjCObjectType>(T1);
1174
947
    const auto *Obj2 = cast<ObjCObjectType>(T2);
1175
947
    if (!IsStructurallyEquivalent(Context, Obj1->getBaseType(),
1176
947
                                  Obj2->getBaseType()))
1177
0
      return false;
1178
947
    if (Obj1->getNumProtocols() != Obj2->getNumProtocols())
1179
0
      return false;
1180
947
    for (unsigned I = 0, N = Obj1->getNumProtocols(); I != N; 
++I0
) {
1181
0
      if (!IsStructurallyEquivalent(Context, Obj1->getProtocol(I),
1182
0
                                    Obj2->getProtocol(I)))
1183
0
        return false;
1184
0
    }
1185
947
    break;
1186
947
  }
1187
1188
1.01k
  case Type::ObjCObjectPointer: {
1189
1.01k
    const auto *Ptr1 = cast<ObjCObjectPointerType>(T1);
1190
1.01k
    const auto *Ptr2 = cast<ObjCObjectPointerType>(T2);
1191
1.01k
    if (!IsStructurallyEquivalent(Context, Ptr1->getPointeeType(),
1192
1.01k
                                  Ptr2->getPointeeType()))
1193
0
      return false;
1194
1.01k
    break;
1195
1.01k
  }
1196
1197
1.01k
  case Type::Atomic:
1198
0
    if (!IsStructurallyEquivalent(Context, cast<AtomicType>(T1)->getValueType(),
1199
0
                                  cast<AtomicType>(T2)->getValueType()))
1200
0
      return false;
1201
0
    break;
1202
1203
0
  case Type::Pipe:
1204
0
    if (!IsStructurallyEquivalent(Context, cast<PipeType>(T1)->getElementType(),
1205
0
                                  cast<PipeType>(T2)->getElementType()))
1206
0
      return false;
1207
0
    break;
1208
0
  case Type::ExtInt: {
1209
0
    const auto *Int1 = cast<ExtIntType>(T1);
1210
0
    const auto *Int2 = cast<ExtIntType>(T2);
1211
1212
0
    if (Int1->isUnsigned() != Int2->isUnsigned() ||
1213
0
        Int1->getNumBits() != Int2->getNumBits())
1214
0
      return false;
1215
0
    break;
1216
0
  }
1217
0
  case Type::DependentExtInt: {
1218
0
    const auto *Int1 = cast<DependentExtIntType>(T1);
1219
0
    const auto *Int2 = cast<DependentExtIntType>(T2);
1220
1221
0
    if (Int1->isUnsigned() != Int2->isUnsigned() ||
1222
0
        !IsStructurallyEquivalent(Context, Int1->getNumBitsExpr(),
1223
0
                                  Int2->getNumBitsExpr()))
1224
0
      return false;
1225
0
  }
1226
5.72M
  } // end switch
1227
1228
5.07M
  return true;
1229
5.72M
}
1230
1231
/// Determine structural equivalence of two fields.
1232
static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
1233
157k
                                     FieldDecl *Field1, FieldDecl *Field2) {
1234
157k
  const auto *Owner2 = cast<RecordDecl>(Field2->getDeclContext());
1235
1236
  // For anonymous structs/unions, match up the anonymous struct/union type
1237
  // declarations directly, so that we don't go off searching for anonymous
1238
  // types
1239
157k
  if (Field1->isAnonymousStructOrUnion() &&
1240
157k
      
Field2->isAnonymousStructOrUnion()257
) {
1241
257
    RecordDecl *D1 = Field1->getType()->castAs<RecordType>()->getDecl();
1242
257
    RecordDecl *D2 = Field2->getType()->castAs<RecordType>()->getDecl();
1243
257
    return IsStructurallyEquivalent(Context, D1, D2);
1244
257
  }
1245
1246
  // Check for equivalent field names.
1247
156k
  IdentifierInfo *Name1 = Field1->getIdentifier();
1248
156k
  IdentifierInfo *Name2 = Field2->getIdentifier();
1249
156k
  if (!::IsStructurallyEquivalent(Name1, Name2)) {
1250
191
    if (Context.Complain) {
1251
14
      Context.Diag2(
1252
14
          Owner2->getLocation(),
1253
14
          Context.getApplicableDiagnostic(diag::err_odr_tag_type_inconsistent))
1254
14
          << Context.ToCtx.getTypeDeclType(Owner2);
1255
14
      Context.Diag2(Field2->getLocation(), diag::note_odr_field_name)
1256
14
          << Field2->getDeclName();
1257
14
      Context.Diag1(Field1->getLocation(), diag::note_odr_field_name)
1258
14
          << Field1->getDeclName();
1259
14
    }
1260
191
    return false;
1261
191
  }
1262
1263
156k
  if (!IsStructurallyEquivalent(Context, Field1->getType(),
1264
156k
                                Field2->getType())) {
1265
211
    if (Context.Complain) {
1266
19
      Context.Diag2(
1267
19
          Owner2->getLocation(),
1268
19
          Context.getApplicableDiagnostic(diag::err_odr_tag_type_inconsistent))
1269
19
          << Context.ToCtx.getTypeDeclType(Owner2);
1270
19
      Context.Diag2(Field2->getLocation(), diag::note_odr_field)
1271
19
          << Field2->getDeclName() << Field2->getType();
1272
19
      Context.Diag1(Field1->getLocation(), diag::note_odr_field)
1273
19
          << Field1->getDeclName() << Field1->getType();
1274
19
    }
1275
211
    return false;
1276
211
  }
1277
1278
156k
  if (Field1->isBitField())
1279
18
    return IsStructurallyEquivalent(Context, Field1->getBitWidth(),
1280
18
                                    Field2->getBitWidth());
1281
1282
156k
  return true;
1283
156k
}
1284
1285
/// Determine structural equivalence of two methods.
1286
static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
1287
                                     CXXMethodDecl *Method1,
1288
284k
                                     CXXMethodDecl *Method2) {
1289
284k
  bool PropertiesEqual =
1290
284k
      Method1->getDeclKind() == Method2->getDeclKind() &&
1291
284k
      Method1->getRefQualifier() == Method2->getRefQualifier() &&
1292
284k
      
Method1->getAccess() == Method2->getAccess()284k
&&
1293
284k
      
Method1->getOverloadedOperator() == Method2->getOverloadedOperator()274k
&&
1294
284k
      
Method1->isStatic() == Method2->isStatic()274k
&&
1295
284k
      
Method1->isConst() == Method2->isConst()274k
&&
1296
284k
      
Method1->isVolatile() == Method2->isVolatile()255k
&&
1297
284k
      
Method1->isVirtual() == Method2->isVirtual()254k
&&
1298
284k
      
Method1->isPure() == Method2->isPure()254k
&&
1299
284k
      
Method1->isDefaulted() == Method2->isDefaulted()254k
&&
1300
284k
      
Method1->isDeleted() == Method2->isDeleted()247k
;
1301
284k
  if (!PropertiesEqual)
1302
37.4k
    return false;
1303
  // FIXME: Check for 'final'.
1304
1305
247k
  if (auto *Constructor1 = dyn_cast<CXXConstructorDecl>(Method1)) {
1306
94.5k
    auto *Constructor2 = cast<CXXConstructorDecl>(Method2);
1307
94.5k
    if (!Constructor1->getExplicitSpecifier().isEquivalent(
1308
94.5k
            Constructor2->getExplicitSpecifier()))
1309
21.7k
      return false;
1310
94.5k
  }
1311
1312
225k
  if (auto *Conversion1 = dyn_cast<CXXConversionDecl>(Method1)) {
1313
374
    auto *Conversion2 = cast<CXXConversionDecl>(Method2);
1314
374
    if (!Conversion1->getExplicitSpecifier().isEquivalent(
1315
374
            Conversion2->getExplicitSpecifier()))
1316
0
      return false;
1317
374
    if (!IsStructurallyEquivalent(Context, Conversion1->getConversionType(),
1318
374
                                  Conversion2->getConversionType()))
1319
2
      return false;
1320
374
  }
1321
1322
225k
  const IdentifierInfo *Name1 = Method1->getIdentifier();
1323
225k
  const IdentifierInfo *Name2 = Method2->getIdentifier();
1324
225k
  if (!::IsStructurallyEquivalent(Name1, Name2)) {
1325
0
    return false;
1326
    // TODO: Names do not match, add warning like at check for FieldDecl.
1327
0
  }
1328
1329
  // Check the prototypes.
1330
225k
  if (!::IsStructurallyEquivalent(Context,
1331
225k
                                  Method1->getType(), Method2->getType()))
1332
160k
    return false;
1333
1334
64.6k
  return true;
1335
225k
}
1336
1337
/// Determine structural equivalence of two lambda classes.
1338
static bool
1339
IsStructurallyEquivalentLambdas(StructuralEquivalenceContext &Context,
1340
8
                                CXXRecordDecl *D1, CXXRecordDecl *D2) {
1341
8
  assert(D1->isLambda() && D2->isLambda() &&
1342
8
         "Must be called on lambda classes");
1343
8
  if (!IsStructurallyEquivalent(Context, D1->getLambdaCallOperator(),
1344
8
                                D2->getLambdaCallOperator()))
1345
2
    return false;
1346
1347
6
  return true;
1348
8
}
1349
1350
/// Determine structural equivalence of two records.
1351
static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
1352
511k
                                     RecordDecl *D1, RecordDecl *D2) {
1353
1354
  // Check for equivalent structure names.
1355
511k
  IdentifierInfo *Name1 = D1->getIdentifier();
1356
511k
  if (!Name1 && 
D1->getTypedefNameForAnonDecl()454
)
1357
24
    Name1 = D1->getTypedefNameForAnonDecl()->getIdentifier();
1358
511k
  IdentifierInfo *Name2 = D2->getIdentifier();
1359
511k
  if (!Name2 && 
D2->getTypedefNameForAnonDecl()454
)
1360
26
    Name2 = D2->getTypedefNameForAnonDecl()->getIdentifier();
1361
511k
  if (!IsStructurallyEquivalent(Name1, Name2))
1362
2.65k
    return false;
1363
1364
508k
  if (D1->isUnion() != D2->isUnion()) {
1365
3
    if (Context.Complain) {
1366
1
      Context.Diag2(D2->getLocation(), Context.getApplicableDiagnostic(
1367
1
                                           diag::err_odr_tag_type_inconsistent))
1368
1
          << Context.ToCtx.getTypeDeclType(D2);
1369
1
      Context.Diag1(D1->getLocation(), diag::note_odr_tag_kind_here)
1370
1
          << D1->getDeclName() << (unsigned)D1->getTagKind();
1371
1
    }
1372
3
    return false;
1373
3
  }
1374
1375
508k
  if (!D1->getDeclName() && 
!D2->getDeclName()450
) {
1376
    // If both anonymous structs/unions are in a record context, make sure
1377
    // they occur in the same location in the context records.
1378
450
    if (Optional<unsigned> Index1 =
1379
450
            StructuralEquivalenceContext::findUntaggedStructOrUnionIndex(D1)) {
1380
403
      if (Optional<unsigned> Index2 =
1381
403
              StructuralEquivalenceContext::findUntaggedStructOrUnionIndex(
1382
403
                  D2)) {
1383
403
        if (*Index1 != *Index2)
1384
47
          return false;
1385
403
      }
1386
403
    }
1387
450
  }
1388
1389
  // If both declarations are class template specializations, we know
1390
  // the ODR applies, so check the template and template arguments.
1391
508k
  const auto *Spec1 = dyn_cast<ClassTemplateSpecializationDecl>(D1);
1392
508k
  const auto *Spec2 = dyn_cast<ClassTemplateSpecializationDecl>(D2);
1393
508k
  if (Spec1 && 
Spec288.4k
) {
1394
    // Check that the specialized templates are the same.
1395
88.4k
    if (!IsStructurallyEquivalent(Context, Spec1->getSpecializedTemplate(),
1396
88.4k
                                  Spec2->getSpecializedTemplate()))
1397
58
      return false;
1398
1399
    // Check that the template arguments are the same.
1400
88.3k
    if (Spec1->getTemplateArgs().size() != Spec2->getTemplateArgs().size())
1401
18
      return false;
1402
1403
252k
    
for (unsigned I = 0, N = Spec1->getTemplateArgs().size(); 88.3k
I != N;
++I164k
)
1404
165k
      if (!IsStructurallyEquivalent(Context, Spec1->getTemplateArgs().get(I),
1405
165k
                                    Spec2->getTemplateArgs().get(I)))
1406
1.12k
        return false;
1407
88.3k
  }
1408
  // If one is a class template specialization and the other is not, these
1409
  // structures are different.
1410
420k
  else if (Spec1 || Spec2)
1411
0
    return false;
1412
1413
  // Compare the definitions of these two records. If either or both are
1414
  // incomplete (i.e. it is a forward decl), we assume that they are
1415
  // equivalent.
1416
507k
  D1 = D1->getDefinition();
1417
507k
  D2 = D2->getDefinition();
1418
507k
  if (!D1 || 
!D2455k
)
1419
56.2k
    return true;
1420
1421
  // If any of the records has external storage and we do a minimal check (or
1422
  // AST import) we assume they are equivalent. (If we didn't have this
1423
  // assumption then `RecordDecl::LoadFieldsFromExternalStorage` could trigger
1424
  // another AST import which in turn would call the structural equivalency
1425
  // check again and finally we'd have an improper result.)
1426
451k
  if (Context.EqKind == StructuralEquivalenceKind::Minimal)
1427
450k
    if (D1->hasExternalLexicalStorage() || 
D2->hasExternalLexicalStorage()264k
)
1428
217k
      return true;
1429
1430
  // If one definition is currently being defined, we do not compare for
1431
  // equality and we assume that the decls are equal.
1432
233k
  if (D1->isBeingDefined() || 
D2->isBeingDefined()233k
)
1433
98
    return true;
1434
1435
233k
  if (auto *D1CXX = dyn_cast<CXXRecordDecl>(D1)) {
1436
233k
    if (auto *D2CXX = dyn_cast<CXXRecordDecl>(D2)) {
1437
233k
      if (D1CXX->hasExternalLexicalStorage() &&
1438
233k
          
!D1CXX->isCompleteDefinition()62
) {
1439
0
        D1CXX->getASTContext().getExternalSource()->CompleteType(D1CXX);
1440
0
      }
1441
1442
233k
      if (D1CXX->isLambda() != D2CXX->isLambda())
1443
0
        return false;
1444
233k
      if (D1CXX->isLambda()) {
1445
8
        if (!IsStructurallyEquivalentLambdas(Context, D1CXX, D2CXX))
1446
2
          return false;
1447
8
      }
1448
1449
233k
      if (D1CXX->getNumBases() != D2CXX->getNumBases()) {
1450
0
        if (Context.Complain) {
1451
0
          Context.Diag2(D2->getLocation(),
1452
0
                        Context.getApplicableDiagnostic(
1453
0
                            diag::err_odr_tag_type_inconsistent))
1454
0
              << Context.ToCtx.getTypeDeclType(D2);
1455
0
          Context.Diag2(D2->getLocation(), diag::note_odr_number_of_bases)
1456
0
              << D2CXX->getNumBases();
1457
0
          Context.Diag1(D1->getLocation(), diag::note_odr_number_of_bases)
1458
0
              << D1CXX->getNumBases();
1459
0
        }
1460
0
        return false;
1461
0
      }
1462
1463
      // Check the base classes.
1464
233k
      for (CXXRecordDecl::base_class_iterator Base1 = D1CXX->bases_begin(),
1465
233k
                                              BaseEnd1 = D1CXX->bases_end(),
1466
233k
                                              Base2 = D2CXX->bases_begin();
1467
367k
           Base1 != BaseEnd1; 
++Base1, ++Base2134k
) {
1468
134k
        if (!IsStructurallyEquivalent(Context, Base1->getType(),
1469
134k
                                      Base2->getType())) {
1470
27
          if (Context.Complain) {
1471
0
            Context.Diag2(D2->getLocation(),
1472
0
                          Context.getApplicableDiagnostic(
1473
0
                              diag::err_odr_tag_type_inconsistent))
1474
0
                << Context.ToCtx.getTypeDeclType(D2);
1475
0
            Context.Diag2(Base2->getBeginLoc(), diag::note_odr_base)
1476
0
                << Base2->getType() << Base2->getSourceRange();
1477
0
            Context.Diag1(Base1->getBeginLoc(), diag::note_odr_base)
1478
0
                << Base1->getType() << Base1->getSourceRange();
1479
0
          }
1480
27
          return false;
1481
27
        }
1482
1483
        // Check virtual vs. non-virtual inheritance mismatch.
1484
134k
        if (Base1->isVirtual() != Base2->isVirtual()) {
1485
2
          if (Context.Complain) {
1486
0
            Context.Diag2(D2->getLocation(),
1487
0
                          Context.getApplicableDiagnostic(
1488
0
                              diag::err_odr_tag_type_inconsistent))
1489
0
                << Context.ToCtx.getTypeDeclType(D2);
1490
0
            Context.Diag2(Base2->getBeginLoc(), diag::note_odr_virtual_base)
1491
0
                << Base2->isVirtual() << Base2->getSourceRange();
1492
0
            Context.Diag1(Base1->getBeginLoc(), diag::note_odr_base)
1493
0
                << Base1->isVirtual() << Base1->getSourceRange();
1494
0
          }
1495
2
          return false;
1496
2
        }
1497
134k
      }
1498
1499
      // Check the friends for consistency.
1500
233k
      CXXRecordDecl::friend_iterator Friend2 = D2CXX->friend_begin(),
1501
233k
                                     Friend2End = D2CXX->friend_end();
1502
233k
      for (CXXRecordDecl::friend_iterator Friend1 = D1CXX->friend_begin(),
1503
233k
                                          Friend1End = D1CXX->friend_end();
1504
325k
           Friend1 != Friend1End; 
++Friend1, ++Friend292.4k
) {
1505
92.9k
        if (Friend2 == Friend2End) {
1506
466
          if (Context.Complain) {
1507
0
            Context.Diag2(D2->getLocation(),
1508
0
                          Context.getApplicableDiagnostic(
1509
0
                              diag::err_odr_tag_type_inconsistent))
1510
0
                << Context.ToCtx.getTypeDeclType(D2CXX);
1511
0
            Context.Diag1((*Friend1)->getFriendLoc(), diag::note_odr_friend);
1512
0
            Context.Diag2(D2->getLocation(), diag::note_odr_missing_friend);
1513
0
          }
1514
466
          return false;
1515
466
        }
1516
1517
92.4k
        if (!IsStructurallyEquivalent(Context, *Friend1, *Friend2)) {
1518
0
          if (Context.Complain) {
1519
0
            Context.Diag2(D2->getLocation(),
1520
0
                          Context.getApplicableDiagnostic(
1521
0
                              diag::err_odr_tag_type_inconsistent))
1522
0
                << Context.ToCtx.getTypeDeclType(D2CXX);
1523
0
            Context.Diag1((*Friend1)->getFriendLoc(), diag::note_odr_friend);
1524
0
            Context.Diag2((*Friend2)->getFriendLoc(), diag::note_odr_friend);
1525
0
          }
1526
0
          return false;
1527
0
        }
1528
92.4k
      }
1529
1530
232k
      if (Friend2 != Friend2End) {
1531
5
        if (Context.Complain) {
1532
4
          Context.Diag2(D2->getLocation(),
1533
4
                        Context.getApplicableDiagnostic(
1534
4
                            diag::err_odr_tag_type_inconsistent))
1535
4
              << Context.ToCtx.getTypeDeclType(D2);
1536
4
          Context.Diag2((*Friend2)->getFriendLoc(), diag::note_odr_friend);
1537
4
          Context.Diag1(D1->getLocation(), diag::note_odr_missing_friend);
1538
4
        }
1539
5
        return false;
1540
5
      }
1541
232k
    } else 
if (0
D1CXX->getNumBases() > 00
) {
1542
0
      if (Context.Complain) {
1543
0
        Context.Diag2(D2->getLocation(),
1544
0
                      Context.getApplicableDiagnostic(
1545
0
                          diag::err_odr_tag_type_inconsistent))
1546
0
            << Context.ToCtx.getTypeDeclType(D2);
1547
0
        const CXXBaseSpecifier *Base1 = D1CXX->bases_begin();
1548
0
        Context.Diag1(Base1->getBeginLoc(), diag::note_odr_base)
1549
0
            << Base1->getType() << Base1->getSourceRange();
1550
0
        Context.Diag2(D2->getLocation(), diag::note_odr_missing_base);
1551
0
      }
1552
0
      return false;
1553
0
    }
1554
233k
  }
1555
1556
  // Check the fields for consistency.
1557
233k
  RecordDecl::field_iterator Field2 = D2->field_begin(),
1558
233k
                             Field2End = D2->field_end();
1559
233k
  for (RecordDecl::field_iterator Field1 = D1->field_begin(),
1560
233k
                                  Field1End = D1->field_end();
1561
389k
       Field1 != Field1End; 
++Field1, ++Field2156k
) {
1562
157k
    if (Field2 == Field2End) {
1563
26
      if (Context.Complain) {
1564
25
        Context.Diag2(D2->getLocation(),
1565
25
                      Context.getApplicableDiagnostic(
1566
25
                          diag::err_odr_tag_type_inconsistent))
1567
25
            << Context.ToCtx.getTypeDeclType(D2);
1568
25
        Context.Diag1(Field1->getLocation(), diag::note_odr_field)
1569
25
            << Field1->getDeclName() << Field1->getType();
1570
25
        Context.Diag2(D2->getLocation(), diag::note_odr_missing_field);
1571
25
      }
1572
26
      return false;
1573
26
    }
1574
1575
157k
    if (!IsStructurallyEquivalent(Context, *Field1, *Field2))
1576
407
      return false;
1577
157k
  }
1578
1579
232k
  if (Field2 != Field2End) {
1580
12
    if (Context.Complain) {
1581
11
      Context.Diag2(D2->getLocation(), Context.getApplicableDiagnostic(
1582
11
                                           diag::err_odr_tag_type_inconsistent))
1583
11
          << Context.ToCtx.getTypeDeclType(D2);
1584
11
      Context.Diag2(Field2->getLocation(), diag::note_odr_field)
1585
11
          << Field2->getDeclName() << Field2->getType();
1586
11
      Context.Diag1(D1->getLocation(), diag::note_odr_missing_field);
1587
11
    }
1588
12
    return false;
1589
12
  }
1590
1591
232k
  return true;
1592
232k
}
1593
1594
/// Determine structural equivalence of two enums.
1595
static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
1596
2.00k
                                     EnumDecl *D1, EnumDecl *D2) {
1597
1598
  // Check for equivalent enum names.
1599
2.00k
  IdentifierInfo *Name1 = D1->getIdentifier();
1600
2.00k
  if (!Name1 && 
D1->getTypedefNameForAnonDecl()99
)
1601
15
    Name1 = D1->getTypedefNameForAnonDecl()->getIdentifier();
1602
2.00k
  IdentifierInfo *Name2 = D2->getIdentifier();
1603
2.00k
  if (!Name2 && 
D2->getTypedefNameForAnonDecl()99
)
1604
15
    Name2 = D2->getTypedefNameForAnonDecl()->getIdentifier();
1605
2.00k
  if (!IsStructurallyEquivalent(Name1, Name2))
1606
135
    return false;
1607
1608
  // Compare the definitions of these two enums. If either or both are
1609
  // incomplete (i.e. forward declared), we assume that they are equivalent.
1610
1.87k
  D1 = D1->getDefinition();
1611
1.87k
  D2 = D2->getDefinition();
1612
1.87k
  if (!D1 || 
!D21.84k
)
1613
40
    return true;
1614
1615
1.83k
  EnumDecl::enumerator_iterator EC2 = D2->enumerator_begin(),
1616
1.83k
                                EC2End = D2->enumerator_end();
1617
1.83k
  for (EnumDecl::enumerator_iterator EC1 = D1->enumerator_begin(),
1618
1.83k
                                     EC1End = D1->enumerator_end();
1619
6.92k
       EC1 != EC1End; 
++EC1, ++EC25.09k
) {
1620
5.16k
    if (EC2 == EC2End) {
1621
20
      if (Context.Complain) {
1622
17
        Context.Diag2(D2->getLocation(),
1623
17
                      Context.getApplicableDiagnostic(
1624
17
                          diag::err_odr_tag_type_inconsistent))
1625
17
            << Context.ToCtx.getTypeDeclType(D2);
1626
17
        Context.Diag1(EC1->getLocation(), diag::note_odr_enumerator)
1627
17
            << EC1->getDeclName() << toString(EC1->getInitVal(), 10);
1628
17
        Context.Diag2(D2->getLocation(), diag::note_odr_missing_enumerator);
1629
17
      }
1630
20
      return false;
1631
20
    }
1632
1633
5.14k
    llvm::APSInt Val1 = EC1->getInitVal();
1634
5.14k
    llvm::APSInt Val2 = EC2->getInitVal();
1635
5.14k
    if (!llvm::APSInt::isSameValue(Val1, Val2) ||
1636
5.14k
        
!IsStructurallyEquivalent(EC1->getIdentifier(), EC2->getIdentifier())5.09k
) {
1637
55
      if (Context.Complain) {
1638
23
        Context.Diag2(D2->getLocation(),
1639
23
                      Context.getApplicableDiagnostic(
1640
23
                          diag::err_odr_tag_type_inconsistent))
1641
23
            << Context.ToCtx.getTypeDeclType(D2);
1642
23
        Context.Diag2(EC2->getLocation(), diag::note_odr_enumerator)
1643
23
            << EC2->getDeclName() << toString(EC2->getInitVal(), 10);
1644
23
        Context.Diag1(EC1->getLocation(), diag::note_odr_enumerator)
1645
23
            << EC1->getDeclName() << toString(EC1->getInitVal(), 10);
1646
23
      }
1647
55
      return false;
1648
55
    }
1649
5.14k
  }
1650
1651
1.75k
  if (EC2 != EC2End) {
1652
1
    if (Context.Complain) {
1653
1
      Context.Diag2(D2->getLocation(), Context.getApplicableDiagnostic(
1654
1
                                           diag::err_odr_tag_type_inconsistent))
1655
1
          << Context.ToCtx.getTypeDeclType(D2);
1656
1
      Context.Diag2(EC2->getLocation(), diag::note_odr_enumerator)
1657
1
          << EC2->getDeclName() << toString(EC2->getInitVal(), 10);
1658
1
      Context.Diag1(D1->getLocation(), diag::note_odr_missing_enumerator);
1659
1
    }
1660
1
    return false;
1661
1
  }
1662
1663
1.75k
  return true;
1664
1.75k
}
1665
1666
static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
1667
                                     TemplateParameterList *Params1,
1668
1.16M
                                     TemplateParameterList *Params2) {
1669
1.16M
  if (Params1->size() != Params2->size()) {
1670
389k
    if (Context.Complain) {
1671
318
      Context.Diag2(Params2->getTemplateLoc(),
1672
318
                    Context.getApplicableDiagnostic(
1673
318
                        diag::err_odr_different_num_template_parameters))
1674
318
          << Params1->size() << Params2->size();
1675
318
      Context.Diag1(Params1->getTemplateLoc(),
1676
318
                    diag::note_odr_template_parameter_list);
1677
318
    }
1678
389k
    return false;
1679
389k
  }
1680
1681
2.36M
  
for (unsigned I = 0, N = Params1->size(); 770k
I != N;
++I1.59M
) {
1682
1.62M
    if (Params1->getParam(I)->getKind() != Params2->getParam(I)->getKind()) {
1683
33.0k
      if (Context.Complain) {
1684
68
        Context.Diag2(Params2->getParam(I)->getLocation(),
1685
68
                      Context.getApplicableDiagnostic(
1686
68
                          diag::err_odr_different_template_parameter_kind));
1687
68
        Context.Diag1(Params1->getParam(I)->getLocation(),
1688
68
                      diag::note_odr_template_parameter_here);
1689
68
      }
1690
33.0k
      return false;
1691
33.0k
    }
1692
1693
1.59M
    if (!IsStructurallyEquivalent(Context, Params1->getParam(I),
1694
1.59M
                                  Params2->getParam(I)))
1695
758
      return false;
1696
1.59M
  }
1697
1698
736k
  return true;
1699
770k
}
1700
1701
static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
1702
                                     TemplateTypeParmDecl *D1,
1703
905k
                                     TemplateTypeParmDecl *D2) {
1704
905k
  if (D1->isParameterPack() != D2->isParameterPack()) {
1705
0
    if (Context.Complain) {
1706
0
      Context.Diag2(D2->getLocation(),
1707
0
                    Context.getApplicableDiagnostic(
1708
0
                        diag::err_odr_parameter_pack_non_pack))
1709
0
          << D2->isParameterPack();
1710
0
      Context.Diag1(D1->getLocation(), diag::note_odr_parameter_pack_non_pack)
1711
0
          << D1->isParameterPack();
1712
0
    }
1713
0
    return false;
1714
0
  }
1715
1716
905k
  return true;
1717
905k
}
1718
1719
static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
1720
                                     NonTypeTemplateParmDecl *D1,
1721
195k
                                     NonTypeTemplateParmDecl *D2) {
1722
195k
  if (D1->isParameterPack() != D2->isParameterPack()) {
1723
0
    if (Context.Complain) {
1724
0
      Context.Diag2(D2->getLocation(),
1725
0
                    Context.getApplicableDiagnostic(
1726
0
                        diag::err_odr_parameter_pack_non_pack))
1727
0
          << D2->isParameterPack();
1728
0
      Context.Diag1(D1->getLocation(), diag::note_odr_parameter_pack_non_pack)
1729
0
          << D1->isParameterPack();
1730
0
    }
1731
0
    return false;
1732
0
  }
1733
1734
  // Check types.
1735
195k
  if (!IsStructurallyEquivalent(Context, D1->getType(), D2->getType())) {
1736
882
    if (Context.Complain) {
1737
57
      Context.Diag2(D2->getLocation(),
1738
57
                    Context.getApplicableDiagnostic(
1739
57
                        diag::err_odr_non_type_parameter_type_inconsistent))
1740
57
          << D2->getType() << D1->getType();
1741
57
      Context.Diag1(D1->getLocation(), diag::note_odr_value_here)
1742
57
          << D1->getType();
1743
57
    }
1744
882
    return false;
1745
882
  }
1746
1747
195k
  return true;
1748
195k
}
1749
1750
static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
1751
                                     TemplateTemplateParmDecl *D1,
1752
608
                                     TemplateTemplateParmDecl *D2) {
1753
608
  if (D1->isParameterPack() != D2->isParameterPack()) {
1754
0
    if (Context.Complain) {
1755
0
      Context.Diag2(D2->getLocation(),
1756
0
                    Context.getApplicableDiagnostic(
1757
0
                        diag::err_odr_parameter_pack_non_pack))
1758
0
          << D2->isParameterPack();
1759
0
      Context.Diag1(D1->getLocation(), diag::note_odr_parameter_pack_non_pack)
1760
0
          << D1->isParameterPack();
1761
0
    }
1762
0
    return false;
1763
0
  }
1764
1765
  // Check template parameter lists.
1766
608
  return IsStructurallyEquivalent(Context, D1->getTemplateParameters(),
1767
608
                                  D2->getTemplateParameters());
1768
608
}
1769
1770
static bool IsTemplateDeclCommonStructurallyEquivalent(
1771
1.19M
    StructuralEquivalenceContext &Ctx, TemplateDecl *D1, TemplateDecl *D2) {
1772
1.19M
  if (!IsStructurallyEquivalent(D1->getIdentifier(), D2->getIdentifier()))
1773
35.8k
    return false;
1774
1.15M
  if (!D1->getIdentifier()) // Special name
1775
555k
    if (D1->getNameAsString() != D2->getNameAsString())
1776
114
      return false;
1777
1.15M
  return IsStructurallyEquivalent(Ctx, D1->getTemplateParameters(),
1778
1.15M
                                  D2->getTemplateParameters());
1779
1.15M
}
1780
1781
static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
1782
                                     ClassTemplateDecl *D1,
1783
405k
                                     ClassTemplateDecl *D2) {
1784
  // Check template parameters.
1785
405k
  if (!IsTemplateDeclCommonStructurallyEquivalent(Context, D1, D2))
1786
12.2k
    return false;
1787
1788
  // Check the templated declaration.
1789
393k
  return IsStructurallyEquivalent(Context, D1->getTemplatedDecl(),
1790
393k
                                  D2->getTemplatedDecl());
1791
405k
}
1792
1793
static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
1794
                                     FunctionTemplateDecl *D1,
1795
790k
                                     FunctionTemplateDecl *D2) {
1796
  // Check template parameters.
1797
790k
  if (!IsTemplateDeclCommonStructurallyEquivalent(Context, D1, D2))
1798
447k
    return false;
1799
1800
  // Check the templated declaration.
1801
342k
  return IsStructurallyEquivalent(Context, D1->getTemplatedDecl()->getType(),
1802
342k
                                  D2->getTemplatedDecl()->getType());
1803
790k
}
1804
1805
static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
1806
                                     ConceptDecl *D1,
1807
0
                                     ConceptDecl *D2) {
1808
  // Check template parameters.
1809
0
  if (!IsTemplateDeclCommonStructurallyEquivalent(Context, D1, D2))
1810
0
    return false;
1811
1812
  // Check the constraint expression.
1813
0
  return IsStructurallyEquivalent(Context, D1->getConstraintExpr(),
1814
0
                                  D2->getConstraintExpr());
1815
0
}
1816
1817
static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
1818
92.1k
                                     FriendDecl *D1, FriendDecl *D2) {
1819
92.1k
  if ((D1->getFriendType() && 
D2->getFriendDecl()8.05k
) ||
1820
92.1k
      (D1->getFriendDecl() && 
D2->getFriendType()84.0k
)) {
1821
0
      return false;
1822
0
  }
1823
92.1k
  if (D1->getFriendType() && 
D2->getFriendType()8.05k
)
1824
8.05k
    return IsStructurallyEquivalent(Context,
1825
8.05k
                                    D1->getFriendType()->getType(),
1826
8.05k
                                    D2->getFriendType()->getType());
1827
84.0k
  if (D1->getFriendDecl() && D2->getFriendDecl())
1828
84.0k
    return IsStructurallyEquivalent(Context, D1->getFriendDecl(),
1829
84.0k
                                    D2->getFriendDecl());
1830
0
  return false;
1831
84.0k
}
1832
1833
static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
1834
0
                                     TypedefNameDecl *D1, TypedefNameDecl *D2) {
1835
0
  if (!IsStructurallyEquivalent(D1->getIdentifier(), D2->getIdentifier()))
1836
0
    return false;
1837
1838
0
  return IsStructurallyEquivalent(Context, D1->getUnderlyingType(),
1839
0
                                  D2->getUnderlyingType());
1840
0
}
1841
1842
static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
1843
53.8k
                                     FunctionDecl *D1, FunctionDecl *D2) {
1844
53.8k
  if (!IsStructurallyEquivalent(D1->getIdentifier(), D2->getIdentifier()))
1845
301
    return false;
1846
1847
53.5k
  if (D1->isOverloadedOperator()) {
1848
48.3k
    if (!D2->isOverloadedOperator())
1849
0
      return false;
1850
48.3k
    if (D1->getOverloadedOperator() != D2->getOverloadedOperator())
1851
7.69k
      return false;
1852
48.3k
  }
1853
1854
  // FIXME: Consider checking for function attributes as well.
1855
45.8k
  if (!IsStructurallyEquivalent(Context, D1->getType(), D2->getType()))
1856
14.9k
    return false;
1857
1858
30.8k
  return true;
1859
45.8k
}
1860
1861
/// Determine structural equivalence of two declarations.
1862
static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
1863
4.61M
                                     Decl *D1, Decl *D2) {
1864
  // FIXME: Check for known structural equivalences via a callback of some sort.
1865
1866
4.61M
  D1 = D1->getCanonicalDecl();
1867
4.61M
  D2 = D2->getCanonicalDecl();
1868
4.61M
  std::pair<Decl *, Decl *> P{D1, D2};
1869
1870
  // Check whether we already know that these two declarations are not
1871
  // structurally equivalent.
1872
4.61M
  if (Context.NonEquivalentDecls.count(P))
1873
472k
    return false;
1874
1875
  // Check if a check for these declarations is already pending.
1876
  // If yes D1 and D2 will be checked later (from DeclsToCheck),
1877
  // or these are already checked (and equivalent).
1878
4.14M
  bool Inserted = Context.VisitedDecls.insert(P).second;
1879
4.14M
  if (!Inserted)
1880
544k
    return true;
1881
1882
3.59M
  Context.DeclsToCheck.push(P);
1883
1884
3.59M
  return true;
1885
4.14M
}
1886
1887
DiagnosticBuilder StructuralEquivalenceContext::Diag1(SourceLocation Loc,
1888
558
                                                      unsigned DiagID) {
1889
558
  assert(Complain && "Not allowed to complain");
1890
558
  if (LastDiagFromC2)
1891
558
    FromCtx.getDiagnostics().notePriorDiagnosticFrom(ToCtx.getDiagnostics());
1892
558
  LastDiagFromC2 = false;
1893
558
  return FromCtx.getDiagnostics().Report(Loc, DiagID);
1894
558
}
1895
1896
DiagnosticBuilder StructuralEquivalenceContext::Diag2(SourceLocation Loc,
1897
672
                                                      unsigned DiagID) {
1898
672
  assert(Complain && "Not allowed to complain");
1899
672
  if (!LastDiagFromC2)
1900
600
    ToCtx.getDiagnostics().notePriorDiagnosticFrom(FromCtx.getDiagnostics());
1901
672
  LastDiagFromC2 = true;
1902
672
  return ToCtx.getDiagnostics().Report(Loc, DiagID);
1903
672
}
1904
1905
Optional<unsigned>
1906
853
StructuralEquivalenceContext::findUntaggedStructOrUnionIndex(RecordDecl *Anon) {
1907
853
  ASTContext &Context = Anon->getASTContext();
1908
853
  QualType AnonTy = Context.getRecordType(Anon);
1909
1910
853
  const auto *Owner = dyn_cast<RecordDecl>(Anon->getDeclContext());
1911
853
  if (!Owner)
1912
47
    return None;
1913
1914
806
  unsigned Index = 0;
1915
3.30k
  for (const auto *D : Owner->noload_decls()) {
1916
3.30k
    const auto *F = dyn_cast<FieldDecl>(D);
1917
3.30k
    if (!F)
1918
2.38k
      continue;
1919
1920
919
    if (F->isAnonymousStructOrUnion()) {
1921
678
      if (Context.hasSameType(F->getType(), AnonTy))
1922
638
        break;
1923
40
      ++Index;
1924
40
      continue;
1925
678
    }
1926
1927
    // If the field looks like this:
1928
    // struct { ... } A;
1929
241
    QualType FieldType = F->getType();
1930
    // In case of nested structs.
1931
452
    while (const auto *ElabType = dyn_cast<ElaboratedType>(FieldType))
1932
211
      FieldType = ElabType->getNamedType();
1933
1934
241
    if (const auto *RecType = dyn_cast<RecordType>(FieldType)) {
1935
241
      const RecordDecl *RecDecl = RecType->getDecl();
1936
241
      if (RecDecl->getDeclContext() == Owner && !RecDecl->getIdentifier()) {
1937
241
        if (Context.hasSameType(FieldType, AnonTy))
1938
168
          break;
1939
73
        ++Index;
1940
73
        continue;
1941
241
      }
1942
241
    }
1943
241
  }
1944
1945
806
  return Index;
1946
853
}
1947
1948
unsigned StructuralEquivalenceContext::getApplicableDiagnostic(
1949
558
    unsigned ErrorDiagnostic) {
1950
558
  if (ErrorOnTagTypeMismatch)
1951
4
    return ErrorDiagnostic;
1952
1953
554
  switch (ErrorDiagnostic) {
1954
0
  case diag::err_odr_variable_type_inconsistent:
1955
0
    return diag::warn_odr_variable_type_inconsistent;
1956
0
  case diag::err_odr_variable_multiple_def:
1957
0
    return diag::warn_odr_variable_multiple_def;
1958
0
  case diag::err_odr_function_type_inconsistent:
1959
0
    return diag::warn_odr_function_type_inconsistent;
1960
111
  case diag::err_odr_tag_type_inconsistent:
1961
111
    return diag::warn_odr_tag_type_inconsistent;
1962
0
  case diag::err_odr_field_type_inconsistent:
1963
0
    return diag::warn_odr_field_type_inconsistent;
1964
0
  case diag::err_odr_ivar_type_inconsistent:
1965
0
    return diag::warn_odr_ivar_type_inconsistent;
1966
0
  case diag::err_odr_objc_superclass_inconsistent:
1967
0
    return diag::warn_odr_objc_superclass_inconsistent;
1968
0
  case diag::err_odr_objc_method_result_type_inconsistent:
1969
0
    return diag::warn_odr_objc_method_result_type_inconsistent;
1970
0
  case diag::err_odr_objc_method_num_params_inconsistent:
1971
0
    return diag::warn_odr_objc_method_num_params_inconsistent;
1972
0
  case diag::err_odr_objc_method_param_type_inconsistent:
1973
0
    return diag::warn_odr_objc_method_param_type_inconsistent;
1974
0
  case diag::err_odr_objc_method_variadic_inconsistent:
1975
0
    return diag::warn_odr_objc_method_variadic_inconsistent;
1976
0
  case diag::err_odr_objc_property_type_inconsistent:
1977
0
    return diag::warn_odr_objc_property_type_inconsistent;
1978
0
  case diag::err_odr_objc_property_impl_kind_inconsistent:
1979
0
    return diag::warn_odr_objc_property_impl_kind_inconsistent;
1980
0
  case diag::err_odr_objc_synthesize_ivar_inconsistent:
1981
0
    return diag::warn_odr_objc_synthesize_ivar_inconsistent;
1982
318
  case diag::err_odr_different_num_template_parameters:
1983
318
    return diag::warn_odr_different_num_template_parameters;
1984
68
  case diag::err_odr_different_template_parameter_kind:
1985
68
    return diag::warn_odr_different_template_parameter_kind;
1986
0
  case diag::err_odr_parameter_pack_non_pack:
1987
0
    return diag::warn_odr_parameter_pack_non_pack;
1988
57
  case diag::err_odr_non_type_parameter_type_inconsistent:
1989
57
    return diag::warn_odr_non_type_parameter_type_inconsistent;
1990
554
  }
1991
0
  llvm_unreachable("Diagnostic kind not handled in preceding switch");
1992
0
}
1993
1994
1.66M
bool StructuralEquivalenceContext::IsEquivalent(Decl *D1, Decl *D2) {
1995
1996
  // Ensure that the implementation functions (all static functions in this TU)
1997
  // never call the public ASTStructuralEquivalence::IsEquivalent() functions,
1998
  // because that will wreak havoc the internal state (DeclsToCheck and
1999
  // VisitedDecls members) and can cause faulty behaviour.
2000
  // In other words: Do not start a graph search from a new node with the
2001
  // internal data of another search in progress.
2002
  // FIXME: Better encapsulation and separation of internal and public
2003
  // functionality.
2004
1.66M
  assert(DeclsToCheck.empty());
2005
0
  assert(VisitedDecls.empty());
2006
2007
1.66M
  if (!::IsStructurallyEquivalent(*this, D1, D2))
2008
437k
    return false;
2009
2010
1.23M
  return !Finish();
2011
1.66M
}
2012
2013
19.5k
bool StructuralEquivalenceContext::IsEquivalent(QualType T1, QualType T2) {
2014
19.5k
  assert(DeclsToCheck.empty());
2015
0
  assert(VisitedDecls.empty());
2016
19.5k
  if (!::IsStructurallyEquivalent(*this, T1, T2))
2017
2.06k
    return false;
2018
2019
17.4k
  return !Finish();
2020
19.5k
}
2021
2022
82
bool StructuralEquivalenceContext::IsEquivalent(Stmt *S1, Stmt *S2) {
2023
82
  assert(DeclsToCheck.empty());
2024
0
  assert(VisitedDecls.empty());
2025
82
  if (!::IsStructurallyEquivalent(*this, S1, S2))
2026
40
    return false;
2027
2028
42
  return !Finish();
2029
82
}
2030
2031
2.96M
bool StructuralEquivalenceContext::CheckCommonEquivalence(Decl *D1, Decl *D2) {
2032
  // Check for equivalent described template.
2033
2.96M
  TemplateDecl *Template1 = D1->getDescribedTemplate();
2034
2.96M
  TemplateDecl *Template2 = D2->getDescribedTemplate();
2035
2.96M
  if ((Template1 != nullptr) != (Template2 != nullptr))
2036
63.8k
    return false;
2037
2.89M
  if (Template1 && 
!IsStructurallyEquivalent(*this, Template1, Template2)321
)
2038
40
    return false;
2039
2040
  // FIXME: Move check for identifier names into this function.
2041
2042
2.89M
  return true;
2043
2.89M
}
2044
2045
bool StructuralEquivalenceContext::CheckKindSpecificEquivalence(
2046
2.89M
    Decl *D1, Decl *D2) {
2047
2048
  // Kind mismatch.
2049
2.89M
  if (D1->getKind() != D2->getKind())
2050
50.9k
    return false;
2051
2052
  // Cast the Decls to their actual subclass so that the right overload of
2053
  // IsStructurallyEquivalent is called.
2054
2.84M
  switch (D1->getKind()) {
2055
0
#define ABSTRACT_DECL(DECL)
2056
0
#define DECL(DERIVED, BASE)                                                    \
2057
2.84M
  case Decl::Kind::DERIVED:                                                    \
2058
2.84M
    return ::IsStructurallyEquivalent(*this, static_cast<DERIVED##Decl *>(D1), \
2059
2.84M
                                      static_cast<DERIVED##Decl *>(D2));
2060
2.84M
#include 
"clang/AST/DeclNodes.inc"0
2061
2.84M
  }
2062
0
  return true;
2063
2.84M
}
2064
2065
1.24M
bool StructuralEquivalenceContext::Finish() {
2066
3.15M
  while (!DeclsToCheck.empty()) {
2067
    // Check the next declaration.
2068
2.96M
    std::pair<Decl *, Decl *> P = DeclsToCheck.front();
2069
2.96M
    DeclsToCheck.pop();
2070
2071
2.96M
    Decl *D1 = P.first;
2072
2.96M
    Decl *D2 = P.second;
2073
2074
2.96M
    bool Equivalent =
2075
2.96M
        CheckCommonEquivalence(D1, D2) && 
CheckKindSpecificEquivalence(D1, D2)2.89M
;
2076
2077
2.96M
    if (!Equivalent) {
2078
      // Note that these two declarations are not equivalent (and we already
2079
      // know about it).
2080
1.05M
      NonEquivalentDecls.insert(P);
2081
2082
1.05M
      return true;
2083
1.05M
    }
2084
2.96M
  }
2085
2086
191k
  return false;
2087
1.24M
}