23#define DEBUG_TYPE "effectanalysis"
29enum class ViolationID : uint8_t {
34 AllocatesMemory = BaseDiagnosticIndex,
35 ThrowsOrCatchesExceptions,
36 HasStaticLocalVariable,
37 AccessesThreadLocalVariable,
38 AccessesObjCMethodOrProperty,
41 DeclDisallowsInference,
47 CallsDeclWithoutEffect,
48 CallsExprWithoutEffect,
55 enum class Kind : uint8_t {
62 llvm::PointerIntPair<CXXDefaultArgExpr *, 2, Kind> Impl;
65 ViolationSite() =
default;
68 : Impl(
E, Kind::DefaultArgExpr) {}
70 Kind kind()
const {
return static_cast<Kind
>(Impl.getInt()); }
73 void setKind(Kind K) { Impl.setPointerAndInt(
nullptr, K); }
84 std::optional<FunctionEffect>
85 CalleeEffectPreventingInference;
86 ViolationID ID = ViolationID::None;
94 std::optional<FunctionEffect> CalleeEffect = std::nullopt)
95 : Effect(Effect), CalleeEffectPreventingInference(CalleeEffect), ID(ID),
96 Site(VS),
Loc(
Loc), Callee(Callee) {}
98 unsigned diagnosticSelectIndex()
const {
103enum class SpecialFuncType : uint8_t {
None, OperatorNew, OperatorDelete };
104enum class CallableType : uint8_t {
114static bool functionIsVerifiable(
const FunctionDecl *FD) {
125 return FPT && (FPT->isNothrow() || FD->
hasAttr<NoThrowAttr>());
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:
157 case Builtin::ID::BIfopen:
158 case Builtin::ID::BIpthread_create:
159 case Builtin::ID::BI_Block_object_dispose:
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:
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:
189 case Builtin::ID::BIfread:
190 case Builtin::ID::BIfwrite:
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:
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:
227 CallableType CType = CallableType::Unknown;
232 SpecialFuncType FuncType = SpecialFuncType::None;
237 CallableInfo(
const Decl &CD, SpecialFuncType FT = SpecialFuncType::None)
238 : CDecl(&CD), FuncType(FT) {
240 if (
auto *FD = dyn_cast<FunctionDecl>(CDecl)) {
244 CType = CallableType::Function;
245 if (
auto *Method = dyn_cast<CXXMethodDecl>(FD);
246 Method && Method->isVirtual())
247 CType = CallableType::Virtual;
249 }
else if (
auto *BD = dyn_cast<BlockDecl>(CDecl)) {
250 CType = CallableType::Block;
251 DeclEffects = BD->getFunctionEffects();
252 }
else if (
auto *VD = dyn_cast<ValueDecl>(CDecl)) {
259 CallableType
type()
const {
return CType; }
261 bool isCalledDirectly()
const {
262 return CType == CallableType::Function || CType == CallableType::Block;
265 bool isVerifiable()
const {
267 case CallableType::Unknown:
268 case CallableType::Virtual:
270 case CallableType::Block:
272 case CallableType::Function:
273 return functionIsVerifiable(dyn_cast<FunctionDecl>(CDecl));
275 llvm_unreachable(
"undefined CallableType");
279 std::string getNameForDiagnostic(
Sema &S)
const {
281 llvm::raw_string_ostream OS(Name);
283 if (
auto *FD = dyn_cast<FunctionDecl>(CDecl))
286 else if (
auto *BD = dyn_cast<BlockDecl>(CDecl))
287 OS <<
"(block " << BD->getBlockManglingNumber() <<
")";
288 else if (
auto *VD = dyn_cast<NamedDecl>(CDecl))
289 VD->printQualifiedName(OS);
297class EffectToViolationMap {
304 std::unique_ptr<ImplVec> Impl;
308 void maybeInsert(
const Violation &Viol) {
310 Impl = std::make_unique<ImplVec>();
311 else if (lookup(Viol.Effect) !=
nullptr)
314 Impl->push_back(Viol);
321 auto *
Iter = llvm::find_if(
322 *Impl, [&](
const auto &Item) {
return Item.Effect == Key; });
323 return Iter != Impl->end() ? &*
Iter :
nullptr;
326 size_t size()
const {
return Impl ? Impl->size() : 0; }
332class PendingFunctionAnalysis {
333 friend class CompleteFunctionAnalysis;
341 bool Recursed =
false;
345 : Callee(
D), CallLoc(CallLoc), VSite(VSite) {}
359 EffectToViolationMap InferrableEffectToFirstViolation;
366 PendingFunctionAnalysis(
Sema &S,
const CallableInfo &CInfo,
368 : DeclaredVerifiableEffects(CInfo.Effects) {
373 std::optional<FunctionEffect> ProblemCalleeEffect =
374 effect.effectProhibitingInference(*CInfo.CDecl, CInfo.Effects);
375 if (!ProblemCalleeEffect)
376 InferrableEffects.
insert(effect);
380 InferrableEffectToFirstViolation.maybeInsert(Violation(
381 effect, ViolationID::DeclDisallowsInference, ViolationSite{},
382 CInfo.CDecl->getLocation(),
nullptr, ProblemCalleeEffect));
388 InferrableEffects, DeclaredVerifiableEffects);
393 void checkAddViolation(
bool Inferring,
const Violation &NewViol) {
395 ViolationsForExplicitEffects.push_back(NewViol);
397 InferrableEffectToFirstViolation.maybeInsert(NewViol);
401 ViolationSite VSite) {
402 UnverifiedDirectCalls.emplace_back(
D, CallLoc, VSite);
406 bool isComplete()
const {
return UnverifiedDirectCalls.empty(); }
408 const Violation *violationForInferrableEffect(
FunctionEffect effect) {
409 return InferrableEffectToFirstViolation.lookup(effect);
414 assert(!isComplete());
415 return UnverifiedDirectCalls;
419 if (!ViolationsForExplicitEffects.empty())
420 llvm::sort(ViolationsForExplicitEffects,
421 [&
SM](
const Violation &LHS,
const Violation &RHS) {
422 return SM.isBeforeInTranslationUnit(LHS.Loc, RHS.Loc);
424 return ViolationsForExplicitEffects;
427 void dump(
Sema &SemaRef, llvm::raw_ostream &OS)
const {
428 OS <<
"Pending: Declared ";
429 DeclaredVerifiableEffects.
dump(OS);
430 OS <<
", " << ViolationsForExplicitEffects.size() <<
" violations; ";
432 EffectsToInfer.
dump(OS);
433 OS <<
", " << InferrableEffectToFirstViolation.size() <<
" violations";
434 if (!UnverifiedDirectCalls.empty()) {
436 for (
const DirectCall &
Call : UnverifiedDirectCalls) {
437 CallableInfo CI(*
Call.Callee);
438 OS <<
" " << CI.getNameForDiagnostic(SemaRef);
446class CompleteFunctionAnalysis {
457 EffectToViolationMap InferrableEffectToFirstViolation;
461 CompleteFunctionAnalysis(
ASTContext &Ctx, PendingFunctionAnalysis &&Pending,
464 : VerifiedEffects(DeclaredEffects) {
466 if (Pending.violationForInferrableEffect(effect) ==
nullptr)
467 VerifiedEffects.
insert(effect);
469 InferrableEffectToFirstViolation =
470 std::move(Pending.InferrableEffectToFirstViolation);
474 return InferrableEffectToFirstViolation.lookup(Effect);
477 void dump(llvm::raw_ostream &OS)
const {
478 OS <<
"Complete: Verified ";
479 VerifiedEffects.
dump(OS);
481 OS << InferrableEffectToFirstViolation.size() <<
" violations\n";
492 using FuncAnalysisPtr =
493 llvm::PointerUnion<PendingFunctionAnalysis *, CompleteFunctionAnalysis *>;
498 class AnalysisMap : llvm::DenseMap<const Decl *, FuncAnalysisPtr> {
499 using Base = llvm::DenseMap<const Decl *, FuncAnalysisPtr>;
507 FuncAnalysisPtr lookup(
const Decl *Key)
const {
511 FuncAnalysisPtr &operator[](
const Decl *Key) {
516 CompleteFunctionAnalysis *completedAnalysisForDecl(
const Decl *
D)
const {
517 if (FuncAnalysisPtr AP = lookup(
D);
518 isa_and_nonnull<CompleteFunctionAnalysis *>(AP))
519 return cast<CompleteFunctionAnalysis *>(AP);
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) <<
" : ";
531 }
else if (
auto *CFA = dyn_cast<CompleteFunctionAnalysis *>(AP)) {
534 }
else if (
auto *PFA = dyn_cast<PendingFunctionAnalysis *>(AP)) {
536 PFA->dump(SemaRef, OS);
538 llvm_unreachable(
"never");
543 AnalysisMap DeclAnalysis;
546 Analyzer(
Sema &S) : S(S) {}
554 AllInferrableEffectsToVerify.
insert(Effect);
556 LLVM_DEBUG(llvm::dbgs() <<
"AllInferrableEffectsToVerify: ";
557 AllInferrableEffectsToVerify.
dump(llvm::dbgs());
558 llvm::dbgs() <<
"\n";);
565 std::reverse(VerificationQueue.begin(), VerificationQueue.end());
567 while (!VerificationQueue.empty()) {
568 const Decl *
D = VerificationQueue.back();
569 if (FuncAnalysisPtr AP = DeclAnalysis.lookup(
D)) {
570 if (
auto *Pending = AP.dyn_cast<PendingFunctionAnalysis *>()) {
572 finishPendingAnalysis(
D, Pending);
574 VerificationQueue.pop_back();
579 PendingFunctionAnalysis *Pending = verifyDecl(
D);
580 if (Pending ==
nullptr) {
582 VerificationQueue.pop_back();
588 for (PendingFunctionAnalysis::DirectCall &
Call :
589 Pending->unverifiedCalls()) {
590 FuncAnalysisPtr AP = DeclAnalysis.lookup(
Call.Callee);
592 VerificationQueue.push_back(
Call.Callee);
599 assert(isa<PendingFunctionAnalysis *>(AP));
600 Call.Recursed =
true;
608 PendingFunctionAnalysis *verifyDecl(
const Decl *
D) {
609 CallableInfo CInfo(*
D);
623 bool IsNoexcept =
false;
626 }
else if (
auto *BD = dyn_cast<BlockDecl>(
D)) {
627 if (
auto *TSI = BD->getSignatureAsWritten()) {
629 IsNoexcept = FPT->
isNothrow() || BD->hasAttr<NoThrowAttr>();
634 << GetCallableDeclKind(
D,
nullptr) << Effect.
name();
642 PendingFunctionAnalysis FAnalysis(S, CInfo, AllInferrableEffectsToVerify);
644 LLVM_DEBUG(llvm::dbgs()
645 <<
"\nVerifying " << CInfo.getNameForDiagnostic(S) <<
" ";
646 FAnalysis.dump(S, llvm::dbgs()););
648 FunctionBodyASTVisitor Visitor(*
this, FAnalysis, CInfo);
651 if (FAnalysis.isComplete()) {
652 completeAnalysis(CInfo, std::move(FAnalysis));
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()););
666 void completeAnalysis(
const CallableInfo &CInfo,
667 PendingFunctionAnalysis &&Pending) {
673 CompleteFunctionAnalysis *CompletePtr =
new CompleteFunctionAnalysis(
675 AllInferrableEffectsToVerify);
676 DeclAnalysis[CInfo.CDecl] = CompletePtr;
677 LLVM_DEBUG(llvm::dbgs() <<
"inserted complete " << CompletePtr <<
"\n";
678 DeclAnalysis.dump(S, llvm::dbgs()););
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()) {
694 CallableInfo Callee(*
Call.Callee);
695 followCall(Caller, *Pending, Callee,
Call.CallLoc,
698 completeAnalysis(Caller, std::move(*Pending));
704 void followCall(
const CallableInfo &Caller, PendingFunctionAnalysis &PFA,
706 bool AssertNoFurtherInference, ViolationSite VSite) {
707 const bool DirectCall = Callee.isCalledDirectly();
712 bool IsInferencePossible = DirectCall;
715 if (CompleteFunctionAnalysis *CFA =
716 DeclAnalysis.completedAnalysisForDecl(Callee.CDecl)) {
718 CalleeEffects.
insert(CFA->VerifiedEffects);
719 IsInferencePossible =
false;
722 if (AssertNoFurtherInference) {
723 assert(!IsInferencePossible);
726 if (!Callee.isVerifiable())
727 IsInferencePossible =
false;
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";);
743 if (!IsInferencePossible ||
745 if (Callee.FuncType == SpecialFuncType::None)
746 PFA.checkAddViolation(Inferring,
747 {Effect, ViolationID::CallsDeclWithoutEffect,
748 VSite, CallLoc, Callee.CDecl});
750 PFA.checkAddViolation(
752 {Effect, ViolationID::AllocatesMemory, VSite, CallLoc});
755 PFA.addUnverifiedDirectCall(Callee.CDecl, CallLoc, VSite);
760 Check1Effect(Effect,
false);
763 Check1Effect(Effect,
true);
769 enum CallableDeclKind {
775 CDK_MemberInitializer,
781 static CallableDeclKind GetCallableDeclKind(
const Decl *
D,
782 const Violation *
V) {
784 V->Site.kind() == ViolationSite::Kind::MemberInitializer)
785 return CDK_MemberInitializer;
786 if (isa<BlockDecl>(
D))
788 if (
auto *Method = dyn_cast<CXXMethodDecl>(
D)) {
789 if (isa<CXXConstructorDecl>(
D))
790 return CDK_Constructor;
791 if (isa<CXXDestructorDecl>(
D))
792 return CDK_Destructor;
806 auto MaybeAddTemplateNote = [&](
const Decl *
D) {
811 diag::note_func_effect_from_template);
818 enum { Indirect_VirtualMethod, Indirect_FunctionPtr };
820 auto MaybeAddSiteContext = [&](
const Decl *
D,
const Violation &
V) {
823 if (
V.Site.kind() == ViolationSite::Kind::MemberInitializer) {
824 unsigned ImplicitCtor = 0;
825 if (
auto *Ctor = dyn_cast<CXXConstructorDecl>(
D);
826 Ctor && Ctor->isImplicit())
834 else if (
V.Site.kind() == ViolationSite::Kind::DefaultArgExpr)
835 S.
Diag(
V.Site.defaultArgExpr()->getUsedLocation(),
836 diag::note_in_evaluating_default_argument);
840 for (
const Violation &Viol1 : Viols) {
841 StringRef effectName = Viol1.Effect.name();
843 case ViolationID::None:
844 case ViolationID::DeclDisallowsInference:
846 llvm_unreachable(
"Unexpected violation kind");
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);
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);
866 case ViolationID::CallsDeclWithoutEffect: {
867 CallableInfo CalleeInfo(*Viol1.Callee);
868 std::string CalleeName = CalleeInfo.getNameForDiagnostic(S);
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);
878 for (
const Decl *Callee = Viol1.Callee; Callee !=
nullptr;) {
879 std::optional<CallableInfo> MaybeNextCallee;
880 CompleteFunctionAnalysis *Completed =
881 DeclAnalysis.completedAnalysisForDecl(CalleeInfo.CDecl);
882 if (Completed ==
nullptr) {
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<FunctionDecl>(Callee);
906 S.
Diag(Callee->getLocation(), diag::note_func_effect_call_extern)
911 const Violation *PtrViol2 =
912 Completed->firstViolationForEffect(Viol1.Effect);
913 if (PtrViol2 ==
nullptr)
916 const Violation &Viol2 = *PtrViol2;
918 case ViolationID::None:
919 llvm_unreachable(
"Unexpected violation kind");
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();
926 case ViolationID::CallsExprWithoutEffect:
927 S.
Diag(Viol2.Loc, diag::note_func_effect_call_indirect)
928 << Indirect_FunctionPtr << effectName;
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);
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);
948 MaybeAddTemplateNote(Callee);
949 Callee = Viol2.Callee;
950 if (MaybeNextCallee) {
951 CalleeInfo = *MaybeNextCallee;
952 CalleeName = CalleeInfo.getNameForDiagnostic(S);
970 PendingFunctionAnalysis &CurrentFunction;
971 CallableInfo &CurrentCaller;
973 const Expr *TrailingRequiresClause =
nullptr;
974 const Expr *NoexceptExpr =
nullptr;
976 FunctionBodyASTVisitor(Analyzer &Outer,
977 PendingFunctionAnalysis &CurrentFunction,
978 CallableInfo &CurrentCaller)
979 : Outer(Outer), CurrentFunction(CurrentFunction),
980 CurrentCaller(CurrentCaller) {
981 ShouldVisitImplicitCode =
true;
982 ShouldWalkTypesOfTypeLocs =
false;
989 if (
auto *Dtor = dyn_cast<CXXDestructorDecl>(CurrentCaller.CDecl))
990 followDestructor(dyn_cast<CXXRecordDecl>(Dtor->getParent()), Dtor);
992 if (
auto *FD = dyn_cast<FunctionDecl>(CurrentCaller.CDecl)) {
1004 NoexceptExpr = FPT->getNoexceptExpr();
1009 TraverseDecl(
const_cast<Decl *
>(CurrentCaller.CDecl));
1019 const Decl *Callee =
nullptr) {
1022 for (
FunctionEffect Effect : CurrentFunction.DeclaredVerifiableEffects) {
1023 if (Effect.
flags() & Flag) {
1024 addViolation(
false, Effect, VID,
Loc, Callee);
1031 if (Effect.
flags() & Flag)
1032 addViolation(
true, Effect, VID,
Loc, Callee);
1035 void addViolation(
bool Inferring,
FunctionEffect Effect, ViolationID VID,
1037 CurrentFunction.checkAddViolation(
1038 Inferring, Violation(Effect, VID, VSite,
Loc, Callee));
1046 if (
const auto *FD = dyn_cast<FunctionDecl>(CI.CDecl)) {
1048 CI.Effects = getBuiltinFunctionEffects(BuiltinID);
1049 if (CI.Effects.empty()) {
1061 (!Outer.S.getLangOpts().CPlusPlus ||
isNoexcept(FD)))
1066 Outer.followCall(CurrentCaller, CurrentFunction, CI, CallLoc,
1074 CalleeEffects.
insert(Effects);
1078 false, CalleeEffects))
1079 addViolation(Inferring, Effect, ViolationID::CallsExprWithoutEffect,
1080 Call->getBeginLoc());
1083 for (
FunctionEffect Effect : CurrentFunction.DeclaredVerifiableEffects)
1084 Check1Effect(Effect,
false);
1087 Check1Effect(Effect,
true);
1096 followTypeDtor(Field->getType(), DtorLoc);
1098 if (
const auto *
Class = dyn_cast<CXXRecordDecl>(Rec))
1100 followTypeDtor(
Base.getType(), DtorLoc);
1115 CallableInfo CI(*Dtor);
1116 followCall(CI, CallSite);
1126 ViolationID::ThrowsOrCatchesExceptions,
1133 ViolationID::ThrowsOrCatchesExceptions,
1140 ViolationID::ThrowsOrCatchesExceptions,
1147 ViolationID::ThrowsOrCatchesExceptions,
1154 ViolationID::ThrowsOrCatchesExceptions,
1161 ViolationID::AccessesObjCMethodOrProperty,
1171 ViolationID::AccessesObjCMethodOrProperty,
1181 ViolationID::AccessesObjCMethodOrProperty,
1188 ViolationID::ThrowsOrCatchesExceptions,
1194 LLVM_DEBUG(llvm::dbgs()
1195 <<
"VisitCallExpr : "
1196 <<
Call->getBeginLoc().printToString(Outer.S.SourceMgr)
1199 Expr *CalleeExpr =
Call->getCallee();
1201 CallableInfo CI(*Callee);
1202 followCall(CI,
Call->getBeginLoc());
1206 if (isa<CXXPseudoDestructorExpr>(CalleeExpr)) {
1217 bool VisitVarDecl(
VarDecl *Var)
override {
1218 LLVM_DEBUG(llvm::dbgs()
1219 <<
"VisitVarDecl : "
1225 ViolationID::HasStaticLocalVariable,
1235 bool VisitCXXNewExpr(
CXXNewExpr *New)
override {
1238 CallableInfo CI(*FD, SpecialFuncType::OperatorNew);
1254 CallableInfo CI(*FD, SpecialFuncType::OperatorDelete);
1255 followCall(CI,
Delete->getBeginLoc());
1264 LLVM_DEBUG(llvm::dbgs() <<
"VisitCXXConstructExpr : "
1272 CallableInfo CI(*Ctor);
1278 bool TraverseStmt(
Stmt *Statement)
override {
1284 if (Statement != TrailingRequiresClause && Statement != NoexceptExpr)
1290 ViolationSite PrevVS = VSite;
1291 if (
Init->isAnyMemberInitializer())
1292 VSite.setKind(ViolationSite::Kind::MemberInitializer);
1300 LLVM_DEBUG(llvm::dbgs()
1301 <<
"TraverseCXXDefaultArgExpr : "
1302 <<
E->getUsedLocation().printToString(Outer.S.SourceMgr)
1305 ViolationSite PrevVS = VSite;
1306 if (VSite.kind() == ViolationSite::Kind::Default)
1307 VSite = ViolationSite{
E};
1309 bool Result = DynamicRecursiveASTVisitor::TraverseCXXDefaultArgExpr(
E);
1314 bool TraverseLambdaExpr(
LambdaExpr *Lambda)
override {
1320 for (
unsigned I = 0, N = Lambda->
capture_size(); I < N; ++I)
1327 bool TraverseBlockExpr(
BlockExpr * )
override {
1335 if (
const auto *Var = dyn_cast<VarDecl>(Val)) {
1340 ViolationID::AccessesThreadLocalVariable,
1348 return TraverseStmt(
Node->getResultExpr());
1374Analyzer::AnalysisMap::~AnalysisMap() {
1375 for (
const auto &Item : *
this) {
1376 FuncAnalysisPtr AP = Item.second;
1377 if (
auto *PFA = dyn_cast<PendingFunctionAnalysis *>(AP))
1380 delete cast<CompleteFunctionAnalysis *>(AP);
1398 Diag(NewAttrLoc, diag::err_attributes_are_not_compatible)
1400 << (
"'" + PrevEC.description() +
"'") <<
false;
1411 if (PrevEC.Cond.getCondition() !=
nullptr)
1417 if (PrevEC.Effect.oppositeKind() == NewKind)
1438 Diag(NewLoc, diag::warn_conflicting_func_effects)
1439 << Conflict.Kept.description() << Conflict.Rejected.description();
1440 Diag(OldLoc, diag::note_previous_declaration);
1463 if (cast<DeclContext>(
D)->isDependentContext())
1474 bool AnyVerifiable =
false;
1478 AnyVerifiable =
true;
1491 Analyzer{*
this}.run(*TU);
1504 if (POld == OldEnd) {
1508 }
else if (PNew == NewEnd)
1536 }
else if (cmp > 0) {
1541 std::nullopt, New});
1554 switch (EffectKind) {
1558 if (DiffKind == Kind::Added) {
1559 for (
const auto &CFE : SrcFX) {
1572 case Kind::ConditionMismatch:
1584 llvm_unreachable(
"unknown effect kind");
1590 switch (EffectKind) {
1599 case Kind::ConditionMismatch:
1608 llvm_unreachable(
"unknown effect kind");
1615 switch (EffectKind) {
1622 return OverrideResult::NoAction;
1626 return OverrideResult::Merge;
1630 case Kind::ConditionMismatch:
1631 return OverrideResult::Warn;
1636 return OverrideResult::NoAction;
1638 llvm_unreachable(
"unknown effect kind");
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<specific type>'.
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...