clang: lib/Sema/SemaFunctionEffects.cpp Source File (original) (raw)

1

2

3

4

5

6

7

8

9

10

11

12

22

23#define DEBUG_TYPE "effectanalysis"

24

25using namespace clang;

26

27namespace {

28

29enum class ViolationID : uint8_t {

30 None = 0,

31

32

33 BaseDiagnosticIndex,

34 AllocatesMemory = BaseDiagnosticIndex,

35 ThrowsOrCatchesExceptions,

36 HasStaticLocalVariable,

37 AccessesThreadLocalVariable,

38 AccessesObjCMethodOrProperty,

39

40

41 DeclDisallowsInference,

42

43

44

45

46

47 CallsDeclWithoutEffect,

48 CallsExprWithoutEffect,

49};

50

51

52

53class ViolationSite {

54public:

55 enum class Kind : uint8_t {

56 Default,

57 MemberInitializer,

58 DefaultArgExpr

59 };

60

61private:

62 llvm::PointerIntPair<CXXDefaultArgExpr *, 2, Kind> Impl;

63

64public:

65 ViolationSite() = default;

66

68 : Impl(E, Kind::DefaultArgExpr) {}

69

70 Kind kind() const { return static_cast<Kind>(Impl.getInt()); }

71 CXXDefaultArgExpr *defaultArgExpr() const { return Impl.getPointer(); }

72

73 void setKind(Kind K) { Impl.setPointerAndInt(nullptr, K); }

74};

75

76

77

78

79

80

81

82struct Violation {

84 std::optional

85 CalleeEffectPreventingInference;

86 ViolationID ID = ViolationID::None;

87 ViolationSite Site;

89 const Decl *Callee =

90 nullptr;

91

92 Violation(FunctionEffect Effect, ViolationID ID, ViolationSite VS,

94 std::optional CalleeEffect = std::nullopt)

95 : Effect(Effect), CalleeEffectPreventingInference(CalleeEffect), ID(ID),

96 Site(VS), Loc(Loc), Callee(Callee) {}

97

98 unsigned diagnosticSelectIndex() const {

99 return unsigned(ID) - unsigned(ViolationID::BaseDiagnosticIndex);

100 }

101};

102

103enum class SpecialFuncType : uint8_t { None, OperatorNew, OperatorDelete };

104enum class CallableType : uint8_t {

105

110};

111

112

113

114static bool functionIsVerifiable(const FunctionDecl *FD) {

116

117

118 return true;

119 }

121}

122

125 return FPT && (FPT->isNothrow() || FD->hasAttr());

126}

127

128

129

130

131

132

133

134

137

138 switch (BuiltinID) {

139 case 0:

140 default:

141 break;

142

143

144 case Builtin::ID::BI__builtin_calloc:

145 case Builtin::ID::BI__builtin_malloc:

146 case Builtin::ID::BI__builtin_realloc:

147 case Builtin::ID::BI__builtin_free:

148 case Builtin::ID::BI__builtin_operator_delete:

149 case Builtin::ID::BI__builtin_operator_new:

150 case Builtin::ID::BIaligned_alloc:

151 case Builtin::ID::BIcalloc:

152 case Builtin::ID::BImalloc:

153 case Builtin::ID::BImemalign:

154 case Builtin::ID::BIrealloc:

155 case Builtin::ID::BIfree:

156

157 case Builtin::ID::BIfopen:

158 case Builtin::ID::BIpthread_create:

159 case Builtin::ID::BI_Block_object_dispose:

160 Result.insert(FunctionEffect(FunctionEffect::Kind::Allocating));

161 break;

162

163

164

165

166 case Builtin::ID::BIlongjmp:

167 case Builtin::ID::BI_longjmp:

168 case Builtin::ID::BIsiglongjmp:

169 case Builtin::ID::BI__builtin_longjmp:

170 case Builtin::ID::BIobjc_exception_throw:

171

172

173 case Builtin::ID::BIobjc_msgSend:

174 case Builtin::ID::BIobjc_msgSend_fpret:

175 case Builtin::ID::BIobjc_msgSend_fp2ret:

176 case Builtin::ID::BIobjc_msgSend_stret:

177 case Builtin::ID::BIobjc_msgSendSuper:

178 case Builtin::ID::BIobjc_getClass:

179 case Builtin::ID::BIobjc_getMetaClass:

180 case Builtin::ID::BIobjc_enumerationMutation:

181 case Builtin::ID::BIobjc_assign_ivar:

182 case Builtin::ID::BIobjc_assign_global:

183 case Builtin::ID::BIobjc_sync_enter:

184 case Builtin::ID::BIobjc_sync_exit:

185 case Builtin::ID::BINSLog:

186 case Builtin::ID::BINSLogv:

187

188

189 case Builtin::ID::BIfread:

190 case Builtin::ID::BIfwrite:

191

192

193 case Builtin::ID::BIprintf:

194 case Builtin::ID::BI__builtin_printf:

195 case Builtin::ID::BIfprintf:

196 case Builtin::ID::BIsnprintf:

197 case Builtin::ID::BIsprintf:

198 case Builtin::ID::BIvprintf:

199 case Builtin::ID::BIvfprintf:

200 case Builtin::ID::BIvsnprintf:

201 case Builtin::ID::BIvsprintf:

202

203

204 case Builtin::ID::BIscanf:

205 case Builtin::ID::BIfscanf:

206 case Builtin::ID::BIsscanf:

207 case Builtin::ID::BIvscanf:

208 case Builtin::ID::BIvfscanf:

209 case Builtin::ID::BIvsscanf:

210 Result.insert(FunctionEffect(FunctionEffect::Kind::Blocking));

211 break;

212 }

213

214 return Result;

215}

216

217

218

219struct CallableInfo {

220

221

222

223 const Decl *CDecl;

224

225

226

227 CallableType CType = CallableType::Unknown;

228

229

230

231

232 SpecialFuncType FuncType = SpecialFuncType::None;

233

234

236

237 CallableInfo(const Decl &CD, SpecialFuncType FT = SpecialFuncType::None)

238 : CDecl(&CD), FuncType(FT) {

240 if (auto *FD = dyn_cast(CDecl)) {

241

243 CDecl = FD = Def;

244 CType = CallableType::Function;

245 if (auto *Method = dyn_cast(FD);

246 Method && Method->isVirtual())

247 CType = CallableType::Virtual;

249 } else if (auto *BD = dyn_cast(CDecl)) {

250 CType = CallableType::Block;

251 DeclEffects = BD->getFunctionEffects();

252 } else if (auto *VD = dyn_cast(CDecl)) {

253

255 }

257 }

258

259 CallableType type() const { return CType; }

260

261 bool isCalledDirectly() const {

262 return CType == CallableType::Function || CType == CallableType::Block;

263 }

264

265 bool isVerifiable() const {

266 switch (CType) {

267 case CallableType::Unknown:

268 case CallableType::Virtual:

269 return false;

270 case CallableType::Block:

271 return true;

272 case CallableType::Function:

273 return functionIsVerifiable(dyn_cast(CDecl));

274 }

275 llvm_unreachable("undefined CallableType");

276 }

277

278

279 std::string getNameForDiagnostic(Sema &S) const {

280 std::string Name;

281 llvm::raw_string_ostream OS(Name);

282

283 if (auto *FD = dyn_cast(CDecl))

285 true);

286 else if (auto *BD = dyn_cast(CDecl))

287 OS << "(block " << BD->getBlockManglingNumber() << ")";

288 else if (auto *VD = dyn_cast(CDecl))

289 VD->printQualifiedName(OS);

290 return Name;

291 }

