23#define DEBUG_TYPE "effectanalysis"
29enum class ViolationID :
uint8_t {
35 ThrowsOrCatchesExceptions,
36 HasStaticLocalVariable,
37 AccessesThreadLocalVariable,
38 AccessesObjCMethodOrProperty,
41 DeclDisallowsInference,
47 CallsDeclWithoutEffect,
48 CallsExprWithoutEffect,
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::BI__builtin___fprintf_chk:
205 case Builtin::ID::BI__builtin___printf_chk:
206 case Builtin::ID::BI__builtin___snprintf_chk:
207 case Builtin::ID::BI__builtin___sprintf_chk:
208 case Builtin::ID::BI__builtin___vfprintf_chk:
209 case Builtin::ID::BI__builtin___vprintf_chk:
210 case Builtin::ID::BI__builtin___vsnprintf_chk:
211 case Builtin::ID::BI__builtin___vsprintf_chk:
214 case Builtin::ID::BIscanf:
215 case Builtin::ID::BIfscanf:
216 case Builtin::ID::BIsscanf:
217 case Builtin::ID::BIvscanf:
218 case Builtin::ID::BIvfscanf:
219 case Builtin::ID::BIvsscanf:
237 CallableType CType = CallableType::Unknown;
242 SpecialFuncType FuncType = SpecialFuncType::None;
247 CallableInfo(
const Decl &CD, SpecialFuncType FT = SpecialFuncType::None)
248 : CDecl(&CD), FuncType(FT) {
250 if (
auto *FD = dyn_cast<FunctionDecl>(CDecl)) {
254 CType = CallableType::Function;
255 if (
auto *Method = dyn_cast<CXXMethodDecl>(FD);
256 Method && Method->isVirtual())
257 CType = CallableType::Virtual;
259 }
else if (
auto *BD = dyn_cast<BlockDecl>(CDecl)) {
260 CType = CallableType::Block;
261 DeclEffects = BD->getFunctionEffects();
262 }
else if (
auto *VD = dyn_cast<ValueDecl>(CDecl)) {
269 CallableType
type()
const {
return CType; }
271 bool isCalledDirectly()
const {
272 return CType == CallableType::Function || CType == CallableType::Block;
275 bool isVerifiable()
const {
277 case CallableType::Unknown:
278 case CallableType::Virtual:
280 case CallableType::Block:
282 case CallableType::Function:
283 return functionIsVerifiable(dyn_cast<FunctionDecl>(CDecl));
285 llvm_unreachable(
"undefined CallableType");
289 std::string getNameForDiagnostic(
Sema &S)
const {
291 llvm::raw_string_ostream OS(Name);
293 if (
auto *FD = dyn_cast<FunctionDecl>(CDecl))
296 else if (
auto *BD = dyn_cast<BlockDecl>(CDecl))
297 OS <<
"(block " << BD->getBlockManglingNumber() <<
")";
298 else if (
auto *VD = dyn_cast<NamedDecl>(CDecl))
299 VD->printQualifiedName(OS);
307class EffectToViolationMap {
314 std::unique_ptr<ImplVec> Impl;
318 void maybeInsert(
const Violation &Viol) {
320 Impl = std::make_unique<ImplVec>();
321 else if (lookup(Viol.Effect) !=
nullptr)
324 Impl->push_back(Viol);
331 auto *Iter = llvm::find_if(
332 *Impl, [&](
const auto &Item) {
return Item.Effect == Key; });
333 return Iter != Impl->end() ? &*Iter :
nullptr;
336 size_t size()
const {
return Impl ? Impl->size() : 0; }
342class PendingFunctionAnalysis {
343 friend class CompleteFunctionAnalysis;
351 bool Recursed =
false;
355 : Callee(D), CallLoc(CallLoc), VSite(VSite) {}
369 EffectToViolationMap InferrableEffectToFirstViolation;
376 PendingFunctionAnalysis(
Sema &S,
const CallableInfo &CInfo,
378 : DeclaredVerifiableEffects(CInfo.Effects) {
383 std::optional<FunctionEffect> ProblemCalleeEffect =
384 effect.effectProhibitingInference(*CInfo.CDecl, CInfo.Effects);
385 if (!ProblemCalleeEffect)
386 InferrableEffects.
insert(effect);
390 InferrableEffectToFirstViolation.maybeInsert(Violation(
391 effect, ViolationID::DeclDisallowsInference, ViolationSite{},
392 CInfo.CDecl->
getLocation(),
nullptr, ProblemCalleeEffect));
398 InferrableEffects, DeclaredVerifiableEffects);
403 void checkAddViolation(
bool Inferring,
const Violation &NewViol) {
405 ViolationsForExplicitEffects.push_back(NewViol);
407 InferrableEffectToFirstViolation.maybeInsert(NewViol);
411 ViolationSite VSite) {
412 UnverifiedDirectCalls.emplace_back(D, CallLoc, VSite);
416 bool isComplete()
const {
return UnverifiedDirectCalls.empty(); }
418 const Violation *violationForInferrableEffect(
FunctionEffect effect) {
419 return InferrableEffectToFirstViolation.lookup(effect);
424 assert(!isComplete());
425 return UnverifiedDirectCalls;
429 if (!ViolationsForExplicitEffects.empty())
430 llvm::sort(ViolationsForExplicitEffects,
431 [&SM](
const Violation &LHS,
const Violation &RHS) {
434 return ViolationsForExplicitEffects;
437 void dump(
Sema &SemaRef, llvm::raw_ostream &OS)
const {
438 OS <<
"Pending: Declared ";
439 DeclaredVerifiableEffects.
dump(OS);
440 OS <<
", " << ViolationsForExplicitEffects.size() <<
" violations; ";
442 EffectsToInfer.
dump(OS);
443 OS <<
", " << InferrableEffectToFirstViolation.size() <<
" violations";
444 if (!UnverifiedDirectCalls.empty()) {
446 for (
const DirectCall &
Call : UnverifiedDirectCalls) {
447 CallableInfo CI(*
Call.Callee);
448 OS <<
" " << CI.getNameForDiagnostic(SemaRef);
456class CompleteFunctionAnalysis {
467 EffectToViolationMap InferrableEffectToFirstViolation;
471 CompleteFunctionAnalysis(
ASTContext &Ctx, PendingFunctionAnalysis &&Pending,
474 : VerifiedEffects(DeclaredEffects) {
476 if (Pending.violationForInferrableEffect(effect) ==
nullptr)
477 VerifiedEffects.
insert(effect);
479 InferrableEffectToFirstViolation =
480 std::move(Pending.InferrableEffectToFirstViolation);
484 return InferrableEffectToFirstViolation.lookup(Effect);
487 void dump(llvm::raw_ostream &OS)
const {
488 OS <<
"Complete: Verified ";
489 VerifiedEffects.
dump(OS);
491 OS << InferrableEffectToFirstViolation.size() <<
" violations\n";
502 using FuncAnalysisPtr =
503 llvm::PointerUnion<PendingFunctionAnalysis *, CompleteFunctionAnalysis *>;
508 class AnalysisMap : llvm::DenseMap<const Decl *, FuncAnalysisPtr> {
509 using Base = llvm::DenseMap<const Decl *, FuncAnalysisPtr>;
517 FuncAnalysisPtr lookup(
const Decl *Key)
const {
521 FuncAnalysisPtr &operator[](
const Decl *Key) {
526 CompleteFunctionAnalysis *completedAnalysisForDecl(
const Decl *D)
const {
527 if (FuncAnalysisPtr AP = lookup(D);
528 isa_and_nonnull<CompleteFunctionAnalysis *>(AP))
533 void dump(
Sema &SemaRef, llvm::raw_ostream &OS) {
534 OS <<
"\nAnalysisMap:\n";
535 for (
const auto &item : *
this) {
536 CallableInfo CI(*item.first);
537 const auto AP = item.second;
538 OS << item.first <<
" " << CI.getNameForDiagnostic(SemaRef) <<
" : ";
541 }
else if (
auto *CFA = dyn_cast<CompleteFunctionAnalysis *>(AP)) {
544 }
else if (
auto *PFA = dyn_cast<PendingFunctionAnalysis *>(AP)) {
546 PFA->dump(SemaRef, OS);
548 llvm_unreachable(
"never");
553 AnalysisMap DeclAnalysis;
556 Analyzer(
Sema &S) : S(S) {}
564 AllInferrableEffectsToVerify.
insert(Effect);
566 LLVM_DEBUG(llvm::dbgs() <<
"AllInferrableEffectsToVerify: ";
567 AllInferrableEffectsToVerify.
dump(llvm::dbgs());
568 llvm::dbgs() <<
"\n";);
575 std::reverse(VerificationQueue.begin(), VerificationQueue.end());
577 while (!VerificationQueue.empty()) {
578 const Decl *D = VerificationQueue.back();
579 if (FuncAnalysisPtr AP = DeclAnalysis.lookup(D)) {
580 if (
auto *Pending = dyn_cast<PendingFunctionAnalysis *>(AP)) {
582 finishPendingAnalysis(D, Pending);
584 VerificationQueue.pop_back();
589 PendingFunctionAnalysis *Pending = verifyDecl(D);
590 if (Pending ==
nullptr) {
592 VerificationQueue.pop_back();
598 for (PendingFunctionAnalysis::DirectCall &
Call :
599 Pending->unverifiedCalls()) {
600 FuncAnalysisPtr AP = DeclAnalysis.lookup(
Call.Callee);
602 VerificationQueue.push_back(
Call.Callee);
610 Call.Recursed =
true;
618 PendingFunctionAnalysis *verifyDecl(
const Decl *D) {
619 CallableInfo CInfo(*D);
633 bool IsNoexcept =
false;
636 }
else if (
auto *BD = dyn_cast<BlockDecl>(D)) {
637 if (
auto *TSI = BD->getSignatureAsWritten()) {
639 IsNoexcept = FPT->isNothrow() || BD->hasAttr<NoThrowAttr>();
644 << GetCallableDeclKind(D,
nullptr) << Effect.
name();
652 PendingFunctionAnalysis FAnalysis(S, CInfo, AllInferrableEffectsToVerify);
654 LLVM_DEBUG(llvm::dbgs()
655 <<
"\nVerifying " << CInfo.getNameForDiagnostic(S) <<
" ";
656 FAnalysis.dump(S, llvm::dbgs()););
658 FunctionBodyASTVisitor Visitor(*
this, FAnalysis, CInfo);
661 if (FAnalysis.isComplete()) {
662 completeAnalysis(CInfo, std::move(FAnalysis));
666 PendingFunctionAnalysis *PendingPtr =
667 new PendingFunctionAnalysis(std::move(FAnalysis));
668 DeclAnalysis[D] = PendingPtr;
669 LLVM_DEBUG(llvm::dbgs() <<
"inserted pending " << PendingPtr <<
"\n";
670 DeclAnalysis.dump(S, llvm::dbgs()););
676 void completeAnalysis(
const CallableInfo &CInfo,
677 PendingFunctionAnalysis &&Pending) {
683 CompleteFunctionAnalysis *CompletePtr =
new CompleteFunctionAnalysis(
685 AllInferrableEffectsToVerify);
686 DeclAnalysis[CInfo.CDecl] = CompletePtr;
687 LLVM_DEBUG(llvm::dbgs() <<
"inserted complete " << CompletePtr <<
"\n";
688 DeclAnalysis.dump(S, llvm::dbgs()););
694 void finishPendingAnalysis(
const Decl *D, PendingFunctionAnalysis *Pending) {
695 CallableInfo Caller(*D);
696 LLVM_DEBUG(llvm::dbgs() <<
"finishPendingAnalysis for "
697 << Caller.getNameForDiagnostic(S) <<
" : ";
698 Pending->dump(S, llvm::dbgs()); llvm::dbgs() <<
"\n";);
699 for (
const PendingFunctionAnalysis::DirectCall &
Call :
700 Pending->unverifiedCalls()) {
704 CallableInfo Callee(*
Call.Callee);
705 followCall(Caller, *Pending, Callee,
Call.CallLoc,
708 completeAnalysis(Caller, std::move(*Pending));
714 void followCall(
const CallableInfo &Caller, PendingFunctionAnalysis &PFA,
716 bool AssertNoFurtherInference, ViolationSite VSite) {
717 const bool DirectCall = Callee.isCalledDirectly();
722 bool IsInferencePossible = DirectCall;
725 if (CompleteFunctionAnalysis *CFA =
726 DeclAnalysis.completedAnalysisForDecl(Callee.CDecl)) {
728 CalleeEffects.
insert(CFA->VerifiedEffects);
729 IsInferencePossible =
false;
732 if (AssertNoFurtherInference) {
733 assert(!IsInferencePossible);
736 if (!Callee.isVerifiable())
737 IsInferencePossible =
false;
739 LLVM_DEBUG(llvm::dbgs()
740 <<
"followCall from " << Caller.getNameForDiagnostic(S)
741 <<
" to " << Callee.getNameForDiagnostic(S)
742 <<
"; verifiable: " << Callee.isVerifiable() <<
"; callee ";
743 CalleeEffects.
dump(llvm::dbgs()); llvm::dbgs() <<
"\n";
744 llvm::dbgs() <<
" callee " << Callee.CDecl <<
" canonical "
745 << Callee.CDecl->getCanonicalDecl() <<
"\n";);
753 if (!IsInferencePossible ||
755 if (Callee.FuncType == SpecialFuncType::None)
756 PFA.checkAddViolation(Inferring,
757 {Effect, ViolationID::CallsDeclWithoutEffect,
758 VSite, CallLoc, Callee.CDecl});
760 PFA.checkAddViolation(
762 {Effect, ViolationID::AllocatesMemory, VSite, CallLoc});
765 PFA.addUnverifiedDirectCall(Callee.CDecl, CallLoc, VSite);
770 Check1Effect(Effect,
false);
773 Check1Effect(Effect,
true);
779 enum CallableDeclKind {
785 CDK_MemberInitializer,
791 static CallableDeclKind GetCallableDeclKind(
const Decl *D,
792 const Violation *
V) {
794 V->Site.kind() == ViolationSite::Kind::MemberInitializer)
795 return CDK_MemberInitializer;
798 if (
auto *Method = dyn_cast<CXXMethodDecl>(D)) {
800 return CDK_Constructor;
802 return CDK_Destructor;
816 auto MaybeAddTemplateNote = [&](
const Decl *D) {
817 if (
const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
821 diag::note_func_effect_from_template);
828 enum { Indirect_VirtualMethod, Indirect_FunctionPtr };
830 auto MaybeAddSiteContext = [&](
const Decl *D,
const Violation &
V) {
833 if (
V.Site.kind() == ViolationSite::Kind::MemberInitializer) {
834 unsigned ImplicitCtor = 0;
835 if (
auto *Ctor = dyn_cast<CXXConstructorDecl>(D);
836 Ctor && Ctor->isImplicit())
844 else if (
V.Site.kind() == ViolationSite::Kind::DefaultArgExpr)
845 S.
Diag(
V.Site.defaultArgExpr()->getUsedLocation(),
846 diag::note_in_evaluating_default_argument);
850 for (
const Violation &Viol1 : Viols) {
851 StringRef effectName = Viol1.Effect.name();
853 case ViolationID::None:
854 case ViolationID::DeclDisallowsInference:
856 llvm_unreachable(
"Unexpected violation kind");
858 case ViolationID::AllocatesMemory:
859 case ViolationID::ThrowsOrCatchesExceptions:
860 case ViolationID::HasStaticLocalVariable:
861 case ViolationID::AccessesThreadLocalVariable:
862 case ViolationID::AccessesObjCMethodOrProperty:
863 S.
Diag(Viol1.Loc, diag::warn_func_effect_violation)
864 << GetCallableDeclKind(CInfo.CDecl, &Viol1) << effectName
865 << Viol1.diagnosticSelectIndex();
866 MaybeAddSiteContext(CInfo.CDecl, Viol1);
867 MaybeAddTemplateNote(CInfo.CDecl);
869 case ViolationID::CallsExprWithoutEffect:
870 S.
Diag(Viol1.Loc, diag::warn_func_effect_calls_expr_without_effect)
871 << GetCallableDeclKind(CInfo.CDecl, &Viol1) << effectName;
872 MaybeAddSiteContext(CInfo.CDecl, Viol1);
873 MaybeAddTemplateNote(CInfo.CDecl);
876 case ViolationID::CallsDeclWithoutEffect: {
877 CallableInfo CalleeInfo(*Viol1.Callee);
878 std::string CalleeName = CalleeInfo.getNameForDiagnostic(S);
880 S.
Diag(Viol1.Loc, diag::warn_func_effect_calls_func_without_effect)
881 << GetCallableDeclKind(CInfo.CDecl, &Viol1) << effectName
882 << GetCallableDeclKind(CalleeInfo.CDecl,
nullptr) << CalleeName;
883 MaybeAddSiteContext(CInfo.CDecl, Viol1);
884 MaybeAddTemplateNote(CInfo.CDecl);
888 for (
const Decl *Callee = Viol1.Callee; Callee !=
nullptr;) {
889 std::optional<CallableInfo> MaybeNextCallee;
890 CompleteFunctionAnalysis *Completed =
891 DeclAnalysis.completedAnalysisForDecl(CalleeInfo.CDecl);
892 if (Completed ==
nullptr) {
898 CallableType CType = CalleeInfo.type();
899 if (CType == CallableType::Virtual)
900 S.
Diag(Callee->getLocation(),
901 diag::note_func_effect_call_indirect)
902 << Indirect_VirtualMethod << effectName;
903 else if (CType == CallableType::Unknown)
904 S.
Diag(Callee->getLocation(),
905 diag::note_func_effect_call_indirect)
906 << Indirect_FunctionPtr << effectName;
907 else if (CalleeInfo.Effects.
contains(Viol1.Effect.oppositeKind()))
908 S.
Diag(Callee->getLocation(),
909 diag::note_func_effect_call_disallows_inference)
910 << GetCallableDeclKind(CInfo.CDecl,
nullptr) << effectName
912 else if (
const FunctionDecl *FD = dyn_cast<FunctionDecl>(Callee);
916 S.
Diag(Callee->getLocation(), diag::note_func_effect_call_extern)
921 const Violation *PtrViol2 =
922 Completed->firstViolationForEffect(Viol1.Effect);
923 if (PtrViol2 ==
nullptr)
926 const Violation &Viol2 = *PtrViol2;
928 case ViolationID::None:
929 llvm_unreachable(
"Unexpected violation kind");
931 case ViolationID::DeclDisallowsInference:
932 S.
Diag(Viol2.Loc, diag::note_func_effect_call_disallows_inference)
933 << GetCallableDeclKind(CalleeInfo.CDecl,
nullptr) << effectName
934 << Viol2.CalleeEffectPreventingInference->name();
936 case ViolationID::CallsExprWithoutEffect:
937 S.
Diag(Viol2.Loc, diag::note_func_effect_call_indirect)
938 << Indirect_FunctionPtr << effectName;
940 case ViolationID::AllocatesMemory:
941 case ViolationID::ThrowsOrCatchesExceptions:
942 case ViolationID::HasStaticLocalVariable:
943 case ViolationID::AccessesThreadLocalVariable:
944 case ViolationID::AccessesObjCMethodOrProperty:
945 S.
Diag(Viol2.Loc, diag::note_func_effect_violation)
946 << GetCallableDeclKind(CalleeInfo.CDecl, &Viol2) << effectName
947 << Viol2.diagnosticSelectIndex();
948 MaybeAddSiteContext(CalleeInfo.CDecl, Viol2);
950 case ViolationID::CallsDeclWithoutEffect:
951 MaybeNextCallee.emplace(*Viol2.Callee);
952 S.
Diag(Viol2.Loc, diag::note_func_effect_calls_func_without_effect)
953 << GetCallableDeclKind(CalleeInfo.CDecl, &Viol2) << effectName
954 << GetCallableDeclKind(Viol2.Callee,
nullptr)
955 << MaybeNextCallee->getNameForDiagnostic(S);
958 MaybeAddTemplateNote(Callee);
959 Callee = Viol2.Callee;
960 if (MaybeNextCallee) {
961 CalleeInfo = *MaybeNextCallee;
962 CalleeName = CalleeInfo.getNameForDiagnostic(S);
980 PendingFunctionAnalysis &CurrentFunction;
981 CallableInfo &CurrentCaller;
983 const Expr *TrailingRequiresClause =
nullptr;
984 const Expr *NoexceptExpr =
nullptr;
986 FunctionBodyASTVisitor(Analyzer &Outer,
987 PendingFunctionAnalysis &CurrentFunction,
988 CallableInfo &CurrentCaller)
989 : Outer(Outer), CurrentFunction(CurrentFunction),
990 CurrentCaller(CurrentCaller) {
991 ShouldVisitImplicitCode =
true;
992 ShouldWalkTypesOfTypeLocs =
false;
999 if (
auto *Dtor = dyn_cast<CXXDestructorDecl>(CurrentCaller.CDecl))
1000 followDestructor(Dtor->getParent(), Dtor);
1002 if (
auto *FD = dyn_cast<FunctionDecl>(CurrentCaller.CDecl)) {
1014 NoexceptExpr = FPT->getNoexceptExpr();
1019 TraverseDecl(
const_cast<Decl *
>(CurrentCaller.CDecl));
1029 const Decl *Callee =
nullptr) {
1032 for (
FunctionEffect Effect : CurrentFunction.DeclaredVerifiableEffects) {
1033 if (Effect.
flags() & Flag) {
1034 addViolation(
false, Effect, VID, Loc, Callee);
1041 if (Effect.
flags() & Flag)
1042 addViolation(
true, Effect, VID, Loc, Callee);
1045 void addViolation(
bool Inferring,
FunctionEffect Effect, ViolationID VID,
1047 CurrentFunction.checkAddViolation(
1048 Inferring, Violation(Effect, VID, VSite, Loc, Callee));
1056 if (
const auto *FD = dyn_cast<FunctionDecl>(CI.CDecl)) {
1058 CI.Effects = getBuiltinFunctionEffects(BuiltinID);
1059 if (CI.Effects.
empty()) {
1076 Outer.followCall(CurrentCaller, CurrentFunction, CI, CallLoc,
1084 CalleeEffects.
insert(Effects);
1088 false, CalleeEffects))
1089 addViolation(Inferring, Effect, ViolationID::CallsExprWithoutEffect,
1090 Call->getBeginLoc());
1093 for (
FunctionEffect Effect : CurrentFunction.DeclaredVerifiableEffects)
1094 Check1Effect(Effect,
false);
1097 Check1Effect(Effect,
true);
1106 followTypeDtor(Field->getType(), DtorLoc);
1109 followTypeDtor(
Base.getType(), DtorLoc);
1123 Dtor && !Dtor->isDeleted()) {
1124 CallableInfo CI(*Dtor);
1125 followCall(CI, CallSite);
1135 ViolationID::ThrowsOrCatchesExceptions,
1142 ViolationID::ThrowsOrCatchesExceptions,
1149 ViolationID::ThrowsOrCatchesExceptions,
1156 ViolationID::ThrowsOrCatchesExceptions,
1163 ViolationID::ThrowsOrCatchesExceptions,
1170 ViolationID::AccessesObjCMethodOrProperty,
1180 ViolationID::AccessesObjCMethodOrProperty,
1190 ViolationID::AccessesObjCMethodOrProperty,
1197 ViolationID::ThrowsOrCatchesExceptions,
1203 LLVM_DEBUG(llvm::dbgs()
1204 <<
"VisitCallExpr : "
1208 Expr *CalleeExpr =
Call->getCallee();
1210 CallableInfo CI(*Callee);
1211 followCall(CI,
Call->getBeginLoc());
1229 checkIndirectCall(
Call, CalleeExprQT);
1234 bool VisitVarDecl(
VarDecl *Var)
override {
1235 LLVM_DEBUG(llvm::dbgs()
1236 <<
"VisitVarDecl : "
1242 ViolationID::HasStaticLocalVariable,
1255 CallableInfo CI(*FD, SpecialFuncType::OperatorNew);
1256 followCall(CI,
New->getBeginLoc());
1274 followTypeDtor(QT,
Delete->getBeginLoc());
1280 if (OpDelete !=
nullptr) {
1281 CallableInfo CI(*OpDelete, SpecialFuncType::OperatorDelete);
1282 followCall(CI,
Delete->getBeginLoc());
1289 LLVM_DEBUG(llvm::dbgs() <<
"VisitCXXConstructExpr : "
1297 CallableInfo CI(*Ctor);
1304 if (Dtor !=
nullptr) {
1305 CallableInfo CI(*Dtor);
1311 bool TraverseStmt(
Stmt *Statement)
override {
1317 if (Statement != TrailingRequiresClause && Statement != NoexceptExpr)
1331 ViolationSite PrevVS = VSite;
1332 if (
Init->isAnyMemberInitializer())
1333 VSite.setKind(ViolationSite::Kind::MemberInitializer);
1341 LLVM_DEBUG(llvm::dbgs()
1342 <<
"TraverseCXXDefaultArgExpr : "
1346 ViolationSite PrevVS = VSite;
1347 if (VSite.kind() == ViolationSite::Kind::Default)
1348 VSite = ViolationSite{E};
1350 bool Result = DynamicRecursiveASTVisitor::TraverseCXXDefaultArgExpr(E);
1355 bool TraverseLambdaExpr(
LambdaExpr *Lambda)
override {
1361 for (
unsigned I = 0, N = Lambda->
capture_size(); I < N; ++I)
1368 bool TraverseBlockExpr(
BlockExpr * )
override {
1376 if (
const auto *Var = dyn_cast<VarDecl>(Val)) {
1381 ViolationID::AccessesThreadLocalVariable,
1397 bool TraverseQualifier)
override {
1402 bool TraverseQualifier)
override {
1410 bool TraverseCXXTypeidExpr(
CXXTypeidExpr *Node)
override {
return true; }
1419Analyzer::AnalysisMap::~AnalysisMap() {
1420 for (
const auto &Item : *
this) {
1421 FuncAnalysisPtr AP = Item.second;
1422 if (
auto *PFA = dyn_cast<PendingFunctionAnalysis *>(AP))
1443 Diag(NewAttrLoc, diag::err_attributes_are_not_compatible)
1445 << (
"'" + PrevEC.description() +
"'") <<
false;
1456 if (PrevEC.Cond.getCondition() !=
nullptr)
1462 if (PrevEC.Effect.oppositeKind() == NewKind)
1483 Diag(NewLoc, diag::warn_conflicting_func_effects)
1484 << Conflict.Kept.description() << Conflict.Rejected.description();
1485 Diag(OldLoc, diag::note_previous_declaration);
1497 if (
Diags.getIgnoreAllWarnings() ||
1498 (
Diags.getSuppressSystemWarnings() &&
1519 bool AnyVerifiable =
false;
1523 AnyVerifiable =
true;
1536 Analyzer{*
this}.run(*TU);
1549 if (POld == OldEnd) {
1553 }
else if (PNew == NewEnd)
1581 }
else if (cmp > 0) {
1586 std::nullopt,
New});
1604 for (
const auto &CFE : SrcFX) {
1629 llvm_unreachable(
"unknown effect kind");
1653 llvm_unreachable(
"unknown effect kind");
1683 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....
Result
Implement __builtin_bit_cast and related operations.
static bool AllocatesMemory(QualType T)
static DiagnosticBuilder Diag(DiagnosticsEngine *Diags, const LangOptions &Features, FullSourceLoc TokLoc, const char *TokBegin, const char *TokRangeBegin, const char *TokRangeEnd, unsigned DiagID)
Produce a diagnostic highlighting some portion of a literal.
static bool isExternC(const NamedDecl *ND)
static void emitDiagnostics(BoundNodes &Match, const Decl *D, BugReporter &BR, AnalysisManager &AM, const ObjCAutoreleaseWriteChecker *Checker)
*collection of selector each with an associated kind and an ordered *collection of selectors A selector has a kind
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.
Represents binding an expression to a temporary.
CXXTemporary * getTemporary()
SourceLocation getBeginLoc() const LLVM_READONLY
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]).
SourceLocation getUsedLocation() const
Retrieve the location where this default argument was actually used.
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)".
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.
const CXXDestructorDecl * getDestructor() const
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.
SourceLocation getLocation() const
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
const AssociatedConstraint & getTrailingRequiresClause() const
Get the constraint-expression introduced by the trailing requires-clause in the function/member decla...
TypeSourceInfo * getTypeSourceInfo() const
virtual bool TraverseConstructorInitializer(MaybeConst< CXXCtorInitializer > *Init)
virtual bool TraverseStmt(MaybeConst< Stmt > *S)
Expr * getCondition() const
This represents one expression.
static QualType findBoundMemberType(const Expr *expr)
Given an expression of bound-member type, find the type of the member.
Decl * getReferencedDeclOfCallee()
bool isBoundMemberFunction(ASTContext &Ctx) const
Returns true if this expression is a bound member function.
Represents a member of a struct/union/class.
Represents a function declaration or definition.
bool isDestroyingOperatorDelete() const
Determine whether this is a destroying operator delete.
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.
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.
A mutable set of FunctionEffect::Kind.
static FunctionEffectKindSet difference(FunctionEffectKindSet LHS, FunctionEffectKindSet RHS)
bool contains(const FunctionEffect::Kind EK) const
void dump(llvm::raw_ostream &OS) const
void insert(FunctionEffect Effect)
SmallVector< Conflict > Conflicts
Represents an abstract function effect, using just an enumeration describing its kind.
Kind kind() const
The kind of the effect.
unsigned Flags
Flags describing some behaviors 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.
FunctionEffectIterator< FunctionEffectsRef > iterator
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.
Represents a C11 generic selection.
Expr * getResultExpr()
Return the result expression of this controlling expression.
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.
bool isNull() const
Return true if this QualType doesn't point to a type yet.
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)
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)
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 isBeforeInTranslationUnit(SourceLocation LHS, SourceLocation RHS) const
Determines the order of 2 source locations in the translation unit.
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.
Top level wrappers for InstallAPI frontend operations.
bool isa(CodeGen::Address addr)
@ Delete
'delete' clause, allowed on the 'exit data' construct.
@ Default
Set to the current date and time.
@ Incompatible
Incompatible - We reject this conversion outright, it is invalid to represent it in the AST.
DynamicRecursiveASTVisitorBase< false > DynamicRecursiveASTVisitor
U cast(CodeGen::Address addr)
__builtin_bitreverse32 uint32_t __builtin_riscv_aaddu_u32 __builtin_riscv_asubu_u32 __builtin_elementwise_add_sat __builtin_elementwise_sub_sat int32_t uint32_t uint32_t __builtin_riscv_mhacc_i32 __builtin_riscv_mhaccu_u32 __builtin_riscv_mhaccsu_i32 __builtin_riscv_mulq_i32 __builtin_riscv_mqwacc_i64 uint8_t
const Expr * ConstraintExpr
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...
FunctionEffect::Kind EffectKind