;
29enum classViolationID : uint8_t {
34AllocatesMemory = BaseDiagnosticIndex,
35ThrowsOrCatchesExceptions,
36HasStaticLocalVariable,
37AccessesThreadLocalVariable,
38AccessesObjCMethodOrProperty,
41DeclDisallowsInference,
47CallsDeclWithoutEffect,
48CallsExprWithoutEffect,
55 enum classKind : uint8_t {
62llvm::PointerIntPair<CXXDefaultArgExpr *, 2, Kind> Impl;
65ViolationSite() =
default;
68: Impl(
E, Kind::DefaultArgExpr) {}
70Kind kind()
const{
return static_cast<Kind
>(Impl.getInt()); }
73 voidsetKind(Kind K) { Impl.setPointerAndInt(
nullptr, K); }
84std::optional<FunctionEffect>
85CalleeEffectPreventingInference;
86ViolationID ID = ViolationID::None;
92Violation(
FunctionEffectEffect, ViolationID ID, ViolationSite VS,
94std::optional<FunctionEffect> CalleeEffect = std::nullopt)
95: Effect(Effect), CalleeEffectPreventingInference(CalleeEffect), ID(ID),
96Site(VS),
Loc(
Loc), Callee(Callee) {}
98 unsigneddiagnosticSelectIndex()
const{
103enum classSpecialFuncType : uint8_t {
None, OperatorNew, OperatorDelete };
104enum classCallableType : uint8_t {
114static boolfunctionIsVerifiable(
const FunctionDecl*FD) {
125 returnFPT && (FPT->isNothrow() || FD->
hasAttr<NoThrowAttr>());
144 caseBuiltin::ID::BI__builtin_calloc:
145 caseBuiltin::ID::BI__builtin_malloc:
146 caseBuiltin::ID::BI__builtin_realloc:
147 caseBuiltin::ID::BI__builtin_free:
148 caseBuiltin::ID::BI__builtin_operator_delete:
149 caseBuiltin::ID::BI__builtin_operator_new:
150 caseBuiltin::ID::BIaligned_alloc:
151 caseBuiltin::ID::BIcalloc:
152 caseBuiltin::ID::BImalloc:
153 caseBuiltin::ID::BImemalign:
154 caseBuiltin::ID::BIrealloc:
155 caseBuiltin::ID::BIfree:
157 caseBuiltin::ID::BIfopen:
158 caseBuiltin::ID::BIpthread_create:
159 caseBuiltin::ID::BI_Block_object_dispose:
160Result.insert(
FunctionEffect(FunctionEffect::Kind::Allocating));
166 caseBuiltin::ID::BIlongjmp:
167 caseBuiltin::ID::BI_longjmp:
168 caseBuiltin::ID::BIsiglongjmp:
169 caseBuiltin::ID::BI__builtin_longjmp:
170 caseBuiltin::ID::BIobjc_exception_throw:
173 caseBuiltin::ID::BIobjc_msgSend:
174 caseBuiltin::ID::BIobjc_msgSend_fpret:
175 caseBuiltin::ID::BIobjc_msgSend_fp2ret:
176 caseBuiltin::ID::BIobjc_msgSend_stret:
177 caseBuiltin::ID::BIobjc_msgSendSuper:
178 caseBuiltin::ID::BIobjc_getClass:
179 caseBuiltin::ID::BIobjc_getMetaClass:
180 caseBuiltin::ID::BIobjc_enumerationMutation:
181 caseBuiltin::ID::BIobjc_assign_ivar:
182 caseBuiltin::ID::BIobjc_assign_global:
183 caseBuiltin::ID::BIobjc_sync_enter:
184 caseBuiltin::ID::BIobjc_sync_exit:
185 caseBuiltin::ID::BINSLog:
186 caseBuiltin::ID::BINSLogv:
189 caseBuiltin::ID::BIfread:
190 caseBuiltin::ID::BIfwrite:
193 caseBuiltin::ID::BIprintf:
194 caseBuiltin::ID::BI__builtin_printf:
195 caseBuiltin::ID::BIfprintf:
196 caseBuiltin::ID::BIsnprintf:
197 caseBuiltin::ID::BIsprintf:
198 caseBuiltin::ID::BIvprintf:
199 caseBuiltin::ID::BIvfprintf:
200 caseBuiltin::ID::BIvsnprintf:
201 caseBuiltin::ID::BIvsprintf:
204 caseBuiltin::ID::BIscanf:
205 caseBuiltin::ID::BIfscanf:
206 caseBuiltin::ID::BIsscanf:
207 caseBuiltin::ID::BIvscanf:
208 caseBuiltin::ID::BIvfscanf:
209 caseBuiltin::ID::BIvsscanf:
227CallableType CType = CallableType::Unknown;
232SpecialFuncType FuncType = SpecialFuncType::None;
237CallableInfo(
const Decl&CD, SpecialFuncType FT = SpecialFuncType::None)
238: CDecl(&CD), FuncType(FT) {
240 if(
auto*FD = dyn_cast<FunctionDecl>(CDecl)) {
244CType = CallableType::Function;
245 if(
auto*Method = dyn_cast<CXXMethodDecl>(FD);
246Method && Method->isVirtual())
247CType = CallableType::Virtual;
249}
else if(
auto*BD = dyn_cast<BlockDecl>(CDecl)) {
250CType = CallableType::Block;
251DeclEffects = BD->getFunctionEffects();
252}
else if(
auto*VD = dyn_cast<ValueDecl>(CDecl)) {
259CallableType
type()
const{
returnCType; }
261 boolisCalledDirectly()
const{
262 returnCType == CallableType::Function || CType == CallableType::Block;
265 boolisVerifiable()
const{
267 caseCallableType::Unknown:
268 caseCallableType::Virtual:
270 caseCallableType::Block:
272 caseCallableType::Function:
273 returnfunctionIsVerifiable(dyn_cast<FunctionDecl>(CDecl));
275llvm_unreachable(
"undefined CallableType");
279std::string getNameForDiagnostic(
Sema&S)
const{
281llvm::raw_string_ostream OS(Name);
283 if(
auto*FD = dyn_cast<FunctionDecl>(CDecl))
286 else if(
auto*BD = dyn_cast<BlockDecl>(CDecl))
287OS <<
"(block "<< BD->getBlockManglingNumber() <<
")";
288 else if(
auto*VD = dyn_cast<NamedDecl>(CDecl))
289VD->printQualifiedName(OS);
297classEffectToViolationMap {
304std::unique_ptr<ImplVec> Impl;
308 voidmaybeInsert(
constViolation &Viol) {
309 if(Impl ==
nullptr)
310Impl = std::make_unique<ImplVec>();
311 else if(lookup(Viol.Effect) !=
nullptr)
314Impl->push_back(Viol);
318 if(Impl ==
nullptr)
321 auto*
Iter= llvm::find_if(
322*Impl, [&](
const auto&Item) {
returnItem.Effect == Key; });
323 return Iter!= Impl->end() ? &*
Iter:
nullptr;
326 size_tsize()
const{
returnImpl ? Impl->size() : 0; }
332classPendingFunctionAnalysis {
333 friend classCompleteFunctionAnalysis;
341 boolRecursed =
false;
345: Callee(
D), CallLoc(CallLoc), VSite(VSite) {}
359EffectToViolationMap InferrableEffectToFirstViolation;
366PendingFunctionAnalysis(
Sema&S,
constCallableInfo &CInfo,
368: DeclaredVerifiableEffects(CInfo.Effects) {
373std::optional<FunctionEffect> ProblemCalleeEffect =
374effect.effectProhibitingInference(*CInfo.CDecl, CInfo.Effects);
375 if(!ProblemCalleeEffect)
376InferrableEffects.
insert(effect);
380InferrableEffectToFirstViolation.maybeInsert(Violation(
381effect, ViolationID::DeclDisallowsInference, ViolationSite{},
382CInfo.CDecl->getLocation(),
nullptr, ProblemCalleeEffect));
388InferrableEffects, DeclaredVerifiableEffects);
393 voidcheckAddViolation(
boolInferring,
constViolation &NewViol) {
395ViolationsForExplicitEffects.push_back(NewViol);
397InferrableEffectToFirstViolation.maybeInsert(NewViol);
401ViolationSite VSite) {
402UnverifiedDirectCalls.emplace_back(
D, CallLoc, VSite);
406 boolisComplete()
const{
returnUnverifiedDirectCalls.empty(); }
408 constViolation *violationForInferrableEffect(
FunctionEffecteffect) {
409 returnInferrableEffectToFirstViolation.lookup(effect);
414assert(!isComplete());
415 returnUnverifiedDirectCalls;
419 if(!ViolationsForExplicitEffects.empty())
420llvm::sort(ViolationsForExplicitEffects,
421[&
SM](
constViolation &LHS,
constViolation &RHS) {
422 return SM.isBeforeInTranslationUnit(LHS.Loc, RHS.Loc);
424 returnViolationsForExplicitEffects;
427 void dump(
Sema&SemaRef, llvm::raw_ostream &OS)
const{
428OS <<
"Pending: Declared ";
429DeclaredVerifiableEffects.
dump(OS);
430OS <<
", "<< ViolationsForExplicitEffects.size() <<
" violations; ";
432EffectsToInfer.
dump(OS);
433OS <<
", "<< InferrableEffectToFirstViolation.size() <<
" violations";
434 if(!UnverifiedDirectCalls.empty()) {
436 for(
constDirectCall &
Call: UnverifiedDirectCalls) {
437CallableInfo CI(*
Call.Callee);
438OS <<
" "<< CI.getNameForDiagnostic(SemaRef);
446classCompleteFunctionAnalysis {
457EffectToViolationMap InferrableEffectToFirstViolation;
461CompleteFunctionAnalysis(
ASTContext&Ctx, PendingFunctionAnalysis &&Pending,
464: VerifiedEffects(DeclaredEffects) {
466 if(Pending.violationForInferrableEffect(effect) ==
nullptr)
467VerifiedEffects.
insert(effect);
469InferrableEffectToFirstViolation =
470std::move(Pending.InferrableEffectToFirstViolation);
473 constViolation *firstViolationForEffect(
FunctionEffectEffect) {
474 returnInferrableEffectToFirstViolation.lookup(Effect);
477 void dump(llvm::raw_ostream &OS)
const{
478OS <<
"Complete: Verified ";
479VerifiedEffects.
dump(OS);
481OS << InferrableEffectToFirstViolation.size() <<
" violations\n";
492 usingFuncAnalysisPtr =
493llvm::PointerUnion<PendingFunctionAnalysis *, CompleteFunctionAnalysis *>;
498 classAnalysisMap : llvm::DenseMap<const Decl *, FuncAnalysisPtr> {
499 using Base= llvm::DenseMap<const Decl *, FuncAnalysisPtr>;
507FuncAnalysisPtr lookup(
const Decl*Key)
const{
511FuncAnalysisPtr &operator[](
const Decl*Key) {
516CompleteFunctionAnalysis *completedAnalysisForDecl(
const Decl*
D)
const{
517 if(FuncAnalysisPtr AP = lookup(
D);
518isa_and_nonnull<CompleteFunctionAnalysis *>(AP))
519 returncast<CompleteFunctionAnalysis *>(AP);
523 void dump(
Sema&SemaRef, llvm::raw_ostream &OS) {
524OS <<
"\nAnalysisMap:\n";
525 for(
const auto&item : *
this) {
526CallableInfo CI(*item.first);
527 const autoAP = item.second;
528OS << item.first <<
" "<< CI.getNameForDiagnostic(SemaRef) <<
" : ";
531}
else if(
auto*CFA = dyn_cast<CompleteFunctionAnalysis *>(AP)) {
534}
else if(
auto*PFA = dyn_cast<PendingFunctionAnalysis *>(AP)) {
536PFA->dump(SemaRef, OS);
538llvm_unreachable(
"never");
543AnalysisMap DeclAnalysis;
546Analyzer(
Sema&S) : S(S) {}
554AllInferrableEffectsToVerify.
insert(Effect);
556LLVM_DEBUG(llvm::dbgs() <<
"AllInferrableEffectsToVerify: ";
557AllInferrableEffectsToVerify.
dump(llvm::dbgs());
558llvm::dbgs() <<
"\n";);
565std::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 = dyn_cast<PendingFunctionAnalysis *>(AP)) {
572finishPendingAnalysis(
D, Pending);
574VerificationQueue.pop_back();
579PendingFunctionAnalysis *Pending = verifyDecl(
D);
580 if(Pending ==
nullptr) {
582VerificationQueue.pop_back();
588 for(PendingFunctionAnalysis::DirectCall &
Call:
589Pending->unverifiedCalls()) {
590FuncAnalysisPtr AP = DeclAnalysis.lookup(
Call.Callee);
592VerificationQueue.push_back(
Call.Callee);
599assert(isa<PendingFunctionAnalysis *>(AP));
600 Call.Recursed =
true;
608PendingFunctionAnalysis *verifyDecl(
const Decl*
D) {
609CallableInfo CInfo(*
D);
623 boolIsNoexcept =
false;
626}
else if(
auto*BD = dyn_cast<BlockDecl>(
D)) {
627 if(
auto*TSI = BD->getSignatureAsWritten()) {
629IsNoexcept = FPT->
isNothrow() || BD->hasAttr<NoThrowAttr>();
634<< GetCallableDeclKind(
D,
nullptr) << Effect.
name();
642PendingFunctionAnalysis FAnalysis(S, CInfo, AllInferrableEffectsToVerify);
644LLVM_DEBUG(llvm::dbgs()
645<<
"\nVerifying "<< CInfo.getNameForDiagnostic(S) <<
" ";
646FAnalysis.dump(S, llvm::dbgs()););
648FunctionBodyASTVisitor Visitor(*
this, FAnalysis, CInfo);
651 if(FAnalysis.isComplete()) {
652completeAnalysis(CInfo, std::move(FAnalysis));
656PendingFunctionAnalysis *PendingPtr =
657 newPendingFunctionAnalysis(std::move(FAnalysis));
658DeclAnalysis[
D] = PendingPtr;
659LLVM_DEBUG(llvm::dbgs() <<
"inserted pending "<< PendingPtr <<
"\n";
660DeclAnalysis.dump(S, llvm::dbgs()););
666 voidcompleteAnalysis(
constCallableInfo &CInfo,
667PendingFunctionAnalysis &&Pending) {
673CompleteFunctionAnalysis *CompletePtr =
newCompleteFunctionAnalysis(
675AllInferrableEffectsToVerify);
676DeclAnalysis[CInfo.CDecl] = CompletePtr;
677LLVM_DEBUG(llvm::dbgs() <<
"inserted complete "<< CompletePtr <<
"\n";
678DeclAnalysis.dump(S, llvm::dbgs()););
684 voidfinishPendingAnalysis(
const Decl*
D, PendingFunctionAnalysis *Pending) {
685CallableInfo Caller(*
D);
686LLVM_DEBUG(llvm::dbgs() <<
"finishPendingAnalysis for " 687<< Caller.getNameForDiagnostic(S) <<
" : ";
688Pending->dump(S, llvm::dbgs()); llvm::dbgs() <<
"\n";);
689 for(
constPendingFunctionAnalysis::DirectCall &
Call:
690Pending->unverifiedCalls()) {
694CallableInfo Callee(*
Call.Callee);
695followCall(Caller, *Pending, Callee,
Call.CallLoc,
698completeAnalysis(Caller, std::move(*Pending));
704 voidfollowCall(
constCallableInfo &Caller, PendingFunctionAnalysis &PFA,
706 boolAssertNoFurtherInference, ViolationSite VSite) {
707 const boolDirectCall = Callee.isCalledDirectly();
712 boolIsInferencePossible = DirectCall;
715 if(CompleteFunctionAnalysis *CFA =
716DeclAnalysis.completedAnalysisForDecl(Callee.CDecl)) {
718CalleeEffects.
insert(CFA->VerifiedEffects);
719IsInferencePossible =
false;
722 if(AssertNoFurtherInference) {
723assert(!IsInferencePossible);
726 if(!Callee.isVerifiable())
727IsInferencePossible =
false;
729LLVM_DEBUG(llvm::dbgs()
730<<
"followCall from "<< Caller.getNameForDiagnostic(S)
731<<
" to "<< Callee.getNameForDiagnostic(S)
732<<
"; verifiable: "<< Callee.isVerifiable() <<
"; callee ";
733CalleeEffects.
dump(llvm::dbgs()); llvm::dbgs() <<
"\n";
734llvm::dbgs() <<
" callee "<< Callee.CDecl <<
" canonical " 735<< Callee.CDecl->getCanonicalDecl() <<
"\n";);
743 if(!IsInferencePossible ||
745 if(Callee.FuncType == SpecialFuncType::None)
746PFA.checkAddViolation(Inferring,
747{Effect, ViolationID::CallsDeclWithoutEffect,
748VSite, CallLoc, Callee.CDecl});
750PFA.checkAddViolation(
752{Effect, ViolationID::AllocatesMemory, VSite, CallLoc});
755PFA.addUnverifiedDirectCall(Callee.CDecl, CallLoc, VSite);
760Check1Effect(Effect,
false);
763Check1Effect(Effect,
true);
769 enumCallableDeclKind {
775CDK_MemberInitializer,
781 staticCallableDeclKind GetCallableDeclKind(
const Decl*
D,
782 constViolation *
V) {
784 V->Site.kind() == ViolationSite::Kind::MemberInitializer)
785 returnCDK_MemberInitializer;
786 if(isa<BlockDecl>(
D))
788 if(
auto*Method = dyn_cast<CXXMethodDecl>(
D)) {
789 if(isa<CXXConstructorDecl>(
D))
790 returnCDK_Constructor;
791 if(isa<CXXDestructorDecl>(
D))
792 returnCDK_Destructor;
806 autoMaybeAddTemplateNote = [&](
const Decl*
D) {
811diag::note_func_effect_from_template);
818 enum{ Indirect_VirtualMethod, Indirect_FunctionPtr };
820 autoMaybeAddSiteContext = [&](
const Decl*
D,
constViolation &
V) {
823 if(
V.Site.kind() == ViolationSite::Kind::MemberInitializer) {
824 unsignedImplicitCtor = 0;
825 if(
auto*Ctor = dyn_cast<CXXConstructorDecl>(
D);
826Ctor && Ctor->isImplicit())
834 else if(
V.Site.kind() == ViolationSite::Kind::DefaultArgExpr)
835S.
Diag(
V.Site.defaultArgExpr()->getUsedLocation(),
836diag::note_in_evaluating_default_argument);
840 for(
constViolation &Viol1 : Viols) {
841StringRef effectName = Viol1.Effect.name();
843 caseViolationID::None:
844 caseViolationID::DeclDisallowsInference:
846llvm_unreachable(
"Unexpected violation kind");
848 caseViolationID::AllocatesMemory:
849 caseViolationID::ThrowsOrCatchesExceptions:
850 caseViolationID::HasStaticLocalVariable:
851 caseViolationID::AccessesThreadLocalVariable:
852 caseViolationID::AccessesObjCMethodOrProperty:
853S.
Diag(Viol1.Loc, diag::warn_func_effect_violation)
854<< GetCallableDeclKind(CInfo.CDecl, &Viol1) << effectName
855<< Viol1.diagnosticSelectIndex();
856MaybeAddSiteContext(CInfo.CDecl, Viol1);
857MaybeAddTemplateNote(CInfo.CDecl);
859 caseViolationID::CallsExprWithoutEffect:
860S.
Diag(Viol1.Loc, diag::warn_func_effect_calls_expr_without_effect)
861<< GetCallableDeclKind(CInfo.CDecl, &Viol1) << effectName;
862MaybeAddSiteContext(CInfo.CDecl, Viol1);
863MaybeAddTemplateNote(CInfo.CDecl);
866 caseViolationID::CallsDeclWithoutEffect: {
867CallableInfo CalleeInfo(*Viol1.Callee);
868std::string CalleeName = CalleeInfo.getNameForDiagnostic(S);
870S.
Diag(Viol1.Loc, diag::warn_func_effect_calls_func_without_effect)
871<< GetCallableDeclKind(CInfo.CDecl, &Viol1) << effectName
872<< GetCallableDeclKind(CalleeInfo.CDecl,
nullptr) << CalleeName;
873MaybeAddSiteContext(CInfo.CDecl, Viol1);
874MaybeAddTemplateNote(CInfo.CDecl);
878 for(
const Decl*Callee = Viol1.Callee; Callee !=
nullptr;) {
879std::optional<CallableInfo> MaybeNextCallee;
880CompleteFunctionAnalysis *Completed =
881DeclAnalysis.completedAnalysisForDecl(CalleeInfo.CDecl);
882 if(Completed ==
nullptr) {
888CallableType CType = CalleeInfo.type();
889 if(CType == CallableType::Virtual)
890S.
Diag(Callee->getLocation(),
891diag::note_func_effect_call_indirect)
892<< Indirect_VirtualMethod << effectName;
893 else if(CType == CallableType::Unknown)
894S.
Diag(Callee->getLocation(),
895diag::note_func_effect_call_indirect)
896<< Indirect_FunctionPtr << effectName;
897 else if(CalleeInfo.Effects.contains(Viol1.Effect.oppositeKind()))
898S.
Diag(Callee->getLocation(),
899diag::note_func_effect_call_disallows_inference)
900<< GetCallableDeclKind(CInfo.CDecl,
nullptr) << effectName
902 else if(
const FunctionDecl*FD = dyn_cast<FunctionDecl>(Callee);
906S.
Diag(Callee->getLocation(), diag::note_func_effect_call_extern)
911 constViolation *PtrViol2 =
912Completed->firstViolationForEffect(Viol1.Effect);
913 if(PtrViol2 ==
nullptr)
916 constViolation &Viol2 = *PtrViol2;
918 caseViolationID::None:
919llvm_unreachable(
"Unexpected violation kind");
921 caseViolationID::DeclDisallowsInference:
922S.
Diag(Viol2.Loc, diag::note_func_effect_call_disallows_inference)
923<< GetCallableDeclKind(CalleeInfo.CDecl,
nullptr) << effectName
924<< Viol2.CalleeEffectPreventingInference->name();
926 caseViolationID::CallsExprWithoutEffect:
927S.
Diag(Viol2.Loc, diag::note_func_effect_call_indirect)
928<< Indirect_FunctionPtr << effectName;
930 caseViolationID::AllocatesMemory:
931 caseViolationID::ThrowsOrCatchesExceptions:
932 caseViolationID::HasStaticLocalVariable:
933 caseViolationID::AccessesThreadLocalVariable:
934 caseViolationID::AccessesObjCMethodOrProperty:
935S.
Diag(Viol2.Loc, diag::note_func_effect_violation)
936<< GetCallableDeclKind(CalleeInfo.CDecl, &Viol2) << effectName
937<< Viol2.diagnosticSelectIndex();
938MaybeAddSiteContext(CalleeInfo.CDecl, Viol2);
940 caseViolationID::CallsDeclWithoutEffect:
941MaybeNextCallee.emplace(*Viol2.Callee);
942S.
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);
948MaybeAddTemplateNote(Callee);
949Callee = Viol2.Callee;
950 if(MaybeNextCallee) {
951CalleeInfo = *MaybeNextCallee;
952CalleeName = CalleeInfo.getNameForDiagnostic(S);
970PendingFunctionAnalysis &CurrentFunction;
971CallableInfo &CurrentCaller;
973 const Expr*TrailingRequiresClause =
nullptr;
974 const Expr*NoexceptExpr =
nullptr;
976FunctionBodyASTVisitor(Analyzer &Outer,
977PendingFunctionAnalysis &CurrentFunction,
978CallableInfo &CurrentCaller)
979: Outer(Outer), CurrentFunction(CurrentFunction),
980CurrentCaller(CurrentCaller) {
981ShouldVisitImplicitCode =
true;
982ShouldWalkTypesOfTypeLocs =
false;
989 if(
auto*Dtor = dyn_cast<CXXDestructorDecl>(CurrentCaller.CDecl))
990followDestructor(dyn_cast<CXXRecordDecl>(Dtor->getParent()), Dtor);
992 if(
auto*FD = dyn_cast<FunctionDecl>(CurrentCaller.CDecl)) {
1004NoexceptExpr = FPT->getNoexceptExpr();
1009TraverseDecl(
const_cast<Decl*
>(CurrentCaller.CDecl));
1019 const Decl*Callee =
nullptr) {
1022 for(
FunctionEffectEffect : CurrentFunction.DeclaredVerifiableEffects) {
1023 if(Effect.
flags() & Flag) {
1024addViolation(
false, Effect, VID,
Loc, Callee);
1031 if(Effect.
flags() & Flag)
1032addViolation(
true, Effect, VID,
Loc, Callee);
1035 voidaddViolation(
boolInferring,
FunctionEffectEffect, ViolationID VID,
1037CurrentFunction.checkAddViolation(
1038Inferring, Violation(Effect, VID, VSite,
Loc, Callee));
1046 if(
const auto*FD = dyn_cast<FunctionDecl>(CI.CDecl)) {
1048CI.Effects = getBuiltinFunctionEffects(BuiltinID);
1049 if(CI.Effects.empty()) {
1061(!Outer.S.getLangOpts().CPlusPlus ||
isNoexcept(FD)))
1066Outer.followCall(CurrentCaller, CurrentFunction, CI, CallLoc,
1074CalleeEffects.
insert(Effects);
1076 autoCheck1Effect = [&](
FunctionEffectEffect,
boolInferring) {
1078 false, CalleeEffects))
1079addViolation(Inferring, Effect, ViolationID::CallsExprWithoutEffect,
1080 Call->getBeginLoc());
1083 for(
FunctionEffectEffect : CurrentFunction.DeclaredVerifiableEffects)
1084Check1Effect(Effect,
false);
1087Check1Effect(Effect,
true);
1096followTypeDtor(Field->getType(), DtorLoc);
1098 if(
const auto*
Class= dyn_cast<CXXRecordDecl>(Rec))
1100followTypeDtor(
Base.getType(), DtorLoc);
1115CallableInfo CI(*Dtor);
1116followCall(CI, CallSite);
1124 boolVisitCXXThrowExpr(
CXXThrowExpr*Throw)
override{
1126ViolationID::ThrowsOrCatchesExceptions,
1131 boolVisitCXXCatchStmt(
CXXCatchStmt*Catch)
override{
1133ViolationID::ThrowsOrCatchesExceptions,
1140ViolationID::ThrowsOrCatchesExceptions,
1147ViolationID::ThrowsOrCatchesExceptions,
1154ViolationID::ThrowsOrCatchesExceptions,
1161ViolationID::AccessesObjCMethodOrProperty,
1171ViolationID::AccessesObjCMethodOrProperty,
1181ViolationID::AccessesObjCMethodOrProperty,
1188ViolationID::ThrowsOrCatchesExceptions,
1194LLVM_DEBUG(llvm::dbgs()
1195<<
"VisitCallExpr : " 1196<<
Call->getBeginLoc().printToString(Outer.S.SourceMgr)
1199 Expr*CalleeExpr =
Call->getCallee();
1201CallableInfo CI(*Callee);
1202followCall(CI,
Call->getBeginLoc());
1206 if(isa<CXXPseudoDestructorExpr>(CalleeExpr)) {
1212checkIndirectCall(
Call, CalleeExpr->
getType());
1217 boolVisitVarDecl(
VarDecl*Var)
override{
1218LLVM_DEBUG(llvm::dbgs()
1219<<
"VisitVarDecl : " 1225ViolationID::HasStaticLocalVariable,
1235 boolVisitCXXNewExpr(
CXXNewExpr*New)
override{
1238CallableInfo CI(*FD, SpecialFuncType::OperatorNew);
1254CallableInfo CI(*FD, SpecialFuncType::OperatorDelete);
1255followCall(CI,
Delete->getBeginLoc());
1264LLVM_DEBUG(llvm::dbgs() <<
"VisitCXXConstructExpr : " 1272CallableInfo CI(*Ctor);
1278 boolTraverseStmt(
Stmt*Statement)
override{
1284 if(Statement != TrailingRequiresClause && Statement != NoexceptExpr)
1290ViolationSite PrevVS = VSite;
1291 if(
Init->isAnyMemberInitializer())
1292VSite.setKind(ViolationSite::Kind::MemberInitializer);
1300LLVM_DEBUG(llvm::dbgs()
1301<<
"TraverseCXXDefaultArgExpr : " 1302<<
E->getUsedLocation().printToString(Outer.S.SourceMgr)
1305ViolationSite PrevVS = VSite;
1306 if(VSite.kind() == ViolationSite::Kind::Default)
1307VSite = ViolationSite{
E};
1309 boolResult = DynamicRecursiveASTVisitor::TraverseCXXDefaultArgExpr(
E);
1314 boolTraverseLambdaExpr(
LambdaExpr*Lambda)
override{
1320 for(
unsignedI = 0, N = Lambda->
capture_size(); I < N; ++I)
1321TraverseLambdaCapture(Lambda, Lambda->
capture_begin() + I,
1327 boolTraverseBlockExpr(
BlockExpr*
)
override{
1335 if(
const auto*Var = dyn_cast<VarDecl>(Val)) {
1340ViolationID::AccessesThreadLocalVariable,
1348 returnTraverseStmt(
Node->getResultExpr());
1374Analyzer::AnalysisMap::~AnalysisMap() {
1375 for(
const auto&Item : *
this) {
1376FuncAnalysisPtr AP = Item.second;
1377 if(
auto*PFA = dyn_cast<PendingFunctionAnalysis *>(AP))
1380 deletecast<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 boolAnyVerifiable =
false;
1478AnyVerifiable =
true;
1491Analyzer{*
this}.run(*TU);
1504 if(POld == OldEnd) {
1508}
else if(PNew == NewEnd)
1536}
else if(cmp > 0) {
1541std::nullopt, New});
1554 switch(EffectKind) {
1558 if(DiffKind == Kind::Added) {
1559 for(
const auto&CFE : SrcFX) {
1572 caseKind::ConditionMismatch:
1584llvm_unreachable(
"unknown effect kind");
1590 switch(EffectKind) {
1599 caseKind::ConditionMismatch:
1608llvm_unreachable(
"unknown effect kind");
1615 switch(EffectKind) {
1622 returnOverrideResult::NoAction;
1626 returnOverrideResult::Merge;
1630 caseKind::ConditionMismatch:
1631 returnOverrideResult::Warn;
1636 returnOverrideResult::NoAction;
1638llvm_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 TraverseConstructorInitializer(MaybeConst< CXXCtorInitializer > *Init)
Recursively visit a constructor initializer.
virtual bool TraverseStmt(MaybeConst< Stmt > *S)
Recursively visit a statement or expression, by dispatching to Traverse*() based on the argument's dy...
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...
RetroSearch is an open source project built by @garambo | Open a GitHub Issue
Search and Browse the WWW like it's 1997 | Search results from DuckDuckGo
HTML:
3.2
| Encoding:
UTF-8
| Version:
0.7.4