292};

293

294

295

296

297class EffectToViolationMap {

298

299

300

301

302

304 std::unique_ptr Impl;

305

306public:

307

308 void maybeInsert(const Violation &Viol) {

309 if (Impl == nullptr)

310 Impl = std::make_unique();

311 else if (lookup(Viol.Effect) != nullptr)

312 return;

313

314 Impl->push_back(Viol);

315 }

316

318 if (Impl == nullptr)

319 return nullptr;

320

321 auto *Iter = llvm::find_if(

322 *Impl, [&](const auto &Item) { return Item.Effect == Key; });

323 return Iter != Impl->end() ? &*Iter : nullptr;

324 }

325

326 size_t size() const { return Impl ? Impl->size() : 0; }

327};

328

329

330

331

332class PendingFunctionAnalysis {

333 friend class CompleteFunctionAnalysis;

334

335public:

336 struct DirectCall {

337 const Decl *Callee;

339

340

341 bool Recursed = false;

342 ViolationSite VSite;

343

345 : Callee(D), CallLoc(CallLoc), VSite(VSite) {}

346 };

347

348

349

350

353

354private:

355

357

358

359 EffectToViolationMap InferrableEffectToFirstViolation;

360

361

362

364

365public:

366 PendingFunctionAnalysis(Sema &S, const CallableInfo &CInfo,

368 : DeclaredVerifiableEffects(CInfo.Effects) {

369

371

372 for (FunctionEffect effect : AllInferrableEffectsToVerify) {

373 std::optional ProblemCalleeEffect =

374 effect.effectProhibitingInference(*CInfo.CDecl, CInfo.Effects);

375 if (!ProblemCalleeEffect)

376 InferrableEffects.insert(effect);

377 else {

378

379

380 InferrableEffectToFirstViolation.maybeInsert(Violation(

381 effect, ViolationID::DeclDisallowsInference, ViolationSite{},

382 CInfo.CDecl->getLocation(), nullptr, ProblemCalleeEffect));

383 }

384 }

385

386

388 InferrableEffects, DeclaredVerifiableEffects);

389 }

390

391

392

393 void checkAddViolation(bool Inferring, const Violation &NewViol) {

394 if (!Inferring)

395 ViolationsForExplicitEffects.push_back(NewViol);

396 else

397 InferrableEffectToFirstViolation.maybeInsert(NewViol);

398 }

399

401 ViolationSite VSite) {

402 UnverifiedDirectCalls.emplace_back(D, CallLoc, VSite);

403 }

404

405

406 bool isComplete() const { return UnverifiedDirectCalls.empty(); }

407

408 const Violation *violationForInferrableEffect(FunctionEffect effect) {

409 return InferrableEffectToFirstViolation.lookup(effect);

410 }

411

412

414 assert(!isComplete());

415 return UnverifiedDirectCalls;

416 }

417

419 if (!ViolationsForExplicitEffects.empty())

420 llvm::sort(ViolationsForExplicitEffects,

421 [&SM](const Violation &LHS, const Violation &RHS) {

422 return SM.isBeforeInTranslationUnit(LHS.Loc, RHS.Loc);

423 });

424 return ViolationsForExplicitEffects;

425 }

426

427 void dump(Sema &SemaRef, llvm::raw_ostream &OS) const {

428 OS << "Pending: Declared ";

429 DeclaredVerifiableEffects.dump(OS);

430 OS << ", " << ViolationsForExplicitEffects.size() << " violations; ";

431 OS << " Infer ";

432 EffectsToInfer.dump(OS);

433 OS << ", " << InferrableEffectToFirstViolation.size() << " violations";

434 if (!UnverifiedDirectCalls.empty()) {

435 OS << "; Calls: ";

436 for (const DirectCall &Call : UnverifiedDirectCalls) {

437 CallableInfo CI(*Call.Callee);

438 OS << " " << CI.getNameForDiagnostic(SemaRef);

439 }

440 }

441 OS << "\n";

442 }

443};

444

445

