Index: clang/include/clang/StaticAnalyzer/Checkers/SValExplainer.h =================================================================== --- clang/include/clang/StaticAnalyzer/Checkers/SValExplainer.h +++ clang/include/clang/StaticAnalyzer/Checkers/SValExplainer.h @@ -18,6 +18,7 @@ #include "clang/AST/Attr.h" #include "clang/AST/DeclCXX.h" #include "clang/StaticAnalyzer/Core/PathSensitive/SValVisitor.h" +#include "llvm/ADT/StringExtras.h" namespace clang { @@ -179,7 +180,7 @@ return OS.str(); } - std::string VisitVarRegion(const VarRegion *R) { + std::string VisitNonParamVarRegion(const NonParamVarRegion *R) { const VarDecl *VD = R->getDecl(); std::string Name = VD->getQualifiedNameAsString(); if (isa(VD)) @@ -216,6 +217,39 @@ "' inside " + Visit(R->getSuperRegion()); } + std::string VisitParamVarRegion(const ParamVarRegion *R) { + std::string Str; + llvm::raw_string_ostream OS(Str); + + const ParmVarDecl *PVD = R->getDecl(); + std::string Name = PVD->getQualifiedNameAsString(); + if (!Name.empty()) { + OS << "parameter '" << Name << "'"; + return std::string(OS.str()); + } + + unsigned Index = R->getIndex() + 1; + OS << Index << llvm::getOrdinalSuffix(Index) << " of parameter "; + const Decl *Parent = R->getStackFrame()->getDecl(); + if (const auto *FD = dyn_cast(Parent)) + OS << "function '" << FD->getQualifiedNameAsString() << "()'"; + else if (const auto *CD = dyn_cast(Parent)) + OS << "C++ constructor '" << CD->getQualifiedNameAsString() << "()'"; + else if (const auto *MD = dyn_cast(Parent)) { + if (MD->isClassMethod()) + OS << "Objective-C method '+" << MD->getQualifiedNameAsString() << "'"; + else + OS << "Objective-C method '-" << MD->getQualifiedNameAsString() << "'"; + } else if (isa(Parent)) { + if (cast(Parent)->isConversionFromLambda()) + OS << "lambda"; + else + OS << "block"; + } + + return std::string(OS.str()); + } + std::string VisitSVal(SVal V) { std::string Str; llvm::raw_string_ostream OS(Str); Index: clang/include/clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h =================================================================== --- clang/include/clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h +++ clang/include/clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h @@ -403,8 +403,8 @@ /// Returns memory location for a parameter variable within the callee stack /// frame. May fail; returns null on failure. - const VarRegion *getParameterLocation(unsigned Index, - unsigned BlockCount) const; + const ParamVarRegion *getParameterLocation(unsigned Index, + unsigned BlockCount) const; /// Returns true if on the current path, the argument was constructed by /// calling a C++ constructor over it. This is an internal detail of the Index: clang/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h =================================================================== --- clang/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h +++ clang/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h @@ -97,7 +97,7 @@ class SwitchNodeBuilder; class ExprEngine { - void anchor(); + virtual void anchor(); public: /// The modes of inlining, which override the default analysis-wide settings. enum InliningModes { @@ -177,7 +177,7 @@ SetOfConstDecls *VisitedCalleesIn, FunctionSummariesTy *FS, InliningModes HowToInlineIn); - virtual ~ExprEngine() = default; + ~ExprEngine() = default; /// Returns true if there is still simulation state on the worklist. bool ExecuteWorkList(const LocationContext *L, unsigned Steps = 150000) { Index: clang/include/clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h =================================================================== --- clang/include/clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h +++ clang/include/clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h @@ -890,20 +890,12 @@ class DeclRegion : public TypedValueRegion { protected: - const ValueDecl *D; - - DeclRegion(const ValueDecl *d, const MemRegion *sReg, Kind k) - : TypedValueRegion(sReg, k), D(d) { + DeclRegion(const MemRegion *sReg, Kind k) : TypedValueRegion(sReg, k) { assert(classof(this)); - assert(d && d->isCanonicalDecl()); } - static void ProfileRegion(llvm::FoldingSetNodeID& ID, const Decl *D, - const MemRegion* superRegion, Kind k); - public: - const ValueDecl *getDecl() const { return D; } - void Profile(llvm::FoldingSetNodeID& ID) const override; + virtual const ValueDecl *getDecl() const = 0; static bool classof(const MemRegion* R) { unsigned k = R->getKind(); @@ -914,9 +906,9 @@ class VarRegion : public DeclRegion { friend class MemRegionManager; - // Constructors and private methods. - VarRegion(const VarDecl *vd, const MemRegion *sReg) - : DeclRegion(vd, sReg, VarRegionKind) { +protected: + // Constructors and protected methods. + VarRegion(const MemRegion *sReg, Kind k) : DeclRegion(sReg, k) { // VarRegion appears in unknown space when it's a block variable as seen // from a block using it, when this block is analyzed at top-level. // Other block variables appear within block data regions, @@ -925,17 +917,45 @@ isa(sReg) || isa(sReg)); } - static void ProfileRegion(llvm::FoldingSetNodeID& ID, const VarDecl *VD, - const MemRegion *superRegion) { - DeclRegion::ProfileRegion(ID, VD, superRegion, VarRegionKind); +public: + const VarDecl *getDecl() const override = 0; + + const StackFrameContext *getStackFrame() const; + + QualType getValueType() const override { + // FIXME: We can cache this if needed. + return getDecl()->getType(); } -public: - void Profile(llvm::FoldingSetNodeID& ID) const override; + static bool classof(const MemRegion *R) { + unsigned k = R->getKind(); + return k >= BEGIN_VAR_REGIONS && k <= END_VAR_REGIONS; + } +}; + +class NonParamVarRegion : public VarRegion { + friend class MemRegionManager; - const VarDecl *getDecl() const { return cast(D); } + const VarDecl *VD; - const StackFrameContext *getStackFrame() const; + // Constructors and private methods. + NonParamVarRegion(const VarDecl *vd, const MemRegion *sReg) + : VarRegion(sReg, NonParamVarRegionKind), VD(vd) { + // VarRegion appears in unknown space when it's a block variable as seen + // from a block using it, when this block is analyzed at top-level. + // Other block variables appear within block data regions, + // which, unlike everything else on this list, are not memory spaces. + assert(isa(sReg) || isa(sReg) || + isa(sReg) || isa(sReg)); + } + + static void ProfileRegion(llvm::FoldingSetNodeID &ID, const VarDecl *VD, + const MemRegion *superRegion); + +public: + void Profile(llvm::FoldingSetNodeID &ID) const override; + + const VarDecl *getDecl() const override { return VD; } QualType getValueType() const override { // FIXME: We can cache this if needed. @@ -949,7 +969,49 @@ void printPrettyAsExpr(raw_ostream &os) const override; static bool classof(const MemRegion* R) { - return R->getKind() == VarRegionKind; + return R->getKind() == NonParamVarRegionKind; + } +}; + +/// ParamVarRegion - Represents a region for paremters. Only parameters of the +/// function in the current stack frame are represented as `ParamVarRegion`s. +/// Parameters of top-level analyzed functions as well as captured paremeters +/// by lambdas and blocks are repesented as `VarRegion`s. + +// FIXME: `ParamVarRegion` only supports parameters of functions, C++ +// constructors, blocks and Objective-C methods with existing `Decl`. Upon +// implementing stack frame creations for functions without decl (functions +// passed by function pointer) methods of `ParamVarRegion` must be updated. +class ParamVarRegion : public VarRegion { + friend class MemRegionManager; + + const Expr *OriginExpr; + unsigned Index; + + ParamVarRegion(const Expr *OE, unsigned Idx, const MemRegion *SReg) + : VarRegion(SReg, ParamVarRegionKind), OriginExpr(OE), Index(Idx) { + assert(!cast(SReg)->getStackFrame()->inTopFrame()); + } + + static void ProfileRegion(llvm::FoldingSetNodeID &ID, const Expr *OE, + unsigned Idx, const MemRegion *SReg); + +public: + const Expr *getOriginExpr() const { return OriginExpr; } + unsigned getIndex() const { return Index; } + + void Profile(llvm::FoldingSetNodeID& ID) const override; + + void dumpToStream(raw_ostream &os) const override; + + QualType getValueType() const override; + const ParmVarDecl *getDecl() const override; + + bool canPrintPrettyAsExpr() const override; + void printPrettyAsExpr(raw_ostream &os) const override; + + static bool classof(const MemRegion *R) { + return R->getKind() == ParamVarRegionKind; } }; @@ -991,16 +1053,22 @@ class FieldRegion : public DeclRegion { friend class MemRegionManager; - FieldRegion(const FieldDecl *fd, const SubRegion* sReg) - : DeclRegion(fd, sReg, FieldRegionKind) {} + const FieldDecl *FD; - static void ProfileRegion(llvm::FoldingSetNodeID& ID, const FieldDecl *FD, + FieldRegion(const FieldDecl *fd, const SubRegion *sReg) + : DeclRegion(sReg, FieldRegionKind), FD(fd) {} + + static void ProfileRegion(llvm::FoldingSetNodeID &ID, const FieldDecl *FD, const MemRegion* superRegion) { - DeclRegion::ProfileRegion(ID, FD, superRegion, FieldRegionKind); + ID.AddInteger(static_cast(FieldRegionKind)); + ID.AddPointer(FD); + ID.AddPointer(superRegion); } public: - const FieldDecl *getDecl() const { return cast(D); } + const FieldDecl *getDecl() const override { return FD; } + + void Profile(llvm::FoldingSetNodeID &ID) const override; QualType getValueType() const override { // FIXME: We can cache this if needed. @@ -1022,6 +1090,8 @@ class ObjCIvarRegion : public DeclRegion { friend class MemRegionManager; + const ObjCIvarDecl *IVD; + ObjCIvarRegion(const ObjCIvarDecl *ivd, const SubRegion *sReg); static void ProfileRegion(llvm::FoldingSetNodeID& ID, const ObjCIvarDecl *ivd, @@ -1029,6 +1099,9 @@ public: const ObjCIvarDecl *getDecl() const; + + void Profile(llvm::FoldingSetNodeID& ID) const override; + QualType getValueType() const override; bool canPrintPrettyAsExpr() const override; @@ -1312,11 +1385,18 @@ /// getVarRegion - Retrieve or create the memory region associated with /// a specified VarDecl and LocationContext. - const VarRegion* getVarRegion(const VarDecl *D, const LocationContext *LC); + const VarRegion *getVarRegion(const VarDecl *VD, const LocationContext *LC); /// getVarRegion - Retrieve or create the memory region associated with - /// a specified VarDecl and super region. - const VarRegion *getVarRegion(const VarDecl *D, const MemRegion *superR); + /// a specified VarDecl and LocationContext. + const NonParamVarRegion *getNonParamVarRegion(const VarDecl *VD, + const MemRegion *superR); + + /// getParamVarRegion - Retrieve or create the memory region + /// associated with a specified CallExpr, Index and LocationContext. + const ParamVarRegion *getParamVarRegion(const Expr *OriginExpr, + unsigned Index, + const LocationContext *LC); /// getElementRegion - Retrieve the memory region associated with the /// associated element type, index, and super region. Index: clang/include/clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h =================================================================== --- clang/include/clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h +++ clang/include/clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h @@ -308,6 +308,10 @@ Loc getLValue(const CXXRecordDecl *BaseClass, const SubRegion *Super, bool IsVirtual) const; + /// Get the lvalue for a parameter. + Loc getLValue(const Expr *Call, unsigned Index, + const LocationContext *LC) const; + /// Get the lvalue for a variable reference. Loc getLValue(const VarDecl *D, const LocationContext *LC) const; Index: clang/include/clang/StaticAnalyzer/Core/PathSensitive/Regions.def =================================================================== --- clang/include/clang/StaticAnalyzer/Core/PathSensitive/Regions.def +++ clang/include/clang/StaticAnalyzer/Core/PathSensitive/Regions.def @@ -73,9 +73,13 @@ ABSTRACT_REGION(DeclRegion, TypedValueRegion) REGION(FieldRegion, DeclRegion) REGION(ObjCIvarRegion, DeclRegion) - REGION(VarRegion, DeclRegion) - REGION_RANGE(DECL_REGIONS, FieldRegionKind, - VarRegionKind) + ABSTRACT_REGION(VarRegion, DeclRegion) + REGION(NonParamVarRegion, VarRegion) + REGION(ParamVarRegion, VarRegion) + REGION_RANGE(VAR_REGIONS, NonParamVarRegionKind, + ParamVarRegionKind) + REGION_RANGE(DECL_REGIONS, FieldRegionKind, + ParamVarRegionKind) REGION(ElementRegion, TypedValueRegion) REGION(ObjCStringRegion, TypedValueRegion) REGION(StringRegion, TypedValueRegion) Index: clang/lib/StaticAnalyzer/Checkers/CStringChecker.cpp =================================================================== --- clang/lib/StaticAnalyzer/Checkers/CStringChecker.cpp +++ clang/lib/StaticAnalyzer/Checkers/CStringChecker.cpp @@ -709,7 +709,8 @@ case MemRegion::SymbolicRegionKind: case MemRegion::AllocaRegionKind: - case MemRegion::VarRegionKind: + case MemRegion::NonParamVarRegionKind: + case MemRegion::ParamVarRegionKind: case MemRegion::FieldRegionKind: case MemRegion::ObjCIvarRegionKind: // These are the types we can currently track string lengths for. @@ -814,7 +815,8 @@ } case MemRegion::SymbolicRegionKind: case MemRegion::AllocaRegionKind: - case MemRegion::VarRegionKind: + case MemRegion::NonParamVarRegionKind: + case MemRegion::ParamVarRegionKind: case MemRegion::FieldRegionKind: case MemRegion::ObjCIvarRegionKind: return getCStringLengthForRegion(C, state, Ex, MR, hypothetical); @@ -1009,10 +1011,14 @@ os << "a C++ temp object of type " << cast(MR)->getValueType().getAsString(); return true; - case MemRegion::VarRegionKind: + case MemRegion::NonParamVarRegionKind: os << "a variable of type" << cast(MR)->getValueType().getAsString(); return true; + case MemRegion::ParamVarRegionKind: + os << "a parameter of type" + << cast(MR)->getValueType().getAsString(); + return true; case MemRegion::FieldRegionKind: os << "a field of type " << cast(MR)->getValueType().getAsString(); Index: clang/lib/StaticAnalyzer/Core/CallEvent.cpp =================================================================== --- clang/lib/StaticAnalyzer/Core/CallEvent.cpp +++ clang/lib/StaticAnalyzer/Core/CallEvent.cpp @@ -222,39 +222,17 @@ return ADC->getManager()->getStackFrame(ADC, LCtx, E, B, BlockCount, Idx); } -const VarRegion *CallEvent::getParameterLocation(unsigned Index, - unsigned BlockCount) const { +const ParamVarRegion +*CallEvent::getParameterLocation(unsigned Index, unsigned BlockCount) const { const StackFrameContext *SFC = getCalleeStackFrame(BlockCount); // We cannot construct a VarRegion without a stack frame. if (!SFC) return nullptr; - // Retrieve parameters of the definition, which are different from - // CallEvent's parameters() because getDecl() isn't necessarily - // the definition. SFC contains the definition that would be used - // during analysis. - const Decl *D = SFC->getDecl(); - - // TODO: Refactor into a virtual method of CallEvent, like parameters(). - const ParmVarDecl *PVD = nullptr; - if (const auto *FD = dyn_cast(D)) - PVD = FD->parameters()[Index]; - else if (const auto *BD = dyn_cast(D)) - PVD = BD->parameters()[Index]; - else if (const auto *MD = dyn_cast(D)) - PVD = MD->parameters()[Index]; - else if (const auto *CD = dyn_cast(D)) - PVD = CD->parameters()[Index]; - assert(PVD && "Unexpected Decl kind!"); - - const VarRegion *VR = - State->getStateManager().getRegionManager().getVarRegion(PVD, SFC); - - // This sanity check would fail if our parameter declaration doesn't - // correspond to the stack frame's function declaration. - assert(VR->getStackFrame() == SFC); - - return VR; + const ParamVarRegion *PVR = + State->getStateManager().getRegionManager().getParamVarRegion( + getOriginExpr(), Index, SFC); + return PVR; } /// Returns true if a type is a pointer-to-const or reference-to-const @@ -325,8 +303,9 @@ if (getKind() != CE_CXXAllocator) if (isArgumentConstructedDirectly(Idx)) if (auto AdjIdx = getAdjustedParameterIndex(Idx)) - if (const VarRegion *VR = getParameterLocation(*AdjIdx, BlockCount)) - ValuesToInvalidate.push_back(loc::MemRegionVal(VR)); + if (const TypedValueRegion *TVR = + getParameterLocation(*AdjIdx, BlockCount)) + ValuesToInvalidate.push_back(loc::MemRegionVal(TVR)); } // Invalidate designated regions using the batch invalidation API. @@ -527,7 +506,8 @@ // which makes getArgSVal() fail and return UnknownVal. SVal ArgVal = Call.getArgSVal(Idx); if (!ArgVal.isUnknown()) { - Loc ParamLoc = SVB.makeLoc(MRMgr.getVarRegion(ParamDecl, CalleeCtx)); + Loc ParamLoc = SVB.makeLoc( + MRMgr.getParamVarRegion(Call.getOriginExpr(), Idx, CalleeCtx)); Bindings.push_back(std::make_pair(ParamLoc, ArgVal)); } } Index: clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp =================================================================== --- clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp +++ clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp @@ -218,7 +218,7 @@ auto CE = BD->capture_end(); for (; I != E; ++I) { const VarRegion *capturedR = I.getCapturedRegion(); - const VarRegion *originalR = I.getOriginalRegion(); + const TypedValueRegion *originalR = I.getOriginalRegion(); // If the capture had a copy expression, use the result of evaluating // that expression, otherwise use the original value. Index: clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp =================================================================== --- clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp +++ clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp @@ -342,12 +342,12 @@ // Operator arguments do not correspond to operator parameters // because this-argument is implemented as a normal argument in // operator call expressions but not in operator declarations. - const VarRegion *VR = Caller->getParameterLocation( + const TypedValueRegion *TVR = Caller->getParameterLocation( *Caller->getAdjustedParameterIndex(Idx), currBldrCtx->blockCount()); - if (!VR) + if (!TVR) return None; - return loc::MemRegionVal(VR); + return loc::MemRegionVal(TVR); }; if (const auto *CE = dyn_cast(E)) { Index: clang/lib/StaticAnalyzer/Core/MemRegion.cpp =================================================================== --- clang/lib/StaticAnalyzer/Core/MemRegion.cpp +++ clang/lib/StaticAnalyzer/Core/MemRegion.cpp @@ -160,11 +160,9 @@ } ObjCIvarRegion::ObjCIvarRegion(const ObjCIvarDecl *ivd, const SubRegion *sReg) - : DeclRegion(ivd, sReg, ObjCIvarRegionKind) {} + : DeclRegion(sReg, ObjCIvarRegionKind), IVD(ivd) {} -const ObjCIvarDecl *ObjCIvarRegion::getDecl() const { - return cast(D); -} +const ObjCIvarDecl *ObjCIvarRegion::getDecl() const { return IVD; } QualType ObjCIvarRegion::getValueType() const { return getDecl()->getType(); @@ -178,6 +176,33 @@ return QualType(getDecl()->getTypeForDecl(), 0); } +QualType ParamVarRegion::getValueType() const { + assert(getDecl() && + "`ParamVarRegion` support functions without `Decl` not implemented" + " yet."); + return getDecl()->getType(); +} + +const ParmVarDecl *ParamVarRegion::getDecl() const { + const Decl *D = getStackFrame()->getDecl(); + + if (const auto *FD = dyn_cast(D)) { + assert(Index < FD->param_size()); + return FD->parameters()[Index]; + } else if (const auto *BD = dyn_cast(D)) { + assert(Index < BD->param_size()); + return BD->parameters()[Index]; + } else if (const auto *MD = dyn_cast(D)) { + assert(Index < MD->param_size()); + return MD->parameters()[Index]; + } else if (const auto *CD = dyn_cast(D)) { + assert(Index < CD->param_size()); + return CD->parameters()[Index]; + } else { + llvm_unreachable("Unexpected Decl kind!"); + } +} + //===----------------------------------------------------------------------===// // FoldingSet profiling. //===----------------------------------------------------------------------===// @@ -249,25 +274,44 @@ CXXThisRegion::ProfileRegion(ID, ThisPointerTy, superRegion); } +void FieldRegion::Profile(llvm::FoldingSetNodeID &ID) const { + ProfileRegion(ID, getDecl(), superRegion); +} + void ObjCIvarRegion::ProfileRegion(llvm::FoldingSetNodeID& ID, const ObjCIvarDecl *ivd, const MemRegion* superRegion) { - DeclRegion::ProfileRegion(ID, ivd, superRegion, ObjCIvarRegionKind); + ID.AddInteger(static_cast(ObjCIvarRegionKind)); + ID.AddPointer(ivd); + ID.AddPointer(superRegion); +} + +void ObjCIvarRegion::Profile(llvm::FoldingSetNodeID &ID) const { + ProfileRegion(ID, getDecl(), superRegion); } -void DeclRegion::ProfileRegion(llvm::FoldingSetNodeID& ID, const Decl *D, - const MemRegion* superRegion, Kind k) { - ID.AddInteger(static_cast(k)); - ID.AddPointer(D); +void NonParamVarRegion::ProfileRegion(llvm::FoldingSetNodeID &ID, + const VarDecl *VD, + const MemRegion *superRegion) { + ID.AddInteger(static_cast(NonParamVarRegionKind)); + ID.AddPointer(VD); ID.AddPointer(superRegion); } -void DeclRegion::Profile(llvm::FoldingSetNodeID& ID) const { - DeclRegion::ProfileRegion(ID, D, superRegion, getKind()); +void NonParamVarRegion::Profile(llvm::FoldingSetNodeID &ID) const { + ProfileRegion(ID, getDecl(), superRegion); } -void VarRegion::Profile(llvm::FoldingSetNodeID &ID) const { - VarRegion::ProfileRegion(ID, getDecl(), superRegion); +void ParamVarRegion::ProfileRegion(llvm::FoldingSetNodeID &ID, const Expr *OE, + unsigned Idx, const MemRegion *SReg) { + ID.AddInteger(static_cast(ParamVarRegionKind)); + ID.AddPointer(OE); + ID.AddInteger(Idx); + ID.AddPointer(SReg); +} + +void ParamVarRegion::Profile(llvm::FoldingSetNodeID &ID) const { + ProfileRegion(ID, getOriginExpr(), getIndex(), superRegion); } void SymbolicRegion::ProfileRegion(llvm::FoldingSetNodeID& ID, SymbolRef sym, @@ -479,12 +523,11 @@ os << "SymRegion{" << sym << '}'; } -void VarRegion::dumpToStream(raw_ostream &os) const { - const auto *VD = cast(D); +void NonParamVarRegion::dumpToStream(raw_ostream &os) const { if (const IdentifierInfo *ID = VD->getIdentifier()) os << ID->getName(); else - os << "VarRegion{D" << VD->getID() << '}'; + os << "NonParamVarRegion{D" << VD->getID() << '}'; } LLVM_DUMP_METHOD void RegionRawOffset::dump() const { @@ -531,6 +574,18 @@ os << "StackLocalsSpaceRegion"; } +void ParamVarRegion::dumpToStream(raw_ostream &os) const { + const ParmVarDecl *PVD = getDecl(); + assert(PVD && + "`ParamVarRegion` support functions without `Decl` not implemented" + " yet."); + if (const IdentifierInfo *ID = PVD->getIdentifier()) { + os << ID->getName(); + } else { + os << "ParamVarRegion{P" << PVD->getID() << '}'; + } +} + bool MemRegion::canPrintPretty() const { return canPrintPrettyAsExpr(); } @@ -550,11 +605,18 @@ llvm_unreachable("This region cannot be printed pretty."); } -bool VarRegion::canPrintPrettyAsExpr() const { - return true; +bool NonParamVarRegion::canPrintPrettyAsExpr() const { return true; } + +void NonParamVarRegion::printPrettyAsExpr(raw_ostream &os) const { + os << getDecl()->getName(); } -void VarRegion::printPrettyAsExpr(raw_ostream &os) const { +bool ParamVarRegion::canPrintPrettyAsExpr() const { return true; } + +void ParamVarRegion::printPrettyAsExpr(raw_ostream &os) const { + assert(getDecl() && + "`ParamVarRegion` support functions without `Decl` not implemented" + " yet."); os << getDecl()->getName(); } @@ -693,7 +755,8 @@ case MemRegion::CXXTempObjectRegionKind: case MemRegion::CXXThisRegionKind: case MemRegion::ObjCIvarRegionKind: - case MemRegion::VarRegionKind: + case MemRegion::NonParamVarRegionKind: + case MemRegion::ParamVarRegionKind: case MemRegion::ElementRegionKind: case MemRegion::ObjCStringRegionKind: { QualType Ty = cast(SR)->getDesugaredValueType(Ctx); @@ -847,9 +910,11 @@ for (BlockDataRegion::referenced_vars_iterator I = BR->referenced_vars_begin(), E = BR->referenced_vars_end(); I != E; ++I) { - const VarRegion *VR = I.getOriginalRegion(); - if (VR->getDecl() == VD) - return cast(I.getCapturedRegion()); + const TypedValueRegion *OrigR = I.getOriginalRegion(); + if (const auto *VR = dyn_cast(OrigR)) { + if (VR->getDecl() == VD) + return cast(I.getCapturedRegion()); + } } } @@ -858,8 +923,30 @@ return (const StackFrameContext *)nullptr; } -const VarRegion* MemRegionManager::getVarRegion(const VarDecl *D, +const VarRegion *MemRegionManager::getVarRegion(const VarDecl *D, const LocationContext *LC) { + const auto *PVD = dyn_cast(D); + if (PVD) { + unsigned Index = PVD->getFunctionScopeIndex(); + const StackFrameContext *SFC = LC->getStackFrame(); + const Stmt *CallSite = SFC->getCallSite(); + if (CallSite) { + const Decl *D = SFC->getDecl(); + if (const auto *FD = dyn_cast(D)) { + if (Index < FD->param_size() && FD->parameters()[Index] == PVD) + return getSubRegion(cast(CallSite), Index, + getStackArgumentsRegion(SFC)); + } else if (const auto *BD = dyn_cast(D)) { + if (Index < BD->param_size() && BD->parameters()[Index] == PVD) + return getSubRegion(cast(CallSite), Index, + getStackArgumentsRegion(SFC)); + } else { + return getSubRegion(cast(CallSite), Index, + getStackArgumentsRegion(SFC)); + } + } + } + D = D->getCanonicalDecl(); const MemRegion *sReg = nullptr; @@ -942,13 +1029,23 @@ } } - return getSubRegion(D, sReg); + return getSubRegion(D, sReg); } -const VarRegion *MemRegionManager::getVarRegion(const VarDecl *D, - const MemRegion *superR) { +const NonParamVarRegion * +MemRegionManager::getNonParamVarRegion(const VarDecl *D, + const MemRegion *superR) { D = D->getCanonicalDecl(); - return getSubRegion(D, superR); + return getSubRegion(D, superR); +} + +const ParamVarRegion * +MemRegionManager::getParamVarRegion(const Expr *OriginExpr, unsigned Index, + const LocationContext *LC) { + const StackFrameContext *SFC = LC->getStackFrame(); + assert(SFC); + return getSubRegion(OriginExpr, Index, + getStackArgumentsRegion(SFC)); } const BlockDataRegion * @@ -1341,7 +1438,8 @@ case MemRegion::CXXThisRegionKind: case MemRegion::StringRegionKind: case MemRegion::ObjCStringRegionKind: - case MemRegion::VarRegionKind: + case MemRegion::NonParamVarRegionKind: + case MemRegion::ParamVarRegionKind: case MemRegion::CXXTempObjectRegionKind: // Usual base regions. goto Finish; @@ -1497,7 +1595,7 @@ const VarRegion *OriginalVR = nullptr; if (!VD->hasAttr() && VD->hasLocalStorage()) { - VR = MemMgr.getVarRegion(VD, this); + VR = MemMgr.getNonParamVarRegion(VD, this); OriginalVR = MemMgr.getVarRegion(VD, LC); } else { @@ -1506,7 +1604,7 @@ OriginalVR = VR; } else { - VR = MemMgr.getVarRegion(VD, MemMgr.getUnknownRegion()); + VR = MemMgr.getNonParamVarRegion(VD, MemMgr.getUnknownRegion()); OriginalVR = MemMgr.getVarRegion(VD, LC); } } Index: clang/lib/StaticAnalyzer/Core/Store.cpp =================================================================== --- clang/lib/StaticAnalyzer/Core/Store.cpp +++ clang/lib/StaticAnalyzer/Core/Store.cpp @@ -134,7 +134,8 @@ case MemRegion::FieldRegionKind: case MemRegion::ObjCIvarRegionKind: case MemRegion::ObjCStringRegionKind: - case MemRegion::VarRegionKind: + case MemRegion::NonParamVarRegionKind: + case MemRegion::ParamVarRegionKind: case MemRegion::CXXTempObjectRegionKind: case MemRegion::CXXBaseObjectRegionKind: case MemRegion::CXXDerivedObjectRegionKind: Index: clang/test/Analysis/explain-svals.c =================================================================== --- clang/test/Analysis/explain-svals.c +++ clang/test/Analysis/explain-svals.c @@ -27,3 +27,15 @@ clang_analyzer_explain_voidp(&s); // expected-warning-re{{{{^pointer to parameter 's'$}}}} clang_analyzer_explain_int(s.z); // expected-warning-re{{{{^initial value of field 'z' of parameter 's'$}}}} } + +void test_3(int param) { + clang_analyzer_explain_voidp(¶m); // expected-warning-re{{{{^pointer to parameter 'param'$}}}} +} + +void test_non_top_level(int param) { + clang_analyzer_explain_voidp(¶m); // expected-warning-re{{{{^pointer to parameter 'param'$}}}} +} + +void test_4(int n) { + test_non_top_level(n); +} Index: clang/test/Analysis/explain-svals.cpp =================================================================== --- clang/test/Analysis/explain-svals.cpp +++ clang/test/Analysis/explain-svals.cpp @@ -19,6 +19,7 @@ void clang_analyzer_explain(int); void clang_analyzer_explain(void *); +void clang_analyzer_explain(const int *); void clang_analyzer_explain(S); size_t clang_analyzer_getExtent(void *); @@ -100,3 +101,30 @@ clang_analyzer_explain(conjure_S()); // expected-warning-re{{{{^lazily frozen compound value of temporary object constructed at statement 'conjure_S\(\)'$}}}} clang_analyzer_explain(conjure_S().z); // expected-warning-re{{{{^value derived from \(symbol of type 'int' conjured at statement 'conjure_S\(\)'\) for field 'z' of temporary object constructed at statement 'conjure_S\(\)'$}}}} } + +class C_top_level { +public: + C_top_level(int param) { + clang_analyzer_explain(¶m); // expected-warning-re{{{{^pointer to parameter 'param'$}}}} + } +}; + +class C_non_top_level { +public: + C_non_top_level(int param) { + clang_analyzer_explain(¶m); // expected-warning-re{{{{^pointer to parameter 'param'$}}}} + } +}; + +void test_7(int n) { + C_non_top_level c(n); + + auto lambda_top_level = [n](int param) { + clang_analyzer_explain(¶m); // expected-warning-re{{{{^pointer to parameter 'param'$}}}} + }; + auto lambda_non_top_level = [n](int param) { + clang_analyzer_explain(¶m); // expected-warning-re{{{{^pointer to parameter 'param'$}}}} + }; + + lambda_non_top_level(n); +} Index: clang/test/Analysis/explain-svals.m =================================================================== --- clang/test/Analysis/explain-svals.m +++ clang/test/Analysis/explain-svals.m @@ -28,3 +28,44 @@ }; clang_analyzer_explain(&x); // expected-warning-re{{{{^pointer to block variable 'x'$}}}} } + +@interface O ++ (instancetype)top_level_class_method:(int)param; ++ (instancetype)non_top_level_class_method:(int)param; +- top_level_instance_method:(int)param; +- non_top_level_instance_method:(int)param; +@end + +@implementation O ++ (instancetype)top_level_class_method:(int)param { + clang_analyzer_explain(¶m); // expected-warning-re{{{{^pointer to parameter 'param'$}}}} +} + ++ (instancetype)non_top_level_class_method:(int)param { + clang_analyzer_explain(¶m); // expected-warning-re{{{{^pointer to parameter 'param'$}}}} +} + +- top_level_instance_method:(int)param { + clang_analyzer_explain(¶m); // expected-warning-re{{{{^pointer to parameter 'param'$}}}} +} + +- non_top_level_instance_method:(int)param { + clang_analyzer_explain(¶m); // expected-warning-re{{{{^pointer to parameter 'param'$}}}} +} +@end + +void test_3(int n, int m) { + O *o = [O non_top_level_class_method:n]; + [o non_top_level_instance_method:m]; + + void (^block_top_level)(int) = ^(int param) { + clang_analyzer_explain(¶m); // expected-warning-re{{{{^pointer to parameter 'param'$}}}} + clang_analyzer_explain(&n); // expected-warning-re{{{{^pointer to parameter 'n'$}}}} + }; + void (^block_non_top_level)(int) = ^(int param) { + clang_analyzer_explain(¶m); // expected-warning-re{{{{^pointer to parameter 'param'$}}}} + clang_analyzer_explain(&n); // expected-warning-re{{{{^pointer to parameter 'n'$}}}} + }; + + block_non_top_level(n); +} Index: clang/unittests/StaticAnalyzer/CMakeLists.txt =================================================================== --- clang/unittests/StaticAnalyzer/CMakeLists.txt +++ clang/unittests/StaticAnalyzer/CMakeLists.txt @@ -8,6 +8,7 @@ CallDescriptionTest.cpp CallEventTest.cpp StoreTest.cpp + ParamRegionTest.cpp RegisterCustomCheckersTest.cpp SymbolReaperTest.cpp RangeSetTest.cpp Index: clang/unittests/StaticAnalyzer/ParamRegionTest.cpp =================================================================== --- /dev/null +++ clang/unittests/StaticAnalyzer/ParamRegionTest.cpp @@ -0,0 +1,109 @@ +//===- unittests/StaticAnalyzer/ParamRegionTest.cpp -----------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "Reusables.h" + +#include "clang/Tooling/Tooling.h" +#include "gtest/gtest.h" + +namespace clang { +namespace ento { +namespace { + +class ParamRegionTestConsumer : public ExprEngineConsumer { + void performTest(const Decl *D) { + StoreManager &StMgr = Eng.getStoreManager(); + MemRegionManager &MRMgr = StMgr.getRegionManager(); + const StackFrameContext *SFC = + Eng.getAnalysisDeclContextManager().getStackFrame(D); + + if (const auto *FD = dyn_cast(D)) { + for (const auto *P : FD->parameters()) { + const TypedValueRegion *Reg = MRMgr.getVarRegion(P, SFC); + if (SFC->inTopFrame()) + assert(isa(Reg)); + else + assert(isa(Reg)); + } + } else if (const auto *CD = dyn_cast(D)) { + for (const auto *P : CD->parameters()) { + const TypedValueRegion *Reg = MRMgr.getVarRegion(P, SFC); + if (SFC->inTopFrame()) + assert(isa(Reg)); + else + assert(isa(Reg)); + } + } else if (const auto *MD = dyn_cast(D)) { + for (const auto *P : MD->parameters()) { + const TypedValueRegion *Reg = MRMgr.getVarRegion(P, SFC); + if (SFC->inTopFrame()) + assert(isa(Reg)); + else + assert(isa(Reg)); + } + } + } + +public: + ParamRegionTestConsumer(CompilerInstance &C) : ExprEngineConsumer(C) {} + + bool HandleTopLevelDecl(DeclGroupRef DG) override { + for (const auto *D : DG) { + performTest(D); + } + return true; + } +}; + +class ParamRegionTestAction : public ASTFrontendAction { +public: + std::unique_ptr CreateASTConsumer(CompilerInstance &Compiler, + StringRef File) override { + return std::make_unique(Compiler); + } +}; + +TEST(ParamRegion, ParamRegionTest) { + EXPECT_TRUE( + tooling::runToolOnCode(std::make_unique(), + R"(void foo(int n) { + auto lambda = [n](int m) { + return n + m; + }; + + int k = lambda(2); + } + + void bar(int l) { + foo(l); + } + + struct S { + int n; + S(int nn): n(nn) {} + }; + + void baz(int p) { + S s(p); + })")); + EXPECT_TRUE( + tooling::runToolOnCode(std::make_unique(), + R"(@interface O + + alloc; + - initWithInt:(int)q; + @end + + void qix(int r) { + O *o = [[O alloc] initWithInt:r]; + })", + "input.m")); +} + +} // namespace +} // namespace ento +} // namespace clang Index: compiler-rt/lib/fuzzer/afl/afl_driver.cpp =================================================================== --- compiler-rt/lib/fuzzer/afl/afl_driver.cpp +++ compiler-rt/lib/fuzzer/afl/afl_driver.cpp @@ -111,7 +111,7 @@ // Use this optionally defined function to output sanitizer messages even if // user asks to close stderr. -extern "C" __attribute__((weak)) void __sanitizer_set_report_fd(void *); +__attribute__((weak)) extern "C" void __sanitizer_set_report_fd(void *); // Keep track of where stderr content is being written to, so that // dup_and_close_stderr can use the correct one. Index: lld/ELF/InputFiles.cpp =================================================================== --- lld/ELF/InputFiles.cpp +++ lld/ELF/InputFiles.cpp @@ -1224,12 +1224,14 @@ ArrayRef data = CHECK(obj.getSectionContents(sec), this); const uint8_t *verneedBuf = data.begin(); for (unsigned i = 0; i != sec->sh_info; ++i) { - if (verneedBuf + sizeof(typename ELFT::Verneed) > data.end()) + if (verneedBuf + sizeof(typename ELFT::Verneed) > data.end() || + uintptr_t(verneedBuf) % sizeof(uint32_t) != 0) fatal(toString(this) + " has an invalid Verneed"); auto *vn = reinterpret_cast(verneedBuf); const uint8_t *vernauxBuf = verneedBuf + vn->vn_aux; for (unsigned j = 0; j != vn->vn_cnt; ++j) { - if (vernauxBuf + sizeof(typename ELFT::Vernaux) > data.end()) + if (vernauxBuf + sizeof(typename ELFT::Vernaux) > data.end() || + uintptr_t(vernauxBuf) % sizeof(uint32_t) != 0) fatal(toString(this) + " has an invalid Vernaux"); auto *aux = reinterpret_cast(vernauxBuf); if (aux->vna_name >= this->stringTable.size()) Index: lld/test/ELF/invalid/verneed-shared.yaml =================================================================== --- lld/test/ELF/invalid/verneed-shared.yaml +++ lld/test/ELF/invalid/verneed-shared.yaml @@ -6,7 +6,7 @@ ## sh_offset(SHT_GNU_verneed) is out of bounds. # RUN: yaml2obj --docnum=1 %s -o %t1.so # RUN: not ld.lld %t.o %t1.so -o /dev/null 2>&1 | FileCheck --check-prefix=SHOFFSET %s -# SHOFFSET: error: {{.*}}.so: section [index 1] has a sh_offset (0xffffffff) + sh_size (0x0) that is greater than the file size (0x168) +# SHOFFSET: error: {{.*}}.so: section [index 1] has a sh_offset (0xffffffff) + sh_size (0x0) that is greater than the file size (0x228) --- !ELF FileHeader: Class: ELFCLASS64 @@ -17,14 +17,12 @@ - Name: .gnu.version_r Type: SHT_GNU_verneed Flags: [ SHF_ALLOC ] - Info: 1 ShOffset: 0xFFFFFFFF -## A Verneed entry is misaligned (not a multiple of 4). This may happen -## some interface shared objects. We use memcpy to read the fields, so -## misalignment isn't a problem and there is no need to diagnose. +## A Verneed entry is misaligned (not a multiple of 4). # RUN: yaml2obj --docnum=2 %s -o %t2.so -# RUN: ld.lld %t.o %t2.so -o /dev/null +# RUN: not ld.lld %t.o %t2.so -o /dev/null 2>&1 | FileCheck --check-prefix=VN-MISALIGNED %s +# VN-MISALIGNED: {{.*}}.so has an invalid Verneed --- !ELF FileHeader: Class: ELFCLASS64 Index: lldb/include/lldb/Utility/Args.h =================================================================== --- lldb/include/lldb/Utility/Args.h +++ lldb/include/lldb/Utility/Args.h @@ -391,7 +391,7 @@ return lldb_private::Args::ArgEntry(value, quote); } StringRef value; - uint8_t quote; + char quote; }; static void mapping(IO &io, lldb_private::Args::ArgEntry &v); }; Index: lldb/test/API/python_api/hello_world/TestHelloWorld.py =================================================================== --- lldb/test/API/python_api/hello_world/TestHelloWorld.py +++ lldb/test/API/python_api/hello_world/TestHelloWorld.py @@ -75,7 +75,6 @@ @add_test_categories(['pyapi']) @skipIfiOSSimulator @expectedFailureNetBSD - @skipIfReproducer # File synchronization is not supported during replay. def test_with_attach_to_process_with_id_api(self): """Create target, spawn a process, and attach to it with process id.""" exe = '%s_%d'%(self.testMethodName, os.getpid()) Index: lldb/test/API/python_api/sbdata/TestSBData.py =================================================================== --- lldb/test/API/python_api/sbdata/TestSBData.py +++ lldb/test/API/python_api/sbdata/TestSBData.py @@ -21,7 +21,6 @@ self.line = line_number('main.cpp', '// set breakpoint here') @add_test_categories(['pyapi']) - @skipIfReproducer # SBData::SetData is not instrumented. def test_byte_order_and_address_byte_size(self): """Test the SBData::SetData() to ensure the byte order and address byte size are obeyed""" @@ -42,7 +41,6 @@ self.assertTrue(addr == 0x8877665544332211); @add_test_categories(['pyapi']) - @skipIfReproducer # SBData::SetData is not instrumented. def test_with_run_command(self): """Test the SBData APIs.""" self.build() Index: llvm/include/llvm/Analysis/ObjCARCAnalysisUtils.h =================================================================== --- llvm/include/llvm/Analysis/ObjCARCAnalysisUtils.h +++ llvm/include/llvm/Analysis/ObjCARCAnalysisUtils.h @@ -23,13 +23,17 @@ #define LLVM_LIB_ANALYSIS_OBJCARCANALYSISUTILS_H #include "llvm/ADT/Optional.h" +#include "llvm/ADT/StringSwitch.h" #include "llvm/Analysis/AliasAnalysis.h" #include "llvm/Analysis/ObjCARCInstKind.h" +#include "llvm/Analysis/Passes.h" #include "llvm/Analysis/ValueTracking.h" #include "llvm/IR/Constants.h" +#include "llvm/IR/InstIterator.h" #include "llvm/IR/LLVMContext.h" #include "llvm/IR/Module.h" #include "llvm/IR/ValueHandle.h" +#include "llvm/Pass.h" namespace llvm { namespace objcarc { Index: llvm/include/llvm/CodeGen/ResourcePriorityQueue.h =================================================================== --- llvm/include/llvm/CodeGen/ResourcePriorityQueue.h +++ llvm/include/llvm/CodeGen/ResourcePriorityQueue.h @@ -16,15 +16,15 @@ #ifndef LLVM_CODEGEN_RESOURCEPRIORITYQUEUE_H #define LLVM_CODEGEN_RESOURCEPRIORITYQUEUE_H +#include "llvm/CodeGen/DFAPacketizer.h" #include "llvm/CodeGen/ScheduleDAG.h" +#include "llvm/CodeGen/SelectionDAGISel.h" +#include "llvm/CodeGen/TargetInstrInfo.h" +#include "llvm/CodeGen/TargetRegisterInfo.h" +#include "llvm/MC/MCInstrItineraries.h" namespace llvm { - class DFAPacketizer; - class InstrItineraryData; class ResourcePriorityQueue; - class SelectionDAGISel; - class TargetInstrInfo; - class TargetRegisterInfo; /// Sorting functions for the Available queue. struct resource_sort { Index: llvm/include/llvm/Support/YAMLTraits.h =================================================================== --- llvm/include/llvm/Support/YAMLTraits.h +++ llvm/include/llvm/Support/YAMLTraits.h @@ -1159,6 +1159,12 @@ static QuotingType mustQuote(StringRef) { return QuotingType::None; } }; +template <> struct ScalarTraits { + static void output(const char &, void *, raw_ostream &); + static StringRef input(StringRef, void *, char &); + static QuotingType mustQuote(StringRef S) { return needsQuotes(S); } +}; + template<> struct ScalarTraits { static void output(const StringRef &, void *, raw_ostream &); Index: llvm/lib/Analysis/ObjCARCAliasAnalysis.cpp =================================================================== --- llvm/lib/Analysis/ObjCARCAliasAnalysis.cpp +++ llvm/lib/Analysis/ObjCARCAliasAnalysis.cpp @@ -24,7 +24,6 @@ #include "llvm/Analysis/ObjCARCAliasAnalysis.h" #include "llvm/Analysis/ObjCARCAnalysisUtils.h" -#include "llvm/Analysis/Passes.h" #include "llvm/IR/Function.h" #include "llvm/IR/Instruction.h" #include "llvm/IR/Value.h" Index: llvm/lib/CodeGen/SelectionDAG/ResourcePriorityQueue.cpp =================================================================== --- llvm/lib/CodeGen/SelectionDAG/ResourcePriorityQueue.cpp +++ llvm/lib/CodeGen/SelectionDAG/ResourcePriorityQueue.cpp @@ -19,13 +19,9 @@ //===----------------------------------------------------------------------===// #include "llvm/CodeGen/ResourcePriorityQueue.h" -#include "llvm/CodeGen/DFAPacketizer.h" #include "llvm/CodeGen/MachineInstr.h" -#include "llvm/CodeGen/SelectionDAGISel.h" #include "llvm/CodeGen/SelectionDAGNodes.h" -#include "llvm/CodeGen/TargetInstrInfo.h" #include "llvm/CodeGen/TargetLowering.h" -#include "llvm/CodeGen/TargetRegisterInfo.h" #include "llvm/CodeGen/TargetSubtargetInfo.h" #include "llvm/Support/CommandLine.h" #include "llvm/Support/Debug.h" Index: llvm/lib/Support/YAMLTraits.cpp =================================================================== --- llvm/lib/Support/YAMLTraits.cpp +++ llvm/lib/Support/YAMLTraits.cpp @@ -864,6 +864,17 @@ return "invalid boolean"; } +void ScalarTraits::output(const char &Val, void *, raw_ostream &Out) { + Out << Val; +} + +StringRef ScalarTraits::input(StringRef Scalar, void *, char &Val) { + if (Scalar.size() != 1) + return "invalid character"; + Val = Scalar[0]; + return StringRef(); +} + void ScalarTraits::output(const StringRef &Val, void *, raw_ostream &Out) { Out << Val; Index: llvm/test/CodeGen/PowerPC/pr45709.ll =================================================================== --- llvm/test/CodeGen/PowerPC/pr45709.ll +++ llvm/test/CodeGen/PowerPC/pr45709.ll @@ -10,37 +10,30 @@ define dso_local void @_ZN1a1bEv(<4 x float> %in) local_unnamed_addr #0 align 2 { ; CHECK-LABEL: _ZN1a1bEv: ; CHECK: # %bb.0: -; CHECK-NEXT: bc 12, 4*cr5+lt, .LBB0_6 -; CHECK-NEXT: b .LBB0_1 -; CHECK-NEXT: .LBB0_1: # %.preheader -; CHECK-NEXT: b .LBB0_2 -; CHECK-NEXT: .LBB0_2: -; CHECK-NEXT: b .LBB0_3 -; CHECK-NEXT: .LBB0_3: +; CHECK-NEXT: bclr 12, 4*cr5+lt, 0 +; CHECK-NEXT: # %bb.1: # %.preheader ; CHECK-NEXT: addis r3, r2, .LCPI0_0@toc@ha -; CHECK-NEXT: addi r3, r3, .LCPI0_0@toc@l -; CHECK-NEXT: lvx v3, 0, r3 -; CHECK-NEXT: vperm v2, v2, v2, v3 ; CHECK-NEXT: vxor v3, v3, v3 +; CHECK-NEXT: addi r3, r3, .LCPI0_0@toc@l +; CHECK-NEXT: lvx v4, 0, r3 ; CHECK-NEXT: addi r3, r1, -48 ; CHECK-NEXT: stvx v3, 0, r3 ; CHECK-NEXT: addi r3, r1, -32 +; CHECK-NEXT: vperm v2, v2, v2, v4 ; CHECK-NEXT: stvx v2, 0, r3 ; CHECK-NEXT: lwz r3, -48(r1) ; CHECK-NEXT: lwz r4, -32(r1) ; CHECK-NEXT: cmpw r4, r3 -; CHECK-NEXT: bc 12, gt, .LBB0_4 -; CHECK-NEXT: b .LBB0_5 -; CHECK-NEXT: .LBB0_4: +; CHECK-NEXT: bc 12, gt, .LBB0_2 +; CHECK-NEXT: b .LBB0_3 +; CHECK-NEXT: .LBB0_2: # %.preheader ; CHECK-NEXT: addi r3, r4, 0 -; CHECK-NEXT: .LBB0_5: -; CHECK-NEXT: cmpw r3, r3 +; CHECK-NEXT: .LBB0_3: # %.preheader ; CHECK-NEXT: stw r3, -64(r1) ; CHECK-NEXT: addi r3, r1, -64 ; CHECK-NEXT: lvx v2, 0, r3 ; CHECK-NEXT: addi r3, r1, -16 ; CHECK-NEXT: stvx v2, 0, r3 -; CHECK-NEXT: .LBB0_6: ; CHECK-NEXT: blr br i1 undef, label %7, label %1 @@ -62,4 +55,4 @@ declare <4 x float> @llvm.maxnum.v4f32(<4 x float>, <4 x float>) #0 -attributes #0 = { nounwind optnone noinline } +attributes #0 = { nounwind } Index: llvm/unittests/Support/YAMLIOTest.cpp =================================================================== --- llvm/unittests/Support/YAMLIOTest.cpp +++ llvm/unittests/Support/YAMLIOTest.cpp @@ -333,6 +333,7 @@ uint16_t u16; uint8_t u8; bool b; + char c; int64_t s64; int32_t s32; int16_t s16; @@ -357,6 +358,7 @@ io.mapRequired("u16", bt.u16); io.mapRequired("u8", bt.u8); io.mapRequired("b", bt.b); + io.mapRequired("c", bt.c); io.mapRequired("s64", bt.s64); io.mapRequired("s32", bt.s32); io.mapRequired("s16", bt.s16); @@ -386,6 +388,7 @@ "u16: 65000\n" "u8: 255\n" "b: false\n" + "c: 'c'\n" "s64: -5000000000\n" "s32: -2000000000\n" "s16: -32000\n" @@ -396,7 +399,7 @@ "h16: 0x8765\n" "h32: 0xFEDCBA98\n" "h64: 0xFEDCBA9876543210\n" - "...\n"); + "...\n"); yin >> map; EXPECT_FALSE(yin.error()); @@ -407,6 +410,7 @@ EXPECT_EQ(map.u16, 65000); EXPECT_EQ(map.u8, 255); EXPECT_EQ(map.b, false); + EXPECT_EQ(map.c, 'c'); EXPECT_EQ(map.s64, -5000000000LL); EXPECT_EQ(map.s32, -2000000000L); EXPECT_EQ(map.s16, -32000); @@ -434,6 +438,7 @@ map.u16 = 50000; map.u8 = 254; map.b = true; + map.c = 'd'; map.s64 = -6000000000LL; map.s32 = -2000000000; map.s16 = -32000; @@ -463,6 +468,7 @@ EXPECT_EQ(map.u16, 50000); EXPECT_EQ(map.u8, 254); EXPECT_EQ(map.b, true); + EXPECT_EQ(map.c, 'd'); EXPECT_EQ(map.s64, -6000000000LL); EXPECT_EQ(map.s32, -2000000000L); EXPECT_EQ(map.s16, -32000); Index: llvm/utils/gn/secondary/clang/lib/StaticAnalyzer/Core/BUILD.gn =================================================================== --- llvm/utils/gn/secondary/clang/lib/StaticAnalyzer/Core/BUILD.gn +++ llvm/utils/gn/secondary/clang/lib/StaticAnalyzer/Core/BUILD.gn @@ -55,6 +55,7 @@ "SimpleConstraintManager.cpp", "SimpleSValBuilder.cpp", "Store.cpp", + "SubEngine.cpp", "SymbolManager.cpp", "TextDiagnostics.cpp", "WorkList.cpp",