clang: lib/AST/ASTStructuralEquivalence.cpp Source File (original) (raw)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
89#include "llvm/ADT/APInt.h"
90#include "llvm/ADT/APSInt.h"
91#include "llvm/ADT/StringExtras.h"
92#include "llvm/Support/Compiler.h"
93#include "llvm/Support/ErrorHandling.h"
94#include
95#include
96#include
97
98using namespace clang;
99
105 const Stmt *S1, const Stmt *S2);
117
122 return false;
123
125
129
135
140 return false;
144 }
145
148
152
154 return true;
155
159 return true;
160 }
161
162 llvm_unreachable("Unhandled kind of DeclarationName");
163 return true;
164}
165
166namespace {
167
168class StmtComparer {
169 StructuralEquivalenceContext &Context;
170
171
172
173
174
175 bool IsStmtEquivalent(const AddrLabelExpr *E1, const AddrLabelExpr *E2) {
177 }
178
179 bool IsStmtEquivalent(const AtomicExpr *E1, const AtomicExpr *E2) {
181 }
182
183 bool IsStmtEquivalent(const BinaryOperator *E1, const BinaryOperator *E2) {
185 }
186
187 bool IsStmtEquivalent(const CallExpr *E1, const CallExpr *E2) {
188
191
192
193 if (static_cast<bool>(Callee1) != static_cast<bool>(Callee2))
194 return false;
195
196
197 if (!static_cast<bool>(Callee1))
198 return true;
199
200 assert(Callee2);
202 }
203
204 bool IsStmtEquivalent(const CharacterLiteral *E1,
205 const CharacterLiteral *E2) {
207 }
208
209 bool IsStmtEquivalent(const ChooseExpr *E1, const ChooseExpr *E2) {
210 return true;
211 }
212
214
215
216
217
218
219 return E1->size() == E2->size();
220 }
221
222 bool IsStmtEquivalent(const DeclRefExpr *DRE1, const DeclRefExpr *DRE2) {
223 const ValueDecl *Decl1 = DRE1->getDecl();
224 const ValueDecl *Decl2 = DRE2->getDecl();
225 if (!Decl1 || !Decl2)
226 return false;
228 const_cast<ValueDecl *>(Decl2));
229 }
230
231 bool IsStmtEquivalent(const DependentScopeDeclRefExpr *DE1,
232 const DependentScopeDeclRefExpr *DE2) {
235 return false;
238 }
239
240 bool IsStmtEquivalent(const Expr *E1, const Expr *E2) {
242 }
243
244 bool IsStmtEquivalent(const ExpressionTraitExpr *E1,
245 const ExpressionTraitExpr *E2) {
247 }
248
249 bool IsStmtEquivalent(const FloatingLiteral *E1, const FloatingLiteral *E2) {
251 }
252
253 bool IsStmtEquivalent(const GenericSelectionExpr *E1,
254 const GenericSelectionExpr *E2) {
257 std::optional<TypeSourceInfo *> Child1 = std::get<0>(Pair);
258 std::optional<TypeSourceInfo *> Child2 = std::get<1>(Pair);
259
260 if (!Child1 || !Child2)
261 return false;
262
264 (*Child2)->getType()))
265 return false;
266 }
267
268 return true;
269 }
270
271 bool IsStmtEquivalent(const ImplicitCastExpr *CastE1,
272 const ImplicitCastExpr *CastE2) {
275 }
276
277 bool IsStmtEquivalent(const IntegerLiteral *E1, const IntegerLiteral *E2) {
279 }
280
281 bool IsStmtEquivalent(const MemberExpr *E1, const MemberExpr *E2) {
284 }
285
286 bool IsStmtEquivalent(const ObjCStringLiteral *E1,
287 const ObjCStringLiteral *E2) {
288
289 return true;
290 }
291
292 bool IsStmtEquivalent(const Stmt *S1, const Stmt *S2) { return true; }
293
294 bool IsStmtEquivalent(const GotoStmt *S1, const GotoStmt *S2) {
295 LabelDecl *L1 = S1->getLabel();
296 LabelDecl *L2 = S2->getLabel();
297 if (!L1 || !L2)
298 return L1 == L2;
299
302 return ::IsStructurallyEquivalent(Name1, Name2);
303 }
304
305 bool IsStmtEquivalent(const SourceLocExpr *E1, const SourceLocExpr *E2) {
307 }
308
309 bool IsStmtEquivalent(const StmtExpr *E1, const StmtExpr *E2) {
311 }
312
313 bool IsStmtEquivalent(const StringLiteral *E1, const StringLiteral *E2) {
315 }
316
317 bool IsStmtEquivalent(const SubstNonTypeTemplateParmExpr *E1,
318 const SubstNonTypeTemplateParmExpr *E2) {
321 return false;
323 return false;
325 return false;
326 return true;
327 }
328
329 bool IsStmtEquivalent(const SubstNonTypeTemplateParmPackExpr *E1,
330 const SubstNonTypeTemplateParmPackExpr *E2) {
333 }
334
335 bool IsStmtEquivalent(const TypeTraitExpr *E1, const TypeTraitExpr *E2) {
337 return false;
338
339 for (auto Pair : zip_longest(E1->getArgs(), E2->getArgs())) {
340 std::optional<TypeSourceInfo *> Child1 = std::get<0>(Pair);
341 std::optional<TypeSourceInfo *> Child2 = std::get<1>(Pair);
342
343 if (!Child1 || !Child2)
344 return false;
345
347 (*Child2)->getType()))
348 return false;
349 }
350 return true;
351 }
352
353 bool IsStmtEquivalent(const CXXDependentScopeMemberExpr *E1,
354 const CXXDependentScopeMemberExpr *E2) {
356 return false;
357 }
360 }
361
362 bool IsStmtEquivalent(const UnaryExprOrTypeTraitExpr *E1,
363 const UnaryExprOrTypeTraitExpr *E2) {
365 return false;
368 }
369
370 bool IsStmtEquivalent(const UnaryOperator *E1, const UnaryOperator *E2) {
372 }
373
374 bool IsStmtEquivalent(const VAArgExpr *E1, const VAArgExpr *E2) {
375
376 return true;
377 }
378
379 bool IsStmtEquivalent(const OverloadExpr *E1, const OverloadExpr *E2) {
381 return false;
382
385 return false;
389 return false;
390
392 return false;
393 const TemplateArgumentLoc *Args1 = E1->getTemplateArgs();
394 const TemplateArgumentLoc *Args2 = E2->getTemplateArgs();
395 for (unsigned int ArgI = 0, ArgN = E1->getNumTemplateArgs(); ArgI < ArgN;
396 ++ArgI)
398 return false;
399
400 return true;
401 }
402
403 bool IsStmtEquivalent(const CXXBoolLiteralExpr *E1, const CXXBoolLiteralExpr *E2) {
405 }
406
407
408 bool TraverseStmt(const Stmt *S1, const Stmt *S2) { return true; }
409
410
411
412
413
414
415#define STMT(CLASS, PARENT) \
416 bool TraverseStmt(const CLASS *S1, const CLASS *S2) { \
417 if (!TraverseStmt(static_cast<const PARENT *>(S1), \
418 static_cast<const PARENT *>(S2))) \
419 return false; \
420 return IsStmtEquivalent(S1, S2); \
421 }
422#include "clang/AST/StmtNodes.inc"
423
424public:
426
427
428
429
430 bool IsEquivalent(const Stmt *S1, const Stmt *S2) {
432 return false;
433
434
435
436
437
438
441 llvm_unreachable("Can't traverse NoStmtClass");
442#define STMT(CLASS, PARENT) \
443 case Stmt::StmtClass::CLASS##Class: \
444 return TraverseStmt(static_cast<const CLASS *>(S1), \
445 static_cast<const CLASS *>(S2));
446#define ABSTRACT_STMT(S)
447#include "clang/AST/StmtNodes.inc"
448 }
449 llvm_unreachable("Invalid statement kind");
450 }
451};
452}
453
454static bool
456 const Decl *D1, const Decl *D2,
457 const Decl *PrimaryDecl = nullptr) {
458
459
460
461
462
463
464
465
466
467
468 const Attr *D1Attr = nullptr, *D2Attr = nullptr;
470 D1Attr = *D1->getAttrs().begin();
472 D2Attr = *D2->getAttrs().begin();
474 const auto *DiagnoseDecl = cast(PrimaryDecl ? PrimaryDecl : D2);
475 Context.Diag2(DiagnoseDecl->getLocation(),
476 diag::warn_odr_tag_type_with_attributes)
477 << Context.ToCtx.getTypeDeclType(DiagnoseDecl)
478 << (PrimaryDecl != nullptr);
479 if (D1Attr)
480 Context.Diag1(D1Attr->getLoc(), diag::note_odr_attr_here) << D1Attr;
481 if (D2Attr)
482 Context.Diag1(D2Attr->getLoc(), diag::note_odr_attr_here) << D2Attr;
483 }
484
485
486
487
488 return true;
489}
490
498
506
515
524
525
527 const Stmt *S1, const Stmt *S2) {
528 if (!S1 || !S2)
529 return S1 == S2;
530
531
532
533
534
535
536
537
538
539 if (const auto *E2CXXOperatorCall = dyn_cast(S2)) {
540 if (const auto *E1Unary = dyn_cast(S1))
542 if (const auto *E1Binary = dyn_cast(S1))
544 }
545 if (const auto *E1CXXOperatorCall = dyn_cast(S1)) {
546 if (const auto *E2Unary = dyn_cast(S2))
548 if (const auto *E2Binary = dyn_cast(S2))
550 }
551
552
553 StmtComparer Comparer(Context);
554 if (!Comparer.IsEquivalent(S1, S2))
555 return false;
556
557
558 for (auto Pair : zip_longest(S1->children(), S2->children())) {
559 std::optional<const Stmt *> Child1 = std::get<0>(Pair);
560 std::optional<const Stmt *> Child2 = std::get<1>(Pair);
561
562
563 if (!Child1 || !Child2)
564 return false;
566 return false;
567 }
568 return true;
569}
570
571
574 if (!Name1 || !Name2)
575 return Name1 == Name2;
576
578}
579
580
584 auto Kind = NNS1.getKind();
585 if (Kind != NNS2.getKind())
586 return false;
587 switch (Kind) {
590 return true;
597 return false;
599 }
606 }
607 return false;
608}
609
614 return false;
615
618 if (!II1 || !II2)
619 return IO1.getOperator() == IO2.getOperator();
621}
622
628 if (TemplateDeclN1 && TemplateDeclN2) {
630 return false;
631
633 return true;
634 } else if (TemplateDeclN1 || TemplateDeclN2)
635 return false;
637 return false;
638
639
641
646 E1 = OS1->end(), E2 = OS2->end();
647 for (; I1 != E1 && I2 != E2; ++I1, ++I2)
649 return false;
650 return I1 == E1 && I2 == E2;
651 }
652
656 return TN1->getDeclName() == TN2->getDeclName();
657 }
658
662
668 P2->getArgumentPack()) &&
670 P2->getAssociatedDecl()) &&
671 P1->getIndex() == P2->getIndex();
672 }
673
678
679 break;
680
682
683 llvm_unreachable("unimplemented");
684 }
685
686 return true;
687}
688
692
693
698 return false;
699
700 switch (Arg1.getKind()) {
702 return true;
703
706
710 return false;
711
712 return llvm::APSInt::isSameValue(Arg1.getAsIntegral(),
714
717
719 return true;
720
724
729
733
736
740 }
741
742 llvm_unreachable("Invalid template argument kind");
743}
744
745
749 if (Args1.size() != Args2.size())
750 return false;
751 for (unsigned I = 0, N = Args1.size(); I != N; ++I) {
753 return false;
754 }
755 return true;
756}
757
758
765
766
767
773 return false;
775 return false;
777 return false;
778
779 return true;
780}
781
782
783
784
788
790 return false;
791
792
794 return false;
796 return false;
797
799 return false;
801 return false;
803 return false;
804
805 return true;
806}
807
808
812
815
817 return true;
818
819 if (Spec1 != Spec2)
820 return false;
823 return false;
824 for (unsigned I = 0, N = Proto1->getNumExceptions(); I != N; ++I) {
827 return false;
828 }
832 return false;
833 }
834
835 return true;
836}
837
838
843
846
847 if (!Context.StrictTypeSpelling) {
848
849
852 }
853
855 return false;
856
858
860
861
862 if (T1->getTypeClass() == Type::FunctionProto &&
864 TC = Type::FunctionNoProto;
865 else if (T1->getTypeClass() == Type::FunctionNoProto &&
867 TC = Type::FunctionNoProto;
868 else if (Context.LangOpts.C23 && !Context.StrictTypeSpelling &&
871
872
873
874
875
876
877
878
879
881 T1 = cast(T1)->getDecl()->getIntegerType();
883 } else if (T2->getTypeClass() == Type::Enum) {
884 T2 = cast(T2)->getDecl()->getIntegerType();
886 }
887 TC = Type::Builtin;
888 } else
889 return false;
890 }
891
892 switch (TC) {
893 case Type::Builtin:
894
896 return false;
897 break;
898
899 case Type::Complex:
903 return false;
904 break;
905
906 case Type::Adjusted:
907 case Type::Decayed:
908 case Type::ArrayParameter:
912 return false;
913 break;
914
915 case Type::Pointer:
919 return false;
920 break;
921
922 case Type::BlockPointer:
926 return false;
927 break;
928
929 case Type::LValueReference:
930 case Type::RValueReference: {
933 if (Ref1->isSpelledAsLValue() != Ref2->isSpelledAsLValue())
934 return false;
935 if (Ref1->isInnerRef() != Ref2->isInnerRef())
936 return false;
938 Ref2->getPointeeTypeAsWritten()))
939 return false;
940 break;
941 }
942
943 case Type::MemberPointer: {
947 MemPtr2->getPointeeType()))
948 return false;
950 MemPtr2->getQualifier()))
951 return false;
952 CXXRecordDecl *D1 = MemPtr1->getMostRecentCXXRecordDecl(),
953 *D2 = MemPtr2->getMostRecentCXXRecordDecl();
954 if (D1 == D2)
955 break;
957 return false;
958 break;
959 }
960
961 case Type::ConstantArray: {
964 if (!llvm::APInt::isSameValue(Array1->getSize(), Array2->getSize()))
965 return false;
966
968 return false;
969 break;
970 }
971
972 case Type::IncompleteArray:
975 return false;
976 break;
977
978 case Type::VariableArray: {
982 Array2->getSizeExpr()))
983 return false;
984
986 return false;
987
988 break;
989 }
990
991 case Type::DependentSizedArray: {
995 Array2->getSizeExpr()))
996 return false;
997
999 return false;
1000
1001 break;
1002 }
1003
1004 case Type::DependentAddressSpace: {
1008 DepAddressSpace2->getAddrSpaceExpr()))
1009 return false;
1011 DepAddressSpace2->getPointeeType()))
1012 return false;
1013
1014 break;
1015 }
1016
1017 case Type::DependentSizedExtVector: {
1021 Vec2->getSizeExpr()))
1022 return false;
1024 Vec2->getElementType()))
1025 return false;
1026 break;
1027 }
1028
1029 case Type::DependentVector: {
1032 if (Vec1->getVectorKind() != Vec2->getVectorKind())
1033 return false;
1035 Vec2->getSizeExpr()))
1036 return false;
1038 Vec2->getElementType()))
1039 return false;
1040 break;
1041 }
1042
1043 case Type::Vector:
1044 case Type::ExtVector: {
1048 Vec2->getElementType()))
1049 return false;
1050 if (Vec1->getNumElements() != Vec2->getNumElements())
1051 return false;
1052 if (Vec1->getVectorKind() != Vec2->getVectorKind())
1053 return false;
1054 break;
1055 }
1056
1057 case Type::DependentSizedMatrix: {
1060
1061
1068 return false;
1069 break;
1070 }
1071
1072 case Type::ConstantMatrix: {
1075
1076
1081 return false;
1082 break;
1083 }
1084
1085 case Type::FunctionProto: {
1088
1089 if (Proto1->getNumParams() != Proto2->getNumParams())
1090 return false;
1091 for (unsigned I = 0, N = Proto1->getNumParams(); I != N; ++I) {
1093 Proto2->getParamType(I)))
1094 return false;
1095 }
1096 if (Proto1->isVariadic() != Proto2->isVariadic())
1097 return false;
1098
1099 if (Proto1->getMethodQuals() != Proto2->getMethodQuals())
1100 return false;
1101
1102
1103 const auto *OrigProto1 =
1105 const auto *OrigProto2 =
1108 return false;
1109
1110
1111 [[fallthrough]];
1112 }
1113
1114 case Type::FunctionNoProto: {
1118 Function2->getReturnType()))
1119 return false;
1121 Function2->getExtInfo()))
1122 return false;
1123 break;
1124 }
1125
1126 case Type::UnresolvedUsing:
1130 return false;
1131 break;
1132
1133 case Type::Attributed:
1137 return false;
1141 return false;
1142 break;
1143
1144 case Type::CountAttributed:
1148 return false;
1149 break;
1150
1151 case Type::BTFTagAttributed:
1155 return false;
1156 break;
1157
1158 case Type::HLSLAttributedResource:
1162 return false;
1166 return false;
1169 return false;
1170 break;
1171
1172 case Type::HLSLInlineSpirv:
1179 return false;
1180 for (size_t I = 0; I < cast(T1)->getOperands().size();
1181 I++) {
1184 return false;
1185 }
1186 }
1187 break;
1188
1189 case Type::Paren:
1192 return false;
1193 break;
1194
1195 case Type::MacroQualified:
1199 return false;
1200 break;
1201
1202 case Type::Using: {
1204 if (U1->getKeyword() != U2->getKeyword())
1205 return false;
1207 U2->getQualifier()))
1208 return false;
1210 return false;
1212 return false;
1213 break;
1214 }
1215 case Type::Typedef: {
1217 if (U1->getKeyword() != U2->getKeyword())
1218 return false;
1220 U2->getQualifier()))
1221 return false;
1223 return false;
1224 if (U1->typeMatchesDecl() != U2->typeMatchesDecl())
1225 return false;
1226 if (!U1->typeMatchesDecl() &&
1228 return false;
1229 break;
1230 }
1231
1232 case Type::TypeOfExpr:
1236 return false;
1237 break;
1238
1239 case Type::TypeOf:
1243 return false;
1244 break;
1245
1246 case Type::UnaryTransform:
1250 return false;
1251 break;
1252
1253 case Type::Decltype:
1257 return false;
1258 break;
1259
1260 case Type::Auto: {
1264 Auto2->getDeducedType()))
1265 return false;
1266 if (Auto1->isConstrained() != Auto2->isConstrained())
1267 return false;
1268 if (Auto1->isConstrained()) {
1269 if (Auto1->getTypeConstraintConcept() !=
1270 Auto2->getTypeConstraintConcept())
1271 return false;
1273 Auto1->getTypeConstraintArguments(),
1274 Auto2->getTypeConstraintArguments()))
1275 return false;
1276 }
1277 break;
1278 }
1279
1280 case Type::DeducedTemplateSpecialization: {
1284 DT2->getTemplateName()))
1285 return false;
1287 DT2->getDeducedType()))
1288 return false;
1289 break;
1290 }
1291
1292 case Type::Record:
1293 case Type::Enum:
1294 case Type::InjectedClassName: {
1296 if (TT1->getKeyword() != TT2->getKeyword())
1297 return false;
1298 if (TT1->isTagOwned() != TT2->isTagOwned())
1299 return false;
1301 TT2->getQualifier()))
1302 return false;
1304 return false;
1305 break;
1306 }
1307
1308 case Type::TemplateTypeParm: {
1311 if (!Context.IgnoreTemplateParmDepth &&
1312 Parm1->getDepth() != Parm2->getDepth())
1313 return false;
1314 if (Parm1->getIndex() != Parm2->getIndex())
1315 return false;
1316 if (Parm1->isParameterPack() != Parm2->isParameterPack())
1317 return false;
1318
1319
1320 break;
1321 }
1322
1323 case Type::SubstTemplateTypeParm: {
1327 Subst2->getReplacementType()))
1328 return false;
1330 Subst2->getAssociatedDecl()))
1331 return false;
1332 if (Subst1->getIndex() != Subst2->getIndex())
1333 return false;
1334 if (Subst1->getPackIndex() != Subst2->getPackIndex())
1335 return false;
1336 break;
1337 }
1338
1339 case Type::SubstBuiltinTemplatePack: {
1343 Subst2->getArgumentPack()))
1344 return false;
1345 break;
1346 }
1347 case Type::SubstTemplateTypeParmPack: {
1351 Subst2->getAssociatedDecl()))
1352 return false;
1353 if (Subst1->getIndex() != Subst2->getIndex())
1354 return false;
1356 Subst2->getArgumentPack()))
1357 return false;
1358 break;
1359 }
1360
1361 case Type::TemplateSpecialization: {
1365 Spec2->getTemplateName()))
1366 return false;
1368 Spec2->template_arguments()))
1369 return false;
1370 break;
1371 }
1372
1373 case Type::DependentName: {
1377 Typename2->getQualifier()))
1378 return false;
1380 Typename2->getIdentifier()))
1381 return false;
1382
1383 break;
1384 }
1385
1386 case Type::PackExpansion:
1390 return false;
1391 break;
1392
1393 case Type::PackIndexing:
1400 return false;
1401 break;
1402
1403 case Type::ObjCInterface: {
1407 Iface2->getDecl()))
1408 return false;
1409 break;
1410 }
1411
1412 case Type::ObjCTypeParam: {
1416 return false;
1417
1418 if (Obj1->getNumProtocols() != Obj2->getNumProtocols())
1419 return false;
1420 for (unsigned I = 0, N = Obj1->getNumProtocols(); I != N; ++I) {
1422 Obj2->getProtocol(I)))
1423 return false;
1424 }
1425 break;
1426 }
1427
1428 case Type::ObjCObject: {
1432 Obj2->getBaseType()))
1433 return false;
1434 if (Obj1->getNumProtocols() != Obj2->getNumProtocols())
1435 return false;
1436 for (unsigned I = 0, N = Obj1->getNumProtocols(); I != N; ++I) {
1438 Obj2->getProtocol(I)))
1439 return false;
1440 }
1441 break;
1442 }
1443
1444 case Type::ObjCObjectPointer: {
1448 Ptr2->getPointeeType()))
1449 return false;
1450 break;
1451 }
1452
1453 case Type::Atomic:
1456 return false;
1457 break;
1458
1459 case Type::Pipe:
1462 return false;
1463 break;
1464 case Type::BitInt: {
1467
1468 if (Int1->isUnsigned() != Int2->isUnsigned() ||
1469 Int1->getNumBits() != Int2->getNumBits())
1470 return false;
1471 break;
1472 }
1473 case Type::DependentBitInt: {
1476
1477 if (Int1->isUnsigned() != Int2->isUnsigned() ||
1479 Int2->getNumBitsExpr()))
1480 return false;
1481 break;
1482 }
1483 case Type::PredefinedSugar: {
1486 if (TP1->getKind() != TP2->getKind())
1487 return false;
1488 break;
1489 }
1490 }
1491
1492 return true;
1493}
1494
1500 return false;
1501
1503 return false;
1504
1505
1506
1507
1509 return true;
1510
1512 return false;
1513
1515}
1516
1521
1522
1523
1524 if (Context.LangOpts.C23 &&
1526 return false;
1527
1528
1529
1530
1536 }
1537
1538
1542 if (Context.Complain) {
1543 Context.Diag2(
1544 Owner2->getLocation(),
1545 Context.getApplicableDiagnostic(diag::err_odr_tag_type_inconsistent))
1546 << Owner2Type << (&Context.FromCtx != &Context.ToCtx);
1547 Context.Diag2(Field2->getLocation(), diag::note_odr_field_name)
1549 Context.Diag1(Field1->getLocation(), diag::note_odr_field_name)
1551 }
1552 return false;
1553 }
1554
1557 if (Context.Complain) {
1558 Context.Diag2(
1559 Owner2->getLocation(),
1560 Context.getApplicableDiagnostic(diag::err_odr_tag_type_inconsistent))
1561 << Owner2Type << (&Context.FromCtx != &Context.ToCtx);
1562 Context.Diag2(Field2->getLocation(), diag::note_odr_field)
1564 Context.Diag1(Field1->getLocation(), diag::note_odr_field)
1566 }
1567 return false;
1568 }
1569
1573
1574
1575
1576 bool Diagnose = true;
1579
1580 if (Diagnose && Context.Complain) {
1581 auto DiagNote = [&](const FieldDecl *FD,
1586 (Context.*Diag)(FD->getLocation(), diag::note_odr_field_bit_width)
1588 } else {
1589 (Context.*Diag)(FD->getLocation(), diag::note_odr_field_not_bit_field)
1591 }
1592 };
1593
1594 Context.Diag2(
1595 Owner2->getLocation(),
1596 Context.getApplicableDiagnostic(diag::err_odr_tag_type_inconsistent))
1597 << Owner2Type << (&Context.FromCtx != &Context.ToCtx);
1600 }
1601 return false;
1602 }
1603
1604 return true;
1605}
1606
1607
1612 Context.ToCtx.getCanonicalTagType(Owner2));
1613}
1614
1615
1619 if (!Method1 && !Method2)
1620 return true;
1621 if (!Method1 || !Method2)
1622 return false;
1623
1624 bool PropertiesEqual =
1638 if (!PropertiesEqual)
1639 return false;
1640
1641
1642 if (auto *Constructor1 = dyn_cast(Method1)) {
1644 if (!Constructor1->getExplicitSpecifier().isEquivalent(
1645 Constructor2->getExplicitSpecifier()))
1646 return false;
1647 }
1648
1649 if (auto *Conversion1 = dyn_cast(Method1)) {
1651 if (!Conversion1->getExplicitSpecifier().isEquivalent(
1652 Conversion2->getExplicitSpecifier()))
1653 return false;
1655 Conversion2->getConversionType()))
1656 return false;
1657 }
1658
1662 return false;
1663
1664 }
1665
1666
1669 return false;
1670
1671 return true;
1672}
1673
1674
1675static bool
1679 "Must be called on lambda classes");
1682 return false;
1683
1684 return true;
1685}
1686
1687
1688static bool
1691
1692
1693
1694
1697 while (true) {
1698
1699
1702 return true;
1703
1705 return false;
1707 break;
1709 return false;
1710 if (const auto *ND1 = dyn_cast(DC1)) {
1714 return false;
1715 }
1716
1717 if (auto *D1Spec = dyn_cast(DC1)) {
1718 auto *D2Spec = dyn_cast(DC2);
1720 return false;
1721 }
1722
1725 }
1726
1727 return true;
1728}
1729
1733 return Name;
1734 if (const TypedefNameDecl *TypedefName = D.getTypedefNameForAnonDecl())
1735 return TypedefName->getIdentifier();
1736 return nullptr;
1737 };
1739}
1740
1741
1744
1745
1746
1747
1748
1749
1750
1751
1752
1753
1754
1755
1756
1757
1758
1759
1760
1761
1762
1763
1764
1766 return false;
1767
1769 if (Context.Complain) {
1770 Context.Diag2(D2->getLocation(), Context.getApplicableDiagnostic(
1771 diag::err_odr_tag_type_inconsistent))
1772 << Context.ToCtx.getCanonicalTagType(D2)
1773 << (&Context.FromCtx != &Context.ToCtx);
1774 Context.Diag1(D1->getLocation(), diag::note_odr_tag_kind_here)
1776 }
1777 return false;
1778 }
1779
1781
1782
1787 D2)) {
1788 if (*Index1 != *Index2)
1789 return false;
1790 }
1791 }
1792 }
1793
1794
1795
1796 if (Context.LangOpts.C23 &&
1798 return false;
1799
1800
1801
1802
1803
1804
1805 if (!Context.LangOpts.C23 &&
1807 return false;
1808
1809
1810
1811 const auto *Spec1 = dyn_cast(D1);
1812 const auto *Spec2 = dyn_cast(D2);
1813 if (Spec1 && Spec2) {
1814
1816 Spec2->getSpecializedTemplate()))
1817 return false;
1818
1819
1820 if (Spec1->getTemplateArgs().size() != Spec2->getTemplateArgs().size())
1821 return false;
1822
1823 for (unsigned I = 0, N = Spec1->getTemplateArgs().size(); I != N; ++I)
1825 Spec2->getTemplateArgs().get(I)))
1826 return false;
1827 }
1828
1829
1830 else if (Spec1 || Spec2)
1831 return false;
1832
1833
1834
1835
1838 if (!D1 || !D2)
1839 return !Context.LangOpts.C23;
1840
1841
1842
1843
1844
1845
1848 return true;
1849
1850
1851
1853 return true;
1854
1855 if (auto *D1CXX = dyn_cast(D1)) {
1856 if (auto *D2CXX = dyn_cast(D2)) {
1857 if (D1CXX->hasExternalLexicalStorage() &&
1858 !D1CXX->isCompleteDefinition()) {
1859 D1CXX->getASTContext().getExternalSource()->CompleteType(D1CXX);
1860 }
1861
1862 if (D1CXX->isLambda() != D2CXX->isLambda())
1863 return false;
1864 if (D1CXX->isLambda()) {
1866 return false;
1867 }
1868
1869 if (D1CXX->getNumBases() != D2CXX->getNumBases()) {
1870 if (Context.Complain) {
1872 Context.getApplicableDiagnostic(
1873 diag::err_odr_tag_type_inconsistent))
1874 << Context.ToCtx.getCanonicalTagType(D2)
1875 << (&Context.FromCtx != &Context.ToCtx);
1876 Context.Diag2(D2->getLocation(), diag::note_odr_number_of_bases)
1877 << D2CXX->getNumBases();
1878 Context.Diag1(D1->getLocation(), diag::note_odr_number_of_bases)
1879 << D1CXX->getNumBases();
1880 }
1881 return false;
1882 }
1883
1884
1886 BaseEnd1 = D1CXX->bases_end(),
1887 Base2 = D2CXX->bases_begin();
1888 Base1 != BaseEnd1; ++Base1, ++Base2) {
1890 Base2->getType())) {
1891 if (Context.Complain) {
1893 Context.getApplicableDiagnostic(
1894 diag::err_odr_tag_type_inconsistent))
1895 << Context.ToCtx.getCanonicalTagType(D2)
1896 << (&Context.FromCtx != &Context.ToCtx);
1897 Context.Diag2(Base2->getBeginLoc(), diag::note_odr_base)
1898 << Base2->getType() << Base2->getSourceRange();
1899 Context.Diag1(Base1->getBeginLoc(), diag::note_odr_base)
1900 << Base1->getType() << Base1->getSourceRange();
1901 }
1902 return false;
1903 }
1904
1905
1906 if (Base1->isVirtual() != Base2->isVirtual()) {
1907 if (Context.Complain) {
1909 Context.getApplicableDiagnostic(
1910 diag::err_odr_tag_type_inconsistent))
1911 << Context.ToCtx.getCanonicalTagType(D2)
1912 << (&Context.FromCtx != &Context.ToCtx);
1913 Context.Diag2(Base2->getBeginLoc(), diag::note_odr_virtual_base)
1914 << Base2->isVirtual() << Base2->getSourceRange();
1915 Context.Diag1(Base1->getBeginLoc(), diag::note_odr_base)
1916 << Base1->isVirtual() << Base1->getSourceRange();
1917 }
1918 return false;
1919 }
1920 }
1921
1922
1924 Friend2End = D2CXX->friend_end();
1926 Friend1End = D1CXX->friend_end();
1927 Friend1 != Friend1End; ++Friend1, ++Friend2) {
1928 if (Friend2 == Friend2End) {
1929 if (Context.Complain) {
1931 Context.getApplicableDiagnostic(
1932 diag::err_odr_tag_type_inconsistent))
1933 << Context.ToCtx.getCanonicalTagType(D2CXX)
1934 << (&Context.FromCtx != &Context.ToCtx);
1935 Context.Diag1((*Friend1)->getFriendLoc(), diag::note_odr_friend);
1936 Context.Diag2(D2->getLocation(), diag::note_odr_missing_friend);
1937 }
1938 return false;
1939 }
1940
1942 if (Context.Complain) {
1944 Context.getApplicableDiagnostic(
1945 diag::err_odr_tag_type_inconsistent))
1946 << Context.ToCtx.getCanonicalTagType(D2CXX)
1947 << (&Context.FromCtx != &Context.ToCtx);
1948 Context.Diag1((*Friend1)->getFriendLoc(), diag::note_odr_friend);
1949 Context.Diag2((*Friend2)->getFriendLoc(), diag::note_odr_friend);
1950 }
1951 return false;
1952 }
1953 }
1954
1955 if (Friend2 != Friend2End) {
1956 if (Context.Complain) {
1958 Context.getApplicableDiagnostic(
1959 diag::err_odr_tag_type_inconsistent))
1960 << Context.ToCtx.getCanonicalTagType(D2)
1961 << (&Context.FromCtx != &Context.ToCtx);
1962 Context.Diag2((*Friend2)->getFriendLoc(), diag::note_odr_friend);
1963 Context.Diag1(D1->getLocation(), diag::note_odr_missing_friend);
1964 }
1965 return false;
1966 }
1967 } else if (D1CXX->getNumBases() > 0) {
1968 if (Context.Complain) {
1970 Context.getApplicableDiagnostic(
1971 diag::err_odr_tag_type_inconsistent))
1972 << Context.ToCtx.getCanonicalTagType(D2)
1973 << (&Context.FromCtx != &Context.ToCtx);
1975 Context.Diag1(Base1->getBeginLoc(), diag::note_odr_base)
1977 Context.Diag2(D2->getLocation(), diag::note_odr_missing_base);
1978 }
1979 return false;
1980 }
1981 }
1982
1983
1984 CanQualType D2Type = Context.ToCtx.getCanonicalTagType(D2);
1989 Field1 != Field1End; ++Field1, ++Field2) {
1990 if (Field2 == Field2End) {
1991 if (Context.Complain) {
1993 Context.getApplicableDiagnostic(
1994 diag::err_odr_tag_type_inconsistent))
1995 << Context.ToCtx.getCanonicalTagType(D2)
1996 << (&Context.FromCtx != &Context.ToCtx);
1997 Context.Diag1(Field1->getLocation(), diag::note_odr_field)
1998 << Field1->getDeclName() << Field1->getType();
1999 Context.Diag2(D2->getLocation(), diag::note_odr_missing_field);
2000 }
2001 return false;
2002 }
2003
2005 return false;
2006 }
2007
2008 if (Field2 != Field2End) {
2009 if (Context.Complain) {
2010 Context.Diag2(D2->getLocation(), Context.getApplicableDiagnostic(
2011 diag::err_odr_tag_type_inconsistent))
2012 << Context.ToCtx.getCanonicalTagType(D2)
2013 << (&Context.FromCtx != &Context.ToCtx);
2014 Context.Diag2(Field2->getLocation(), diag::note_odr_field)
2015 << Field2->getDeclName() << Field2->getType();
2016 Context.Diag1(D1->getLocation(), diag::note_odr_missing_field);
2017 }
2018 return false;
2019 }
2020
2021 return true;
2022}
2023
2027 const llvm::APSInt &FromVal = D1->getInitVal();
2028 const llvm::APSInt &ToVal = D2->getInitVal();
2029 if (FromVal.isSigned() != ToVal.isSigned())
2030 return false;
2031 if (FromVal.getBitWidth() != ToVal.getBitWidth())
2032 return false;
2033 if (FromVal != ToVal)
2034 return false;
2035
2037 return false;
2038
2039
2042}
2043
2044
2048 return false;
2049 }
2050
2051
2052
2053
2054
2057 if (!D1 || !D2)
2058 return true;
2059
2060 if (Context.LangOpts.C23 &&
2062 return false;
2063
2064
2065
2066 if (Context.LangOpts.C23) {
2068 if (Context.Complain) {
2070 Context.getApplicableDiagnostic(
2071 diag::err_odr_tag_type_inconsistent))
2072 << Context.ToCtx.getCanonicalTagType(D2)
2073 << (&Context.FromCtx != &Context.ToCtx);
2076 ? diag::note_odr_fixed_underlying_type
2077 : diag::note_odr_missing_fixed_underlying_type)
2078 << D1;
2081 ? diag::note_odr_fixed_underlying_type
2082 : diag::note_odr_missing_fixed_underlying_type)
2083 << D2;
2084 }
2085 return false;
2086 }
2088 assert(D2->isFixed() && "enums expected to have fixed underlying types");
2091 if (Context.Complain) {
2093 Context.getApplicableDiagnostic(
2094 diag::err_odr_tag_type_inconsistent))
2095 << Context.ToCtx.getCanonicalTagType(D2)
2096 << (&Context.FromCtx != &Context.ToCtx);
2098 diag::note_odr_incompatible_fixed_underlying_type)
2100 }
2101 return false;
2102 }
2103 }
2104 }
2105
2107 auto CopyEnumerators =
2110 Cont.push_back(ECD);
2111 };
2112 CopyEnumerators(D1->enumerators(), D1Enums);
2113 CopyEnumerators(D2->enumerators(), D2Enums);
2114
2115
2116
2117 if (Context.LangOpts.C23) {
2119 return LHS->getName() < RHS->getName();
2120 };
2121 llvm::sort(D1Enums, Sorter);
2122 llvm::sort(D2Enums, Sorter);
2123 }
2124
2125 auto EC2 = D2Enums.begin(), EC2End = D2Enums.end();
2126 for (auto EC1 = D1Enums.begin(), EC1End = D1Enums.end(); EC1 != EC1End;
2127 ++EC1, ++EC2) {
2128 if (EC2 == EC2End) {
2129 if (Context.Complain) {
2131 Context.getApplicableDiagnostic(
2132 diag::err_odr_tag_type_inconsistent))
2133 << Context.ToCtx.getCanonicalTagType(D2)
2134 << (&Context.FromCtx != &Context.ToCtx);
2135 Context.Diag1((*EC1)->getLocation(), diag::note_odr_enumerator)
2136 << (*EC1)->getDeclName() << toString((*EC1)->getInitVal(), 10);
2137 Context.Diag2(D2->getLocation(), diag::note_odr_missing_enumerator);
2138 }
2139 return false;
2140 }
2141
2142 llvm::APSInt Val1 = (*EC1)->getInitVal();
2143 llvm::APSInt Val2 = (*EC2)->getInitVal();
2144 if (!llvm::APSInt::isSameValue(Val1, Val2) ||
2146 (*EC2)->getIdentifier())) {
2147 if (Context.Complain) {
2149 Context.getApplicableDiagnostic(
2150 diag::err_odr_tag_type_inconsistent))
2151 << Context.ToCtx.getCanonicalTagType(D2)
2152 << (&Context.FromCtx != &Context.ToCtx);
2153 Context.Diag2((*EC2)->getLocation(), diag::note_odr_enumerator)
2154 << (*EC2)->getDeclName() << toString((*EC2)->getInitVal(), 10);
2155 Context.Diag1((*EC1)->getLocation(), diag::note_odr_enumerator)
2156 << (*EC1)->getDeclName() << toString((*EC1)->getInitVal(), 10);
2157 }
2158 return false;
2159 }
2160 if (Context.LangOpts.C23 &&
2162 return false;
2163 }
2164
2165 if (EC2 != EC2End) {
2166 if (Context.Complain) {
2167 Context.Diag2(D2->getLocation(), Context.getApplicableDiagnostic(
2168 diag::err_odr_tag_type_inconsistent))
2169 << Context.ToCtx.getCanonicalTagType(D2)
2170 << (&Context.FromCtx != &Context.ToCtx);
2171 Context.Diag2((*EC2)->getLocation(), diag::note_odr_enumerator)
2172 << (*EC2)->getDeclName() << toString((*EC2)->getInitVal(), 10);
2173 Context.Diag1(D1->getLocation(), diag::note_odr_missing_enumerator);
2174 }
2175 return false;
2176 }
2177
2178 return true;
2179}
2180
2184 if (Params1->size() != Params2->size()) {
2185 if (Context.Complain) {
2187 Context.getApplicableDiagnostic(
2188 diag::err_odr_different_num_template_parameters))
2189 << Params1->size() << Params2->size();
2191 diag::note_odr_template_parameter_list);
2192 }
2193 return false;
2194 }
2195
2196 for (unsigned I = 0, N = Params1->size(); I != N; ++I) {
2198 if (Context.Complain) {
2200 Context.getApplicableDiagnostic(
2201 diag::err_odr_different_template_parameter_kind));
2203 diag::note_odr_template_parameter_here);
2204 }
2205 return false;
2206 }
2207
2210 return false;
2211 }
2212
2213 return true;
2214}
2215
2220 if (Context.Complain) {
2222 Context.getApplicableDiagnostic(
2223 diag::err_odr_parameter_pack_non_pack))
2225 Context.Diag1(D1->getLocation(), diag::note_odr_parameter_pack_non_pack)
2227 }
2228 return false;
2229 }
2230
2231 return true;
2232}
2233
2238 if (Context.Complain) {
2240 Context.getApplicableDiagnostic(
2241 diag::err_odr_parameter_pack_non_pack))
2243 Context.Diag1(D1->getLocation(), diag::note_odr_parameter_pack_non_pack)
2245 }
2246 return false;
2247 }
2248 if (!Context.IgnoreTemplateParmDepth && D1->getDepth() != D2->getDepth())
2249 return false;
2251 return false;
2252
2254 if (Context.Complain) {
2256 Context.getApplicableDiagnostic(
2257 diag::err_odr_non_type_parameter_type_inconsistent))
2259 Context.Diag1(D1->getLocation(), diag::note_odr_value_here)
2261 }
2262 return false;
2263 }
2264
2265 return true;
2266}
2267
2272 if (Context.Complain) {
2274 Context.getApplicableDiagnostic(
2275 diag::err_odr_parameter_pack_non_pack))
2277 Context.Diag1(D1->getLocation(), diag::note_odr_parameter_pack_non_pack)
2279 }
2280 return false;
2281 }
2282
2283
2287}
2288
2292 return false;
2295 return false;
2298}
2299
2303
2305 return false;
2306
2307
2310}
2311
2315
2317 return false;
2318
2319
2322}
2323
2327
2329 return false;
2330
2331
2334}
2335
2339
2341 return false;
2342
2343
2346}
2347
2352 return false;
2353 }
2361 return false;
2362}
2363
2367 return false;
2368
2371}
2372
2376 return false;
2377
2380 return false;
2382 return false;
2383 }
2384
2385
2387 return false;
2388
2389 return true;
2390}
2391
2396 return false;
2397
2400}
2401
2408
2412 bool PropertiesEqual =
2416 if (!PropertiesEqual)
2417 return false;
2418
2419
2422 unsigned NumArgs = Selector1.getNumArgs();
2423 if (NumArgs != Selector2.getNumArgs())
2424 return false;
2425
2426
2427 unsigned SlotsToCheck = NumArgs > 0 ? NumArgs : 1;
2428 for (unsigned I = 0; I < SlotsToCheck; ++I) {
2430 Selector2.getIdentifierInfoForSlot(I)))
2431 return false;
2432 }
2433
2434
2437 return false;
2438 assert(
2440 "Same number of arguments should be already enforced in Selector checks");
2446 (ParamT1 != ParamT1End) && (ParamT2 != ParamT2End);
2447 ++ParamT1, ++ParamT2) {
2449 return false;
2450 }
2451
2452 return true;
2453}
2454
2459 return false;
2460
2463 if ((!Intf1 || !Intf2) && (Intf1 != Intf2))
2464 return false;
2465
2466 if (Intf1 &&
2468 return false;
2469
2470
2475 Protocol1 != Protocol1End; ++Protocol1, ++Protocol2) {
2476 if (Protocol2 == Protocol2End)
2477 return false;
2479 (*Protocol2)->getIdentifier()))
2480 return false;
2481 }
2482 if (Protocol2 != Protocol2End)
2483 return false;
2484
2485
2487 Intf2 ? Context.ToCtx.getObjCInterfaceType(Intf2) : QualType();
2492 Ivar1 != Ivar1End; ++Ivar1, ++Ivar2) {
2493 if (Ivar2 == Ivar2End)
2494 return false;
2496 return false;
2497 }
2498 if (Ivar2 != Ivar2End)
2499 return false;
2500
2501
2503 Method2End = D2->meth_end();
2505 Method1End = D1->meth_end();
2506 Method1 != Method1End; ++Method1, ++Method2) {
2507 if (Method2 == Method2End)
2508 return false;
2510 return false;
2511 }
2512 if (Method2 != Method2End)
2513 return false;
2514
2515 return true;
2516}
2517
2518
2521
2522
2525 std::pair<Decl *, Decl *> P{D1, D2};
2526
2527
2528
2529 if (Context.NonEquivalentDecls.count(
2530 std::make_tuple(D1, D2, Context.IgnoreTemplateParmDepth)))
2531 return false;
2532
2533
2534
2535
2536 bool Inserted = Context.VisitedDecls.insert(P).second;
2537 if (!Inserted)
2538 return true;
2539
2540 Context.DeclsToCheck.push(P);
2541
2542 return true;
2543}
2544
2546 unsigned DiagID) {
2547 assert(Complain && "Not allowed to complain");
2549 FromCtx.getDiagnostics().notePriorDiagnosticFrom(ToCtx.getDiagnostics());
2551 return FromCtx.getDiagnostics().Report(Loc, DiagID);
2552}
2553
2555 unsigned DiagID) {
2556 assert(Complain && "Not allowed to complain");
2558 ToCtx.getDiagnostics().notePriorDiagnosticFrom(FromCtx.getDiagnostics());
2560 return ToCtx.getDiagnostics().Report(Loc, DiagID);
2561}
2562
2566 CanQualType AnonTy = Context.getCanonicalTagType(Anon);
2567
2568 const auto *Owner = dyn_cast(Anon->getDeclContext());
2569 if (!Owner)
2570 return std::nullopt;
2571
2572 unsigned Index = 0;
2573 for (const auto *D : Owner->noload_decls()) {
2574 const auto *F = dyn_cast(D);
2575 if (!F)
2576 continue;
2577
2578 if (F->isAnonymousStructOrUnion()) {
2579 if (Context.hasSameType(F->getType(), AnonTy))
2580 break;
2581 ++Index;
2582 continue;
2583 }
2584
2585
2586
2587 QualType FieldType = F->getType();
2588 if (const auto *RecType = dyn_cast(FieldType)) {
2589 const RecordDecl *RecDecl = RecType->getDecl();
2591 if (Context.hasSameType(FieldType, AnonTy))
2592 break;
2593 ++Index;
2594 continue;
2595 }
2596 }
2597 }
2598
2599 return Index;
2600}
2601
2603 unsigned ErrorDiagnostic) {
2605 return ErrorDiagnostic;
2606
2607 switch (ErrorDiagnostic) {
2608 case diag::err_odr_variable_type_inconsistent:
2609 return diag::warn_odr_variable_type_inconsistent;
2610 case diag::err_odr_variable_multiple_def:
2611 return diag::warn_odr_variable_multiple_def;
2612 case diag::err_odr_function_type_inconsistent:
2613 return diag::warn_odr_function_type_inconsistent;
2614 case diag::err_odr_tag_type_inconsistent:
2615 return diag::warn_odr_tag_type_inconsistent;
2616 case diag::err_odr_field_type_inconsistent:
2617 return diag::warn_odr_field_type_inconsistent;
2618 case diag::err_odr_ivar_type_inconsistent:
2619 return diag::warn_odr_ivar_type_inconsistent;
2620 case diag::err_odr_objc_superclass_inconsistent:
2621 return diag::warn_odr_objc_superclass_inconsistent;
2622 case diag::err_odr_objc_method_result_type_inconsistent:
2623 return diag::warn_odr_objc_method_result_type_inconsistent;
2624 case diag::err_odr_objc_method_num_params_inconsistent:
2625 return diag::warn_odr_objc_method_num_params_inconsistent;
2626 case diag::err_odr_objc_method_param_type_inconsistent:
2627 return diag::warn_odr_objc_method_param_type_inconsistent;
2628 case diag::err_odr_objc_method_variadic_inconsistent:
2629 return diag::warn_odr_objc_method_variadic_inconsistent;
2630 case diag::err_odr_objc_property_type_inconsistent:
2631 return diag::warn_odr_objc_property_type_inconsistent;
2632 case diag::err_odr_objc_property_impl_kind_inconsistent:
2633 return diag::warn_odr_objc_property_impl_kind_inconsistent;
2634 case diag::err_odr_objc_synthesize_ivar_inconsistent:
2635 return diag::warn_odr_objc_synthesize_ivar_inconsistent;
2636 case diag::err_odr_different_num_template_parameters:
2637 return diag::warn_odr_different_num_template_parameters;
2638 case diag::err_odr_different_template_parameter_kind:
2639 return diag::warn_odr_different_template_parameter_kind;
2640 case diag::err_odr_parameter_pack_non_pack:
2641 return diag::warn_odr_parameter_pack_non_pack;
2642 case diag::err_odr_non_type_parameter_type_inconsistent:
2643 return diag::warn_odr_non_type_parameter_type_inconsistent;
2644 }
2645 llvm_unreachable("Diagnostic kind not handled in preceding switch");
2646}
2647
2649
2650
2651
2652
2653
2654
2655
2656
2657
2660
2662 return false;
2663
2664 return !Finish();
2665}
2666
2671 return false;
2672
2673 return !Finish();
2674}
2675
2680 return false;
2681
2682 return !Finish();
2683}
2684
2685bool StructuralEquivalenceContext::CheckCommonEquivalence(Decl *D1, Decl *D2) {
2686
2689 if ((Template1 != nullptr) != (Template2 != nullptr))
2690 return false;
2692 return false;
2693
2694
2695
2696 return true;
2697}
2698
2699bool StructuralEquivalenceContext::CheckKindSpecificEquivalence(
2701
2702
2704 return false;
2705
2706
2707
2708 switch (D1->getKind()) {
2709#define ABSTRACT_DECL(DECL)
2710#define DECL(DERIVED, BASE) \
2711 case Decl::Kind::DERIVED: \
2712 return ::IsStructurallyEquivalent(*this, static_cast<DERIVED##Decl *>(D1), \
2713 static_cast<DERIVED##Decl *>(D2));
2714#include "clang/AST/DeclNodes.inc"
2715 }
2716 return true;
2717}
2718
2719bool StructuralEquivalenceContext::Finish() {
2721
2722 std::pair<Decl *, Decl *> P = DeclsToCheck.front();
2724
2725 Decl *D1 = P.first;
2726 Decl *D2 = P.second;
2727
2729 CheckCommonEquivalence(D1, D2) && CheckKindSpecificEquivalence(D1, D2);
2730
2732
2733
2736
2737 return true;
2738 }
2739 }
2740
2741 return false;
2742}
Defines the clang::ASTContext interface.
static bool IsTemplateDeclCommonStructurallyEquivalent(StructuralEquivalenceContext &Ctx, TemplateDecl *D1, TemplateDecl *D2)
Definition ASTStructuralEquivalence.cpp:2289
static bool CheckStructurallyEquivalentAttributes(StructuralEquivalenceContext &Context, const Decl *D1, const Decl *D2, const Decl *PrimaryDecl=nullptr)
Definition ASTStructuralEquivalence.cpp:455
static bool IsStructurallyEquivalentLambdas(StructuralEquivalenceContext &Context, CXXRecordDecl *D1, CXXRecordDecl *D2)
Determine structural equivalence of two lambda classes.
Definition ASTStructuralEquivalence.cpp:1676
static bool NameIsStructurallyEquivalent(const TagDecl &D1, const TagDecl &D2)
Definition ASTStructuralEquivalence.cpp:1730
static bool IsRecordContextStructurallyEquivalent(StructuralEquivalenceContext &Context, RecordDecl *D1, RecordDecl *D2)
Determine if context of a class is equivalent.
Definition ASTStructuralEquivalence.cpp:1689
static bool IsEquivalentExceptionSpec(StructuralEquivalenceContext &Context, const FunctionProtoType *Proto1, const FunctionProtoType *Proto2)
Check the equivalence of exception specifications.
Definition ASTStructuralEquivalence.cpp:809
static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, QualType T1, QualType T2)
Determine structural equivalence of two types.
Definition ASTStructuralEquivalence.cpp:839
static bool IsArrayStructurallyEquivalent(StructuralEquivalenceContext &Context, const ArrayType *Array1, const ArrayType *Array2)
Determine structural equivalence for the common part of array types.
Definition ASTStructuralEquivalence.cpp:768
static Decl::Kind getKind(const Decl *D)
Defines the C++ Decl subclasses, other than those for templates (found in DeclTemplate....
This file defines OpenACC nodes for declarative directives.
This file defines OpenMP nodes for declarative directives.
Defines the C++ template declaration subclasses.
Defines the ExceptionSpecificationType enumeration and various utility functions.
Defines the clang::Expr interface and subclasses for C++ expressions.
Defines Expressions and AST nodes for C++2a concepts.
Defines the clang::IdentifierInfo, clang::IdentifierTable, and clang::Selector interfaces.
Forward-declares and imports various common LLVM datatypes that clang wants to use unqualified.
static DiagnosticBuilder Diag(DiagnosticsEngine *Diags, const LangOptions &Features, FullSourceLoc TokLoc, const char *TokBegin, const char *TokRangeBegin, const char *TokRangeEnd, unsigned DiagID)
Produce a diagnostic highlighting some portion of a literal.
static QualType getUnderlyingType(const SubRegion *R)
static std::string toString(const clang::SanitizerSet &Sanitizers)
Produce a string containing comma-separated names of sanitizers in Sanitizers set.
Defines the clang::SourceLocation class and associated facilities.
Defines the Objective-C statement AST node classes.
This file defines OpenACC AST classes for statement-level contructs.
This file defines OpenMP AST classes for executable directives and clauses.
This file defines SYCL AST classes used to represent calls to SYCL kernels.
static QualType getPointeeType(const MemRegion *R)
C Language Family Type Representation.
llvm::APInt getValue() const
Holds long-lived AST nodes (such as types and decls) that can be referred to throughout the semantic ...
LabelDecl * getLabel() const
Represents an array type, per C99 6.7.5.2 - Array Declarators.
ArraySizeModifier getSizeModifier() const
Qualifiers getIndexTypeQualifiers() const
QualType getElementType() const
A structure for storing the information associated with a name that has been assumed to be a template...
DeclarationName getDeclName() const
Get the name of the template.
Attr - This represents one attribute.
SourceLocation getLoc() const
A builtin binary operation expression such as "x + y" or "x <= y".
static OverloadedOperatorKind getOverloadedOperator(Opcode Opc)
Retrieve the overloaded operator kind that corresponds to the given binary opcode.
Represents a base class of a C++ class.
SourceLocation getBeginLoc() const LLVM_READONLY
QualType getType() const
Retrieves the type of the base class.
SourceRange getSourceRange() const LLVM_READONLY
Retrieves the source range that contains the entire base specifier.
QualType getBaseType() const
DeclarationName getMember() const
Retrieve the name of the member that this expression refers to.
Represents a static or instance method of a struct/union/class.
bool isImplicitObjectMemberFunction() const
[C++2b][dcl.fct]/p7 An implicit object member function is a non-static member function without an exp...
RefQualifierKind getRefQualifier() const
Retrieve the ref-qualifier associated with this method.
A call to an overloaded operator written using operator syntax.
OverloadedOperatorKind getOperator() const
Returns the kind of overloaded operator that this expression refers to.
An iterator over the friend declarations of a class.
Represents a C++ struct/union/class.
CXXBaseSpecifier * base_class_iterator
Iterator that traverses the base classes of a class.
bool isLambda() const
Determine whether this class describes a lambda function object.
CXXMethodDecl * getLambdaCallOperator() const
Retrieve the lambda call operator of the closure type if this is a closure type.
Expr * getArg(unsigned Arg)
getArg - Return the specified argument.
unsigned getValue() const
CharacterLiteralKind getKind() const
Declaration of a class template.
CXXRecordDecl * getTemplatedDecl() const
Get the underlying class declarations of the template.
Declaration of a C++20 concept.
Expr * getConstraintExpr() const
Represents a concrete matrix type with constant number of rows and columns.
unsigned getNumColumns() const
Returns the number of columns in the matrix.
unsigned getNumRows() const
Returns the number of rows in the matrix.
DeclContext - This is used only as base class of specific decl types that can act as declaration cont...
DeclContext * getParent()
getParent - Returns the containing DeclContext.
bool isTranslationUnit() const
bool hasExternalLexicalStorage() const
Whether this DeclContext has external storage containing additional declarations that are lexically i...
bool isInlineNamespace() const
bool isFunctionOrMethod() const
Decl::Kind getDeclKind() const
DeclContext * getNonTransparentContext()
Decl - This represents one declaration (or definition), e.g.
TemplateDecl * getDescribedTemplate() const
If this is a declaration that describes some template, this method returns that template declaration.
ASTContext & getASTContext() const LLVM_READONLY
bool isImplicit() const
isImplicit - Indicates whether the declaration was implicitly generated by the implementation.
SourceLocation getLocation() const
DeclContext * getDeclContext()
AccessSpecifier getAccess() const
virtual Decl * getCanonicalDecl()
Retrieves the "canonical" declaration of the given declaration.
The name of a declaration.
IdentifierInfo * getAsIdentifierInfo() const
Retrieve the IdentifierInfo * stored in this declaration name, or null if this declaration name isn't...
TemplateDecl * getCXXDeductionGuideTemplate() const
If this name is the name of a C++ deduction guide, return the template associated with that name.
const IdentifierInfo * getCXXLiteralIdentifier() const
If this name is the name of a literal operator, retrieve the identifier associated with it.
OverloadedOperatorKind getCXXOverloadedOperator() const
If this name is the name of an overloadable operator in C++ (e.g., operator+), retrieve the kind of o...
@ CXXConversionFunctionName
QualType getCXXNameType() const
If this name is one of the C++ names (of a constructor, destructor, or conversion function),...
NameKind getNameKind() const
Determine what kind of name this is.
NestedNameSpecifier getQualifier() const
Retrieve the nested-name-specifier that qualifies this declaration.
DeclarationName getDeclName() const
Retrieve the name that this expression refers to.
Represents a matrix type where the type and the number of rows and columns is dependent on a template...
Expr * getColumnExpr() const
Expr * getRowExpr() const
Represents a dependent template name that cannot be resolved prior to template instantiation.
IdentifierOrOverloadedOperator getName() const
NestedNameSpecifier getQualifier() const
Return the nested name specifier that qualifies this name.
A little helper class used to produce diagnostics.
An instance of this object exists for each enum constant that is defined.
llvm::APSInt getInitVal() const
const Expr * getInitExpr() const
enumerator_range enumerators() const
bool isFixed() const
Returns true if this is an Objective-C, C++11, or Microsoft-style enumeration with a fixed underlying...
QualType getIntegerType() const
Return the integer type this enum decl corresponds to.
EnumDecl * getDefinition() const
ExpressionTrait getTrait() const
Represents a member of a struct/union/class.
bool isBitField() const
Determines whether this field is a bitfield.
unsigned getBitWidthValue() const
Computes the bit width of this field, if this is a bit field.
bool isAnonymousStructOrUnion() const
Determines whether this field is a representative for an anonymous struct or union.
Expr * getBitWidth() const
Returns the expression that represents the bit width, if this field is a bit field.
llvm::APFloat getValue() const
FriendDecl - Represents the declaration of a friend entity, which can be a function,...
NamedDecl * getFriendDecl() const
If this friend declaration doesn't name a type, return the inner declaration.
TypeSourceInfo * getFriendType() const
If this friend declaration names an (untemplated but possibly dependent) type, return the type; other...
Represents a function declaration or definition.
bool isDeleted() const
Whether this function has been deleted.
bool isPureVirtual() const
Whether this virtual function is pure, i.e.
bool isDefaulted() const
Whether this function is defaulted.
bool isOverloadedOperator() const
Whether this function declaration represents an C++ overloaded operator, e.g., "operator+".
OverloadedOperatorKind getOverloadedOperator() const
getOverloadedOperator - Which C++ overloaded operator this function represents, if any.
Represents a prototype with parameter type info, e.g.
ExceptionSpecificationType getExceptionSpecType() const
Get the kind of exception specification on this function.
QualType getExceptionType(unsigned i) const
Return the ith exception type, where 0 <= i < getNumExceptions().
unsigned getNumExceptions() const
Return the number of types in the exception specification.
Expr * getNoexceptExpr() const
Return the expression inside noexcept(expression), or a null pointer if there is none (because the ex...
Declaration of a template function.
FunctionDecl * getTemplatedDecl() const
Get the underlying function declaration of the template.
A class which abstracts out some details necessary for making a call.
CallingConv getCC() const
bool getNoCfCheck() const
unsigned getRegParm() const
bool getNoCallerSavedRegs() const
bool getHasRegParm() const
bool getProducesResult() const
ArrayRef< TypeSourceInfo * > getAssocTypeSourceInfos() const
LabelDecl * getLabel() const
One of these records is kept for each identifier that is lexed.
StringRef getName() const
Return the actual identifier string.
QualType getElementType() const
Returns type of the elements being stored in the matrix.
DeclAccessPair getFoundDecl() const
Retrieves the declaration found by lookup.
IdentifierInfo * getIdentifier() const
Get the identifier that names this declaration, if there is one.
StringRef getName() const
Get the name of identifier for this declaration as a StringRef.
DeclarationName getDeclName() const
Get the actual, stored name of the declaration, which may be a special name.
std::string getNameAsString() const
Get a human-readable name for the declaration, even if it is one of the special kinds of names (C++ c...
Represents C++ namespaces and their aliases.
Represents a C++ nested name specifier, such as "\::std::vector::".
CXXRecordDecl * getAsMicrosoftSuper() const
NamespaceAndPrefix getAsNamespaceAndPrefix() const
const Type * getAsType() const
@ MicrosoftSuper
Microsoft's '__super' specifier, stored as a CXXRecordDecl* of the class it appeared in.
@ Global
The global specifier '::'. There is no stored value.
@ Type
A type, stored as a Type*.
@ Namespace
A namespace-like entity, stored as a NamespaceBaseDecl*.
NonTypeTemplateParmDecl - Declares a non-type template parameter, e.g., "Size" in.
bool isParameterPack() const
Whether this parameter is a non-type template parameter pack.
unsigned getIndex() const
Get the index of the template parameter within its parameter list.
unsigned getDepth() const
Get the nesting depth of the template parameter.
ObjCCategoryDecl - Represents a category declaration.
ivar_iterator ivar_begin() const
ivar_iterator ivar_end() const
ObjCInterfaceDecl * getClassInterface()
specific_decl_iterator< ObjCIvarDecl > ivar_iterator
protocol_iterator protocol_end() const
protocol_iterator protocol_begin() const
ObjCProtocolList::iterator protocol_iterator
method_iterator meth_begin() const
specific_decl_iterator< ObjCMethodDecl > method_iterator
method_iterator meth_end() const
Represents an ObjC class declaration.
ObjCIvarDecl - Represents an ObjC instance variable.
AccessControl getAccessControl() const
ObjCInterfaceDecl * getContainingInterface()
Return the class interface that this ivar is logically contained in; this is either the interface whe...
ObjCMethodDecl - Represents an instance or class method declaration.
unsigned param_size() const
param_type_iterator param_type_begin() const
param_type_iterator param_type_end() const
bool isDirectMethod() const
True if the method is tagged as objc_direct.
Selector getSelector() const
bool isInstanceMethod() const
llvm::mapped_iterator< param_const_iterator, GetTypeFn > param_type_iterator
QualType getReturnType() const
NestedNameSpecifier getQualifier() const
Fetches the nested-name qualifier, if one was given.
TemplateArgumentLoc const * getTemplateArgs() const
unsigned getNumTemplateArgs() const
DeclarationName getName() const
Gets the name looked up.
A structure for storing the information associated with an overloaded template name.
NamedDecl *const * iterator
A (possibly-)qualified type.
QualType getDesugaredType(const ASTContext &Context) const
Return the specified type with any "sugar" removed from the type.
bool isNull() const
Return true if this QualType doesn't point to a type yet.
Qualifiers getQualifiers() const
Retrieve the set of qualifiers applied to this type.
QualType getCanonicalType() const
Represents a struct/union/class.
field_iterator field_end() const
RecordDecl * getDefinition() const
Returns the RecordDecl that actually defines this struct/union/class.
specific_decl_iterator< FieldDecl > field_iterator
field_iterator field_begin() const
Smart pointer class that efficiently represents Objective-C method names.
const IdentifierInfo * getIdentifierInfoForSlot(unsigned argIndex) const
Retrieve the identifier at a given position in the selector.
unsigned getNumArgs() const
SourceLocIdentKind getIdentKind() const
Encodes a location in the source.
unsigned getTemplateDepth() const
Stmt - This represents one statement.
StmtClass getStmtClass() const
StringRef getBytes() const
Allow access to clients that need the byte representation, such as ASTWriterStmt::VisitStringLiteral(...
Decl * getAssociatedDecl() const
A template-like entity which owns the whole pattern being substituted.
UnsignedOrNone getPackIndex() const
unsigned getIndex() const
Returns the index of the replaced parameter in the associated declaration.
TemplateArgument getArgumentPack() const
Retrieve the template argument pack containing the substituted template arguments.
A structure for storing an already-substituted template template parameter pack.
Decl * getAssociatedDecl() const
A template-like entity which owns the whole pattern being substituted.
TemplateArgument getArgumentPack() const
Retrieve the template template argument pack with which this parameter was substituted.
unsigned getIndex() const
Returns the index of the replaced parameter in the associated declaration.
Represents the declaration of a struct/union/class/enum.
bool isBeingDefined() const
Return true if this decl is currently being defined.
TagKind getTagKind() const
Location wrapper for a TemplateArgument.
const TemplateArgument & getArgument() const
Represents a template argument.
Expr * getAsExpr() const
Retrieve the template argument as an expression.
QualType getAsType() const
Retrieve the type for a type template argument.
llvm::APSInt getAsIntegral() const
Retrieve the template argument as an integral value.
TemplateName getAsTemplate() const
Retrieve the template name for a template name argument.
bool structurallyEquals(const TemplateArgument &Other) const
Determines whether two template arguments are superficially the same.
QualType getIntegralType() const
Retrieve the type of the integral value.
ValueDecl * getAsDecl() const
Retrieve the declaration for a declaration non-type template argument.
ArrayRef< TemplateArgument > pack_elements() const
Iterator range referencing all of the elements of a template argument pack.
@ Declaration
The template argument is a declaration that was provided for a pointer, reference,...
@ Template
The template argument is a template name that was provided for a template template parameter.
@ StructuralValue
The template argument is a non-type template argument that can't be represented by the special-case D...
@ Pack
The template argument is actually a parameter pack.
@ TemplateExpansion
The template argument is a pack expansion of a template name that was provided for a template templat...
@ NullPtr
The template argument is a null pointer or null pointer to member that was provided for a non-type te...
@ Type
The template argument is a type.
@ Null
Represents an empty template argument, e.g., one that has not been deduced.
@ Integral
The template argument is an integral value stored in an llvm::APSInt that was provided for an integra...
@ Expression
The template argument is an expression, and we've not resolved it to one of the other forms yet,...
ArgKind getKind() const
Return the kind of stored template argument.
TemplateName getAsTemplateOrTemplatePattern() const
Retrieve the template argument as a template name; if the argument is a pack expansion,...
The base class of all kinds of template declarations (e.g., class, function, etc.).
TemplateParameterList * getTemplateParameters() const
Get the list of template parameters.
Represents a C++ template name within the type system.
TemplateDecl * getAsTemplateDecl(bool IgnoreDeduced=false) const
Retrieve the underlying template declaration that this template name refers to, if known.
DependentTemplateName * getAsDependentTemplateName() const
Retrieve the underlying dependent template name structure, if any.
OverloadedTemplateStorage * getAsOverloadedTemplate() const
Retrieve the underlying, overloaded function template declarations that this template name refers to,...
AssumedTemplateStorage * getAsAssumedTemplateName() const
Retrieve information on a name that has been assumed to be a template-name in order to permit a call ...
@ UsingTemplate
A template name that refers to a template declaration found through a specific using shadow declarati...
@ OverloadedTemplate
A set of overloaded template declarations.
@ Template
A single template declaration.
@ DependentTemplate
A dependent template name that has not been resolved to a template (or set of templates).
@ SubstTemplateTemplateParm
A template template parameter that has been substituted for some other template name.
@ SubstTemplateTemplateParmPack
A template template parameter pack that has been substituted for a template template argument pack,...
@ DeducedTemplate
A template name that refers to another TemplateName with deduced default arguments.
@ QualifiedTemplate
A qualified template name, where the qualification is kept to describe the source code as written.
@ AssumedTemplate
An unqualified-id that has been assumed to name a function template that will be found by ADL.
SubstTemplateTemplateParmPackStorage * getAsSubstTemplateTemplateParmPack() const
Retrieve the substituted template template parameter pack, if known.
Stores a list of template parameters for a TemplateDecl and its derived classes.
NamedDecl * getParam(unsigned Idx)
SourceLocation getTemplateLoc() const
TemplateTemplateParmDecl - Declares a template template parameter, e.g., "T" in.
TemplateNameKind templateParameterKind() const
bool isParameterPack() const
Whether this template template parameter is a template parameter pack.
Declaration of a template type parameter.
bool isParameterPack() const
Returns whether this is a parameter pack.
Declaration of an alias template.
TypeAliasDecl * getTemplatedDecl() const
Get the underlying function declaration of the template.
QualType getType() const
Return the type wrapped by this type source info.
ArrayRef< TypeSourceInfo * > getArgs() const
Retrieve the argument types.
TypeTrait getTrait() const
Determine which type trait this expression uses.
const T * castAs() const
Member-template castAs.
bool isBuiltinType() const
Helper methods to distinguish type categories.
TypeClass getTypeClass() const
Base class for declarations which introduce a typedef-name.
QualType getUnderlyingType() const
QualType getTypeOfArgument() const
Gets the argument type, or the type of the argument expression, whichever is appropriate.
UnaryExprOrTypeTrait getKind() const
UnaryOperator - This represents the unary-expression's (except sizeof and alignof),...
Expr * getSubExpr() const
static OverloadedOperatorKind getOverloadedOperator(Opcode Opc)
Retrieve the overloaded operator kind that corresponds to the given unary opcode.
Represents a variable declaration or definition.
DefinitionKind isThisDeclarationADefinition(ASTContext &) const
Check whether this declaration is a definition.
const Expr * getInit() const
StorageClass getStorageClass() const
Returns the storage class as written in the source.
std::variant< struct RequiresDecl, struct HeaderDecl, struct UmbrellaDirDecl, struct ModuleDecl, struct ExcludeDecl, struct ExportDecl, struct ExportAsDecl, struct ExternModuleDecl, struct UseDecl, struct LinkDecl, struct ConfigMacrosDecl, struct ConflictDecl > Decl
All declarations that can appear in a module declaration.
The JSON file list parser is used to communicate input to InstallAPI.
CanQual< Type > CanQualType
Represents a canonical, potentially-qualified type.
bool isUnresolvedExceptionSpec(ExceptionSpecificationType ESpecType)
bool isComputedNoexcept(ExceptionSpecificationType ESpecType)
U cast(CodeGen::Address addr)
@ EST_Dynamic
throw(T1, T2)
const IdentifierInfo * getIdentifier() const
Returns the identifier to which this template name refers.
OverloadedOperatorKind getOperator() const
Return the overloaded operator to which this template name refers.
ASTContext & FromCtx
AST contexts for which we are checking structural equivalence.
bool LastDiagFromC2
true if the last diagnostic came from ToCtx.
std::queue< std::pair< Decl *, Decl * > > DeclsToCheck
llvm::DenseSet< std::pair< Decl *, Decl * > > VisitedDecls
static UnsignedOrNone findUntaggedStructOrUnionIndex(RecordDecl *Anon)
Find the index of the given anonymous struct/union within its context.
Definition ASTStructuralEquivalence.cpp:2564
bool IgnoreTemplateParmDepth
Whether to ignore comparing the depth of template param(TemplateTypeParm)
bool ErrorOnTagTypeMismatch
Whether warn or error on tag type mismatches.
NonEquivalentDeclSet & NonEquivalentDecls
Declaration (from, to) pairs that are known not to be equivalent (which we have already complained ab...
bool Complain
Whether to complain about failures.
DiagnosticBuilder Diag2(SourceLocation Loc, unsigned DiagID)
Definition ASTStructuralEquivalence.cpp:2554
unsigned getApplicableDiagnostic(unsigned ErrorDiagnostic)
Definition ASTStructuralEquivalence.cpp:2602
DiagnosticBuilder Diag1(SourceLocation Loc, unsigned DiagID)
Definition ASTStructuralEquivalence.cpp:2545
bool IsEquivalent(Decl *D1, Decl *D2)
Determine whether the two declarations are structurally equivalent.
Definition ASTStructuralEquivalence.cpp:2648