446class CompleteFunctionAnalysis {

447

448public:

449

450

451

452

454

455private:

456

457 EffectToViolationMap InferrableEffectToFirstViolation;

458

459public:

460

461 CompleteFunctionAnalysis(ASTContext &Ctx, PendingFunctionAnalysis &&Pending,

464 : VerifiedEffects(DeclaredEffects) {

465 for (FunctionEffect effect : AllInferrableEffectsToVerify)

466 if (Pending.violationForInferrableEffect(effect) == nullptr)

467 VerifiedEffects.insert(effect);

468

469 InferrableEffectToFirstViolation =

470 std::move(Pending.InferrableEffectToFirstViolation);

471 }

472

473 const Violation *firstViolationForEffect(FunctionEffect Effect) {

474 return InferrableEffectToFirstViolation.lookup(Effect);

475 }

476

477 void dump(llvm::raw_ostream &OS) const {

478 OS << "Complete: Verified ";

479 VerifiedEffects.dump(OS);

480 OS << "; Infer ";

481 OS << InferrableEffectToFirstViolation.size() << " violations\n";

482 }

483};

484

485

486class Analyzer {

488

489

491

492 using FuncAnalysisPtr =

493 llvm::PointerUnion<PendingFunctionAnalysis *, CompleteFunctionAnalysis *>;

494

495

496

497

498 class AnalysisMap : llvm::DenseMap<const Decl *, FuncAnalysisPtr> {

499 using Base = llvm::DenseMap<const Decl *, FuncAnalysisPtr>;

500

501 public:

502 ~AnalysisMap();

503

504

505

506

507 FuncAnalysisPtr lookup(const Decl *Key) const {

509 }

510

511 FuncAnalysisPtr &operator[](const Decl *Key) {

513 }

514

515

516 CompleteFunctionAnalysis *completedAnalysisForDecl(const Decl *D) const {

517 if (FuncAnalysisPtr AP = lookup(D);

518 isa_and_nonnull<CompleteFunctionAnalysis *>(AP))

519 return cast<CompleteFunctionAnalysis *>(AP);

520 return nullptr;

521 }

522

523 void dump(Sema &SemaRef, llvm::raw_ostream &OS) {

524 OS << "\nAnalysisMap:\n";

525 for (const auto &item : *this) {

526 CallableInfo CI(*item.first);

527 const auto AP = item.second;

528 OS << item.first << " " << CI.getNameForDiagnostic(SemaRef) << " : ";

529 if (AP.isNull()) {

530 OS << "null\n";

531 } else if (auto *CFA = dyn_cast<CompleteFunctionAnalysis *>(AP)) {

532 OS << CFA << " ";

533 CFA->dump(OS);

534 } else if (auto *PFA = dyn_cast<PendingFunctionAnalysis *>(AP)) {

535 OS << PFA << " ";

536 PFA->dump(SemaRef, OS);

537 } else

538 llvm_unreachable("never");

539 }

540 OS << "---\n";

541 }

542 };

543 AnalysisMap DeclAnalysis;

544

545public:

546 Analyzer(Sema &S) : S(S) {}

547

549

550

554 AllInferrableEffectsToVerify.insert(Effect);

555 }

556 LLVM_DEBUG(llvm::dbgs() << "AllInferrableEffectsToVerify: ";

557 AllInferrableEffectsToVerify.dump(llvm::dbgs());

558 llvm::dbgs() << "\n";);

559

560

561

562

563

565 std::reverse(VerificationQueue.begin(), VerificationQueue.end());

566

567 while (!VerificationQueue.empty()) {

568 const Decl *D = VerificationQueue.back();

569 if (FuncAnalysisPtr AP = DeclAnalysis.lookup(D)) {

570 if (auto *Pending = dyn_cast<PendingFunctionAnalysis *>(AP)) {

571

572 finishPendingAnalysis(D, Pending);

573 }

574 VerificationQueue.pop_back();

575 continue;

576 }

577

578

579 PendingFunctionAnalysis *Pending = verifyDecl(D);

580 if (Pending == nullptr) {

581

582 VerificationQueue.pop_back();

583 continue;

584 }

585

586

587

588 for (PendingFunctionAnalysis::DirectCall &Call :

589 Pending->unverifiedCalls()) {

590 FuncAnalysisPtr AP = DeclAnalysis.lookup(Call.Callee);

591 if (AP.isNull()) {

592 VerificationQueue.push_back(Call.Callee);

593 continue;

594 }

595

596

597

598

599 assert(isa<PendingFunctionAnalysis *>(AP));

600 Call.Recursed = true;

601 }

602 }

603 }

604

605private:

606

607

608 PendingFunctionAnalysis *verifyDecl(const Decl *D) {

609 CallableInfo CInfo(*D);

611

612 if (const FunctionDecl *FD = dyn_cast(D))

614

615

616

617

621 continue;

622

623 bool IsNoexcept = false;

626 } else if (auto *BD = dyn_cast(D)) {

627 if (auto *TSI = BD->getSignatureAsWritten()) {

629 IsNoexcept = FPT->isNothrow() || BD->hasAttr();

630 }

631 }

632 if (!IsNoexcept)

633 S.Diag(D->getBeginLoc(), diag::warn_perf_constraint_implies_noexcept)

634 << GetCallableDeclKind(D, nullptr) << Effect.name();

635 break;

636 }

637 }

638

639

640

641

642 PendingFunctionAnalysis FAnalysis(S, CInfo, AllInferrableEffectsToVerify);

643

644 LLVM_DEBUG(llvm::dbgs()

645 << "\nVerifying " << CInfo.getNameForDiagnostic(S) << " ";

646 FAnalysis.dump(S, llvm::dbgs()););

647

648 FunctionBodyASTVisitor Visitor(*this, FAnalysis, CInfo);

649

650 Visitor.run();

651 if (FAnalysis.isComplete()) {

652 completeAnalysis(CInfo, std::move(FAnalysis));

653 return nullptr;

654 }

655

656 PendingFunctionAnalysis *PendingPtr =

657 new PendingFunctionAnalysis(std::move(FAnalysis));

658 DeclAnalysis[D] = PendingPtr;

659 LLVM_DEBUG(llvm::dbgs() << "inserted pending " << PendingPtr << "\n";

660 DeclAnalysis.dump(S, llvm::dbgs()););

661 return PendingPtr;

662 }

663

664

665

666 void completeAnalysis(const CallableInfo &CInfo,

667 PendingFunctionAnalysis &&Pending) {

669 Pending.getSortedViolationsForExplicitEffects(S.getSourceManager());

670 !Viols.empty())

672

673 CompleteFunctionAnalysis *CompletePtr = new CompleteFunctionAnalysis(

674 S.getASTContext(), std::move(Pending), CInfo.Effects,

675 AllInferrableEffectsToVerify);

676 DeclAnalysis[CInfo.CDecl] = CompletePtr;

677 LLVM_DEBUG(llvm::dbgs() << "inserted complete " << CompletePtr << "\n";

678 DeclAnalysis.dump(S, llvm::dbgs()););

679 }

680

681

682

683

684 void finishPendingAnalysis(const Decl *D, PendingFunctionAnalysis *Pending) {

685 CallableInfo Caller(*D);

686 LLVM_DEBUG(llvm::dbgs() << "finishPendingAnalysis for "

687 << Caller.getNameForDiagnostic(S) << " : ";

688 Pending->dump(S, llvm::dbgs()); llvm::dbgs() << "\n";);

689 for (const PendingFunctionAnalysis::DirectCall &Call :

690 Pending->unverifiedCalls()) {

691 if (Call.Recursed)

692 continue;

693

694 CallableInfo Callee(*Call.Callee);

695 followCall(Caller, *Pending, Callee, Call.CallLoc,

696 true, Call.VSite);

697 }

698 completeAnalysis(Caller, std::move(*Pending));

699 delete Pending;

700 }

701

702

703

704 void followCall(const CallableInfo &Caller, PendingFunctionAnalysis &PFA,

706 bool AssertNoFurtherInference, ViolationSite VSite) {

707 const bool DirectCall = Callee.isCalledDirectly();

708

709

711

712 bool IsInferencePossible = DirectCall;

713

714 if (DirectCall)

715 if (CompleteFunctionAnalysis *CFA =

716 DeclAnalysis.completedAnalysisForDecl(Callee.CDecl)) {

717

718 CalleeEffects.insert(CFA->VerifiedEffects);

719 IsInferencePossible = false;

720 }

721

722 if (AssertNoFurtherInference) {

723 assert(!IsInferencePossible);

724 }

725

726 if (!Callee.isVerifiable())

727 IsInferencePossible = false;

728

729 LLVM_DEBUG(llvm::dbgs()

730 << "followCall from " << Caller.getNameForDiagnostic(S)

731 << " to " << Callee.getNameForDiagnostic(S)

732 << "; verifiable: " << Callee.isVerifiable() << "; callee ";

733 CalleeEffects.dump(llvm::dbgs()); llvm::dbgs() << "\n";

734 llvm::dbgs() << " callee " << Callee.CDecl << " canonical "

735 << Callee.CDecl->getCanonicalDecl() << "\n";);

736

737 auto Check1Effect = [&](FunctionEffect Effect, bool Inferring) {

739 return;

740

741

742

743 if (!IsInferencePossible ||

745 if (Callee.FuncType == SpecialFuncType::None)

746 PFA.checkAddViolation(Inferring,

747 {Effect, ViolationID::CallsDeclWithoutEffect,

748 VSite, CallLoc, Callee.CDecl});

749 else

750 PFA.checkAddViolation(

751 Inferring,

752 {Effect, ViolationID::AllocatesMemory, VSite, CallLoc});

753 } else {

754

755 PFA.addUnverifiedDirectCall(Callee.CDecl, CallLoc, VSite);

756 }

757 };

758

759 for (FunctionEffect Effect : PFA.DeclaredVerifiableEffects)

760 Check1Effect(Effect, false);

761

763 Check1Effect(Effect, true);

764 }

