static CallInlinePolicy mayInlineCallKind(const CallEvent &Call, const ExplodedNode *Pred, AnalyzerOptions &Opts) { const LocationContext *CurLC = Pred->getLocationContext(); const StackFrameContext *CallerSFC = CurLC->getCurrentStackFrame(); switch (Call.getKind()) { case CE_Function: case CE_Block: break; case CE_CXXMember: case CE_CXXMemberOperator: if (!Opts.mayInlineCXXMemberFunction(CIMK_MemberFunctions)) return CIP_DisallowedAlways; break; case CE_CXXConstructor: { if (!Opts.mayInlineCXXMemberFunction(CIMK_Constructors)) return CIP_DisallowedAlways; const CXXConstructorCall &Ctor = cast<CXXConstructorCall>(Call); // FIXME: We don't handle constructors or destructors for arrays properly. // Even once we do, we still need to be careful about implicitly-generated // initializers for array fields in default move/copy constructors. const MemRegion *Target = Ctor.getCXXThisVal().getAsRegion(); if (Target && isa<ElementRegion>(Target)) return CIP_DisallowedOnce; // FIXME: This is a hack. We don't use the correct region for a new // expression, so if we inline the constructor its result will just be // thrown away. This short-term hack is tracked in <rdar://problem/12180598> // and the longer-term possible fix is discussed in PR12014. const CXXConstructExpr *CtorExpr = Ctor.getOriginExpr(); if (const Stmt *Parent = CurLC->getParentMap().getParent(CtorExpr)) if (isa<CXXNewExpr>(Parent)) return CIP_DisallowedOnce; // Inlining constructors requires including initializers in the CFG. const AnalysisDeclContext *ADC = CallerSFC->getAnalysisDeclContext(); assert(ADC->getCFGBuildOptions().AddInitializers && "No CFG initializers"); (void)ADC; // If the destructor is trivial, it's always safe to inline the constructor. if (Ctor.getDecl()->getParent()->hasTrivialDestructor()) break; // For other types, only inline constructors if destructor inlining is // also enabled. if (!Opts.mayInlineCXXMemberFunction(CIMK_Destructors)) return CIP_DisallowedAlways; // FIXME: This is a hack. We don't handle temporary destructors // right now, so we shouldn't inline their constructors. if (CtorExpr->getConstructionKind() == CXXConstructExpr::CK_Complete) if (!Target || !isa<DeclRegion>(Target)) return CIP_DisallowedOnce; break; } case CE_CXXDestructor: { if (!Opts.mayInlineCXXMemberFunction(CIMK_Destructors)) return CIP_DisallowedAlways; // Inlining destructors requires building the CFG correctly. const AnalysisDeclContext *ADC = CallerSFC->getAnalysisDeclContext(); assert(ADC->getCFGBuildOptions().AddImplicitDtors && "No CFG destructors"); (void)ADC; const CXXDestructorCall &Dtor = cast<CXXDestructorCall>(Call); // FIXME: We don't handle constructors or destructors for arrays properly. const MemRegion *Target = Dtor.getCXXThisVal().getAsRegion(); if (Target && isa<ElementRegion>(Target)) return CIP_DisallowedOnce; break; } case CE_CXXAllocator: if (Opts.mayInlineCXXAllocator()) break; // Do not inline allocators until we model deallocators. // This is unfortunate, but basically necessary for smart pointers and such. return CIP_DisallowedAlways; case CE_ObjCMessage: if (!Opts.mayInlineObjCMethod()) return CIP_DisallowedAlways; if (!(Opts.getIPAMode() == IPAK_DynamicDispatch || Opts.getIPAMode() == IPAK_DynamicDispatchBifurcate)) return CIP_DisallowedAlways; break; } return CIP_Allowed; }
ExprEngine::CallInlinePolicy ExprEngine::mayInlineCallKind(const CallEvent &Call, const ExplodedNode *Pred, AnalyzerOptions &Opts, const ExprEngine::EvalCallOptions &CallOpts) { const LocationContext *CurLC = Pred->getLocationContext(); const StackFrameContext *CallerSFC = CurLC->getCurrentStackFrame(); switch (Call.getKind()) { case CE_Function: case CE_Block: break; case CE_CXXMember: case CE_CXXMemberOperator: if (!Opts.mayInlineCXXMemberFunction(CIMK_MemberFunctions)) return CIP_DisallowedAlways; break; case CE_CXXConstructor: { if (!Opts.mayInlineCXXMemberFunction(CIMK_Constructors)) return CIP_DisallowedAlways; const CXXConstructorCall &Ctor = cast<CXXConstructorCall>(Call); const CXXConstructExpr *CtorExpr = Ctor.getOriginExpr(); // FIXME: ParentMap is slow and ugly. The callee should provide the // necessary context. Ideally as part of the call event, or maybe as part of // location context. const Stmt *ParentExpr = CurLC->getParentMap().getParent(CtorExpr); if (ParentExpr && isa<CXXNewExpr>(ParentExpr) && !Opts.mayInlineCXXAllocator()) return CIP_DisallowedOnce; // FIXME: We don't handle constructors or destructors for arrays properly. // Even once we do, we still need to be careful about implicitly-generated // initializers for array fields in default move/copy constructors. // We still allow construction into ElementRegion targets when they don't // represent array elements. if (CallOpts.IsArrayConstructorOrDestructor) return CIP_DisallowedOnce; // Inlining constructors requires including initializers in the CFG. const AnalysisDeclContext *ADC = CallerSFC->getAnalysisDeclContext(); assert(ADC->getCFGBuildOptions().AddInitializers && "No CFG initializers"); (void)ADC; // If the destructor is trivial, it's always safe to inline the constructor. if (Ctor.getDecl()->getParent()->hasTrivialDestructor()) break; // For other types, only inline constructors if destructor inlining is // also enabled. if (!Opts.mayInlineCXXMemberFunction(CIMK_Destructors)) return CIP_DisallowedAlways; // FIXME: This is a hack. We don't handle temporary destructors // right now, so we shouldn't inline their constructors. if (CtorExpr->getConstructionKind() == CXXConstructExpr::CK_Complete) if (CallOpts.IsConstructorWithImproperlyModeledTargetRegion) return CIP_DisallowedOnce; break; } case CE_CXXDestructor: { if (!Opts.mayInlineCXXMemberFunction(CIMK_Destructors)) return CIP_DisallowedAlways; // Inlining destructors requires building the CFG correctly. const AnalysisDeclContext *ADC = CallerSFC->getAnalysisDeclContext(); assert(ADC->getCFGBuildOptions().AddImplicitDtors && "No CFG destructors"); (void)ADC; // FIXME: We don't handle constructors or destructors for arrays properly. if (CallOpts.IsArrayConstructorOrDestructor) return CIP_DisallowedOnce; break; } case CE_CXXAllocator: if (Opts.mayInlineCXXAllocator()) break; // Do not inline allocators until we model deallocators. // This is unfortunate, but basically necessary for smart pointers and such. return CIP_DisallowedAlways; case CE_ObjCMessage: if (!Opts.mayInlineObjCMethod()) return CIP_DisallowedAlways; if (!(Opts.getIPAMode() == IPAK_DynamicDispatch || Opts.getIPAMode() == IPAK_DynamicDispatchBifurcate)) return CIP_DisallowedAlways; break; } return CIP_Allowed; }