Index: lib/StaticAnalyzer/Core/ExprEngine.cpp =================================================================== --- lib/StaticAnalyzer/Core/ExprEngine.cpp +++ lib/StaticAnalyzer/Core/ExprEngine.cpp @@ -389,6 +389,15 @@ if (!isa(S.getStmt())) return true; + if (const CXXNewExpr *NE = dyn_cast_or_null(S.getStmt())) + return false; + + if (const CXXConstructExpr *CE = + dyn_cast_or_null(S.getStmt())) + if (const Stmt *Parent = LC->getParentMap().getParent(CE)) + if (isa(Parent)) + return false; + // Run before processing a call. if (CallEvent::isCallStmt(S.getStmt())) return true; Index: lib/StaticAnalyzer/Core/ExprEngineCXX.cpp =================================================================== --- lib/StaticAnalyzer/Core/ExprEngineCXX.cpp +++ lib/StaticAnalyzer/Core/ExprEngineCXX.cpp @@ -114,14 +114,21 @@ if (auto Elem = findElementDirectlyInitializedByCurrentConstructor()) { if (Optional StmtElem = Elem->getAs()) { - auto *DS = cast(StmtElem->getStmt()); - if (const auto *Var = dyn_cast(DS->getSingleDecl())) { - if (Var->getInit() && Var->getInit()->IgnoreImplicit() == CE) { - SVal LValue = State->getLValue(Var, LCtx); - QualType Ty = Var->getType(); - LValue = makeZeroElementRegion(State, LValue, Ty); - return LValue.getAsRegion(); + if (auto *NE = dyn_cast(StmtElem->getStmt())) { + SVal NewVal = State->getSVal(NE, LCtx); + if (const MemRegion *MR = NewVal.getAsRegion()) + return MR; + } else if (auto *DS = dyn_cast(StmtElem->getStmt())) { + if (const auto *Var = dyn_cast(DS->getSingleDecl())) { + if (Var->getInit() && Var->getInit()->IgnoreImplicit() == CE) { + SVal LValue = State->getLValue(Var, LCtx); + QualType Ty = Var->getType(); + LValue = makeZeroElementRegion(State, LValue, Ty); + return LValue.getAsRegion(); + } } + } else { + llvm_unreachable("Unexpected directly initialized element!"); } } else if (Optional InitElem = Elem->getAs()) { const CXXCtorInitializer *Init = InitElem->getInitializer(); @@ -165,6 +172,9 @@ if (isa(StmtElem->getStmt())) { return true; } + if (isa(StmtElem->getStmt())) { + return true; + } } if (Elem.getKind() == CFGElement::Initializer) { @@ -456,7 +466,7 @@ unsigned blockCount = currBldrCtx->blockCount(); const LocationContext *LCtx = Pred->getLocationContext(); - DefinedOrUnknownSVal symVal = UnknownVal(); + SVal symVal = UnknownVal(); FunctionDecl *FD = CNE->getOperatorNew(); bool IsStandardGlobalOpNewFunction = false; @@ -475,11 +485,17 @@ // We assume all standard global 'operator new' functions allocate memory in // heap. We realize this is an approximation that might not correctly model // a custom global allocator. - if (IsStandardGlobalOpNewFunction) - symVal = svalBuilder.getConjuredHeapSymbolVal(CNE, LCtx, blockCount); - else - symVal = svalBuilder.conjureSymbolVal(nullptr, CNE, LCtx, CNE->getType(), - blockCount); + if (const Expr *Init = CNE->getInitializer()) + if (isa(Init)) + symVal = Pred->getState()->getSVal(CNE, LCtx); + + if (symVal.isUnknown()) { + if (IsStandardGlobalOpNewFunction) + symVal = svalBuilder.getConjuredHeapSymbolVal(CNE, LCtx, blockCount); + else + symVal = svalBuilder.conjureSymbolVal(nullptr, CNE, LCtx, CNE->getType(), + blockCount); + } ProgramStateRef State = Pred->getState(); CallEventManager &CEMgr = getStateManager().getCallEventManager(); @@ -504,7 +520,8 @@ QualType Ty = FD->getType(); if (const FunctionProtoType *ProtoType = Ty->getAs()) if (!ProtoType->isNothrow(getContext())) - State = State->assume(symVal, true); + if (auto dSymVal = symVal.getAs()) + State = State->assume(*dSymVal, true); } StmtNodeBuilder Bldr(Pred, Dst, *currBldrCtx); Index: lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp =================================================================== --- lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp +++ lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp @@ -596,21 +596,30 @@ const CXXConstructorCall &Ctor = cast(Call); + const CXXConstructExpr *CtorExpr = Ctor.getOriginExpr(); + const Stmt *ParentExpr = CurLC->getParentMap().getParent(CtorExpr); + + if (ParentExpr && isa(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. const MemRegion *Target = Ctor.getCXXThisVal().getAsRegion(); - if (Target && isa(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 - // 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(Parent)) - return CIP_DisallowedOnce; + if (Target && isa(Target)) { + if (ParentExpr) + if (const CXXNewExpr *NewExpr = dyn_cast(ParentExpr)) + if (NewExpr->isArray()) + return CIP_DisallowedOnce; + + if (const TypedValueRegion *TR = dyn_cast( + cast(Target)->getSuperRegion())) + if (TR->getValueType()->isArrayType()) + return CIP_DisallowedOnce; + } // Inlining constructors requires including initializers in the CFG. const AnalysisDeclContext *ADC = CallerSFC->getAnalysisDeclContext(); @@ -629,7 +638,7 @@ // 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(Target)) + if (!Target || isa(Target)) return CIP_DisallowedOnce; break; Index: test/Analysis/inline.cpp =================================================================== --- test/Analysis/inline.cpp +++ test/Analysis/inline.cpp @@ -315,17 +315,13 @@ int value; IntWrapper(int input) : value(input) { - // We don't want this constructor to be inlined unless we can actually - // use the proper region for operator new. - // See PR12014 and . - clang_analyzer_checkInlined(false); // no-warning + clang_analyzer_checkInlined(true); // expected-warning{{TRUE}} } }; void test() { IntWrapper *obj = new IntWrapper(42); - // should be TRUE - clang_analyzer_eval(obj->value == 42); // expected-warning{{UNKNOWN}} + clang_analyzer_eval(obj->value == 42); // expected-warning{{TRUE}} delete obj; } Index: test/Analysis/new-ctor.cpp =================================================================== --- /dev/null +++ test/Analysis/new-ctor.cpp @@ -0,0 +1,14 @@ +// RUN: %clang_analyze_cc1 -analyzer-checker=core,debug.ExprInspection -analyzer-config c++-allocator-inlining=true -std=c++11 -verify %s + +void clang_analyzer_eval(bool); + +struct S { + int x; + S() : x(1) {} + ~S() {} +}; + +void foo() { + S *s = new S; + clang_analyzer_eval(s->x == 1); // expected-warning{{TRUE}} +}