765

766

767

768

769 enum CallableDeclKind {

770 CDK_Function,

771 CDK_Constructor,

772 CDK_Destructor,

773 CDK_Lambda,

774 CDK_Block,

775 CDK_MemberInitializer,

776 };

777

778

779

780

781 static CallableDeclKind GetCallableDeclKind(const Decl *D,

782 const Violation *V) {

783 if (V != nullptr &&

784 V->Site.kind() == ViolationSite::Kind::MemberInitializer)

785 return CDK_MemberInitializer;

786 if (isa(D))

787 return CDK_Block;

788 if (auto *Method = dyn_cast(D)) {

789 if (isa(D))

790 return CDK_Constructor;

791 if (isa(D))

792 return CDK_Destructor;

795 return CDK_Lambda;

796 }

797 return CDK_Function;

798 };

799

800

801

803 if (Viols.empty())

804 return;

805

806 auto MaybeAddTemplateNote = [&](const Decl *D) {

807 if (const FunctionDecl *FD = dyn_cast(D)) {

811 diag::note_func_effect_from_template);

813 }

814 }

815 };

816

817

818 enum { Indirect_VirtualMethod, Indirect_FunctionPtr };

819

820 auto MaybeAddSiteContext = [&](const Decl *D, const Violation &V) {

821

822

823 if (V.Site.kind() == ViolationSite::Kind::MemberInitializer) {

824 unsigned ImplicitCtor = 0;

825 if (auto *Ctor = dyn_cast(D);

826 Ctor && Ctor->isImplicit())

827 ImplicitCtor = 1;

828 S.Diag(D->getLocation(), diag::note_func_effect_in_constructor)

829 << ImplicitCtor;

830 }

831

832

833

834 else if (V.Site.kind() == ViolationSite::Kind::DefaultArgExpr)

835 S.Diag(V.Site.defaultArgExpr()->getUsedLocation(),

836 diag::note_in_evaluating_default_argument);

837 };

838

839

840 for (const Violation &Viol1 : Viols) {

841 StringRef effectName = Viol1.Effect.name();

842 switch (Viol1.ID) {

843 case ViolationID::None:

844 case ViolationID::DeclDisallowsInference:

845

846 llvm_unreachable("Unexpected violation kind");

847 break;

848 case ViolationID::AllocatesMemory:

849 case ViolationID::ThrowsOrCatchesExceptions:

850 case ViolationID::HasStaticLocalVariable:

851 case ViolationID::AccessesThreadLocalVariable:

852 case ViolationID::AccessesObjCMethodOrProperty:

853 S.Diag(Viol1.Loc, diag::warn_func_effect_violation)

854 << GetCallableDeclKind(CInfo.CDecl, &Viol1) << effectName

855 << Viol1.diagnosticSelectIndex();

856 MaybeAddSiteContext(CInfo.CDecl, Viol1);

857 MaybeAddTemplateNote(CInfo.CDecl);

858 break;

859 case ViolationID::CallsExprWithoutEffect:

860 S.Diag(Viol1.Loc, diag::warn_func_effect_calls_expr_without_effect)

861 << GetCallableDeclKind(CInfo.CDecl, &Viol1) << effectName;

862 MaybeAddSiteContext(CInfo.CDecl, Viol1);

863 MaybeAddTemplateNote(CInfo.CDecl);

864 break;

865

866 case ViolationID::CallsDeclWithoutEffect: {

867 CallableInfo CalleeInfo(*Viol1.Callee);

868 std::string CalleeName = CalleeInfo.getNameForDiagnostic(S);

869

870 S.Diag(Viol1.Loc, diag::warn_func_effect_calls_func_without_effect)

871 << GetCallableDeclKind(CInfo.CDecl, &Viol1) << effectName

872 << GetCallableDeclKind(CalleeInfo.CDecl, nullptr) << CalleeName;

873 MaybeAddSiteContext(CInfo.CDecl, Viol1);

874 MaybeAddTemplateNote(CInfo.CDecl);

875

876

877

878 for (const Decl *Callee = Viol1.Callee; Callee != nullptr;) {

879 std::optional MaybeNextCallee;

880 CompleteFunctionAnalysis *Completed =

881 DeclAnalysis.completedAnalysisForDecl(CalleeInfo.CDecl);

882 if (Completed == nullptr) {

883

884

885

886

887

888 CallableType CType = CalleeInfo.type();

889 if (CType == CallableType::Virtual)

890 S.Diag(Callee->getLocation(),

891 diag::note_func_effect_call_indirect)

892 << Indirect_VirtualMethod << effectName;

893 else if (CType == CallableType::Unknown)

894 S.Diag(Callee->getLocation(),

895 diag::note_func_effect_call_indirect)

896 << Indirect_FunctionPtr << effectName;

897 else if (CalleeInfo.Effects.contains(Viol1.Effect.oppositeKind()))

898 S.Diag(Callee->getLocation(),

899 diag::note_func_effect_call_disallows_inference)

900 << GetCallableDeclKind(CInfo.CDecl, nullptr) << effectName

902 else if (const FunctionDecl *FD = dyn_cast(Callee);

904

905

906 S.Diag(Callee->getLocation(), diag::note_func_effect_call_extern)

907 << effectName;

908 }

909 break;

910 }

911 const Violation *PtrViol2 =

912 Completed->firstViolationForEffect(Viol1.Effect);

913 if (PtrViol2 == nullptr)

914 break;

915

916 const Violation &Viol2 = *PtrViol2;

917 switch (Viol2.ID) {

918 case ViolationID::None:

919 llvm_unreachable("Unexpected violation kind");

920 break;

921 case ViolationID::DeclDisallowsInference:

922 S.Diag(Viol2.Loc, diag::note_func_effect_call_disallows_inference)

923 << GetCallableDeclKind(CalleeInfo.CDecl, nullptr) << effectName

924 << Viol2.CalleeEffectPreventingInference->name();

925 break;

926 case ViolationID::CallsExprWithoutEffect:

927 S.Diag(Viol2.Loc, diag::note_func_effect_call_indirect)

928 << Indirect_FunctionPtr << effectName;

929 break;

930 case ViolationID::AllocatesMemory:

931 case ViolationID::ThrowsOrCatchesExceptions:

932 case ViolationID::HasStaticLocalVariable:

933 case ViolationID::AccessesThreadLocalVariable:

934 case ViolationID::AccessesObjCMethodOrProperty:

935 S.Diag(Viol2.Loc, diag::note_func_effect_violation)

936 << GetCallableDeclKind(CalleeInfo.CDecl, &Viol2) << effectName

937 << Viol2.diagnosticSelectIndex();

938 MaybeAddSiteContext(CalleeInfo.CDecl, Viol2);

939 break;

940 case ViolationID::CallsDeclWithoutEffect:

941 MaybeNextCallee.emplace(*Viol2.Callee);

942 S.Diag(Viol2.Loc, diag::note_func_effect_calls_func_without_effect)

943 << GetCallableDeclKind(CalleeInfo.CDecl, &Viol2) << effectName

944 << GetCallableDeclKind(Viol2.Callee, nullptr)

945 << MaybeNextCallee->getNameForDiagnostic(S);

946 break;

947 }

948 MaybeAddTemplateNote(Callee);

949 Callee = Viol2.Callee;

950 if (MaybeNextCallee) {

951 CalleeInfo = *MaybeNextCallee;

952 CalleeName = CalleeInfo.getNameForDiagnostic(S);

953 }

954 }

955 } break;

956 }

957 }

