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