Index: cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h =================================================================== --- cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h +++ cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h @@ -734,10 +734,14 @@ /// /// If \p Result is provided, the new region will be bound to this expression /// instead of \p InitWithAdjustments. - ProgramStateRef createTemporaryRegionIfNeeded(ProgramStateRef State, - const LocationContext *LC, - const Expr *InitWithAdjustments, - const Expr *Result = nullptr); + /// + /// Returns the temporary region with adjustments into the optional + /// OutRegionWithAdjustments out-parameter if a new region was indeed needed, + /// otherwise sets it to nullptr. + ProgramStateRef createTemporaryRegionIfNeeded( + ProgramStateRef State, const LocationContext *LC, + const Expr *InitWithAdjustments, const Expr *Result = nullptr, + const SubRegion **OutRegionWithAdjustments = nullptr); /// Returns a region representing the first element of a (possibly /// multi-dimensional) array, for the purposes of element construction or Index: cfe/trunk/lib/StaticAnalyzer/Core/ExprEngine.cpp =================================================================== --- cfe/trunk/lib/StaticAnalyzer/Core/ExprEngine.cpp +++ cfe/trunk/lib/StaticAnalyzer/Core/ExprEngine.cpp @@ -283,11 +283,10 @@ return state; } -ProgramStateRef -ExprEngine::createTemporaryRegionIfNeeded(ProgramStateRef State, - const LocationContext *LC, - const Expr *InitWithAdjustments, - const Expr *Result) { +ProgramStateRef ExprEngine::createTemporaryRegionIfNeeded( + ProgramStateRef State, const LocationContext *LC, + const Expr *InitWithAdjustments, const Expr *Result, + const SubRegion **OutRegionWithAdjustments) { // FIXME: This function is a hack that works around the quirky AST // we're often having with respect to C++ temporaries. If only we modelled // the actual execution order of statements properly in the CFG, @@ -297,8 +296,11 @@ if (!Result) { // If we don't have an explicit result expression, we're in "if needed" // mode. Only create a region if the current value is a NonLoc. - if (!InitValWithAdjustments.getAs()) + if (!InitValWithAdjustments.getAs()) { + if (OutRegionWithAdjustments) + *OutRegionWithAdjustments = nullptr; return State; + } Result = InitWithAdjustments; } else { // We need to create a region no matter what. For sanity, make sure we don't @@ -418,11 +420,17 @@ // The result expression would now point to the correct sub-region of the // newly created temporary region. Do this last in order to getSVal of Init // correctly in case (Result == Init). - State = State->BindExpr(Result, LC, Reg); + if (Result->isGLValue()) { + State = State->BindExpr(Result, LC, Reg); + } else { + State = State->BindExpr(Result, LC, InitValWithAdjustments); + } // Notify checkers once for two bindLoc()s. State = processRegionChange(State, TR, LC); + if (OutRegionWithAdjustments) + *OutRegionWithAdjustments = cast(Reg.getAsRegion()); return State; } @@ -2532,8 +2540,12 @@ } // Handle regular struct fields / member variables. - state = createTemporaryRegionIfNeeded(state, LCtx, BaseExpr); - SVal baseExprVal = state->getSVal(BaseExpr, LCtx); + const SubRegion *MR = nullptr; + state = createTemporaryRegionIfNeeded(state, LCtx, BaseExpr, + /*Result=*/nullptr, + /*OutRegionWithAdjustments=*/&MR); + SVal baseExprVal = + MR ? loc::MemRegionVal(MR) : state->getSVal(BaseExpr, LCtx); const auto *field = cast(Member); SVal L = state->getLValue(field, baseExprVal); Index: cfe/trunk/test/Analysis/temporaries.cpp =================================================================== --- cfe/trunk/test/Analysis/temporaries.cpp +++ cfe/trunk/test/Analysis/temporaries.cpp @@ -1152,3 +1152,23 @@ // and the non-definition decl should be found by direct lookup. void T::foo(C) {} } // namespace argument_virtual_decl_lookup + +namespace union_indirect_field_crash { +union U { + struct { + int x; + }; +}; + +template class C { +public: + void foo() const { + (void)(true ? U().x : 0); + } +}; + +void test() { + C c; + c.foo(); +} +} // namespace union_indirect_field_crash