958 }

959

960

961

962

963

964

965

966

967

969 Analyzer &Outer;

970 PendingFunctionAnalysis &CurrentFunction;

971 CallableInfo &CurrentCaller;

972 ViolationSite VSite;

973 const Expr *TrailingRequiresClause = nullptr;

974 const Expr *NoexceptExpr = nullptr;

975

976 FunctionBodyASTVisitor(Analyzer &Outer,

977 PendingFunctionAnalysis &CurrentFunction,

978 CallableInfo &CurrentCaller)

979 : Outer(Outer), CurrentFunction(CurrentFunction),

980 CurrentCaller(CurrentCaller) {

981 ShouldVisitImplicitCode = true;

982 ShouldWalkTypesOfTypeLocs = false;

983 }

984

985

986 void run() {

987

988

989 if (auto *Dtor = dyn_cast(CurrentCaller.CDecl))

990 followDestructor(dyn_cast(Dtor->getParent()), Dtor);

991

992 if (auto *FD = dyn_cast(CurrentCaller.CDecl)) {

994

995

996

997

998

999

1004 NoexceptExpr = FPT->getNoexceptExpr();

1005 }

1006 }

1007

1008

1009 TraverseDecl(const_cast<Decl *>(CurrentCaller.CDecl));

1010 }

1011

1012

1013

1014

1015

1016

1019 const Decl *Callee = nullptr) {

1020

1021

1022 for (FunctionEffect Effect : CurrentFunction.DeclaredVerifiableEffects) {

1023 if (Effect.flags() & Flag) {

1024 addViolation(false, Effect, VID, Loc, Callee);

1025 break;

1026 }

1027 }

1028

1029

1030 for (FunctionEffect Effect : CurrentFunction.EffectsToInfer)

1031 if (Effect.flags() & Flag)

1032 addViolation(true, Effect, VID, Loc, Callee);

1033 }

1034

1035 void addViolation(bool Inferring, FunctionEffect Effect, ViolationID VID,

1037 CurrentFunction.checkAddViolation(

1038 Inferring, Violation(Effect, VID, VSite, Loc, Callee));

1039 }

1040

1041

1042

1043 void followCall(CallableInfo &CI, SourceLocation CallLoc) {

1044

1045

1046 if (const auto *FD = dyn_cast(CI.CDecl)) {

1047 if (unsigned BuiltinID = FD->getBuiltinID()) {

1048 CI.Effects = getBuiltinFunctionEffects(BuiltinID);

1049 if (CI.Effects.empty()) {

1050

1051 return;

1052 }

1053

1054

1055

1056 } else {

1057

1058

1059

1061 (!Outer.S.getLangOpts().CPlusPlus || isNoexcept(FD)))

1062 return;

1063 }

1064 }

1065

1066 Outer.followCall(CurrentCaller, CurrentFunction, CI, CallLoc,

1067 false, VSite);

1068 }

1069

1073 !Effects.empty())

1074 CalleeEffects.insert(Effects);

1075

1076 auto Check1Effect = [&](FunctionEffect Effect, bool Inferring) {

1078 false, CalleeEffects))

1079 addViolation(Inferring, Effect, ViolationID::CallsExprWithoutEffect,

1080 Call->getBeginLoc());

1081 };

1082

1083 for (FunctionEffect Effect : CurrentFunction.DeclaredVerifiableEffects)

1084 Check1Effect(Effect, false);

1085

1086 for (FunctionEffect Effect : CurrentFunction.EffectsToInfer)

1087 Check1Effect(Effect, true);

1088 }

1089

1090

1091

1096 followTypeDtor(Field->getType(), DtorLoc);

1097

1098 if (const auto *Class = dyn_cast(Rec))

1100 followTypeDtor(Base.getType(), DtorLoc);

1101 }

1102

1109 }

1110

1115 CallableInfo CI(*Dtor);

1116 followCall(CI, CallSite);

1117 }

1118 }

1119 }

1120 }

1121

1122

1123

1124 bool VisitCXXThrowExpr(CXXThrowExpr *Throw) override {

1126 ViolationID::ThrowsOrCatchesExceptions,

1128 return true;

1129 }

1130

1131 bool VisitCXXCatchStmt(CXXCatchStmt *Catch) override {

1133 ViolationID::ThrowsOrCatchesExceptions,

1135 return true;

1136 }

1137

1138 bool VisitObjCAtThrowStmt(ObjCAtThrowStmt *Throw) override {

1140 ViolationID::ThrowsOrCatchesExceptions,

1142 return true;

1143 }

1144

1145 bool VisitObjCAtCatchStmt(ObjCAtCatchStmt *Catch) override {

1147 ViolationID::ThrowsOrCatchesExceptions,

1149 return true;

1150 }

1151

1152 bool VisitObjCAtFinallyStmt(ObjCAtFinallyStmt *Finally) override {

1154 ViolationID::ThrowsOrCatchesExceptions,

1156 return true;

1157 }

1158

1159 bool VisitObjCMessageExpr(ObjCMessageExpr *Msg) override {

1161 ViolationID::AccessesObjCMethodOrProperty,

1163 return true;

1164 }

1165

1167

1168

1169

1171 ViolationID::AccessesObjCMethodOrProperty,

1173 return true;

1174 }

1175

1177

1178

1179

1181 ViolationID::AccessesObjCMethodOrProperty,

