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...