diff --git a/CMakeLists.txt b/CMakeLists.txt index efe360619a..f02b3cc2e7 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -272,6 +272,7 @@ add_json_schema_validator() # TBB find_package(TBB QUIET) # needed by GCC +set(PHASAR_USE_TBB ${TBB_FOUND}) # Coverage if (CODE_COVERAGE) diff --git a/Config.cmake.in b/Config.cmake.in index 80e4b57cd1..da9ffd1ffa 100644 --- a/Config.cmake.in +++ b/Config.cmake.in @@ -24,6 +24,10 @@ else() find_dependency(roaring REQUIRED CONFIG) endif() +if (@PHASAR_USE_TBB@) + find_dependency(TBB) +endif() + if (PHASAR_USE_Z3) find_dependency(Z3 REQUIRED) endif() diff --git a/examples/how-to/09-export-callsite-cg/export_callsite_cg_streaming.cpp b/examples/how-to/09-export-callsite-cg/export_callsite_cg_streaming.cpp index 0fd7955cee..c51d6659c1 100644 --- a/examples/how-to/09-export-callsite-cg/export_callsite_cg_streaming.cpp +++ b/examples/how-to/09-export-callsite-cg/export_callsite_cg_streaming.cpp @@ -115,12 +115,13 @@ int main(int Argc, char **Argv) { // Walk every function PhASAR's call-graph knows about, and ask it for all // known callers, writing (and forgetting) each result immediately instead of // accumulating all of them. - for (const llvm::Function *Fun : ICF.getAllVertexFunctions()) { + ICF.getCallGraph().iterateCallersView([&](const llvm::Function *Fun, + const auto &Callers) { auto FunName = Fun->getName(); ++FnCount; ResolvedLoc CalleeLoc = resolveLocation(Fun); - for (const auto *CS : ICF.getCallersOf(Fun)) { + for (const auto *CS : Callers) { ResolvedLoc CallerLoc = resolveLocation(CS); OS.write_escaped(CS->getFunction()->getName()) << ',' << CallerLoc << ','; @@ -137,7 +138,7 @@ int main(int Argc, char **Argv) { << ICF.getNumVertexFunctions() << " functions processed so far\n"; } } - } + }); OS.close(); diff --git a/include/phasar/ControlFlow/CallGraph.h b/include/phasar/ControlFlow/CallGraph.h index 67cdc04e38..59409fd82b 100644 --- a/include/phasar/ControlFlow/CallGraph.h +++ b/include/phasar/ControlFlow/CallGraph.h @@ -17,8 +17,10 @@ #include "phasar/Utils/StableVector.h" #include "phasar/Utils/Utilities.h" +#include "llvm/ADT/ArrayRef.h" #include "llvm/IR/Function.h" +#include #include #include #include @@ -52,6 +54,24 @@ class CallGraph : public CallGraphBase> { /// Creates a new, empty call-graph CallGraph() noexcept = default; + auto + iterateCalleesView(std::invocable> auto Fn) const { + return psr::foreachInRange( + CalleesAt, [Fn = copyOrRef(Fn)](const auto &Elem) { + const auto &[CS, Callees] = Elem; + return psr::invokeControlFlow(Fn, CS, llvm::ArrayRef(*Callees)); + }); + } + + auto + iterateCallersView(std::invocable> auto Fn) const { + return psr::foreachInRange( + CallersOf, [Fn = copyOrRef(Fn)](const auto &Elem) { + const auto &[CS, Callers] = Elem; + return psr::invokeControlFlow(Fn, CS, llvm::ArrayRef(*Callers)); + }); + } + /// Deserializes a previously computed call-graph template [[nodiscard]] static CallGraph diff --git a/include/phasar/DataFlow/IfdsIde/Solver/IterativeIDESolver.h b/include/phasar/DataFlow/IfdsIde/Solver/IterativeIDESolver.h index e6ef1bad99..590b4ff686 100644 --- a/include/phasar/DataFlow/IfdsIde/Solver/IterativeIDESolver.h +++ b/include/phasar/DataFlow/IfdsIde/Solver/IterativeIDESolver.h @@ -992,7 +992,7 @@ class IterativeIDESolver for (ByConstRef RetFact : RetFacts) { auto RetFactId = FactCompressor.getOrInsert(RetFact); - auto EF = [&]() mutable { + auto EF = [&] { if constexpr (ComputeValues) { auto RetEF = FECache.getReturnEdgeFunction( Problem, CallSite, Callee, ExitInst, SummaryFact, RetSite, diff --git a/include/phasar/DataFlow/PathSensitivity/PathSensitivityManagerBase.h b/include/phasar/DataFlow/PathSensitivity/PathSensitivityManagerBase.h index 3a58bae1e4..f1f0bf572b 100644 --- a/include/phasar/DataFlow/PathSensitivity/PathSensitivityManagerBase.h +++ b/include/phasar/DataFlow/PathSensitivity/PathSensitivityManagerBase.h @@ -12,6 +12,7 @@ #include "phasar/Utils/AdjacencyList.h" #include "phasar/Utils/Logger.h" +#include "phasar/Utils/TypeTraits.h" #include "phasar/Utils/Utilities.h" #include "llvm/ADT/BitVector.h" @@ -180,7 +181,7 @@ template class PathSensitivityManagerBase { [[nodiscard]] static graph_type reverseDAG(graph_type &&Dag, size_t MaxDepth) { auto Sz = graph_traits_t::size(Dag); - return reverseDAG(std::move(Dag), identity{}, Sz, MaxDepth); + return reverseDAG(std::move(Dag), IdentityFn{}, Sz, MaxDepth); } }; diff --git a/include/phasar/PhasarLLVM/DataFlow/IfdsIde/CFLFieldSensIFDSProblem.h b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/CFLFieldSensIFDSProblem.h index 3d5d9a7e8f..6a5399ceea 100644 --- a/include/phasar/PhasarLLVM/DataFlow/IfdsIde/CFLFieldSensIFDSProblem.h +++ b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/CFLFieldSensIFDSProblem.h @@ -140,7 +140,7 @@ class FieldStringManager { } auto Kills = KillsCompressor[KS]; - Kills.insert(Offs); + Kills.insertUnique(Offs); return KillsCompressor.getOrInsert(std::move(Kills)); } diff --git a/include/phasar/PhasarLLVM/Pointer/LLVMRawAAResults.h b/include/phasar/PhasarLLVM/Pointer/LLVMRawAAResults.h index d4460a880e..f0aafcb3c3 100644 --- a/include/phasar/PhasarLLVM/Pointer/LLVMRawAAResults.h +++ b/include/phasar/PhasarLLVM/Pointer/LLVMRawAAResults.h @@ -26,7 +26,7 @@ namespace psr { constexpr std::invocable auto llvmRawAliasHandler(const ValueCompressor &VC, std::invocable auto Callback) { - return [&VC, Callback{copyOrRef(Callback)}](ValueId Alias) { + return [&VC, Callback{std::move(Callback)}](ValueId Alias) { for (auto V : VC.id2vars(Alias)) { if (const auto *LLVMVar = V.valueOrNull()) [[likely]] { std::invoke(Callback, LLVMVar); diff --git a/include/phasar/PhasarLLVM/Pointer/LLVMRawAliasSet.h b/include/phasar/PhasarLLVM/Pointer/LLVMRawAliasSet.h index 6760a74768..4042f0da29 100644 --- a/include/phasar/PhasarLLVM/Pointer/LLVMRawAliasSet.h +++ b/include/phasar/PhasarLLVM/Pointer/LLVMRawAliasSet.h @@ -27,6 +27,7 @@ #include "phasar/Utils/TypedVector.h" #include "phasar/Utils/ValueCompressor.h" +#include "llvm/IR/GlobalVariable.h" #include "llvm/IR/Instructions.h" #include "llvm/Support/TypeName.h" @@ -226,7 +227,8 @@ class LLVMRawAliasSet : public LLVMRawAliasSetBase, if (!Val->getType()->isPointerTy()) { return false; } - if (llvm::isa(Val)) { + if (llvm::isa( + Val)) { return true; } if (const auto *Call = llvm::dyn_cast(Val)) { diff --git a/include/phasar/PhasarLLVM/TaintConfig/TaintConfigUtilities.h b/include/phasar/PhasarLLVM/TaintConfig/TaintConfigUtilities.h index 797d460938..28786e1185 100644 --- a/include/phasar/PhasarLLVM/TaintConfig/TaintConfigUtilities.h +++ b/include/phasar/PhasarLLVM/TaintConfig/TaintConfigUtilities.h @@ -39,6 +39,9 @@ void forallGeneratedFacts( std::invoke(WithGenFact, CB); } + if (!Callee) { + return; + } for (unsigned I = 0, End = Callee->arg_size(); I < End; ++I) { if (Config.isSource(Callee->getArg(I))) { std::invoke(WithGenFact, CB->getArgOperand(I)); @@ -61,6 +64,9 @@ void collectGeneratedFacts(ContainerTy &Dest, const LLVMTaintConfig &Config, Dest.insert(CB); } + if (!Callee) { + return; + } for (unsigned I = 0, End = Callee->arg_size(); I < End; ++I) { if (Config.isSource(Callee->getArg(I))) { Dest.insert(CB->getArgOperand(I)); @@ -80,6 +86,9 @@ void forallLeakedFacts(const LLVMTaintConfig &Config, const llvm::CallBase *CB, llvm::for_each(llvm::make_filter_range(CBLeaks, LeakIf), WithLeakFact); } + if (!Callee) { + return; + } for (unsigned I = 0, End = Callee->arg_size(); I < End; ++I) { if (Config.isSink(Callee->getArg(I)) && std::invoke(LeakIf, CB->getArgOperand(I))) { @@ -101,6 +110,9 @@ void collectLeakedFacts(ContainerTy &Dest, const LLVMTaintConfig &Config, std::inserter(Dest, Dest.end()), LeakIf); } + if (!Callee) { + return; + } for (unsigned I = 0, End = Callee->arg_size(); I < End; ++I) { if (Config.isSink(Callee->getArg(I)) && LeakIf(CB->getArgOperand(I))) { Dest.insert(CB->getArgOperand(I)); @@ -122,6 +134,9 @@ template void collectSanitizedFacts(ContainerTy &Dest, const LLVMTaintConfig &Config, const llvm::CallBase *CB, const llvm::Function *Callee) { + if (!Callee) { + return; + } for (unsigned I = 0, End = Callee->arg_size(); I < End; ++I) { if (Config.isSanitizer(Callee->getArg(I))) { Dest.insert(CB->getArgOperand(I)); diff --git a/include/phasar/Utils/LibrarySummary.h b/include/phasar/Utils/LibrarySummary.h index 348ce0eedd..84be9dd5b5 100644 --- a/include/phasar/Utils/LibrarySummary.h +++ b/include/phasar/Utils/LibrarySummary.h @@ -22,6 +22,10 @@ namespace psr { /// return the same pointer [[nodiscard]] bool isSingletonReturningFunction(llvm::StringRef FName) noexcept; +/// Checks whether a function with the given (mangled) name may return the +/// block its first argument points to, similar to realloc. +[[nodiscard]] bool isReallocatingFunction(llvm::StringRef FName) noexcept; + } // namespace psr #endif // PHASAR_UTILS_LIBRARY_SUMMARY_H diff --git a/include/phasar/Utils/SmallArraySet.h b/include/phasar/Utils/SmallArraySet.h index e5494ed1d7..85af075520 100644 --- a/include/phasar/Utils/SmallArraySet.h +++ b/include/phasar/Utils/SmallArraySet.h @@ -63,7 +63,7 @@ class SmallArraySet : private llvm::SmallVector { [[nodiscard]] static SmallArraySet fromSorted(llvm::SmallVectorImpl &&Vec) { - assert(std::ranges::is_sorted(Vec) && "Vec is not sorted"); + assert(std::ranges::is_sorted(Vec, std::less{}) && "Vec is not sorted"); SmallArraySet Ret(std::move(Vec), /*PreSortedAndUniqued=*/std::true_type{}); Ret.base().erase(std::unique(begin(), end()), end()); @@ -73,8 +73,8 @@ class SmallArraySet : private llvm::SmallVector { [[nodiscard]] static SmallArraySet fromSortedUniqued(llvm::SmallVectorImpl &&Vec) { - assert(std::ranges::is_sorted(Vec) && "Vec is not sorted"); - assert(std::ranges::adjacent_find(Vec) == Vec.end() && + assert(std::ranges::is_sorted(Vec, std::less{}) && "Vec is not sorted"); + assert(std::ranges::adjacent_find(Vec, std::less{}) == Vec.end() && "Vec is not uniqued"); SmallArraySet Ret(std::move(Vec), /*PreSortedAndUniqued=*/std::true_type{}); @@ -114,7 +114,7 @@ class SmallArraySet : private llvm::SmallVector { this->push_back(Val); if (Size + 1 == LinearThreshold) [[unlikely]] { - std::ranges::sort(base()); + std::ranges::sort(base(), std::less{}); } return true; @@ -154,7 +154,7 @@ class SmallArraySet : private llvm::SmallVector { } if (I == OtherSize) { if (this->size() == LinearThreshold) [[unlikely]] { - std::ranges::sort(base()); + std::ranges::sort(base(), std::less{}); } return; } @@ -221,8 +221,8 @@ class SmallArraySet : private llvm::SmallVector { SmallArraySet Merged{}; Merged.resize_for_overwrite(std::min(Size, OtherSize)); - auto [Unused1, Unused2, LastOut] = - std::ranges::set_intersection(*this, Other, Merged.begin()); + auto [Unused1, Unused2, LastOut] = std::ranges::set_intersection( + *this, Other, Merged.begin(), std::less{}); Merged.base().erase(LastOut, Merged.end()); *this = std::move(Merged); return Size != size(); @@ -245,8 +245,8 @@ class SmallArraySet : private llvm::SmallVector { SmallArraySet Merged{}; Merged.resize_for_overwrite(std::min(Size, OtherSize)); - auto [Unused1, Unused2, LastOut] = - std::ranges::set_intersection(*this, Other, Merged.begin()); + auto [Unused1, Unused2, LastOut] = std::ranges::set_intersection( + *this, Other, Merged.begin(), std::less{}); Merged.base().erase(LastOut, Merged.end()); return Merged; } @@ -256,7 +256,7 @@ class SmallArraySet : private llvm::SmallVector { return llvm::is_contained(base(), Val); } - return std::ranges::binary_search(base(), Val); + return std::ranges::binary_search(base(), Val, std::less{}); } void sort() { @@ -265,7 +265,7 @@ class SmallArraySet : private llvm::SmallVector { return; } - std::ranges::sort(base()); + std::ranges::sort(base(), std::less{}); } LLVM_ATTRIBUTE_ALWAYS_INLINE auto foreach ( @@ -278,7 +278,7 @@ class SmallArraySet : private llvm::SmallVector { if constexpr (std::is_trivially_copyable_v) { T Arr[LinearThreshold]{}; memcpy(&Arr, Set.data(), Set.size_in_bytes()); - std::ranges::sort(Arr, Arr + Set.size()); + std::ranges::sort(Arr, Arr + Set.size(), std::less{}); return llvm::hash_combine_range(Arr, Arr + Set.size()); } else { // Some reduction that ignores the order @@ -322,7 +322,7 @@ class SmallArraySet : private llvm::SmallVector { : llvm::SmallVector(std::move(Elems)) {} bool insertImpl(ByConstRef Val) { - const auto It = std::ranges::lower_bound(base(), Val); + const auto It = std::ranges::lower_bound(base(), Val, std::less{}); if (It != this->end() && *It == Val) { return false; } diff --git a/include/phasar/Utils/StrongTypeDef.h b/include/phasar/Utils/StrongTypeDef.h index ac41d093a0..3f7f13130d 100644 --- a/include/phasar/Utils/StrongTypeDef.h +++ b/include/phasar/Utils/StrongTypeDef.h @@ -22,6 +22,9 @@ #define PHASAR_STRONG_TYPEDEF(NAMESPACE, TYPE, NAME, ...) \ namespace NAMESPACE { \ enum class PSR_ENUM_EXTENSIBILITY(open) NAME : TYPE { __VA_ARGS__ }; \ + [[nodiscard]] inline auto hash_value(NAME Id) noexcept { \ + return llvm::hash_value(TYPE(Id)); \ + } \ } \ namespace llvm { \ template <> struct DenseMapInfo { \ @@ -36,9 +39,7 @@ ? std::numeric_limits::min() + 1 \ : std::numeric_limits::max() - 1); \ } \ - static auto getHashValue(QUAL_NAME Id) noexcept { \ - return llvm::hash_value(TYPE(Id)); \ - } \ + static auto getHashValue(QUAL_NAME Id) noexcept { return hash_value(Id); } \ static constexpr bool isEqual(QUAL_NAME Id1, QUAL_NAME Id2) noexcept { \ return Id1 == Id2; \ } \ diff --git a/include/phasar/Utils/TypeTraits.h b/include/phasar/Utils/TypeTraits.h index 158a072ba7..c52ebe174f 100644 --- a/include/phasar/Utils/TypeTraits.h +++ b/include/phasar/Utils/TypeTraits.h @@ -241,14 +241,16 @@ using ElementType = typename detail::ElementType::type; struct TrueFn { template - [[nodiscard]] bool operator()(const Args &.../*unused*/) const noexcept { + [[nodiscard]] constexpr bool + operator()(const Args &.../*unused*/) const noexcept { return true; } }; struct FalseFn { template - [[nodiscard]] bool operator()(const Args &.../*unused*/) const noexcept { + [[nodiscard]] constexpr bool + operator()(const Args &.../*unused*/) const noexcept { return false; } }; @@ -256,14 +258,15 @@ struct FalseFn { /// Delegates to the ctor of T template struct DefaultConstruct { template - [[nodiscard]] T - operator()(U &&...Val) noexcept(std::is_nothrow_constructible_v) { + [[nodiscard]] constexpr T operator()(U &&...Val) const + noexcept(std::is_nothrow_constructible_v) { return T(std::forward(Val)...); } }; struct IgnoreArgs { - template void operator()(U &&.../*Val*/) noexcept {} + template + constexpr void operator()(U &&.../*Val*/) const noexcept {} }; template @@ -289,13 +292,14 @@ template } struct IdentityFn { - template decltype(auto) operator()(T &&Val) const noexcept { + template + constexpr decltype(auto) operator()(T &&Val) const noexcept { return std::forward(Val); } }; template struct DummyFn { - void operator()(ArgsT... Arg) const noexcept {} + constexpr void operator()(ArgsT... Arg) const noexcept {} }; /// True if T can be relocated by copying its bytes (e.g. via memcpy) without diff --git a/include/phasar/Utils/Utilities.h b/include/phasar/Utils/Utilities.h index b9659a7133..979e23363e 100644 --- a/include/phasar/Utils/Utilities.h +++ b/include/phasar/Utils/Utilities.h @@ -290,7 +290,7 @@ template constexpr auto copyOrRef(T &Val) noexcept { } } -struct identity { +struct [[deprecated("Use IdentityFn from TypeTraits.h instead")]] identity { template decltype(auto) operator()(T &&Val) const noexcept { return std::forward(Val); } diff --git a/include/phasar/Utils/ValueIdMap.h b/include/phasar/Utils/ValueIdMap.h index bb949bfd5c..40f93c7163 100644 --- a/include/phasar/Utils/ValueIdMap.h +++ b/include/phasar/Utils/ValueIdMap.h @@ -203,7 +203,7 @@ class ValueIdMap { /// Move constructor. The allocator is move-constructed from \p Other. ValueIdMap(ValueIdMap &&Other) noexcept - : Alloc(std::move(Other.Alloc)), IsSet(std::move(Other.IsSet)), + : Alloc(std::move(Other.Alloc)), IsSet(std::exchange(Other.IsSet, {})), Capacity(std::exchange(Other.Capacity, 0)), Slots(std::exchange(Other.Slots, nullptr)) {} @@ -479,6 +479,14 @@ class ValueIdMap { } [[nodiscard]] constexpr const_iterator cend() const noexcept { return end(); } + [[nodiscard]] constexpr const BitSet &keys() const & noexcept { + return IsSet; + } + + [[nodiscard]] constexpr BitSet keys() && noexcept { + return std::move(IsSet); + } + auto foreach (std::invocable auto Handler) { return foreachImpl(*this, std::move(Handler)); } @@ -527,7 +535,7 @@ class ValueIdMap { /// Takes ownership of Other's storage (Other must have been cleared first). void stealFrom(ValueIdMap &Other) noexcept { - IsSet = std::move(Other.IsSet); + IsSet = std::exchange(Other.IsSet, {}); Capacity = std::exchange(Other.Capacity, 0); Slots = std::exchange(Other.Slots, nullptr); } diff --git a/lib/PhasarLLVM/Pointer/AndersenOTFAA.cpp b/lib/PhasarLLVM/Pointer/AndersenOTFAA.cpp index 28872793a0..bf13e57ba5 100644 --- a/lib/PhasarLLVM/Pointer/AndersenOTFAA.cpp +++ b/lib/PhasarLLVM/Pointer/AndersenOTFAA.cpp @@ -1214,8 +1214,7 @@ struct [[clang::internal_linkage]] AndersenOTFSolver::SolverData { if (const auto *CB = llvm::dyn_cast(V)) { const auto *Callee = llvm::dyn_cast_or_null( CB->getCalledOperand()->stripPointerCastsAndAliases()); - if (!Callee || - !(psr::isHeapAllocatingFunction(Callee) || isAllocWrapper(Callee))) { + if (!Callee || !isAllocWrapper(Callee)) { return false; } llvm::SmallPtrSet EscVisited; @@ -1266,6 +1265,13 @@ struct [[clang::internal_linkage]] AndersenOTFSolver::SolverData { } bool isAllocWrapper(const llvm::Function *F) { + if (psr::isHeapAllocatingFunction(F)) { + // The allocator list wins over the body, which may hide the allocation, + // e.g., gnulib's xmalloc passes it through check_nonnull. A realloc-like + // allocator may return the block it got instead. + return !psr::isReallocatingFunction(F->getName()); + } + if (F->isDeclaration()) { return false; // real allocators are handled via isHeapAllocatingFunction } diff --git a/lib/Utils/LibrarySummary.cpp b/lib/Utils/LibrarySummary.cpp index b6850eb4df..788f87077c 100644 --- a/lib/Utils/LibrarySummary.cpp +++ b/lib/Utils/LibrarySummary.cpp @@ -141,6 +141,24 @@ static constexpr llvm::StringLiteral SingletonReturningFunctions[] = { "zError", }; +static constexpr llvm::StringLiteral ReallocatingFunNames[] = { + // C functions: + "realloc", + "reallocarray", + + // gnulib and libiberty: + "irealloc", + "ireallocarray", + "x2nrealloc", + "x2realloc", + "xirealloc", + "xireallocarray", + "xnrealloc", + "xpalloc", + "xrealloc", + "xreallocarray", +}; + bool psr::isHeapAllocatingFunction(llvm::StringRef FName) noexcept { // Note: For a performance comparison of different search strategies, see // https://quick-bench.com/q/lNjDT6z-M-L08h372fbCfYjwM64 @@ -148,7 +166,7 @@ bool psr::isHeapAllocatingFunction(llvm::StringRef FName) noexcept { static const llvm::DenseSet HAFs( std::begin(HeapAllocatingFunNames), std::end(HeapAllocatingFunNames)); - return HAFs.count(FName); + return HAFs.contains(FName); } bool psr::isSingletonReturningFunction(llvm::StringRef FName) noexcept { @@ -156,5 +174,12 @@ bool psr::isSingletonReturningFunction(llvm::StringRef FName) noexcept { std::begin(SingletonReturningFunctions), std::end(SingletonReturningFunctions)); - return SRFs.count(FName); + return SRFs.contains(FName); +} + +bool psr::isReallocatingFunction(llvm::StringRef FName) noexcept { + static const llvm::DenseSet RFs( + std::begin(ReallocatingFunNames), std::end(ReallocatingFunNames)); + + return RFs.contains(FName); } diff --git a/unittests/PhasarLLVM/Pointer/FilteredLLVMAliasSetTest.cpp b/unittests/PhasarLLVM/Pointer/FilteredLLVMAliasSetTest.cpp index d4f0e8b599..c0e27a8a27 100644 --- a/unittests/PhasarLLVM/Pointer/FilteredLLVMAliasSetTest.cpp +++ b/unittests/PhasarLLVM/Pointer/FilteredLLVMAliasSetTest.cpp @@ -8,6 +8,7 @@ #include "phasar/PhasarLLVM/Pointer/LLVMAliasSet.h" #include "phasar/PhasarLLVM/TaintConfig/LLVMTaintConfig.h" #include "phasar/PhasarLLVM/Utils/LLVMShorthands.h" +#include "phasar/Pointer/AliasInfoBase.h" #include "llvm/ADT/StringRef.h" #include "llvm/IR/InstrTypes.h" @@ -17,6 +18,8 @@ using namespace psr; +static_assert(IsAliasInfo); + namespace { static LLVMTaintConfig getDefaultConfig() {