1183 return true;

1184 }

1185

1186 bool VisitSEHExceptStmt(SEHExceptStmt *Exc) override {

1188 ViolationID::ThrowsOrCatchesExceptions,

1190 return true;

1191 }

1192

1193 bool VisitCallExpr(CallExpr *Call) override {

1194 LLVM_DEBUG(llvm::dbgs()

1195 << "VisitCallExpr : "

1196 << Call->getBeginLoc().printToString(Outer.S.SourceMgr)

1197 << "\n";);

1198

1199 Expr *CalleeExpr = Call->getCallee();

1201 CallableInfo CI(*Callee);

1202 followCall(CI, Call->getBeginLoc());

1203 return true;

1204 }

1205

1206 if (isa(CalleeExpr)) {

1207

1208 return true;

1209 }

1210

1211

1212 checkIndirectCall(Call, CalleeExpr->getType());

1213

1214 return true;

1215 }

1216

1217 bool VisitVarDecl(VarDecl *Var) override {

1218 LLVM_DEBUG(llvm::dbgs()

1219 << "VisitVarDecl : "

1221 << "\n";);

1222

1225 ViolationID::HasStaticLocalVariable,

1227

1232 return true;

1233 }

1234

1235 bool VisitCXXNewExpr(CXXNewExpr *New) override {

1236

1238 CallableInfo CI(*FD, SpecialFuncType::OperatorNew);

1240 }

1241

1242

1243

1244

1245

1246

1247 return true;

1248 }

1249

1251

1252

1254 CallableInfo CI(*FD, SpecialFuncType::OperatorDelete);

1255 followCall(CI, Delete->getBeginLoc());

1256 }

1257

1258

1259

1260 return true;

1261 }

1262

1263 bool VisitCXXConstructExpr(CXXConstructExpr *Construct) override {

1264 LLVM_DEBUG(llvm::dbgs() << "VisitCXXConstructExpr : "

1266 Outer.S.SourceMgr)

1267 << "\n";);

1268

1269

1270

1272 CallableInfo CI(*Ctor);

1273 followCall(CI, Construct->getLocation());

1274

1275 return true;

1276 }

1277

1278 bool TraverseStmt(Stmt *Statement) override {

1279

1280

1281

1282

1283

1284 if (Statement != TrailingRequiresClause && Statement != NoexceptExpr)

1286 return true;

1287 }

1288

1290 ViolationSite PrevVS = VSite;

1291 if (Init->isAnyMemberInitializer())

1292 VSite.setKind(ViolationSite::Kind::MemberInitializer);

1293 bool Result =

1295 VSite = PrevVS;

1296 return Result;

1297 }

1298

1300 LLVM_DEBUG(llvm::dbgs()

1301 << "TraverseCXXDefaultArgExpr : "

1302 << E->getUsedLocation().printToString(Outer.S.SourceMgr)

1303 << "\n";);

1304

1305 ViolationSite PrevVS = VSite;

1306 if (VSite.kind() == ViolationSite::Kind::Default)

1307 VSite = ViolationSite{E};

1308

1309 bool Result = DynamicRecursiveASTVisitor::TraverseCXXDefaultArgExpr(E);

1310 VSite = PrevVS;

1311 return Result;

1312 }

1313

1314 bool TraverseLambdaExpr(LambdaExpr *Lambda) override {

1315

1316

1317

1318

1319

1320 for (unsigned I = 0, N = Lambda->capture_size(); I < N; ++I)

1321 TraverseLambdaCapture(Lambda, Lambda->capture_begin() + I,

1323

1324 return true;

1325 }

1326

1327 bool TraverseBlockExpr(BlockExpr * ) override {

1328

1329

1330 return true;

1331 }

1332

1333 bool VisitDeclRefExpr(DeclRefExpr *E) override {

1334 const ValueDecl *Val = E->getDecl();

1335 if (const auto *Var = dyn_cast(Val)) {

1337

1338

1340 ViolationID::AccessesThreadLocalVariable,

1341 E->getLocation());

1342 }

1343 }

1344 return true;

1345 }

1346

1348 return TraverseStmt(Node->getResultExpr());

1349 }

1350 bool

1352 return true;

1353 }

1354

1356 return true;

1357 }

1358

1359 bool TraverseDecltypeTypeLoc(DecltypeTypeLoc Node) override { return true; }

1360

1362 return true;

1363 }

1364

1365 bool TraverseCXXTypeidExpr(CXXTypeidExpr *Node) override { return true; }

1366

1367

1369 return true;

1370 }

1371 };

1372};

1373

1374Analyzer::AnalysisMap::~AnalysisMap() {

1375 for (const auto &Item : *this) {

1376 FuncAnalysisPtr AP = Item.second;

1377 if (auto *PFA = dyn_cast<PendingFunctionAnalysis *>(AP))

1378 delete PFA;

1379 else

1380 delete cast<CompleteFunctionAnalysis *>(AP);

1381 }

1382}

1383

1384}

1385

1386namespace clang {

1387

1391

1392

1394 return false;

1395

1396

1398 Diag(NewAttrLoc, diag::err_attributes_are_not_compatible)

1400 << ("'" + PrevEC.description() + "'") << false;

1401

1402

1403 return true;

1404 };

1405

1406

1408

1410

1411 if (PrevEC.Cond.getCondition() != nullptr)

1412 continue;

1413

1415

1416

1417 if (PrevEC.Effect.oppositeKind() == NewKind)

1419

1420

1424

1425

1429 }

1430

1431 return false;

1432}

1433

1438 Diag(NewLoc, diag::warn_conflicting_func_effects)

1439 << Conflict.Kept.description() << Conflict.Rejected.description();

1440 Diag(OldLoc, diag::note_previous_declaration);

1441 }

1442}

1443

1444

1449 return;

1450 }

1451

1455 return;

1456

1458 return;

1459

1460

1461

1462

1463 if (cast(D)->isDependentContext())

1464 return;

1465

1467}

1468

1470

1471

1472

1473

1474 bool AnyVerifiable = false;

1478 AnyVerifiable = true;

1479 }

1480

1481

1482 if (AnyVerifiable)

1484}

1485

1488 return;

1489 if (TU == nullptr)

1490 return;

1491 Analyzer{*this}.run(*TU);

1492}

1493

1496

1501

1502 while (true) {

1503 int cmp = 0;

1504 if (POld == OldEnd) {

1505 if (PNew == NewEnd)

1506 break;

1507 cmp = 1;

1508 } else if (PNew == NewEnd)

1509 cmp = -1;

1510 else {

1514 cmp = -1;

1516 cmp = 1;

1517 else {

1518 cmp = 0;

1520

1521

1524 Old, New});

1525 }

1526 }

1527 }

1528

1529 if (cmp < 0) {

1530

1534 std::nullopt});

1535 ++POld;

1536 } else if (cmp > 0) {

1537

1541 std::nullopt, New});

1542 ++PNew;

1543 } else {

1544 ++POld;

1545 ++PNew;

1546 }

1547 }

1548}

1549

1553

1554 switch (EffectKind) {

1556

1557

1558 if (DiffKind == Kind::Added) {

1559 for (const auto &CFE : SrcFX) {

1561 return false;

1562 }

1563 }

1564 [[fallthrough]];

1566

1567 switch (DiffKind) {

1568 case Kind::Added:

1569 return true;

1570 case Kind::Removed:

1571 return false;

1572 case Kind::ConditionMismatch:

1573

1574

1575

1576

1577 return true;

1578 }

1579 break;

1582 return false;

1583 }

1584 llvm_unreachable("unknown effect kind");

1585}

1586

1590 switch (EffectKind) {

1593

1594 switch (DiffKind) {

1595 case Kind::Added:

1596 return false;

1597 case Kind::Removed:

1598 return true;

1599 case Kind::ConditionMismatch:

1600

1601 return true;

1602 }

1603 break;

1606 return false;

1607 }

1608 llvm_unreachable("unknown effect kind");

1609}

1610

1615 switch (EffectKind) {

1618 switch (DiffKind) {

1619

1620

1621 case Kind::Added:

1622 return OverrideResult::NoAction;

1623

1624

1625 case Kind::Removed:

1626 return OverrideResult::Merge;

1627

1628

1629

1630 case Kind::ConditionMismatch:

1631 return OverrideResult::Warn;

1632 }

1633 break;

1636 return OverrideResult::NoAction;

1637 }

1638 llvm_unreachable("unknown effect kind");

1639}

1640

1641}

static bool isNoexcept(const FunctionDecl *FD)

static void dump(llvm::raw_ostream &OS, StringRef FunctionName, ArrayRef< CounterExpression > Expressions, ArrayRef< CounterMappingRegion > Regions)

Defines the C++ Decl subclasses, other than those for templates (found in DeclTemplate....

static bool isExternC(const NamedDecl *ND)

static void emitDiagnostics(BoundNodes &Match, const Decl *D, BugReporter &BR, AnalysisManager &AM, const ObjCAutoreleaseWriteChecker *Checker)

Defines the SourceManager interface.

Defines the Objective-C statement AST node classes.

C Language Family Type Representation.

Holds long-lived AST nodes (such as types and decls) that can be referred to throughout the semantic ...

Represents an array type, per C99 6.7.5.2 - Array Declarators.

QualType getElementType() const

BlockExpr - Adaptor class for mixing a BlockDecl with expressions.

Represents a base class of a C++ class.

CXXCatchStmt - This represents a C++ catch block.

SourceLocation getCatchLoc() const

Represents a call to a C++ constructor.

SourceLocation getLocation() const

SourceLocation getBeginLoc() const LLVM_READONLY

CXXConstructorDecl * getConstructor() const

Get the constructor that this expression will (ultimately) call.

Represents a C++ constructor within a class.

Represents a C++ base or member initializer.

A default argument (C++ [dcl.fct.default]).

Represents a delete expression for memory deallocation and destructor calls, e.g.

Represents a C++ destructor within a class.

Represents a static or instance method of a struct/union/class.

Represents a new-expression for memory allocation and constructor calls, e.g: "new CXXNewExpr(foo)".

SourceLocation getBeginLoc() const

FunctionDecl * getOperatorNew() const

Represents a C++11 noexcept expression (C++ [expr.unary.noexcept]).

Represents a C++ struct/union/class.

bool isLambda() const

Determine whether this class describes a lambda function object.

A C++ throw-expression (C++ [except.throw]).

SourceLocation getThrowLoc() const

A C++ typeid expression (C++ [expr.typeid]), which gets the type_info that corresponds to the supplie...

CallExpr - Represents a function call (C99 6.5.2.2, C++ [expr.call]).

DeclContext * getParent()

getParent - Returns the containing DeclContext.

bool isExternCContext() const

Determines whether this context or some of its ancestors is a linkage specification context that spec...

A reference to a declared variable, function, enum, etc.

Decl - This represents one declaration (or definition), e.g.

FunctionDecl * getAsFunction() LLVM_READONLY

Returns the function itself, or the templated function if this is a function template.

virtual bool hasBody() const

Returns true if this Decl represents a declaration for a body of code, such as a function or method d...

SourceLocation getLocation() const

SourceLocation getBeginLoc() const LLVM_READONLY

virtual Decl * getCanonicalDecl()

Retrieves the "canonical" declaration of the given declaration.

SourceLocation getBeginLoc() const LLVM_READONLY

Expr * getTrailingRequiresClause()

Get the constraint-expression introduced by the trailing requires-clause in the function/member decla...

TypeSourceInfo * getTypeSourceInfo() const

bool getIgnoreAllWarnings() const

bool getSuppressSystemWarnings() const

Recursive AST visitor that supports extension via dynamic dispatch.

virtual bool TraverseStmt(Stmt *S)

Recursively visit a statement or expression, by dispatching to Traverse*() based on the argument's dy...

virtual bool TraverseConstructorInitializer(CXXCtorInitializer *Init)

Recursively visit a constructor initializer.

Expr * getCondition() const

This represents one expression.

Decl * getReferencedDeclOfCallee()

Represents a member of a struct/union/class.

Represents a function declaration or definition.

unsigned getBuiltinID(bool ConsiderWrapperFunctions=false) const

Returns a value indicating whether this function corresponds to a builtin function.

SourceLocation getPointOfInstantiation() const

Retrieve the (first) point of instantiation of a function template specialization or a member of a cl...

bool isNoReturn() const

Determines whether this function is known to be 'noreturn', through an attribute on its declaration o...

FunctionDecl * getTemplateInstantiationPattern(bool ForDefinition=true) const

Retrieve the function declaration from which this function could be instantiated, if it is an instant...

bool isTrivial() const

Whether this function is "trivial" in some specialized C++ senses.

FunctionDecl * getCanonicalDecl() override

Retrieves the "canonical" declaration of the given declaration.

bool isDeleted() const

Whether this function has been deleted.

FunctionEffectsRef getFunctionEffects() const

bool isTemplateInstantiation() const

Determines if the given function was instantiated from a function template.

FunctionDecl * getDefinition()

Get the definition for this declaration.

bool hasBody(const FunctionDecl *&Definition) const

Returns true if the function has a body.

void getNameForDiagnostic(raw_ostream &OS, const PrintingPolicy &Policy, bool Qualified) const override

Appends a human-readable name for this declaration into the given stream.

bool willHaveBody() const

True if this function will eventually have a body, once it's fully parsed.

Support iteration in parallel through a pair of FunctionEffect and EffectConditionExpr containers.

A mutable set of FunctionEffect::Kind.

static FunctionEffectKindSet difference(FunctionEffectKindSet LHS, FunctionEffectKindSet RHS)

void dump(llvm::raw_ostream &OS) const

void insert(FunctionEffect Effect)

Represents an abstract function effect, using just an enumeration describing its kind.

Kind kind() const

The kind of the effect.

@ FE_ExcludeStaticLocalVars

@ FE_ExcludeThreadLocalVars

@ FE_ExcludeObjCMessageSend

Kind

Identifies the particular effect.

Flags flags() const

Flags describing some behaviors of the effect.

bool shouldDiagnoseFunctionCall(bool Direct, FunctionEffectKindSet CalleeFX) const

StringRef name() const

The description printed in diagnostics, e.g. 'nonblocking'.

An immutable set of FunctionEffects and possibly conditions attached to them.

static FunctionEffectsRef get(QualType QT)

Extract the effects from a Type if it is a function, block, or member function pointer,...

Represents a prototype with parameter type info, e.g.

bool isNothrow(bool ResultIfDependent=false) const

Determine whether this function type has a non-throwing exception specification.

Represents a C11 generic selection.

A C++ lambda expression, which produces a function object (of unspecified type) that can be invoked l...

capture_iterator capture_begin() const

Retrieve an iterator pointing to the first lambda capture.

unsigned capture_size() const

Determine the number of captures in this lambda.

capture_init_iterator capture_init_begin()

Retrieve the first initialization argument for this lambda expression (which initializes the first ca...

Represents Objective-C's @catch statement.

SourceLocation getAtCatchLoc() const

Represents Objective-C's @finally statement.

SourceLocation getAtFinallyLoc() const

Represents Objective-C's @synchronized statement.

SourceLocation getBeginLoc() const LLVM_READONLY

Represents Objective-C's @throw statement.

SourceLocation getThrowLoc() const LLVM_READONLY

Represents Objective-C's @autoreleasepool Statement.

SourceLocation getBeginLoc() const LLVM_READONLY

An expression that sends a message to the given Objective-C object or class.

SourceLocation getBeginLoc() const LLVM_READONLY

A (possibly-)qualified type.

const Type * getTypePtr() const

Retrieves a pointer to the underlying (unqualified) type.

field_range fields() const

SourceLocation getExceptLoc() const

SemaDiagnosticBuilder Diag(SourceLocation Loc, unsigned DiagID, bool DeferHint=false)

Emit a diagnostic.

Sema - This implements semantic analysis and AST building for C.

void addDeclWithEffects(const Decl *D, const FunctionEffectsRef &FX)

Unconditionally add a Decl to DeclsWithEfffectsToVerify.

FunctionEffectKindSet AllEffectsToVerify

The union of all effects present on DeclsWithEffectsToVerify.

ASTContext & getASTContext() const

SmallVector< const Decl * > DeclsWithEffectsToVerify

All functions/lambdas/blocks which have bodies and which have a non-empty FunctionEffectsRef to be ve...

PrintingPolicy getPrintingPolicy() const

Retrieve a suitable printing policy for diagnostics.

const LangOptions & getLangOpts() const

void maybeAddDeclWithEffects(FuncOrBlockDecl *D)

Inline checks from the start of maybeAddDeclWithEffects, to minimize performance impact on code not u...

void performFunctionEffectAnalysis(TranslationUnitDecl *TU)

@ Incompatible

Incompatible - We reject this conversion outright, it is invalid to represent it in the AST.

SourceManager & getSourceManager() const

void diagnoseFunctionEffectMergeConflicts(const FunctionEffectSet::Conflicts &Errs, SourceLocation NewLoc, SourceLocation OldLoc)

bool diagnoseConflictingFunctionEffect(const FunctionEffectsRef &FX, const FunctionEffectWithCondition &EC, SourceLocation NewAttrLoc)

Warn and return true if adding a function effect to a set would create a conflict.

bool hasUncompilableErrorOccurred() const

Whether uncompilable error has occurred.

SourceManager & SourceMgr

DiagnosticsEngine & Diags

Encodes a location in the source.

std::string printToString(const SourceManager &SM) const

bool isValid() const

Return true if this is a valid SourceLocation object.

This class handles loading and caching of source files into memory.

bool isInSystemHeader(SourceLocation Loc) const

Returns if a SourceLocation is in a system header.

Stmt - This represents one statement.

The top declaration context.

T getAs() const

Convert to the specified TypeLoc type, returning a null TypeLoc if this TypeLoc is not of the desired...

A container of type source information.

The base class of the type hierarchy.

CXXRecordDecl * getAsCXXRecordDecl() const

Retrieves the CXXRecordDecl that this type refers to, either because the type is a RecordType or beca...

const ArrayType * getAsArrayTypeUnsafe() const

A variant of getAs<> for array types which silently discards qualifiers from the outermost type.

const T * getAs() const

Member-template getAs'.

bool isRecordType() const

UnaryExprOrTypeTraitExpr - expression with either a type or (unevaluated) expression operand.

Represent the declaration of a variable (in which case it is an lvalue) a function (in which case it ...

Represents a variable declaration or definition.

TLSKind getTLSKind() const

bool isStaticLocal() const

Returns true if a variable with function scope is a static local variable.

QualType::DestructionKind needsDestruction(const ASTContext &Ctx) const

Would the destruction of this variable have any effect, and if so, what kind?

@ TLS_None

Not a TLS variable.

A static requirement that can be used in a requires-expression to check properties of types and expre...

const internal::VariadicAllOfMatcher< Type > type

Matches Types in the clang AST.

The JSON file list parser is used to communicate input to InstallAPI.

@ Delete

'delete' clause, allowed on the 'exit data' construct.

@ None

The alignment was not explicit in code.

@ Class

The "class" keyword introduces the elaborated-type-specifier.

A FunctionEffect plus a potential boolean expression determining whether the effect is declared (e....

std::string description() const

Return a textual description of the effect, and its condition, if any.

FunctionEffectDiffVector(const FunctionEffectsRef &Old, const FunctionEffectsRef &New)

Caller should short-circuit by checking for equality first.

bool shouldDiagnoseConversion(QualType SrcType, const FunctionEffectsRef &SrcFX, QualType DstType, const FunctionEffectsRef &DstFX) const

Return true if adding or removing the effect as part of a type conversion should generate a diagnosti...

bool shouldDiagnoseRedeclaration(const FunctionDecl &OldFunction, const FunctionEffectsRef &OldFX, const FunctionDecl &NewFunction, const FunctionEffectsRef &NewFX) const

Return true if adding or removing the effect in a redeclaration should generate a diagnostic.

OverrideResult shouldDiagnoseMethodOverride(const CXXMethodDecl &OldMethod, const FunctionEffectsRef &OldFX, const CXXMethodDecl &NewMethod, const FunctionEffectsRef &NewFX) const

Return true if adding or removing the effect in a C++ virtual method override should generate a diagn...

OverrideResult

Describes the result of effects differing between a base class's virtual method and an overriding met...