diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 20130f8156..f27f495c2e 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -15,7 +15,7 @@ jobs: fail-fast: true matrix: os: [ubuntu-24.04, ubuntu-24.04-arm] - compiler: [ [clang++-19, clang-19, "clang-19 libclang-rt-19-dev"] ] + compiler: [ [clang++-19, clang-19, "clang-19 libclang-rt-19-dev clang-tools-19"] ] build: [ Debug, Release, DebugLibdeps, DebugCov ] include: - build: Debug diff --git a/BreakingChanges.md b/BreakingChanges.md index 04b00bd925..acb51fa4a9 100644 --- a/BreakingChanges.md +++ b/BreakingChanges.md @@ -2,6 +2,8 @@ ## development HEAD +- Requiring C++20 instead of C++17 + - Type-traits and other templates that are specialized now use `requires` instead of `enable_if`, wherever possible. This may reduce the number of (defaulted) template parameters in some cases. - The `AdjacencyList` struct now now has one more template argument to denote the intege-like `vertex_t` type. It is the second template argument (which previously was the EdgeType). The edge-type is now denoted by the *third* template argument. - The `AdjacencyList` switches from using `llvm::NoneType` as empty-node marker to `psr::EmptyType` for forward-compatibility with LLVM-16 that removes `llvm::NoneType`. diff --git a/Dockerfile b/Dockerfile index 11d69a1894..ae8b16d24f 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,9 +1,9 @@ ARG baseimage="ubuntu:24.04" -FROM "$baseimage" as build +FROM "$baseimage" AS build RUN --mount=type=bind,source=./utils/InstallAptDependencies.sh,target=/InstallAptDependencies.sh \ set -eux; \ - ./InstallAptDependencies.sh --noninteractive tzdata clang-19 libclang-rt-19-dev + ./InstallAptDependencies.sh --noninteractive tzdata clang-19 libclang-rt-19-dev clang-tools-19 ENV CC=/usr/bin/clang-19 \ CXX=/usr/bin/clang++-19 diff --git a/README.md b/README.md index 684f5dffa7..dd3c8df918 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ # PhASAR: A LLVM-based Static Analysis Framework -[![C++ Standard](https://img.shields.io/badge/C++_Standard-C%2B%2B17-blue.svg?style=flat&logo=c%2B%2B)](https://isocpp.org/) +[![C++ Standard](https://img.shields.io/badge/C++_Standard-C%2B%2B20-blue.svg?style=flat&logo=c%2B%2B)](https://isocpp.org/) [![GitHub license](https://img.shields.io/badge/license-MIT-blueviolet.svg)](https://raw.githubusercontent.com/secure-software-engineering/phasar/master/LICENSE.txt) [![GitHub Release](https://img.shields.io/github/v/release/secure-software-engineering/phasar?label=version)](https://github.com/secure-software-engineering/phasar/releases) @@ -24,7 +24,7 @@ this README first. as well. --> Please also have a look on PhASAR's project directory and notice the project directory [examples](./examples/) as well as the custom tool `tools/example-tool/myphasartool.cpp`. -**NEW:** You can find PhASAR's API reference [here](https://secure-software-engineering.github.io/phasar/). +You can find PhASAR's API reference [here](https://secure-software-engineering.github.io/phasar/). ## Secure Software Engineering Group @@ -42,12 +42,9 @@ Currently, PhASAR is maintained by ## Required Version of the C++ Standard -PhASAR requires at least C++-17. +**NEW**: PhASAR requires at least C++-20. -However, building in C++20 mode is supported. You may enable this setting the cmake variable `CMAKE_CXX_STANDARD` to `20`. -Although phasar currently does not make use of C++-20 features (except for some `concept`s behind an #ifdef border), your client application that just *uses* phasar as a library may want to use C++20 earlier. - -**NEW**: PhASAR supports C++20 modules as an experimental feature. +PhASAR supports C++20 modules as an experimental feature. ## Currently Supported Version of LLVM diff --git a/cmake/phasar_macros.cmake b/cmake/phasar_macros.cmake index 0e3f11d826..f6edfef0ee 100644 --- a/cmake/phasar_macros.cmake +++ b/cmake/phasar_macros.cmake @@ -279,7 +279,7 @@ function(add_phasar_library name) EXPORT_NAME ${component_name} ) - target_compile_features(${name} PUBLIC cxx_std_17) + target_compile_features(${name} PUBLIC cxx_std_20) set(install_module) if(PHASAR_LIB_MODULE_FILES) diff --git a/include/phasar/ControlFlow/CFGBase.h b/include/phasar/ControlFlow/CFGBase.h index 5b932f2b5a..3523600428 100644 --- a/include/phasar/ControlFlow/CFGBase.h +++ b/include/phasar/ControlFlow/CFGBase.h @@ -139,10 +139,9 @@ template class CFGBase : public CRTPBase { template // NOLINTNEXTLINE(readability-identifier-naming) -PSR_CONCEPT is_cfg_v = - is_crtp_base_of_v && - std::is_same_v && - std::is_same_v; +concept is_cfg_v = is_crtp_base_of_v && + std::is_same_v && + std::is_same_v; } // namespace psr diff --git a/include/phasar/ControlFlow/ICFGBase.h b/include/phasar/ControlFlow/ICFGBase.h index 4b1ceab7b4..a6ff413d0f 100644 --- a/include/phasar/ControlFlow/ICFGBase.h +++ b/include/phasar/ControlFlow/ICFGBase.h @@ -118,10 +118,9 @@ template class ICFGBase : public CRTPBase { /// from the given analysis-Domain template // NOLINTNEXTLINE(readability-identifier-naming) -PSR_CONCEPT is_icfg_v = - is_crtp_base_of_v && - std::is_same_v && - std::is_same_v; +concept is_icfg_v = is_crtp_base_of_v && + std::is_same_v && + std::is_same_v; } // namespace psr diff --git a/include/phasar/ControlFlow/SparseCFGProvider.h b/include/phasar/ControlFlow/SparseCFGProvider.h index e048310310..f85255e2ee 100644 --- a/include/phasar/ControlFlow/SparseCFGProvider.h +++ b/include/phasar/ControlFlow/SparseCFGProvider.h @@ -37,18 +37,12 @@ template class SparseCFGProvider { } }; -template -struct has_getSparseCFG : std::false_type {}; // NOLINT -template -struct has_getSparseCFG< - T, D, - std::void_t().getSparseCFG( - std::declval(), std::declval()))>> - : std::true_type {}; - template // NOLINTNEXTLINE -constexpr bool has_getSparseCFG_v = has_getSparseCFG::value; +constexpr bool has_getSparseCFG_v = + requires(const T &ICF, typename T::f_t Fun, D Fact) { // + ICF.getSparseCFG(Fun, Fact); + }; } // namespace psr #endif // PHASAR_CONTROLFLOW_SPARSECFGPROVIDER_H diff --git a/include/phasar/DataFlow/IfdsIde/DefaultEdgeFunctionSingletonCache.h b/include/phasar/DataFlow/IfdsIde/DefaultEdgeFunctionSingletonCache.h index 5bba997606..4b93486ff5 100644 --- a/include/phasar/DataFlow/IfdsIde/DefaultEdgeFunctionSingletonCache.h +++ b/include/phasar/DataFlow/IfdsIde/DefaultEdgeFunctionSingletonCache.h @@ -100,9 +100,8 @@ class DefaultEdgeFunctionSingletonCache }; template -class DefaultEdgeFunctionSingletonCache< - EdgeFunctionTy, - std::enable_if_t>> { + requires EdgeFunctionBase::IsSOOCandidate +class DefaultEdgeFunctionSingletonCache { public: [[nodiscard]] const void * lookup(const EdgeFunctionTy & /*EF*/) const noexcept override { diff --git a/include/phasar/DataFlow/IfdsIde/EdgeFunction.h b/include/phasar/DataFlow/IfdsIde/EdgeFunction.h index 5e06b89e12..56ab36cd3e 100644 --- a/include/phasar/DataFlow/IfdsIde/EdgeFunction.h +++ b/include/phasar/DataFlow/IfdsIde/EdgeFunction.h @@ -13,6 +13,7 @@ #include "phasar/DataFlow/IfdsIde/EdgeFunctionSingletonCache.h" #include "phasar/Utils/ByRef.h" #include "phasar/Utils/EmptyBaseOptimizationUtils.h" +#include "phasar/Utils/Macros.h" #include "phasar/Utils/TypeTraits.h" #include "llvm/ADT/DenseMapInfo.h" @@ -35,39 +36,15 @@ namespace psr { template class EdgeFunction; template class EdgeFunctionRef; -#if __cplusplus < 202002L - -namespace detail { -template -struct IsEdgeFunction : std::false_type {}; -template -struct IsEdgeFunction< - T, std::void_t< - typename T::l_t, - decltype(std::declval().computeTarget( - std::declval())), - decltype(T::compose(std::declval>(), - std::declval>())), - decltype(T::join(std::declval>(), - std::declval>()))>> - : std::true_type {}; - -} // namespace detail -template -static constexpr bool IsEdgeFunction = detail::IsEdgeFunction::value; - -#else -// clang-format off template -concept IsEdgeFunction = requires(const T &EF, const EdgeFunction& TEEF, EdgeFunctionRef CEF, typename T::l_t Src) { - typename T::l_t; - {EF.computeTarget(Src)} -> std::convertible_to; - {T::compose(CEF, TEEF)} -> std::same_as>; - {T::join(CEF, TEEF)} -> std::same_as>; -}; -// clang-format on - -#endif +concept IsEdgeFunction = + requires(const T &EF, const EdgeFunction &TEEF, + EdgeFunctionRef CEF, typename T::l_t Src) { + typename T::l_t; + { EF.computeTarget(Src) } -> std::convertible_to; + { T::compose(CEF, TEEF) } -> std::same_as>; + { T::join(CEF, TEEF) } -> std::same_as>; + }; enum class EdgeFunctionAllocationPolicy { SmallObjectOptimized, @@ -231,8 +208,8 @@ class [[clang::trivial_abi]] EdgeFunction final : EdgeFunctionBase { /// Implicit-conversion constructor from EdgeFunctionRef. Increments the /// ref-count if not small-object optimized - template >>> + template + requires(!std::is_same_v>) EdgeFunction(EdgeFunctionRef CEF) noexcept : EdgeFunction(CEF.Instance, {&VTableFor, [CEF] { @@ -249,10 +226,8 @@ class [[clang::trivial_abi]] EdgeFunction final : EdgeFunctionBase { /// Conversion-constructor from any edge function (that satisfies the /// IsEdgeFunction trait). Stores a type-erased copy of CEF and allocates /// space for it on the heap if small-object-optimization cannot be applied. - template > && - IsEdgeFunction>> + template + requires(!std::is_same_v>) EdgeFunction(ConcreteEF &&CEF) noexcept( IsSOOCandidate>) : EdgeFunction(std::in_place_type>, @@ -263,7 +238,7 @@ class [[clang::trivial_abi]] EdgeFunction final : EdgeFunctionBase { /// for it on the heap if small-object-optimization cannot be applied. /// No extra copy- or move construction/assignment is performed. Use this ctor /// if even moving is expensive. - template + template explicit EdgeFunction( std::in_place_type_t /*unused*/, ArgTys &&...Args) noexcept(IsSOOCandidate> && @@ -297,9 +272,8 @@ class [[clang::trivial_abi]] EdgeFunction final : EdgeFunctionBase { /// automatically removes the edge function from EF.Cache. Hence, make sure /// that EF.Cache lives at least as long as the last edge function cached in /// it. - template && - std::is_move_constructible_v>> + template + requires std::is_move_constructible_v EdgeFunction(CachedEdgeFunction EF) : EdgeFunction( [&EF] { @@ -438,14 +412,19 @@ class [[clang::trivial_abi]] EdgeFunction final : EdgeFunctionBase { LHS.VTAndHeapAlloc.getPointer()->equals(LHS.EF, RHS.EF); } - template > && - IsEdgeFunction>> - [[nodiscard]] bool equals(EdgeFunctionRef Other) const noexcept { - // NOTE: Workaround issue in g++ that does not allow transitive friends: If - // putting this code in the operator== below, we cannot access - // Other.Instance, although it is friended... + template + requires(!std::is_same_v>) + [[nodiscard]] PSR_DEPRECATED( + "With C++20, we do not need this helper anymore, use operator== instead", + "operator==") bool equals(EdgeFunctionRef Other) + const noexcept { + return *this == Other; + } + + template + requires(!std::is_same_v>) + [[nodiscard]] bool + operator==(EdgeFunctionRef Other) const noexcept { if (!isa()) { return false; } @@ -459,62 +438,10 @@ class [[clang::trivial_abi]] EdgeFunction final : EdgeFunctionBase { } } - template > && - IsEdgeFunction>> - [[nodiscard]] friend bool operator==(EdgeFunctionRef LHS, - const EdgeFunction &RHS) noexcept { - return RHS.equals(LHS); - } - - template > && - IsEdgeFunction>> - [[nodiscard]] friend bool - operator==(const EdgeFunction &LHS, - EdgeFunctionRef RHS) noexcept { - return RHS == LHS; - } [[nodiscard]] friend bool operator==(const EdgeFunction &EF, std::nullptr_t) noexcept { return EF.VTAndHeapAlloc.getOpaqueValue() == nullptr; } - [[nodiscard]] friend bool operator==(std::nullptr_t, - const EdgeFunction &EF) noexcept { - return EF.VTAndHeapAlloc.getOpaqueValue() == nullptr; - } - [[nodiscard]] friend bool operator!=(const EdgeFunction &LHS, - const EdgeFunction &RHS) noexcept { - return !(LHS == RHS); - } - [[nodiscard]] friend bool operator!=(const EdgeFunction &EF, - std::nullptr_t) noexcept { - return !(EF == nullptr); - } - [[nodiscard]] friend bool operator!=(std::nullptr_t, - const EdgeFunction &EF) noexcept { - return !(EF == nullptr); - } - - template > && - IsEdgeFunction>> - [[nodiscard]] friend bool operator!=(EdgeFunctionRef LHS, - const EdgeFunction &RHS) noexcept { - return !(LHS == RHS); - } - template > && - IsEdgeFunction>> - [[nodiscard]] friend bool - operator!=(const EdgeFunction &LHS, - EdgeFunctionRef RHS) noexcept { - return !(LHS == RHS); - } /// Printing function. Based on llvm::raw_ostream /// &operator<<(llvm::raw_ostream &OS, const ConcreteEF &EF) for the concrete @@ -570,7 +497,7 @@ class [[clang::trivial_abi]] EdgeFunction final : EdgeFunctionBase { /// for all x,y in l_t it holds: computeTarget(x) == computeTarget(y). /// /// Allows for better optimizations in compose and join and should be - /// provided, whehever this knowledge is available. + /// provided, whenever this knowledge is available. [[nodiscard]] bool isConstant() const noexcept { assert(isValid() && "isConstant() called on nullptr!"); return VTAndHeapAlloc.getPointer()->isConstant(EF); @@ -580,7 +507,7 @@ class [[clang::trivial_abi]] EdgeFunction final : EdgeFunctionBase { return VTAndHeapAlloc.getOpaqueValue(); } - /// Performs a null-check. True, iff thie edge function is not null. + /// Performs a null-check. True, iff this edge function is not null. [[nodiscard]] explicit operator bool() const noexcept { return isValid(); } /// Performs a runtime-typecheck. True, if the concrete type of the held edge @@ -836,53 +763,6 @@ template struct DenseMapInfo> { } }; -// LLVM is currently overhauling its casting system. Use the new variant once -// possible! -#if LLVM_VERSION_MAJOR < 15 - -template -struct isa_impl_cl> { - static inline bool doit(const psr::EdgeFunction &Val) noexcept { - assert(Val && "isa<> used on a null pointer"); - return Val.template isa>(); - } -}; - -template -struct cast_retty_impl> { - using ret_type = const To *; -}; - -template -struct cast_retty_impl> - : cast_retty_impl> {}; - -template -struct cast_convert_val, - const psr::EdgeFunction> { - static typename cast_retty>::ret_type - doit(const psr::EdgeFunction &Val) noexcept { - return Val.template cast(); - } -}; -template -struct cast_convert_val, psr::EdgeFunction> - : cast_convert_val, - const psr::EdgeFunction> {}; - -template -[[nodiscard]] inline typename cast_retty>::ret_type -dyn_cast_or_null(const psr::EdgeFunction &EF) noexcept { // NOLINT - return (EF && isa(EF)) ? cast(EF) : nullptr; -} - -template -[[nodiscard]] inline typename cast_retty>::ret_type -cast_or_null(const psr::EdgeFunction &EF) noexcept { // NOLINT - return EF ? cast(EF) : nullptr; -} -#else - template struct CastIsPossible> { static inline bool isPossible(const psr::EdgeFunction &EF) noexcept { @@ -907,7 +787,6 @@ struct CastInfo> CastInfo>> { }; -#endif } // namespace llvm #endif // PHASAR_DATAFLOW_IFDSIDE_EDGEFUNCTION_H diff --git a/include/phasar/DataFlow/IfdsIde/EdgeFunctionUtils.h b/include/phasar/DataFlow/IfdsIde/EdgeFunctionUtils.h index 72c4aa1a3f..bbd82fad88 100644 --- a/include/phasar/DataFlow/IfdsIde/EdgeFunctionUtils.h +++ b/include/phasar/DataFlow/IfdsIde/EdgeFunctionUtils.h @@ -17,6 +17,7 @@ #include "llvm/ADT/ArrayRef.h" +#include #include namespace psr { @@ -51,14 +52,12 @@ template struct ConstantEdgeFunction { return Value; } - template >> + template > ConcreteEF> [[nodiscard]] static EdgeFunction compose(EdgeFunctionRef This, const EdgeFunction &SecondFunction); - template >> + template > ConcreteEF> [[nodiscard]] static EdgeFunction join(EdgeFunctionRef This, const EdgeFunction &OtherFunction); @@ -70,17 +69,18 @@ template struct ConstantEdgeFunction { value_type Value{}; }; -template >>> -[[nodiscard]] bool operator==(ConstantEdgeFunction LHS, - ConstantEdgeFunction RHS) noexcept { +template + requires CanEfficientlyPassByValue> +[[nodiscard]] constexpr bool operator==(ConstantEdgeFunction LHS, + ConstantEdgeFunction RHS) noexcept { return LHS.Value == RHS.Value; } -template >>> -[[nodiscard]] bool operator==(const ConstantEdgeFunction &LHS, - const ConstantEdgeFunction &RHS) noexcept { +template + requires(!CanEfficientlyPassByValue>) +[[nodiscard]] constexpr bool +operator==(const ConstantEdgeFunction &LHS, + const ConstantEdgeFunction &RHS) noexcept { return LHS.Value == RHS.Value; } @@ -144,10 +144,10 @@ template struct AllBottom final { [[nodiscard]] constexpr bool isConstant() const noexcept { return true; } - template >> friend bool operator==(const AllBottom &LHS, - const AllBottom &RHS) noexcept { + const AllBottom &RHS) noexcept + requires(!HasJoinLatticeTraits) + { return LHS.BottomValue == RHS.BottomValue; } }; @@ -183,9 +183,9 @@ template struct AllTop final { [[nodiscard]] constexpr bool isConstant() const noexcept { return true; } - template >> - friend bool operator==(const AllTop &LHS, const AllTop &RHS) noexcept { + friend bool operator==(const AllTop &LHS, const AllTop &RHS) noexcept + requires(!HasJoinLatticeTraits) + { return LHS.TopValue == RHS.TopValue; } }; @@ -234,8 +234,7 @@ template struct EdgeFunctionComposer { * However, it is advised to immediately reduce the resulting edge function * by providing an own implementation of this function. */ - template >> + template ConcreteEF> [[nodiscard]] static EdgeFunction compose(EdgeFunctionRef This, const EdgeFunction &SecondFunction) { @@ -442,7 +441,7 @@ EdgeFunction EdgeIdentity::join(EdgeFunctionRef This, } template -template +template > ConcreteEF> EdgeFunction ConstantEdgeFunction::compose(EdgeFunctionRef This, const EdgeFunction &SecondFunction) { @@ -483,7 +482,7 @@ ConstantEdgeFunction::compose(EdgeFunctionRef This, } template -template +template > ConcreteEF> EdgeFunction ConstantEdgeFunction::join(EdgeFunctionRef This, const EdgeFunction &OtherFunction) { diff --git a/include/phasar/DataFlow/IfdsIde/EntryPointUtils.h b/include/phasar/DataFlow/IfdsIde/EntryPointUtils.h index 6080a9a80e..d5626a2e0d 100644 --- a/include/phasar/DataFlow/IfdsIde/EntryPointUtils.h +++ b/include/phasar/DataFlow/IfdsIde/EntryPointUtils.h @@ -73,12 +73,12 @@ void forallStartingPoints(const EntryRange &EntryPoints, const I *ICF, template -std::enable_if_t && - std::is_convertible_v> -addSeedsForStartingPoints(const EntryRange &EntryPoints, - const ProjectIRDBBase *IRDB, - const CFGBase &CFG, SeedsT &Seeds, - const D &ZeroValue, const L &BottomValue) { + requires(std::is_convertible_v && + std::is_convertible_v) +void addSeedsForStartingPoints(const EntryRange &EntryPoints, + const ProjectIRDBBase *IRDB, + const CFGBase &CFG, SeedsT &Seeds, + const D &ZeroValue, const L &BottomValue) { forallStartingPoints(EntryPoints, IRDB, CFG, [&Seeds, &ZeroValue, &BottomValue](const auto &SP) { Seeds.addSeed(SP, ZeroValue, BottomValue); @@ -87,11 +87,11 @@ addSeedsForStartingPoints(const EntryRange &EntryPoints, template -std::enable_if_t && - std::is_convertible_v> -addSeedsForStartingPoints(const EntryRange &EntryPoints, const I *ICF, - SeedsT &Seeds, const D &ZeroValue, - const L &BottomValue) { + requires(std::is_convertible_v && + std::is_convertible_v) +void addSeedsForStartingPoints(const EntryRange &EntryPoints, const I *ICF, + SeedsT &Seeds, const D &ZeroValue, + const L &BottomValue) { forallStartingPoints(EntryPoints, ICF, [&Seeds, &ZeroValue, &BottomValue](const auto &SP) { Seeds.addSeed(SP, ZeroValue, BottomValue); @@ -101,22 +101,22 @@ addSeedsForStartingPoints(const EntryRange &EntryPoints, const I *ICF, /// Simplification for IFDS, passing BinaryDomain::BOTTOM as L template -std::enable_if_t && - std::is_convertible_v> -addSeedsForStartingPoints(const EntryRange &EntryPoints, - const ProjectIRDBBase *IRDB, - const CFGBase &CFG, SeedsT &Seeds, - const D &ZeroValue) { + requires(std::is_same_v && + std::is_convertible_v) +void addSeedsForStartingPoints(const EntryRange &EntryPoints, + const ProjectIRDBBase *IRDB, + const CFGBase &CFG, SeedsT &Seeds, + const D &ZeroValue) { addSeedsForStartingPoints(EntryPoints, IRDB, CFG, Seeds, ZeroValue, BinaryDomain::BOTTOM); } /// Simplification for IFDS, passing BinaryDomain::BOTTOM as L template -std::enable_if_t && - std::is_convertible_v> -addSeedsForStartingPoints(const EntryRange &EntryPoints, const I *ICF, - SeedsT &Seeds, const D &ZeroValue) { + requires(std::is_same_v && + std::is_convertible_v) +void addSeedsForStartingPoints(const EntryRange &EntryPoints, const I *ICF, + SeedsT &Seeds, const D &ZeroValue) { addSeedsForStartingPoints(EntryPoints, ICF, Seeds, ZeroValue, BinaryDomain::BOTTOM); } diff --git a/include/phasar/DataFlow/IfdsIde/FlowFunctions.h b/include/phasar/DataFlow/IfdsIde/FlowFunctions.h index 783a5a3e91..6c7cc58a87 100644 --- a/include/phasar/DataFlow/IfdsIde/FlowFunctions.h +++ b/include/phasar/DataFlow/IfdsIde/FlowFunctions.h @@ -83,10 +83,10 @@ template struct IsFlowFunction { /// Helper template to check at compile-time whether a type implements the /// FlowFunction interface, no matter which data-flow fact type it uses. template -PSR_CONCEPT is_flowfunction_v = IsFlowFunction::value; // NOLINT +concept is_flowfunction_v = IsFlowFunction::value; // NOLINT /// Given a flow-function type FF, returns a (smart) pointer type pointing to FF -template >> +template using FlowFunctionPtrTypeOf = std::shared_ptr; /// Given a dataflow-fact type and optionally a container-type, returns a @@ -255,8 +255,8 @@ template class FlowFunctionTemplates { /// f(x) = {v, x} if p(x) == true /// f(x) = {x} else. /// \endcode - template >> + template + requires std::is_invocable_r_v static auto generateFlowIf(d_t FactToGenerate, Fn Predicate) { struct GenFlowIf final : public FlowFunction { GenFlowIf(d_t GenValue, Fn &&Predicate) @@ -295,8 +295,7 @@ template class FlowFunctionTemplates { /// v v v v ... \ v ... /// x w v1 v2 ... vN u /// \endcode - template , - typename = std::enable_if_t>> + template Range = std::initializer_list> static auto generateManyFlows(Range &&FactsToGenerate, d_t From) { struct GenMany final : public FlowFunction { GenMany(container_type &&GenValues, d_t FromValue) @@ -363,8 +362,8 @@ template class FlowFunctionTemplates { /// f(x) = {} if p(x) == true /// f(x) = {x} else. /// \endcode - template >> + template + requires std::is_invocable_r_v static auto killFlowIf(Fn Predicate) { struct KillFlowIf final : public FlowFunction { KillFlowIf(Fn &&Predicate) : Predicate(std::forward(Predicate)) {} @@ -402,8 +401,7 @@ template class FlowFunctionTemplates { /// v v /// u v1 v2 ... vN w ... /// \endcode - template , - typename = std::enable_if_t>> + template Range = std::initializer_list> static auto killManyFlows(Range &&FactsToKill) { struct KillMany final : public FlowFunction { KillMany(Container &&KillValues) : KillValues(std::move(KillValues)) {} @@ -501,8 +499,7 @@ template class FlowFunctionTemplates { /// v v v ... \ ... /// x w v1 v2 ... vN u /// \endcode - template , - typename = std::enable_if_t>> + template Range = std::initializer_list> static auto generateManyFlowsAndKillAllOthers(Range &&FactsToGenerate, d_t From) { struct GenManyAndKillAllOthers final @@ -588,12 +585,11 @@ template class FlowFunctionTemplates { /// \code /// f(x) = g(x) u h(x). (where u denotes set-union) /// \endcode - template && - std::is_same_v && - std::is_same_v>> + template + requires(std::is_same_v && + std::is_same_v && + std::is_same_v) auto unionFlows(FlowFunctionPtrTypeOf OneFF, FlowFunctionPtrTypeOf OtherFF) { struct UnionFlow final : public FlowFunction { diff --git a/include/phasar/DataFlow/IfdsIde/GenericFlowFunction.h b/include/phasar/DataFlow/IfdsIde/GenericFlowFunction.h index d124e8a013..a7c9a99124 100644 --- a/include/phasar/DataFlow/IfdsIde/GenericFlowFunction.h +++ b/include/phasar/DataFlow/IfdsIde/GenericFlowFunction.h @@ -57,12 +57,12 @@ class GenericFlowFunction { GenericFlowFunction() noexcept = default; GenericFlowFunction(FlowFunctionPtrType FF) noexcept : FF(std::move(FF)) {} - template >>> + + template T> GenericFlowFunction(T &&FF) : FF(std::make_unique>(std::forward(FF))) {} - template + template T, typename... ArgTys> explicit GenericFlowFunction(std::in_place_type_t /*unused*/, ArgTys &&...Args) : FF(std::make_unique(std::forward(Args)...)) {} diff --git a/include/phasar/DataFlow/IfdsIde/IDETabulationProblem.h b/include/phasar/DataFlow/IfdsIde/IDETabulationProblem.h index cb5c4c131c..b722ca7ae3 100644 --- a/include/phasar/DataFlow/IfdsIde/IDETabulationProblem.h +++ b/include/phasar/DataFlow/IfdsIde/IDETabulationProblem.h @@ -39,7 +39,7 @@ namespace psr { struct HasNoConfigurationType; -template class AllTopFnProvider { +template class AllTopFnProvider { public: virtual ~AllTopFnProvider() = default; /// Returns an edge function that represents the top element of the analysis. @@ -47,9 +47,8 @@ template class AllTopFnProvider { }; template -class AllTopFnProvider< - AnalysisDomainTy, - std::enable_if_t>> { + requires HasJoinLatticeTraits +class AllTopFnProvider { public: virtual ~AllTopFnProvider() = default; /// Returns an edge function that represents the top element of the analysis. @@ -194,21 +193,21 @@ class IDETabulationProblem : public FlowFunctions, AnalysisType); } - template - std::enable_if_t> - onResult(n_t Instr, D &&DfFact, DataFlowAnalysisType AnalysisType) { + template + requires std::is_same_v + void onResult(n_t Instr, D &&DfFact, DataFlowAnalysisType AnalysisType) { Printer->onResult(Instr, PSR_FWD(DfFact), AnalysisType); } /// Seeds that just start with ZeroValue and bottomElement() at the starting /// points of each EntryPoint function. /// Takes the __ALL__ EntryPoint into account. - template < - typename CC = typename AnalysisDomainTy::c_t, - typename = std::enable_if_t>> - [[nodiscard]] InitialSeeds createDefaultSeeds() { + [[nodiscard]] InitialSeeds createDefaultSeeds() + requires std::is_nothrow_default_constructible_v< + typename AnalysisDomainTy::c_t> + { InitialSeeds Seeds; - CC C{}; + typename AnalysisDomainTy::c_t C{}; addSeedsForStartingPoints(EntryPoints, IRDB, C, Seeds, getZeroValue(), this->bottomElement()); diff --git a/include/phasar/DataFlow/IfdsIde/InitialSeeds.h b/include/phasar/DataFlow/IfdsIde/InitialSeeds.h index 140cbc0cee..7bdad2f51e 100644 --- a/include/phasar/DataFlow/IfdsIde/InitialSeeds.h +++ b/include/phasar/DataFlow/IfdsIde/InitialSeeds.h @@ -35,9 +35,9 @@ template class InitialSeeds { InitialSeeds() = default; - template >> - InitialSeeds(const std::map> &Seeds) { + InitialSeeds(const std::map> &Seeds) + requires std::is_same_v + { for (const auto &[Node, Facts] : Seeds) { for (const auto &Fact : Facts) { this->Seeds[Node][Fact] = BinaryDomain::BOTTOM; @@ -47,9 +47,9 @@ template class InitialSeeds { InitialSeeds(GeneralizedSeeds Seeds) : Seeds(std::move(Seeds)) {} - template >> - void addSeed(N Node, D Fact) { + void addSeed(N Node, D Fact) + requires std::is_same_v + { addSeed(Node, Fact, BinaryDomain::BOTTOM); } diff --git a/include/phasar/DataFlow/IfdsIde/Solver/Compressor.h b/include/phasar/DataFlow/IfdsIde/Solver/Compressor.h index 29c900e0bb..fdeef7e304 100644 --- a/include/phasar/DataFlow/IfdsIde/Solver/Compressor.h +++ b/include/phasar/DataFlow/IfdsIde/Solver/Compressor.h @@ -13,8 +13,8 @@ namespace psr { struct NoneCompressor final { constexpr NoneCompressor() noexcept = default; - template >> + template + requires(!std::is_same_v) constexpr NoneCompressor(const T & /*unused*/) noexcept {} template @@ -45,13 +45,14 @@ template struct NodeCompressorTraits { } }; -template struct ValCompressorTraits { +template struct ValCompressorTraits { using type = Compressor; using id_type = uint32_t; }; template -struct ValCompressorTraits>> { + requires CanEfficientlyPassByValue +struct ValCompressorTraits { using type = NoneCompressor; using id_type = T; }; diff --git a/include/phasar/DataFlow/IfdsIde/Solver/FlowFunctionCache.h b/include/phasar/DataFlow/IfdsIde/Solver/FlowFunctionCache.h index f6c0c3a5db..944f711707 100644 --- a/include/phasar/DataFlow/IfdsIde/Solver/FlowFunctionCache.h +++ b/include/phasar/DataFlow/IfdsIde/Solver/FlowFunctionCache.h @@ -6,6 +6,7 @@ #include "phasar/Utils/ByRef.h" #include "phasar/Utils/PointerUtils.h" #include "phasar/Utils/TableWrappers.h" +#include "phasar/Utils/TypeTraits.h" #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/SmallVector.h" @@ -19,23 +20,15 @@ namespace psr { namespace detail { -template -constexpr inline bool IsFlowFunction = false; - template -constexpr inline bool - IsFlowFunction().computeTargets( - std::declval()))>> = true; - -template -constexpr inline bool IsFlowFunctionPtr = false; +concept IsFlowFunction = requires(T &FF, D Fact) { + { FF.computeTargets(Fact) } -> is_iterable_over_v; +}; template -constexpr inline bool - IsFlowFunctionPtr()->computeTargets( - std::declval()))>> = true; +concept IsFlowFunctionPtr = requires(T FF, D Fact) { + { FF->computeTargets(Fact) } -> is_iterable_over_v; +}; template struct AutoAddZeroFF { FFTy FF; diff --git a/include/phasar/DataFlow/IfdsIde/Solver/GenericSolverResults.h b/include/phasar/DataFlow/IfdsIde/Solver/GenericSolverResults.h index 20ff8b6c3e..4fa67d88fa 100644 --- a/include/phasar/DataFlow/IfdsIde/Solver/GenericSolverResults.h +++ b/include/phasar/DataFlow/IfdsIde/Solver/GenericSolverResults.h @@ -37,8 +37,8 @@ template class GenericSolverResults final { /// lifetime. Probably that can be mitigated with use of std::launder, but for /// now, we don't need this complexity - template >>> + template + requires(!std::is_same_v>) GenericSolverResults(const T &SR) noexcept : VT(&VtableFor>) { using type = std::decay_t; @@ -72,9 +72,9 @@ template class GenericSolverResults final { return VT->ResultsAt(Buffer.data(), Stmt, StripZero); } - template >> - [[nodiscard]] std::set ifdsResultsAt(ByConstRef Stmt) const { + [[nodiscard]] std::set ifdsResultsAt(ByConstRef Stmt) const + requires std::is_same_v + { assert(VT != nullptr); assert(VT->IfdsResultsAt != nullptr); return VT->IfdsResultsAt(Buffer.data(), Stmt); @@ -89,21 +89,22 @@ template class GenericSolverResults final { return VT->ContainsNode(Buffer.data(), Stmt); } - template >> + // TODO: Sync with LLVMSolverResults.h [[nodiscard]] l_t resultAtInLLVMSSA(const llvm::Instruction *Stmt, - ByConstRef Node) const { + ByConstRef Node) const + requires std::is_same_v + { if (const auto *Next = Stmt->getNextNode()) { return resultAt(Next, Node); } return resultAt(Stmt, Node); } - template >> [[nodiscard]] std::unordered_map resultsAtInLLVMSSA(const llvm::Instruction *Stmt, - bool StripZero = false) const { + bool StripZero = false) const + requires std::is_same_v + { if (const auto *Next = Stmt->getNextNode()) { return resultsAt(Next, StripZero); } diff --git a/include/phasar/DataFlow/IfdsIde/Solver/IDESolver.h b/include/phasar/DataFlow/IfdsIde/Solver/IDESolver.h index fe1827b661..f105e3558a 100644 --- a/include/phasar/DataFlow/IfdsIde/Solver/IDESolver.h +++ b/include/phasar/DataFlow/IfdsIde/Solver/IDESolver.h @@ -44,6 +44,7 @@ #include "phasar/Utils/Nullable.h" #include "phasar/Utils/PAMMMacros.h" #include "phasar/Utils/Table.h" +#include "phasar/Utils/TypeTraits.h" #include "phasar/Utils/Utilities.h" #include "llvm/ADT/DenseSet.h" @@ -168,10 +169,9 @@ class IDESolver /// This result accessor function returns the results at the successor /// instruction(s) reflecting that the expression on the left-hand side holds /// if the expression on the right-hand side holds. - template - [[nodiscard]] typename std::enable_if_t< - std::is_same_v, llvm::Instruction *>, l_t> - resultAtInLLVMSSA(NTy Stmt, d_t Value) { + [[nodiscard]] l_t resultAtInLLVMSSA(n_t Stmt, d_t Value) + requires same_as_decay, llvm::Instruction> + { return getSolverResults().resultAtInLLVMSSA(Stmt, Value); } @@ -198,11 +198,11 @@ class IDESolver /// This result accessor function returns the results at the successor /// instruction(s) reflecting that the expression on the left-hand side holds /// if the expression on the right-hand side holds. - template - [[nodiscard]] typename std::enable_if_t< - std::is_same_v, llvm::Instruction *>, - std::unordered_map> - resultsAtInLLVMSSA(NTy Stmt, bool StripZero = false) { + [[nodiscard]] + std::unordered_map resultsAtInLLVMSSA(n_t Stmt, + bool StripZero = false) + requires same_as_decay, llvm::Instruction> + { return getSolverResults().resultsAtInLLVMSSA(Stmt, StripZero); } diff --git a/include/phasar/DataFlow/IfdsIde/Solver/IDESolverAPIMixin.h b/include/phasar/DataFlow/IfdsIde/Solver/IDESolverAPIMixin.h index 65ae8a8908..c6d4d3ba7e 100644 --- a/include/phasar/DataFlow/IfdsIde/Solver/IDESolverAPIMixin.h +++ b/include/phasar/DataFlow/IfdsIde/Solver/IDESolverAPIMixin.h @@ -142,11 +142,10 @@ template class IDESolverAPIMixin { /// /// \returns An std::optional holding a view into the analysis results or /// std::nullopt if the analysis was cancelled. - template || - std::is_invocable_r_v>> + template + requires(std::is_invocable_r_v || + std::is_invocable_r_v) auto solveUntil(CancellationRequest CancellationRequested, std::chrono::milliseconds Interval = std::chrono::seconds{1}) & { @@ -169,11 +168,10 @@ template class IDESolverAPIMixin { /// /// \returns An std::optional holding the analysis results or std::nullopt if /// the analysis was cancelled. - template || - std::is_invocable_r_v>> + template + requires(std::is_invocable_r_v || + std::is_invocable_r_v) auto solveUntil(CancellationRequest CancellationRequested, std::chrono::milliseconds Interval = std::chrono::seconds{1}) && { @@ -204,11 +202,10 @@ template class IDESolverAPIMixin { /// /// \returns An std::optional holding a view into the analysis results or /// std::nullopt if the analysis was cancelled. - template || - std::is_invocable_r_v>> + template + requires(std::is_invocable_r_v || + std::is_invocable_r_v) auto continueUntil(CancellationRequest CancellationRequested, std::chrono::milliseconds Interval = std::chrono::seconds{ 1}) & { @@ -238,11 +235,10 @@ template class IDESolverAPIMixin { /// /// \returns An std::optional holding a view into the analysis results or /// std::nullopt if the analysis was cancelled. - template || - std::is_invocable_r_v>> + template + requires(std::is_invocable_r_v || + std::is_invocable_r_v) auto continueUntil(CancellationRequest CancellationRequested, std::chrono::milliseconds Interval = std::chrono::seconds{ 1}) && { @@ -424,7 +420,7 @@ template class IDESolverAPIMixin { } private: - [[nodiscard]] Derived &self() &noexcept { + [[nodiscard]] Derived &self() & noexcept { static_assert(std::is_base_of_v, "Invalid CRTP instantiation"); return static_cast(*this); diff --git a/include/phasar/DataFlow/IfdsIde/Solver/IFDSSolver.h b/include/phasar/DataFlow/IfdsIde/Solver/IFDSSolver.h index cfebf428e3..76c51ce29e 100644 --- a/include/phasar/DataFlow/IfdsIde/Solver/IFDSSolver.h +++ b/include/phasar/DataFlow/IfdsIde/Solver/IFDSSolver.h @@ -21,6 +21,7 @@ #include "phasar/DataFlow/IfdsIde/Solver/IDESolver.h" #include "phasar/Domain/BinaryDomain.h" +#include #include #include #include @@ -45,15 +46,11 @@ class IFDSSolver using n_t = typename AnalysisDomainTy::n_t; using i_t = typename AnalysisDomainTy::i_t; - template >> + template IfdsDomainTy, typename I> IFDSSolver(IFDSTabulationProblem &IFDSProblem, const I *ICF) : IDESolver>(IFDSProblem, ICF) {} - template >> + template IfdsDomainTy, typename I> IFDSSolver(IFDSTabulationProblem *IFDSProblem, const I *ICF) : IDESolver>(IFDSProblem, ICF) {} @@ -85,11 +82,10 @@ class IFDSSolver /// This result accessor function returns the results at the successor /// instruction(s) reflecting that the expression on the left-hand side holds /// if the expression on the right-hand side holds. - template - [[nodiscard]] typename std::enable_if_t< - std::is_same_v, llvm::Instruction *>, - std::set> - ifdsResultsAtInLLVMSSA(NTy Inst) { + [[nodiscard]] + std::set ifdsResultsAtInLLVMSSA(n_t Inst) + requires same_as_decay, llvm::Instruction> + { auto getResultMap // NOLINT = [this, Inst]() { if (Inst->getType()->isVoidTy()) { diff --git a/include/phasar/DataFlow/IfdsIde/Solver/IterativeIDESolver.h b/include/phasar/DataFlow/IfdsIde/Solver/IterativeIDESolver.h index 2fab0ac482..6ec8cc7b6f 100644 --- a/include/phasar/DataFlow/IfdsIde/Solver/IterativeIDESolver.h +++ b/include/phasar/DataFlow/IfdsIde/Solver/IterativeIDESolver.h @@ -236,13 +236,15 @@ class IterativeIDESolver OS << '\n'; } - template > - [[nodiscard]] IterativeIDESolverStats getStats() const noexcept { + [[nodiscard]] IterativeIDESolverStats getStats() const noexcept + requires EnableStatistics + { return *this; } - template > - void dumpStats(llvm::raw_ostream &OS = llvm::outs()) const { + void dumpStats(llvm::raw_ostream &OS = llvm::outs()) const + requires EnableStatistics + { OS << getStats(); } @@ -442,11 +444,11 @@ class IterativeIDESolver } } - template - std::enable_if_t - storeResultsAndPropagate(SummaryEdges &JumpFns, uint32_t SuccId, - uint32_t SourceFact, uint32_t LocalFact, - uint32_t FunId, EdgeFunctionPtrType LocalEF) { + bool storeResultsAndPropagate(SummaryEdges &JumpFns, uint32_t SuccId, + uint32_t SourceFact, uint32_t LocalFact, + uint32_t FunId, EdgeFunctionPtrType LocalEF) + requires ComputeValues + { auto &EF = JumpFns.getOrCreate(combineIds(SourceFact, LocalFact)); if (!EF) { EF = std::move(LocalEF); @@ -492,11 +494,12 @@ class IterativeIDESolver } return false; } - template - std::enable_if_t - storeResultsAndPropagate(SummaryEdges &JumpFns, uint32_t SuccId, - uint32_t SourceFact, uint32_t LocalFact, - uint32_t FunId, EdgeFunctionPtrType /*LocalEF*/) { + + bool storeResultsAndPropagate(SummaryEdges &JumpFns, uint32_t SuccId, + uint32_t SourceFact, uint32_t LocalFact, + uint32_t FunId, EdgeFunctionPtrType /*LocalEF*/) + requires(!ComputeValues) + { if (JumpFns.insert(combineIds(SourceFact, LocalFact)).second) { WorkList.emplace(PropagationJob{{}, SuccId, SourceFact, LocalFact}); @@ -521,10 +524,10 @@ class IterativeIDESolver return false; } - template - std::enable_if_t storeSummary(SummaryEdges_JF1 &JumpFns, - uint32_t LocalFact, - EdgeFunctionPtrType LocalEF) { + void storeSummary(SummaryEdges_JF1 &JumpFns, uint32_t LocalFact, + EdgeFunctionPtrType LocalEF) + requires(UseEndSummaryTab && ComputeValues) + { auto &EF = JumpFns[LocalFact]; if (!EF) { EF = std::move(LocalEF); @@ -550,10 +553,10 @@ class IterativeIDESolver } } - template - std::enable_if_t storeSummary(SummaryEdges_JF1 &JumpFns, - uint32_t LocalFact, - EdgeFunctionPtrType /*LocalEF*/) { + void storeSummary(SummaryEdges_JF1 &JumpFns, uint32_t LocalFact, + EdgeFunctionPtrType /*LocalEF*/) + requires(UseEndSummaryTab && !ComputeValues) + { if (JumpFns.insert({LocalFact, {}}).second) { if constexpr (EnableStatistics) { this->NumPathEdges++; @@ -1039,8 +1042,9 @@ class IterativeIDESolver } } - template > - void submitInitialValues() { + void submitInitialValues() + requires ComputeValues + { auto Seeds = Problem.initialSeeds(); for (const auto &[Inst, SeedMap] : Seeds.getSeeds()) { auto InstId = NodeCompressor.getOrInsert(Inst); @@ -1052,8 +1056,9 @@ class IterativeIDESolver } } - template > - void propagateValue(uint32_t SPId, uint32_t FactId, l_t Val) { + void propagateValue(uint32_t SPId, uint32_t FactId, l_t Val) + requires ComputeValues + { /// TODO: Unbalanced return-sites @@ -1130,8 +1135,9 @@ class IterativeIDESolver } } - template > - void computeValues(uint32_t SPId) { + void computeValues(uint32_t SPId) + requires ComputeValues + { auto SP = NodeCompressor[SPId]; auto Fun = ICFG.getFunctionOf(SP); diff --git a/include/phasar/DataFlow/IfdsIde/Solver/IterativeIDESolverStats.h b/include/phasar/DataFlow/IfdsIde/Solver/IterativeIDESolverStats.h index 4c705ea745..c2735c176c 100644 --- a/include/phasar/DataFlow/IfdsIde/Solver/IterativeIDESolverStats.h +++ b/include/phasar/DataFlow/IfdsIde/Solver/IterativeIDESolverStats.h @@ -52,10 +52,8 @@ template struct SolverStatsSelector {}; template -struct SolverStatsSelector< - StaticSolverConfigTy, - std::enable_if_t> - : IterativeIDESolverStats {}; + requires StaticSolverConfigTy::EnableStatistics +struct SolverStatsSelector : IterativeIDESolverStats {}; } // namespace psr #endif // PHASAR_PHASARLLVM_DATAFLOWSOLVER_IFDSIDE_SOLVER_ITERATIVEIDESOLVERSTATS_H diff --git a/include/phasar/DataFlow/IfdsIde/Solver/StaticIDESolverConfig.h b/include/phasar/DataFlow/IfdsIde/Solver/StaticIDESolverConfig.h index 42b882b27e..6a95bc0dff 100644 --- a/include/phasar/DataFlow/IfdsIde/Solver/StaticIDESolverConfig.h +++ b/include/phasar/DataFlow/IfdsIde/Solver/StaticIDESolverConfig.h @@ -91,11 +91,10 @@ template struct DefaultIDESolverConfig : IDESolverConfig {}; template -struct DefaultIDESolverConfig< - ProblemTy, - std::enable_if_t, - ProblemTy>>> : IFDSSolverConfig {}; + requires std::is_base_of_v< + IFDSTabulationProblem, + ProblemTy> +struct DefaultIDESolverConfig : IFDSSolverConfig {}; } // namespace psr diff --git a/include/phasar/DataFlow/IfdsIde/SolverResults.h b/include/phasar/DataFlow/IfdsIde/SolverResults.h index 51b8b3ce9d..12cc2a9e6a 100644 --- a/include/phasar/DataFlow/IfdsIde/SolverResults.h +++ b/include/phasar/DataFlow/IfdsIde/SolverResults.h @@ -22,6 +22,7 @@ #include "phasar/Utils/PAMMMacros.h" #include "phasar/Utils/Printer.h" #include "phasar/Utils/Table.h" +#include "phasar/Utils/TypeTraits.h" #include "phasar/Utils/Utilities.h" #include @@ -97,10 +98,9 @@ class SolverResultsBase { // this function only exists for IFDS problems which use BinaryDomain as their // value domain L - template >> - [[nodiscard]] std::set ifdsResultsAt(ByConstRef Stmt) const { + [[nodiscard]] std::set ifdsResultsAt(ByConstRef Stmt) const + requires std::is_same_v + { std::set KeySet; const auto &ResultMap = self().Results.row(Stmt); for (const auto &[FlowFact, Val] : ResultMap) { @@ -124,13 +124,10 @@ class SolverResultsBase { /// This result accessor function returns the results at the successor /// instruction(s) reflecting that the expression on the left-hand side holds /// if the expression on the right-hand side holds. - template - [[nodiscard]] typename std::enable_if_t< - std::is_same_v>, - llvm::Instruction>, - std::unordered_map> + [[nodiscard]] std::unordered_map resultsAtInLLVMSSA(ByConstRef Stmt, bool AllowOverapproximation = false, - bool StripZero = false) const; + bool StripZero = false) const + requires same_as_decay, llvm::Instruction>; /// Returns the L-type result at the given statement for the given data-flow /// fact while respecting LLVM's SSA semantics. @@ -147,13 +144,9 @@ class SolverResultsBase { /// This result accessor function returns the results at the successor /// instruction(s) reflecting that the expression on the left-hand side holds /// if the expression on the right-hand side holds. - template - [[nodiscard]] typename std::enable_if_t< - std::is_same_v>, - llvm::Instruction>, - l_t> - resultAtInLLVMSSA(ByConstRef Stmt, d_t Value, - bool AllowOverapproximation = false) const; + [[nodiscard]] l_t resultAtInLLVMSSA(ByConstRef Stmt, d_t Value, + bool AllowOverapproximation = false) const + requires same_as_decay, llvm::Instruction>; [[nodiscard]] std::vector::Cell> getAllResultEntries() const { diff --git a/include/phasar/DataFlow/PathSensitivity/PathSensitivityManagerMixin.h b/include/phasar/DataFlow/PathSensitivity/PathSensitivityManagerMixin.h index 761d7a88de..63d97c29af 100644 --- a/include/phasar/DataFlow/PathSensitivity/PathSensitivityManagerMixin.h +++ b/include/phasar/DataFlow/PathSensitivity/PathSensitivityManagerMixin.h @@ -74,8 +74,7 @@ class PathSensitivityManagerMixin { /// implementation-defined way. template < typename FactsRangeTy, typename ConfigTy, - typename Filter = DefaultPathTracingFilter, - typename = std::enable_if_t>> + is_pathtracingfilter_for_v Filter = DefaultPathTracingFilter> [[nodiscard]] GraphType pathsDagToAll(n_t Inst, FactsRangeTy FactsRange, const PathSensitivityConfigBase &Config, @@ -149,8 +148,8 @@ class PathSensitivityManagerMixin { /// The result is given as graph, where cycles are unrolled once in an /// implementation-defined way. template < - typename ConfigTy, typename L, typename Filter = DefaultPathTracingFilter, - typename = std::enable_if_t>> + typename ConfigTy, typename L, + is_pathtracingfilter_for_v Filter = DefaultPathTracingFilter> [[nodiscard]] GraphType pathsDagTo(n_t Inst, const SolverResults &SR, const PathSensitivityConfigBase &Config, @@ -165,9 +164,8 @@ class PathSensitivityManagerMixin { /// /// The result is given as graph, where cycles are unrolled once in an /// implementation-defined way. - template < - typename ConfigTy, typename Filter = DefaultPathTracingFilter, - typename = std::enable_if_t>> + template Filter = + DefaultPathTracingFilter> [[nodiscard]] GraphType pathsDagTo(n_t Inst, d_t Fact, const PathSensitivityConfigBase &Config, @@ -182,9 +180,8 @@ class PathSensitivityManagerMixin { /// /// The result is given as graph, where cycles are unrolled once in an /// implementation-defined way. - template < - typename ConfigTy, typename Filter = DefaultPathTracingFilter, - typename = std::enable_if_t>> + template Filter = + DefaultPathTracingFilter> [[nodiscard]] GraphType pathsDagToInLLVMSSA(n_t Inst, d_t Fact, const PathSensitivityConfigBase &Config, diff --git a/include/phasar/DataFlow/PathSensitivity/PathTracingFilter.h b/include/phasar/DataFlow/PathSensitivity/PathTracingFilter.h index 8baaa10961..73d26a165d 100644 --- a/include/phasar/DataFlow/PathSensitivity/PathTracingFilter.h +++ b/include/phasar/DataFlow/PathSensitivity/PathTracingFilter.h @@ -37,14 +37,13 @@ template struct is_pathtracingfilter_for : std::false_type {}; template -struct is_pathtracingfilter_for< - PathTracingFilter, NodeRef, - std::enable_if_t && - std::is_invocable_r_v>> - : std::true_type {}; + requires(std::is_invocable_r_v && + std::is_invocable_r_v) +struct is_pathtracingfilter_for, + NodeRef> : std::true_type {}; template -constexpr static bool is_pathtracingfilter_for_v = +concept is_pathtracingfilter_for_v = is_pathtracingfilter_for::value; } // namespace psr diff --git a/include/phasar/Domain/LatticeDomain.h b/include/phasar/Domain/LatticeDomain.h index 560409f370..27092a02f8 100644 --- a/include/phasar/Domain/LatticeDomain.h +++ b/include/phasar/Domain/LatticeDomain.h @@ -78,10 +78,10 @@ struct LatticeDomain : public std::variant { [[nodiscard]] inline const L *getValueOrNull() const noexcept { return std::get_if(this); } - template >> - friend llvm::hash_code - hash_value(const LatticeDomain &LD) noexcept { // NOLINT + + friend llvm::hash_code hash_value(const LatticeDomain &LD) noexcept + requires is_llvm_hashable_v + { // NOLINT if (LD.isBottom()) { return llvm::hash_value(INTPTR_MAX); } @@ -140,9 +140,8 @@ inline bool operator==(const LatticeDomain &Lhs, return true; } -template < - typename L, typename LL, - typename = std::void_t() == std::declval())>> +template + requires AreEqualityComparable inline bool operator==(const LL &Lhs, const LatticeDomain &Rhs) { if (auto RVal = Rhs.getValueOrNull()) { return Lhs == *RVal; @@ -150,9 +149,8 @@ inline bool operator==(const LL &Lhs, const LatticeDomain &Rhs) { return false; } -template < - typename L, typename LL, - typename = std::void_t() == std::declval())>> +template + requires AreEqualityComparable inline bool operator==(const LatticeDomain &Lhs, const LL &Rhs) { return Rhs == Lhs; } @@ -177,52 +175,6 @@ inline bool operator==(Top /*Lhs*/, const LatticeDomain &Rhs) noexcept { return Rhs.isTop(); } -#if __cplusplus < 202002L - -// With C++20 inequality is defaulted if equality is provided - -template -inline bool operator!=(const LatticeDomain &Lhs, - const LatticeDomain &Rhs) { - return !(Lhs == Rhs); -} - -template < - typename L, typename LL, - typename = std::void_t() == std::declval())>> -inline bool operator!=(const LL &Lhs, const LatticeDomain Rhs) { - return !(Lhs == Rhs); -} - -template < - typename L, typename LL, - typename = std::void_t() == std::declval())>> -inline bool operator!=(const LatticeDomain Lhs, const LL &Rhs) { - return !(Rhs == Lhs); -} - -template -inline bool operator!=(const LatticeDomain &Lhs, Bottom /*Rhs*/) noexcept { - return !(Lhs == Bottom{}); -} - -template -inline bool operator!=(const LatticeDomain &Lhs, Top /*Rhs*/) noexcept { - return !(Lhs == Top{}); -} - -template -inline bool operator!=(Bottom /*Lhs*/, const LatticeDomain &Rhs) noexcept { - return !(Bottom{} == Rhs); -} - -template -inline bool operator!=(Top /*Lhs*/, const LatticeDomain &Rhs) noexcept { - return !(Top{} == Rhs); -} - -#endif - template inline bool operator<(const LatticeDomain &Lhs, const LatticeDomain &Rhs) { @@ -268,11 +220,9 @@ template struct JoinLatticeTraits> { /// If we know that a stored L value is never Top or Bottom, we don't need to /// store the discriminator of the std::variant. template -struct NonTopBotValue< - LatticeDomain, - std::enable_if_t< - std::is_nothrow_constructible_v, const L &> || - !std::is_nothrow_copy_constructible_v>>> { + requires(std::is_nothrow_constructible_v, const L &> || + !std::is_nothrow_copy_constructible_v>) +struct NonTopBotValue> { using type = L; static L unwrap(LatticeDomain Value) noexcept( diff --git a/include/phasar/PhasarLLVM/DataFlow/IfdsIde/LLVMFlowFunctions.h b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/LLVMFlowFunctions.h index 83fc7252e4..9e9257fad6 100644 --- a/include/phasar/PhasarLLVM/DataFlow/IfdsIde/LLVMFlowFunctions.h +++ b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/LLVMFlowFunctions.h @@ -53,9 +53,8 @@ namespace psr { /// enable strong updates. /// template , - typename Fn = TrueFn, typename DCtor = DefaultConstruct, - typename = std::enable_if_t< - std::is_invocable_r_v>> + typename Fn = TrueFn, typename DCtor = DefaultConstruct> + requires std::is_invocable_r_v auto mapFactsAlongsideCallSite(const llvm::CallBase *CallSite, Fn &&PropagateArgs = {}, bool PropagateGlobals = true, @@ -128,9 +127,8 @@ auto mapFactsAlongsideCallSite(const llvm::CallBase *CallSite, /// /// \note Unlike the old version, this one is only meant for forward-analyses template , - typename Fn = std::equal_to, typename DCtor = DefaultConstruct, - typename = std::enable_if_t< - std::is_invocable_r_v>> + typename Fn = std::equal_to, typename DCtor = DefaultConstruct> + requires std::is_invocable_r_v FlowFunctionPtrType mapFactsToCallee(const llvm::CallBase *CallSite, const llvm::Function *DestFun, Fn &&PropagateArgumentWithSource = {}, @@ -236,10 +234,9 @@ mapFactsToCallee(const llvm::CallBase *CallSite, const llvm::Function *DestFun, template < typename D = const llvm::Value *, typename Container = std::set, typename FnParam = std::equal_to, typename FnRet = std::equal_to, - typename DCtor = DefaultConstruct, typename PostProcessFn = IgnoreArgs, - typename = std::enable_if_t< - std::is_invocable_r_v && - std::is_invocable_r_v>> + typename DCtor = DefaultConstruct, typename PostProcessFn = IgnoreArgs> + requires(std::is_invocable_r_v && + std::is_invocable_r_v) FlowFunctionPtrType mapFactsToCaller( const llvm::CallBase *CallSite, const llvm::Instruction *ExitInst, FnParam &&PropagateParameter = {}, FnRet &&PropagateRet = {}, @@ -336,9 +333,8 @@ FlowFunctionPtrType mapFactsToCaller( /// f(b) = {}, /// f(x) = {x, b} if pred(x) else {x}. /// -template , - typename = std::enable_if_t< - std::is_invocable_r_v>> +template > + requires std::is_invocable_r_v FlowFunctionPtrType strongUpdateStore(const llvm::StoreInst *Store, Fn &&GeneratePointerOpIf) { // Here we cheat a bit and "look through" the GetElementPtrInst to the diff --git a/include/phasar/PhasarLLVM/DataFlow/IfdsIde/LLVMSolverResults.h b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/LLVMSolverResults.h index b4f7676f6f..6a9c60e45d 100644 --- a/include/phasar/PhasarLLVM/DataFlow/IfdsIde/LLVMSolverResults.h +++ b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/LLVMSolverResults.h @@ -20,6 +20,8 @@ #include "llvm/IR/IntrinsicInst.h" #include "llvm/Support/ErrorHandling.h" +#include + namespace psr::detail { /// FIXME: This is not entirely correct: Does not skip ignored statements and @@ -27,13 +29,11 @@ namespace psr::detail { /// The right way would be to ask the ICFG, but we don't have a reference to it /// here yet (TODO!) template -template auto SolverResultsBase::resultsAtInLLVMSSA( - ByConstRef Stmt, bool AllowOverapproximation, bool StripZero) const -> - typename std::enable_if_t< - std::is_same_v>, - llvm::Instruction>, - std::unordered_map> { + ByConstRef Stmt, bool AllowOverapproximation, bool StripZero) const + -> std::unordered_map + requires same_as_decay, llvm::Instruction> +{ std::unordered_map Result = [this, Stmt, AllowOverapproximation]() { if (Stmt->getType()->isVoidTy()) { return self().Results.row(Stmt); @@ -99,13 +99,11 @@ auto SolverResultsBase::resultsAtInLLVMSSA( } template -template + auto SolverResultsBase::resultAtInLLVMSSA( - ByConstRef Stmt, d_t Value, bool AllowOverapproximation) const -> - typename std::enable_if_t< - std::is_same_v>, - llvm::Instruction>, - l_t> { + ByConstRef Stmt, d_t Value, bool AllowOverapproximation) const -> l_t + requires same_as_decay, llvm::Instruction> +{ if (Stmt->getType()->isVoidTy()) { return self().Results.get(Stmt, Value); } diff --git a/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IDEExtendedTaintAnalysis.h b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IDEExtendedTaintAnalysis.h index f006c9d54a..d33ebfca72 100644 --- a/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IDEExtendedTaintAnalysis.h +++ b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IDEExtendedTaintAnalysis.h @@ -32,6 +32,7 @@ #include "llvm/IR/Value.h" #include "llvm/Support/Casting.h" +#include #include #include #include @@ -122,10 +123,9 @@ class IDEExtendedTaintAnalysis const llvm::Value *ValueOp, const llvm::Instruction *Store); - template >> void forEachAliasOf(AliasInfoRef::AliasSetPtrTy PTS, - const llvm::Value *Of, CallBack &&CB) { + const llvm::Value *Of, + std::invocable auto &&CB) { if (!HasPreciseAliasInfo) { auto OfFF = makeFlowFact(Of); for (const auto *Alias : *PTS) { diff --git a/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IDEFeatureTaintAnalysis.h b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IDEFeatureTaintAnalysis.h index b021f7b5af..7f3e1ef8dc 100644 --- a/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IDEFeatureTaintAnalysis.h +++ b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IDEFeatureTaintAnalysis.h @@ -241,9 +241,9 @@ class FeatureTaintGenerator { createGenerateTaints(std::forward(EFGen))), Printer(createEdgeFactPrinter()) {} - template >>> + template + requires( + !std::is_same_v>) FeatureTaintGenerator(EdgeFactGenerator &&EFGen) : FeatureTaintGenerator( [EFGen](InstOrGlobal IG) { diff --git a/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IDETypeStateAnalysis.h b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IDETypeStateAnalysis.h index 2ad53bb9a2..390b1e2427 100644 --- a/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IDETypeStateAnalysis.h +++ b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IDETypeStateAnalysis.h @@ -174,9 +174,10 @@ class IDETypeStateAnalysis return AllBottom{TSD->bottom()}; } } - template >> - static AllBottom makeAllBottom(EmptyType /*unused*/) noexcept { + + static AllBottom makeAllBottom(EmptyType /*unused*/) noexcept + requires HasJoinLatticeTraits + { return AllBottom{}; } static bool isBottom(l_t State, const TypeStateDescriptionTy *TSD) noexcept { @@ -186,9 +187,10 @@ class IDETypeStateAnalysis return State == TSD->bottom(); } } - template >> - static bool isBottom(l_t State, EmptyType /*unused*/) noexcept { + + static bool isBottom(l_t State, EmptyType /*unused*/) noexcept + requires HasJoinLatticeTraits + { return State == JoinLatticeTraits::bottom(); } @@ -279,9 +281,8 @@ class IDETypeStateAnalysis } } - template >> TSConstant(l_t Value, EmptyType /*unused*/ = {}) noexcept + requires HasJoinLatticeTraits : ConstantEdgeFunction{Value} {} /// XXX: Cannot default compose() and join(), because l_t does not implement diff --git a/include/phasar/PhasarLLVM/DataFlow/PathSensitivity/Z3BasedPathSensitvityManager.h b/include/phasar/PhasarLLVM/DataFlow/PathSensitivity/Z3BasedPathSensitvityManager.h index b3c79d7032..65fe37dee7 100644 --- a/include/phasar/PhasarLLVM/DataFlow/PathSensitivity/Z3BasedPathSensitvityManager.h +++ b/include/phasar/PhasarLLVM/DataFlow/PathSensitivity/Z3BasedPathSensitvityManager.h @@ -67,9 +67,9 @@ class Z3BasedPathSensitivityManagerBase /// /// Filters out paths that are considered infeasible by the Z3 /// constraint solver. -template >> +template + requires std::is_same_v class Z3BasedPathSensitivityManager : public Z3BasedPathSensitivityManagerBase, public PathSensitivityManagerMixin< diff --git a/include/phasar/PhasarLLVM/Pointer/AliasAnalysisView.h b/include/phasar/PhasarLLVM/Pointer/AliasAnalysisView.h index afdedb5de6..72d416822a 100644 --- a/include/phasar/PhasarLLVM/Pointer/AliasAnalysisView.h +++ b/include/phasar/PhasarLLVM/Pointer/AliasAnalysisView.h @@ -37,10 +37,9 @@ class FunctionAliasView { return Alias(Context, V, Rep, DL); } - template < - typename T, typename AliasFn, - typename = std::enable_if_t && - std::is_default_constructible_v>> + template + requires(std::is_empty_v && + std::is_default_constructible_v) constexpr FunctionAliasView(T *Context, AliasFn /*Alias*/) noexcept : Context(Context), Alias(&callAlias) {} diff --git a/include/phasar/PhasarLLVM/Pointer/FilteredLLVMAliasSet.h b/include/phasar/PhasarLLVM/Pointer/FilteredLLVMAliasSet.h index eef61ca4c2..4a53e9cf59 100644 --- a/include/phasar/PhasarLLVM/Pointer/FilteredLLVMAliasSet.h +++ b/include/phasar/PhasarLLVM/Pointer/FilteredLLVMAliasSet.h @@ -43,6 +43,8 @@ class FilteredLLVMAliasSet : private FilteredLLVMAliasIterator, }; static_assert(std::is_convertible_v); +static_assert( + std::is_convertible_v); } // namespace psr #endif // PHASAR_PHASARLLVM_POINTER_FILTEREDLLVMALIASSET_H diff --git a/include/phasar/PhasarLLVM/TaintConfig/TaintConfigData.h b/include/phasar/PhasarLLVM/TaintConfig/TaintConfigData.h index c9ddc240cd..1b4d446c89 100644 --- a/include/phasar/PhasarLLVM/TaintConfig/TaintConfigData.h +++ b/include/phasar/PhasarLLVM/TaintConfig/TaintConfigData.h @@ -18,10 +18,6 @@ namespace psr { enum class TaintCategory; struct FunctionData { -#if __cplusplus < 202002L - FunctionData() noexcept = default; -#endif - std::string Name; TaintCategory ReturnCat{}; std::vector SourceValues{}; @@ -31,10 +27,6 @@ struct FunctionData { }; struct VariableData { -#if __cplusplus < 202002L - VariableData() noexcept = default; -#endif - size_t Line{}; std::string Name; std::string Scope; diff --git a/include/phasar/PhasarLLVM/TaintConfig/TaintConfigUtilities.h b/include/phasar/PhasarLLVM/TaintConfig/TaintConfigUtilities.h index 543e1e575f..1e0f48e6dd 100644 --- a/include/phasar/PhasarLLVM/TaintConfig/TaintConfigUtilities.h +++ b/include/phasar/PhasarLLVM/TaintConfig/TaintConfigUtilities.h @@ -17,13 +17,13 @@ #include "llvm/IR/Instructions.h" #include +#include #include #include namespace psr { -template >> +template + requires std::is_same_v void collectGeneratedFacts(ContainerTy &Dest, const LLVMTaintConfig &Config, const llvm::CallBase *CB, const llvm::Function *Callee) { @@ -44,12 +44,11 @@ void collectGeneratedFacts(ContainerTy &Dest, const LLVMTaintConfig &Config, } } -template >> +template + requires std::is_same_v void collectLeakedFacts(ContainerTy &Dest, const LLVMTaintConfig &Config, const llvm::CallBase *CB, const llvm::Function *Callee, - Pred &&LeakIf) { + std::invocable auto &&LeakIf) { const auto &Callback = Config.getRegisteredSinkCallBack(); if (Callback) { @@ -66,6 +65,7 @@ void collectLeakedFacts(ContainerTy &Dest, const LLVMTaintConfig &Config, } template + requires std::is_same_v inline void collectLeakedFacts(ContainerTy &Dest, const LLVMTaintConfig &Config, const llvm::CallBase *CB, const llvm::Function *Callee) { @@ -73,9 +73,8 @@ inline void collectLeakedFacts(ContainerTy &Dest, const LLVMTaintConfig &Config, [](const llvm::Value * /*V*/) { return true; }); } -template >> +template + requires std::is_same_v void collectSanitizedFacts(ContainerTy &Dest, const LLVMTaintConfig &Config, const llvm::CallBase *CB, const llvm::Function *Callee) { @@ -88,9 +87,8 @@ void collectSanitizedFacts(ContainerTy &Dest, const LLVMTaintConfig &Config, // ---------------------------------- -template >> +template + requires std::is_same_v [[nodiscard]] ContainerTy getGeneratedFacts(const LLVMTaintConfig &Config, const llvm::CallBase *CB, const llvm::Function *Callee) { @@ -99,20 +97,19 @@ template >> +template + requires std::is_same_v [[nodiscard]] ContainerTy getLeakedFacts(const LLVMTaintConfig &Config, const llvm::CallBase *CB, - const llvm::Function *Callee, Pred &&LeakIf) { + const llvm::Function *Callee, + std::invocable auto &&LeakIf) { ContainerTy Ret; collectLeakedFacts(Ret, Config, CB, Callee, PSR_FWD(LeakIf)); return Ret; } -template >> +template + requires std::is_same_v [[nodiscard]] ContainerTy getLeakedFacts(const LLVMTaintConfig &Config, const llvm::CallBase *CB, const llvm::Function *Callee) { @@ -121,9 +118,8 @@ template >> +template + requires std::is_same_v [[nodiscard]] ContainerTy getSanitizedFacts(const LLVMTaintConfig &Config, const llvm::CallBase *CB, const llvm::Function *Callee) { diff --git a/include/phasar/PhasarLLVM/Utils/BasicBlockOrdering.h b/include/phasar/PhasarLLVM/Utils/BasicBlockOrdering.h index 96e2012d06..cd96301843 100644 --- a/include/phasar/PhasarLLVM/Utils/BasicBlockOrdering.h +++ b/include/phasar/PhasarLLVM/Utils/BasicBlockOrdering.h @@ -42,10 +42,9 @@ class BasicBlockOrdering { getDom; // NOLINT public: - template < - typename DTA, - typename = std::enable_if_t>>>> + template + requires(!std::is_same_v>>) explicit BasicBlockOrdering(DTA &&Dta) : getDom(std::forward(Dta)) {} bool mustComeBefore(const llvm::Instruction *LHS, diff --git a/include/phasar/Pointer/AliasInfo.h b/include/phasar/Pointer/AliasInfo.h index 179a533c5b..bd2daa3314 100644 --- a/include/phasar/Pointer/AliasInfo.h +++ b/include/phasar/Pointer/AliasInfo.h @@ -73,11 +73,10 @@ class [[gsl::Pointer]] AliasInfoRef constexpr AliasInfoRef() noexcept = default; constexpr AliasInfoRef(std::nullptr_t) noexcept : AliasInfoRef() {} - template && - std::is_same_v && - std::is_same_v>> + template + requires(!std::is_base_of_v && + std::is_same_v && + std::is_same_v) constexpr AliasInfoRef(ConcreteAA *AA) noexcept : AA(AA), VT((std::is_empty_v || AA) ? &VTableFor : nullptr) {} diff --git a/include/phasar/Pointer/AliasInfoBase.h b/include/phasar/Pointer/AliasInfoBase.h index b0fff91fc8..0892b92171 100644 --- a/include/phasar/Pointer/AliasInfoBase.h +++ b/include/phasar/Pointer/AliasInfoBase.h @@ -11,15 +11,12 @@ #define PHASAR_POINTER_ALIASINFOBASE_H #include "phasar/Pointer/AliasInfoTraits.h" -#include "phasar/Utils/Macros.h" #include "llvm/Support/raw_ostream.h" #include "nlohmann/json_fwd.hpp" -#include -#include -#include +#include namespace llvm { class Function; @@ -37,45 +34,32 @@ class AliasInfoBaseUtils { static const llvm::Function *retrieveFunction(const llvm::Value *V); }; -namespace detail { - -template -auto testAliasInfo( - T &AI, const T &CAI, - const std::optional::n_t> &NT = {}, - const std::optional::v_t> &VT = {}) - -> decltype(std::make_tuple( - CAI.isInterProcedural(), CAI.getAliasAnalysisType(), - AI.alias(*VT, *VT, *NT), AI.getAliasSet(*VT, *NT), - AI.getReachableAllocationSites(*VT, true, *NT), - AI.isInReachableAllocationSites(*VT, *VT, true, *NT), - CAI.getAnalysisProperties(), CAI.isContextSensitive(), - CAI.isFieldSensitive(), CAI.isFlowSensitive())); -template -struct IsAliasInfo : std::false_type {}; template -struct IsAliasInfo< - T, - std::void_t().print(llvm::outs())), - decltype(std::declval().printAsJson(llvm::outs())), - decltype(std::declval().mergeWith(std::declval())), - decltype(std::declval().introduceAlias( - std::declval::v_t>(), - std::declval::v_t>(), - std::declval::n_t>(), - AliasResult{}))>, - std::enable_if_t::AliasSetPtrTy, - typename AliasInfoTraits::AllocationSiteSetPtrTy, bool, - AnalysisProperties, bool, bool, bool>, - decltype(testAliasInfo(std::declval(), - std::declval()))>>> : std::true_type { -}; - -} // namespace detail +concept IsAliasInfo = + requires(const T &CVal, T &MutVal, typename AliasInfoTraits::v_t Ptr, + typename AliasInfoTraits::n_t Inst) { + CVal.print(llvm::outs()); + CVal.printAsJson(llvm::outs()); + MutVal.mergeWith(MutVal); + MutVal.introduceAlias(Ptr, Ptr, Inst, AliasResult{}); -template PSR_CONCEPT IsAliasInfo = detail::IsAliasInfo::value; + { CVal.isInterProcedural() } -> std::convertible_to; + { CVal.getAliasAnalysisType() } -> std::same_as; + { MutVal.alias(Ptr, Ptr, Inst) } -> std::same_as; + { + MutVal.getAliasSet(Ptr, Inst) + } -> std::same_as::AliasSetPtrTy>; + { + MutVal.getReachableAllocationSites(Ptr, bool{}, Inst) + } -> std::same_as::AllocationSiteSetPtrTy>; + { + MutVal.isInReachableAllocationSites(Ptr, Ptr, bool{}, Inst) + } -> std::convertible_to; + { CVal.getAnalysisProperties() } -> std::same_as; + { CVal.isContextSensitive() } -> std::convertible_to; + { CVal.isFieldSensitive() } -> std::convertible_to; + { CVal.isFlowSensitive() } -> std::convertible_to; + }; } // namespace psr diff --git a/include/phasar/Pointer/AliasIterator.h b/include/phasar/Pointer/AliasIterator.h index 26b744f9c4..1e139c88f0 100644 --- a/include/phasar/Pointer/AliasIterator.h +++ b/include/phasar/Pointer/AliasIterator.h @@ -19,45 +19,37 @@ #include "llvm/ADT/STLFunctionalExtras.h" #include +#include #include namespace psr { namespace detail { -template -struct IsAliasIteratorFor : std::false_type {}; - template -struct IsAliasIteratorFor< - T, V, N, - std::void_t().forallAliasesOf( - std::declval(), std::declval(), - std::declval>()))>> : std::true_type {}; - -template -struct IsAliasIterator - : IsAliasIteratorFor {}; - -template -struct HasAlias : std::false_type {}; +concept IsAliasIteratorFor = + requires(T &AI, V Ptr, N Inst, llvm::function_ref Callback) { + AI.forallAliasesOf(Ptr, Inst, Callback); + }; + template -struct HasAlias().alias( - std::declval(), - std::declval(), - std::declval()))> : std::true_type {}; +concept HasAlias = requires(T &AS, typename T::v_t Ptr, typename T::n_t Inst) { + { AS.alias(Ptr, Ptr, Inst) } -> std::same_as; +}; -template -struct HasGetAliasSet : std::false_type {}; template -struct HasGetAliasSet< - T, std::void_t().getAliasSet( - std::declval(), std::declval()))>> - : std::true_type {}; +concept HasGetAliasSet = + requires(T &AS, typename T::v_t Ptr, typename T::n_t Inst) { + AS.getAliasSet(Ptr, Inst); + }; } // namespace detail template -PSR_CONCEPT IsAliasIterator = detail::IsAliasIterator::value; +concept IsAliasIterator = requires { + typename T::v_t; + typename T::n_t; + requires detail::IsAliasIteratorFor; +}; /// \brief A type-erased reference to any object implementing the /// IsAliasIterator interface. Use this, if your alias-aware analysis just needs @@ -81,21 +73,19 @@ class [[gsl::Pointer]] AliasIteratorRef : private TypeErasureUtils { using ForallAliasesOfFn = void (*)(void *, ByConstRef, ByConstRef, llvm::function_ref); - template && - (detail::IsAliasIteratorFor::value || - detail::HasGetAliasSet::value)>> + template + requires(!std::is_base_of_v && + (detail::IsAliasIteratorFor || + detail::HasGetAliasSet)) constexpr AliasIteratorRef(ConcreteAA *AA) noexcept : AA(getOpaquePtr(psr::assertNotNull(AA))), Fn(TypeErase) { static_assert(IsAliasIterator); } - template && - (detail::IsAliasIteratorFor::value || - detail::HasGetAliasSet::value) && - CanSSO>> + template + requires(!std::is_base_of_v && + (detail::IsAliasIteratorFor || + detail::HasGetAliasSet) && + CanSSO) constexpr AliasIteratorRef(ConcreteAA AA) noexcept : AA(getOpaquePtr(AA)), Fn(TypeErase) { static_assert(IsAliasIterator); @@ -147,7 +137,7 @@ class [[gsl::Pointer]] AliasIteratorRef : private TypeErasureUtils { static void aliasesOfThunk(void *AA, ByConstRef Of, ByConstRef At, llvm::function_ref WithAlias) { auto *CAA = fromOpaquePtr(AA); - if constexpr (detail::IsAliasIteratorFor::value) { + if constexpr (detail::IsAliasIteratorFor) { return (void)CAA->forallAliasesOf(Of, At, WithAlias); } else { auto AliasSetPtr = CAA->getAliasSet(Of, At); diff --git a/include/phasar/Pointer/PointsToInfo.h b/include/phasar/Pointer/PointsToInfo.h index fd29a8e96b..9440f74c2e 100644 --- a/include/phasar/Pointer/PointsToInfo.h +++ b/include/phasar/Pointer/PointsToInfo.h @@ -22,8 +22,8 @@ namespace psr { -template class PointsToInfoRef; -template class PointsToInfo; +template class PointsToInfoRef; +template class PointsToInfo; template struct PointsToTraits> : PTATraits {}; @@ -37,9 +37,8 @@ struct PointsToTraits> : PTATraits {}; /// This is a *non-owning* reference similar to std::string_view and /// llvm::ArrayRef. Pass values of this type by value. /// -template -class PointsToInfoRef>> +template +class PointsToInfoRef : public PointsToInfoBase> { friend class PointsToInfo; friend PointsToInfoBase>; @@ -56,11 +55,8 @@ class PointsToInfoRef && - is_equivalent_PointsToTraits_v>>> + template ConcretePTA> + requires(!std::is_base_of_v) constexpr PointsToInfoRef(const ConcretePTA *PT) noexcept : PT(PT), VT(&VTableFor) { if constexpr (!std::is_empty_v) { @@ -94,9 +90,10 @@ class PointsToInfoRef); }; - template struct VTable : VTableBase {}; + template struct VTable : VTableBase {}; template - struct VTable>> : VTableBase { + requires(!std::is_same_v) + struct VTable : VTableBase { bool (*MayPointsToV)(const void *, ByConstRef, ByConstRef, ByConstRef); PointsToSetPtrTy (*GetPointsToSetV)(const void *, ByConstRef, @@ -114,7 +111,7 @@ class PointsToInfoRef Pointer, ByConstRef At, llvm::function_ref WithPointee) { const auto *CPT = static_cast(PT); - if constexpr (detail::IsPointsToIterator::value) { + if constexpr (IsPointsToIterator) { return (void)CPT->forallPointeesOf(Pointer, At, WithPointee); } else { auto PointsToSet = CPT->getPointsToSet(Pointer, At); @@ -186,11 +183,11 @@ class PointsToInfoRefMayPointsTo(PT, Pointer, Obj, AtInstruction); } - template >> [[nodiscard]] bool mayPointsToImpl(ByConstRef Pointer, ByConstRef Obj, - ByConstRef AtInstruction) const { + ByConstRef AtInstruction) const + requires(!std::is_same_v) + { assert(VT); return VT->MayPointsToV(PT, Pointer, Obj, AtInstruction); } @@ -202,11 +199,11 @@ class PointsToInfoRefGetPointsToSet(PT, Pointer, AtInstruction); } - template >> [[nodiscard]] PointsToSetPtrTy getPointsToSetImpl(ByConstRef Pointer, - ByConstRef AtInstruction) const { + ByConstRef AtInstruction) const + requires(!std::is_same_v) + { assert(VT); return VT->GetPointsToSetV(PT, Pointer, AtInstruction); } @@ -221,10 +218,9 @@ class PointsToInfoRef -class [[clang::trivial_abi]] PointsToInfo< - PTATraits, std::enable_if_t>> - final : public PointsToInfoRef { +template +class [[clang::trivial_abi]] PointsToInfo final + : public PointsToInfoRef { using base_t = PointsToInfoRef; public: diff --git a/include/phasar/Pointer/PointsToInfoBase.h b/include/phasar/Pointer/PointsToInfoBase.h index 0bb22091fb..0a30b2c776 100644 --- a/include/phasar/Pointer/PointsToInfoBase.h +++ b/include/phasar/Pointer/PointsToInfoBase.h @@ -29,21 +29,18 @@ template struct PointsToTraits { // (not necessarily PointsToSetTy const *) }; -template -struct is_PointsToTraits : std::false_type {}; // NOLINT template -struct is_PointsToTraits< - T, std::void_t> - : std::true_type {}; - -template -PSR_CONCEPT is_PointsToTraits_v = // NOLINT - is_PointsToTraits::value; +concept is_PointsToTraits_v = requires { // NOLINT + typename T::v_t; + typename T::n_t; + typename T::o_t; + typename T::PointsToSetTy; + typename T::PointsToSetPtrTy; +}; // clang-format off template -PSR_CONCEPT is_equivalent_PointsToTraits_v = // NOLINT +concept is_equivalent_PointsToTraits_v = // NOLINT is_PointsToTraits_v && is_PointsToTraits_v && std::is_same_v && std::is_same_v && @@ -82,10 +79,10 @@ template class PointsToInfoBase : public CRTPBase { return self().mayPointsToImpl(Pointer, Obj, AtInstruction); } - template >> [[nodiscard]] bool mayPointsTo(ByConstRef Pointer, ByConstRef Obj, - ByConstRef AtInstruction) const { + ByConstRef AtInstruction) const + requires(!std::is_same_v) + { return self().mayPointsToImpl(Pointer, Obj, AtInstruction); } @@ -94,10 +91,10 @@ template class PointsToInfoBase : public CRTPBase { return self().getPointsToSetImpl(Pointer, AtInstruction); } - template >> [[nodiscard]] PointsToSetPtrTy - getPointsToSet(ByConstRef Pointer, ByConstRef AtInstruction) const { + getPointsToSet(ByConstRef Pointer, ByConstRef AtInstruction) const + requires(!std::is_same_v) + { return self().getPointsToSetImpl(Pointer, AtInstruction); } @@ -109,20 +106,20 @@ template class PointsToInfoBase : public CRTPBase { return getPointerFrom(Pts)->count(Obj); } - template >> [[nodiscard]] bool mayPointsToImpl(ByConstRef Pointer, ByConstRef Obj, - ByConstRef AtInstruction) const { + ByConstRef AtInstruction) const + requires(!std::is_same_v) + { return self().mayPointsTo(self().asAbstractObject(Pointer), Obj, AtInstruction); } - template >> [[nodiscard]] PointsToSetPtrTy getPointsToSetImpl(ByConstRef Pointer, - ByConstRef AtInstruction) const { + ByConstRef AtInstruction) const + requires(!std::is_same_v) + { return self().getPointsToSetImpl(asAbstractObject(Pointer), AtInstruction); } }; diff --git a/include/phasar/Pointer/PointsToIterator.h b/include/phasar/Pointer/PointsToIterator.h index 1edc667a60..18f19aa2ba 100644 --- a/include/phasar/Pointer/PointsToIterator.h +++ b/include/phasar/Pointer/PointsToIterator.h @@ -18,61 +18,51 @@ #include "llvm/ADT/STLFunctionalExtras.h" +#include #include #include namespace psr { namespace detail { -template -struct IsPointsToIterator : std::false_type {}; template -struct IsPointsToIterator< - T, std::void_t().forallPointeesOf( - std::declval(), std::declval(), - std::declval>()))>> - : std::true_type {}; - -template -struct HasMayPointsTo : std::false_type {}; -template -struct HasMayPointsTo().mayPointsTo( - std::declval(), - std::declval(), - std::declval()))> - : std::true_type {}; - -template -struct HasGetPointsToSet : std::false_type {}; +concept HasMayPointsTo = + requires(const T &PI, typename T::o_t Obj, typename T::n_t Inst) { + { PI.mayPointsTo(Obj, Obj, Inst) } -> std::convertible_to; + }; + template -struct HasGetPointsToSet().getPointsToSet( - std::declval(), - std::declval()))> - : std::true_type {}; +concept HasGetPointsToSet = + requires(const T &PI, typename T::o_t Obj, typename T::n_t Inst) { + PI.getPointsToSet(Obj, Inst); + }; -template -struct HasAsAbstractObject : std::false_type {}; template -struct HasAsAbstractObject().asAbstractObject( - std::declval()))> - : std::true_type {}; +concept HasAsAbstractObject = requires(const T &PI, typename T::v_t Ptr) { + { PI.asAbstractObject(Ptr) } -> std::convertible_to; +}; -template -struct HasReachableAllocationSites : std::false_type {}; template -struct HasReachableAllocationSites< - T, std::void_t().getReachableAllocationSites( - std::declval(), true, - std::declval())), - decltype(std::declval().isInReachableAllocationSites( - std::declval(), - std::declval(), true, - std::declval()))>> : std::true_type {}; +concept HasReachableAllocationSites = + requires(T &PI, typename T::v_t Ptr, typename T::n_t Inst) { + PI.getReachableAllocationSites(Ptr, bool(), Inst); + { + PI.isInReachableAllocationSites(Ptr, Ptr, bool(), Inst) + } -> std::convertible_to; + }; + +template +concept IsMatchingPTA = std::is_same_v && + std::is_same_v && + std::is_same_v; } // namespace detail template -PSR_CONCEPT IsPointsToIterator = detail::IsPointsToIterator::value; +concept IsPointsToIterator = + requires(const T &PI, typename T::o_t Obj, typename T::n_t Inst, + llvm::function_ref Callback) { + PI.forallPointeesOf(Obj, Inst, Callback); + }; /// A type-erased reference to any object implementing the IsPointsToIterator /// interface. Use this, if your alias-aware analysis just needs @@ -100,44 +90,33 @@ class [[gsl::Pointer]] PointsToIteratorRef : protected TypeErasureUtils { void (*Destroy)(const void *) noexcept; // Useful for the owning variant }; - template < - typename ConcretePTA, - std::enable_if_t && - std::is_same_v && - std::is_same_v && - std::is_same_v && - !detail::HasReachableAllocationSites::value> - * = nullptr> + template ConcretePTA> + requires(!std::is_base_of_v && + !detail::HasReachableAllocationSites) constexpr PointsToIteratorRef(const ConcretePTA *PT) noexcept : PT(getOpaquePtr(psr::assertNotNull(PT))), VT(&VTableFor) { static_assert(IsPointsToIterator); } - template < - typename ConcretePTA, - std::enable_if_t && - std::is_same_v && - std::is_same_v && - std::is_same_v && - !std::is_const_v && // Need non-const API - detail::HasReachableAllocationSites::value> - * = nullptr> + template + requires(!std::is_base_of_v && + std::is_same_v && + std::is_same_v && + std::is_same_v && + !std::is_const_v && // Need non-const API + detail::HasReachableAllocationSites) constexpr PointsToIteratorRef(ConcretePTA *PT) noexcept : PT(getOpaquePtr(psr::assertNotNull(PT))), VT(&ReachableAllocSitesVTFor) { static_assert(IsPointsToIterator); } - template && - std::is_same_v && - std::is_same_v && - std::is_same_v && - CanSSO>> + template ConcretePTA> + requires(!std::is_base_of_v && + CanSSO) constexpr PointsToIteratorRef(ConcretePTA PT) noexcept : PT(getOpaquePtr(PT)), VT(&VTableFor) { - static_assert(detail::IsPointsToIterator::value); + static_assert(IsPointsToIterator); } constexpr explicit PointsToIteratorRef(const void *PT, @@ -181,12 +160,12 @@ class [[gsl::Pointer]] PointsToIteratorRef : protected TypeErasureUtils { template static o_t asAbstractObjectThunk(const void *PT, ByConstRef Pointer) noexcept { - if constexpr (detail::HasAsAbstractObject::value) { + if constexpr (detail::HasAsAbstractObject) { return fromOpaquePtr(PT)->asAbstractObject(Pointer); } else if constexpr (std::is_convertible_v) { return Pointer; } else { - static_assert(detail::HasAsAbstractObject::value); + static_assert(detail::HasAsAbstractObject); } } @@ -230,9 +209,9 @@ class [[gsl::Pointer]] PointsToIteratorRef : protected TypeErasureUtils { static bool mayPointsToThunk(const void *PT, ByConstRef Pointer, ByConstRef Obj, ByConstRef At) { const auto *CPT = fromOpaquePtr(PT); - if constexpr (detail::HasMayPointsTo::value) { + if constexpr (detail::HasMayPointsTo) { return CPT->mayPointsTo(Pointer, Obj, At); - } else if constexpr (detail::HasGetPointsToSet::value) { + } else if constexpr (detail::HasGetPointsToSet) { auto &&PointsToSet = CPT->getPointsToSet(Pointer, At); // The PointsToSet can be a set or a pointer to a set auto *PointsToSetPtr = getPointerFrom(PointsToSet); @@ -332,15 +311,15 @@ class [[clang::trivial_abi, gsl::Owner]] PointsToIterator } } - template >> + template + requires(!base_t::template CanSSO) constexpr explicit PointsToIterator( std::in_place_type_t /*unused*/, ArgTys &&...Args) : PointsToIterator( std::make_unique(std::forward(Args)...)) {} - template >> + template + requires(base_t::template CanSSO) constexpr explicit PointsToIterator( std::in_place_type_t /*unused*/, ArgTys &&...Args) : base_t([&] { diff --git a/include/phasar/Utils/AdjacencyList.h b/include/phasar/Utils/AdjacencyList.h index 185fdc6556..8e0c27e7d7 100644 --- a/include/phasar/Utils/AdjacencyList.h +++ b/include/phasar/Utils/AdjacencyList.h @@ -26,6 +26,8 @@ namespace psr { +// TODO: concept-ify AdjacencyList: Wait for #794 to be merged, as it adds major +// changes here template struct AdjacencyList { TypedVector Nodes{}; @@ -56,9 +58,10 @@ struct GraphTraits> { /// Adds a new node to the graph G with node-tag Val /// /// \returns The vertex-descriptor for the newly created node - template >> - static constexpr vertex_t addNode(graph_type &G, TT &&Val) { + template + static constexpr vertex_t addNode(graph_type &G, TT &&Val) + requires(!std::is_empty_v) + { assert(G.Adj.size() == G.Nodes.size()); auto Ret = vertex_t(G.Nodes.size()); @@ -68,11 +71,9 @@ struct GraphTraits> { } /// Adds a new node to the graph G without node-tag - /// - /// \returns The vertex-descriptor for the newly created node - template >> - static constexpr vertex_t addNode(graph_type &G, value_type /*Val*/ = {}) { + static constexpr vertex_t addNode(graph_type &G, value_type /*Val*/ = {}) + requires std::is_empty_v + { auto Ret = vertex_t(G.Adj.size()); G.Adj.emplace_back(); return Ret; @@ -152,24 +153,24 @@ struct GraphTraits> { } /// Gets a const range of all nodes in graph G - template >> - static constexpr const auto &nodes(const graph_type &G) noexcept { + static constexpr const auto &nodes(const graph_type &G) noexcept + requires(!std::is_empty_v) + { assert(G.Adj.size() == G.Nodes.size()); return G.Nodes; } /// Gets a mutable range of all nodes in graph G - template >> - static constexpr auto &nodes(graph_type &G) noexcept { + static constexpr auto &nodes(graph_type &G) noexcept + requires(!std::is_empty_v) + { assert(G.Adj.size() == G.Nodes.size()); return G.Nodes; } /// Gets a range of all nodes in graph G - template >> static constexpr RepeatRangeType - nodes(const graph_type &G) noexcept { + nodes(const graph_type &G) noexcept + requires std::is_empty_v + { return repeat(value_type{}, G.Adj.size()); } @@ -182,28 +183,28 @@ struct GraphTraits> { } /// Gets the node-tag for node Vtx in graph G. Vtx must be part of G - template >> static constexpr const value_type &node(const graph_type &G, - vertex_t Vtx) noexcept { + vertex_t Vtx) noexcept + requires(!std::is_empty_v) + { assert(G.Adj.inbounds(Vtx)); assert(G.Adj.size() == G.Nodes.size()); return G.Nodes[Vtx]; } /// Gets the node-tag for node Vtx in graph G. Vtx must be part of G - template >> - static constexpr value_type &node(graph_type &G, vertex_t Vtx) noexcept { + static constexpr value_type &node(graph_type &G, vertex_t Vtx) noexcept + requires(!std::is_empty_v) + { assert(G.Adj.inbounds(Vtx)); assert(G.Adj.size() == G.Nodes.size()); return G.Nodes[Vtx]; } /// Gets the node-tag for node Vtx in graph G. Vtx must be part of G - template >> static constexpr value_type node([[maybe_unused]] const graph_type &G, - [[maybe_unused]] vertex_t Vtx) noexcept { + [[maybe_unused]] vertex_t Vtx) noexcept + requires std::is_empty_v + { assert(G.Adj.inbounds(Vtx)); return {}; } @@ -251,8 +252,9 @@ struct GraphTraits> { /// Gets the vertex-descriptor of the target-node of the given Edge template - static constexpr std::enable_if_t, vertex_t> - target(edge_t Edge) noexcept { + static constexpr vertex_t target(edge_t Edge) noexcept + requires std::is_same_v + { return Edge; } @@ -260,8 +262,9 @@ struct GraphTraits> { /// weight of the returned edge and the parameter edge is same, but the target /// nodes may differ. template - static constexpr std::enable_if_t, edge_t> - withEdgeTarget(edge_t /*edge*/, vertex_t Tar) noexcept { + static constexpr edge_t withEdgeTarget(edge_t /*edge*/, vertex_t Tar) noexcept + requires std::is_same_v + { return Tar; } diff --git a/include/phasar/Utils/AnalysisPrinterBase.h b/include/phasar/Utils/AnalysisPrinterBase.h index 57ee963d9d..f7689d20a5 100644 --- a/include/phasar/Utils/AnalysisPrinterBase.h +++ b/include/phasar/Utils/AnalysisPrinterBase.h @@ -25,9 +25,10 @@ template class AnalysisPrinterBase { doOnResult(Instr, PSR_FWD(DfFact), PSR_FWD(LatticeElement), AnalysisType); } - template - std::enable_if_t> - onResult(n_t Instr, D &&DfFact, DataFlowAnalysisType AnalysisType) { + template + void onResult(n_t Instr, D &&DfFact, DataFlowAnalysisType AnalysisType) + requires std::is_same_v + { doOnResult(Instr, PSR_FWD(DfFact), psr::BinaryDomain::BOTTOM, AnalysisType); } diff --git a/include/phasar/Utils/BitSet.h b/include/phasar/Utils/BitSet.h index d56cd8308e..b49e1d647e 100644 --- a/include/phasar/Utils/BitSet.h +++ b/include/phasar/Utils/BitSet.h @@ -15,6 +15,7 @@ #include "llvm/Support/MathExtras.h" #include +#include #include #include #include @@ -180,9 +181,8 @@ template class BitSet { /// Calls the given handler function for each sert bit in the bitset. /// /// This is likely faster than using iterators. - template - std::enable_if_t> foreach ( - HandlerFn Handler) const + template HandlerFn> + void foreach (HandlerFn Handler) const noexcept(std::is_nothrow_invocable_v) { uintptr_t Store{}; auto Words = getWords(Bits, Store); diff --git a/include/phasar/Utils/ByRef.h b/include/phasar/Utils/ByRef.h index e36d7a0364..a713344474 100644 --- a/include/phasar/Utils/ByRef.h +++ b/include/phasar/Utils/ByRef.h @@ -17,7 +17,7 @@ namespace psr { template -PSR_CONCEPT CanEfficientlyPassByValue = +concept CanEfficientlyPassByValue = sizeof(T) <= 2 * sizeof(void *) && std::is_trivially_copyable_v; template diff --git a/include/phasar/Utils/Compressor.h b/include/phasar/Utils/Compressor.h index 883e214fd5..c67f54aa11 100644 --- a/include/phasar/Utils/Compressor.h +++ b/include/phasar/Utils/Compressor.h @@ -24,15 +24,15 @@ #include namespace psr { -template -class Compressor; +template class Compressor; /// \brief A utility class that assigns a sequential Id to every inserted /// object. /// /// This specialization handles types that can be efficiently passed by value template -class Compressor>> { + requires CanEfficientlyPassByValue +class Compressor { public: void reserve(size_t Capacity) { assert(Capacity <= UINT32_MAX); @@ -105,7 +105,8 @@ class Compressor>> { /// /// This specialization handles types that cannot be efficiently passed by value template -class Compressor>> { + requires(!CanEfficientlyPassByValue) +class Compressor { public: void reserve(size_t Capacity) { assert(Capacity <= UINT32_MAX); diff --git a/include/phasar/Utils/DFAMinimizer.h b/include/phasar/Utils/DFAMinimizer.h index 9c08a3b7cc..acc40bcc41 100644 --- a/include/phasar/Utils/DFAMinimizer.h +++ b/include/phasar/Utils/DFAMinimizer.h @@ -20,13 +20,9 @@ namespace psr { -template +template [[nodiscard]] std::decay_t -createEquivalentGraphFrom(GraphTy &&G, const llvm::IntEqClasses &Eq) -#if __cplusplus >= 202002L - requires is_graph -#endif -{ +createEquivalentGraphFrom(GraphTy &&G, const llvm::IntEqClasses &Eq) { using traits_t = GraphTraits; using vertex_t = typename traits_t::vertex_t; @@ -83,12 +79,8 @@ createEquivalentGraphFrom(GraphTy &&G, const llvm::IntEqClasses &Eq) return Ret; } -template -[[nodiscard]] llvm::IntEqClasses minimizeGraph(const GraphTy &G) -#if __cplusplus >= 202002L - requires is_graph -#endif -{ +template +[[nodiscard]] llvm::IntEqClasses minimizeGraph(const GraphTy &G) { using traits_t = GraphTraits; using vertex_t = typename traits_t::vertex_t; diff --git a/include/phasar/Utils/DefaultValue.h b/include/phasar/Utils/DefaultValue.h index e63b10018a..223fe0be78 100644 --- a/include/phasar/Utils/DefaultValue.h +++ b/include/phasar/Utils/DefaultValue.h @@ -20,8 +20,8 @@ namespace psr { /// is small and trivially default constructible, creates a temporary instead. /// Useful for getters that return ByConstRef but need to handle the /// non-existing-T case -template >> +template + requires std::is_default_constructible_v [[nodiscard]] ByConstRef getDefaultValue() noexcept(std::is_nothrow_default_constructible_v) { auto DefaultConstruct = [] { @@ -42,14 +42,12 @@ getDefaultValue() noexcept(std::is_nothrow_default_constructible_v) { namespace detail { struct DefaultCast { - template >> - operator To() && { + template operator To() && { return psr::getDefaultValue(); } - template >> + template + requires(!CanEfficientlyPassByValue) operator const To &() && { return psr::getDefaultValue(); } diff --git a/include/phasar/Utils/EmptyBaseOptimizationUtils.h b/include/phasar/Utils/EmptyBaseOptimizationUtils.h index a592780bff..ab936b124f 100644 --- a/include/phasar/Utils/EmptyBaseOptimizationUtils.h +++ b/include/phasar/Utils/EmptyBaseOptimizationUtils.h @@ -30,32 +30,22 @@ template struct DummyPair { [[nodiscard]] auto getHashCode() const noexcept { return std::hash{}(first); } - template - friend std::enable_if_t, bool> + + friend bool operator==(DummyPair LHS, - DummyPair RHS) noexcept(noexcept(LHS.first == RHS.first)) { + DummyPair RHS) noexcept(noexcept(LHS.first == RHS.first)) + requires CanEfficientlyPassByValue + { return LHS.first == RHS.first; } - template - friend std::enable_if_t, bool> + friend bool operator==(const DummyPair &LHS, - const DummyPair &RHS) noexcept(noexcept(LHS.first == RHS.first)) { + const DummyPair &RHS) noexcept(noexcept(LHS.first == RHS.first)) + requires(!CanEfficientlyPassByValue) + { return LHS.first == RHS.first; } - - template - friend std::enable_if_t, bool> - operator!=(DummyPair LHS, DummyPair RHS) noexcept(noexcept(LHS == RHS)) { - return !(LHS == RHS); - } - - template - friend std::enable_if_t, bool> - operator!=(const DummyPair &LHS, - const DummyPair &RHS) noexcept(noexcept(LHS == RHS)) { - return !(LHS == RHS); - } }; } // namespace psr diff --git a/include/phasar/Utils/EnumFlags.h b/include/phasar/Utils/EnumFlags.h index b02c25a347..072caaa1b8 100644 --- a/include/phasar/Utils/EnumFlags.h +++ b/include/phasar/Utils/EnumFlags.h @@ -14,8 +14,12 @@ namespace psr { -template >> -struct EnumFlagAutoBool { +namespace detail { +template +concept is_enum = std::is_enum_v; +} // namespace detail + +template struct EnumFlagAutoBool { T Value; constexpr operator T() const noexcept { return Value; } @@ -24,53 +28,46 @@ struct EnumFlagAutoBool { } }; -template >> +template constexpr EnumFlagAutoBool operator&(T Lhs, T Rhs) noexcept { return {static_cast(static_cast>(Lhs) & static_cast>(Rhs))}; } -template >> -constexpr void operator&=(T &Lhs, T Rhs) noexcept { +template constexpr void operator&=(T &Lhs, T Rhs) noexcept { Lhs = Lhs & Rhs; } -template >> -constexpr T operator|(T Lhs, T Rhs) noexcept { +template constexpr T operator|(T Lhs, T Rhs) noexcept { return static_cast(static_cast>(Lhs) | static_cast>(Rhs)); } -template >> -constexpr void operator|=(T &Lhs, T Rhs) noexcept { +template constexpr void operator|=(T &Lhs, T Rhs) noexcept { Lhs = Lhs | Rhs; } -template >> -constexpr T operator^(T Lhs, T Rhs) noexcept { +template constexpr T operator^(T Lhs, T Rhs) noexcept { return static_cast(static_cast>(Lhs) ^ static_cast>(Rhs)); } -template >> -constexpr void operator^=(T &Lhs, T Rhs) noexcept { +template constexpr void operator^=(T &Lhs, T Rhs) noexcept { Lhs = Lhs ^ Rhs; } -template >> -constexpr T operator~(T Rhs) noexcept { +template constexpr T operator~(T Rhs) noexcept { return static_cast(~static_cast>(Rhs)); } -template >> -constexpr void setFlag(T &This, T Flag) noexcept { +template constexpr void setFlag(T &This, T Flag) noexcept { This |= Flag; } -template >> +template constexpr void unsetFlag(T &This, T Flag) noexcept { This &= ~Flag; } -template >> +template constexpr void setFlag(T &This, T Flag, bool Set) noexcept { if (Set) { setFlag(This, Flag); @@ -79,8 +76,7 @@ constexpr void setFlag(T &This, T Flag, bool Set) noexcept { } } -template >> -constexpr bool hasFlag(T This, T Flag) noexcept { +template constexpr bool hasFlag(T This, T Flag) noexcept { return (This & Flag) == Flag; } } // namespace psr diff --git a/include/phasar/Utils/ErrorHandling.h b/include/phasar/Utils/ErrorHandling.h index 93dfacf2c4..686e7afbaa 100644 --- a/include/phasar/Utils/ErrorHandling.h +++ b/include/phasar/Utils/ErrorHandling.h @@ -38,8 +38,8 @@ std::optional getOrNull(llvm::ErrorOr ValOrErr) noexcept( return std::nullopt; } -template >> +template + requires std::is_default_constructible_v T getOrEmpty(llvm::ErrorOr ValOrErr) noexcept( std::is_nothrow_move_constructible_v) { if (ValOrErr) { diff --git a/include/phasar/Utils/GraphTraits.h b/include/phasar/Utils/GraphTraits.h index dd083a246f..a0c2af5c22 100644 --- a/include/phasar/Utils/GraphTraits.h +++ b/include/phasar/Utils/GraphTraits.h @@ -16,9 +16,7 @@ #include "llvm/ADT/StringRef.h" #include "llvm/Support/raw_ostream.h" -#if __cplusplus >= 202002L #include -#endif #include #include #include @@ -32,8 +30,6 @@ namespace psr { /// concepts template struct GraphTraits; -#if __cplusplus >= 202002L - template concept is_graph_edge = requires(const Edge E1, Edge E2) { { E1 == E2 } -> std::convertible_to; @@ -154,53 +150,7 @@ concept is_removable_graph_trait_v = { GraphTrait::removeRoot(G, RootIt) }; }; -#else -namespace detail { -template -// NOLINTNEXTLINE(readability-identifier-naming) -struct is_reservable_graph_trait : std::false_type {}; -template -struct is_reservable_graph_trait< - GraphTrait, - std::void_t(), size_t()))>> - : std::true_type {}; - -template -// NOLINTNEXTLINE(readability-identifier-naming) -struct is_removable_graph_trait : std::false_type {}; -template -struct is_removable_graph_trait< - GraphTrait, - std::void_t(), - std::declval(), - std::declval())), - decltype(GraphTrait::removeRoot( - std::declval(), - std::declval()))>> - : std::true_type {}; -} // namespace detail - -template -// NOLINTNEXTLINE(readability-identifier-naming) -static constexpr bool is_reservable_graph_trait_v = - detail::is_reservable_graph_trait::value; - -template -// NOLINTNEXTLINE(readability-identifier-naming) -static constexpr bool is_removable_graph_trait_v = - detail::is_removable_graph_trait::value; -#endif - -template -std::decay_t reverseGraph(GraphTy &&G) -#if __cplusplus >= 202002L - requires is_graph -#endif -{ +template std::decay_t reverseGraph(GraphTy &&G) { std::decay_t Ret; using traits_t = GraphTraits>; if constexpr (is_reservable_graph_trait_v) { @@ -239,13 +189,9 @@ struct DefaultNodeTransform { /// \param Name The name of the graph /// \param NodeToString If the graph has node-labels, convert a node-label to /// string -template +template void printGraph(const GraphTy &G, llvm::raw_ostream &OS, - llvm::StringRef Name = "", NodeTransform NodeToString = {}) -#if __cplusplus >= 202002L - requires is_const_graph -#endif -{ + llvm::StringRef Name = "", NodeTransform NodeToString = {}) { using traits_t = GraphTraits; OS << "digraph \""; diff --git a/include/phasar/Utils/JoinLattice.h b/include/phasar/Utils/JoinLattice.h index bfb0f0b02d..27d5069dea 100644 --- a/include/phasar/Utils/JoinLattice.h +++ b/include/phasar/Utils/JoinLattice.h @@ -19,6 +19,7 @@ #include "phasar/Utils/Macros.h" +#include #include #include @@ -30,22 +31,14 @@ template struct JoinLatticeTraits { // static L join(L LHS, L RHS); }; -namespace detail { -template -struct HasJoinLatticeTraitsHelper : std::false_type {}; template -struct HasJoinLatticeTraitsHelper< - L, std::enable_if_t< - std::is_convertible_v::top()), L> && - std::is_convertible_v::bottom()), L> && - std::is_convertible_v::join( - std::declval(), std::declval())), - L>>> : std::true_type {}; -} // namespace detail -template -PSR_CONCEPT HasJoinLatticeTraits = detail::HasJoinLatticeTraitsHelper::value; +concept HasJoinLatticeTraits = requires(const L &Val) { + { JoinLatticeTraits::top() } -> std::convertible_to; + { JoinLatticeTraits::bottom() } -> std::convertible_to; + { JoinLatticeTraits::join(Val, Val) } -> std::convertible_to; +}; -template class JoinLattice { +template class JoinLattice { public: using l_t = typename AnalysisDomainTy::l_t; @@ -56,9 +49,8 @@ template class JoinLattice { }; template -class JoinLattice< - AnalysisDomainTy, - std::enable_if_t>> { + requires HasJoinLatticeTraits +class JoinLattice { public: using l_t = typename AnalysisDomainTy::l_t; @@ -70,7 +62,7 @@ class JoinLattice< }; }; -template struct NonTopBotValue { +template struct NonTopBotValue { using type = L; static L unwrap(L Value) noexcept(std::is_nothrow_move_constructible_v) { diff --git a/include/phasar/Utils/Macros.h b/include/phasar/Utils/Macros.h index 9d089bc4f8..710cd0cff7 100644 --- a/include/phasar/Utils/Macros.h +++ b/include/phasar/Utils/Macros.h @@ -12,19 +12,9 @@ #define PSR_FWD(...) ::std::forward(__VA_ARGS__) -#if __cplusplus < 202002L -#define PSR_CONCEPT static constexpr bool -#else #define PSR_CONCEPT concept -#endif -#if __cpp_constinit >= 201907L #define PSR_CONSTINIT constinit -#elif __clang__ -#define PSR_CONSTINIT [[clang::require_constant_initialization]] -#else -#define PSR_CONSTINIT -#endif #ifndef __has_feature #define __has_feature(x) 0 diff --git a/include/phasar/Utils/MapUtils.h b/include/phasar/Utils/MapUtils.h index c087aaa0ee..f57f352dd5 100644 --- a/include/phasar/Utils/MapUtils.h +++ b/include/phasar/Utils/MapUtils.h @@ -21,8 +21,8 @@ namespace psr { -template >> +template + requires std::is_lvalue_reference_v static auto getOrDefault(MapT &&Map, KeyT &&Key) -> ByConstRef< llvm::remove_cvref_tsecond)>> { auto It = Map.find(PSR_FWD(Key)); @@ -33,11 +33,9 @@ static auto getOrDefault(MapT &&Map, KeyT &&Key) -> ByConstRef< return It->second; } -template < - typename MapT, typename KeyT, - typename = std::enable_if_t>, - std::enable_if_t< - !psr::CanEfficientlyPassByValue>, int> = 0> +template + requires(std::is_lvalue_reference_v && + !psr::CanEfficientlyPassByValue>) static auto getOrNull(MapT &&Map, KeyT &&Key) -> decltype(&Map.find(PSR_FWD(Key))->second) { auto It = Map.find(PSR_FWD(Key)); @@ -49,11 +47,9 @@ static auto getOrNull(MapT &&Map, KeyT &&Key) return Ret; } -template < - typename MapT, typename KeyT, - typename = std::enable_if_t>, - std::enable_if_t>, - int> = 0> +template + requires(std::is_lvalue_reference_v && + psr::CanEfficientlyPassByValue>) static auto getOrNull(MapT &&Map, KeyT Key) -> decltype(&Map.find(Key)->second) { auto It = Map.find(Key); diff --git a/include/phasar/Utils/MaybeUniquePtr.h b/include/phasar/Utils/MaybeUniquePtr.h index 4e50f2304f..11c55553cd 100644 --- a/include/phasar/Utils/MaybeUniquePtr.h +++ b/include/phasar/Utils/MaybeUniquePtr.h @@ -73,9 +73,8 @@ class [[clang::trivial_abi]] MaybeUniquePtr constexpr MaybeUniquePtr(std::unique_ptr &&Owner) noexcept : MaybeUniquePtr(Owner.release(), true) {} - template && - std::is_convertible_v>> + template + requires(!std::is_same_v && std::is_convertible_v) constexpr MaybeUniquePtr(std::unique_ptr &&Owner) noexcept : MaybeUniquePtr(Owner.release(), true) {} @@ -107,9 +106,8 @@ class [[clang::trivial_abi]] MaybeUniquePtr return *this; } - template && - std::is_convertible_v>> + template + requires(!std::is_same_v && std::is_convertible_v) constexpr MaybeUniquePtr &operator=(std::unique_ptr &&Owner) noexcept { if (owns()) { delete Data.getPointer(); @@ -122,10 +120,7 @@ class [[clang::trivial_abi]] MaybeUniquePtr MaybeUniquePtr(const MaybeUniquePtr &) = delete; MaybeUniquePtr &operator=(const MaybeUniquePtr &) = delete; -#if __cplusplus >= 202002L - constexpr -#endif - ~MaybeUniquePtr() { + constexpr ~MaybeUniquePtr() { if (owns()) { delete Data.getPointer(); Data = {}; diff --git a/include/phasar/Utils/Nullable.h b/include/phasar/Utils/Nullable.h index 829db85eab..f2ff726b30 100644 --- a/include/phasar/Utils/Nullable.h +++ b/include/phasar/Utils/Nullable.h @@ -21,23 +21,23 @@ using Nullable = std::conditional_t, T, std::optional>; template -std::enable_if_t, T &&> -unwrapNullable(T &&Val) noexcept { + requires std::is_convertible_v +T &&unwrapNullable(T &&Val) noexcept { return std::forward(Val); } template -std::enable_if_t, T> -unwrapNullable(std::optional &&Val) noexcept { + requires(!std::is_convertible_v) +T unwrapNullable(std::optional &&Val) noexcept { return *std::move(Val); } template -std::enable_if_t, const T &> -unwrapNullable(const std::optional &Val) noexcept { + requires(!std::is_convertible_v) +const T &unwrapNullable(const std::optional &Val) noexcept { return *Val; } template -std::enable_if_t, T &> -unwrapNullable(std::optional &Val) noexcept { + requires(!std::is_convertible_v) +T &unwrapNullable(std::optional &Val) noexcept { return *Val; } } // namespace psr diff --git a/include/phasar/Utils/PointerUtils.h b/include/phasar/Utils/PointerUtils.h index 88da749b84..e930ad5f73 100644 --- a/include/phasar/Utils/PointerUtils.h +++ b/include/phasar/Utils/PointerUtils.h @@ -15,18 +15,18 @@ namespace psr { /// in generic code. This overload set is extendable. template -constexpr std::enable_if_t, T *> -getPointerFrom(T &Ref) noexcept { + requires(!std::is_pointer_v) +constexpr T *getPointerFrom(T &Ref) noexcept { return std::addressof(Ref); } template -constexpr std::enable_if_t, const T *> -getPointerFrom(const T &Ref) noexcept { + requires(!std::is_pointer_v) +constexpr const T *getPointerFrom(const T &Ref) noexcept { return std::addressof(Ref); } template -constexpr std::enable_if_t, T *> -getPointerFrom(T &&Ref) noexcept = delete; + requires(!std::is_pointer_v) +constexpr T *getPointerFrom(T &&Ref) noexcept = delete; template T *getPointerFrom(T *Ptr) noexcept { return Ptr; } template diff --git a/include/phasar/Utils/Printer.h b/include/phasar/Utils/Printer.h index 76cb2e5e55..20aa9f722e 100644 --- a/include/phasar/Utils/Printer.h +++ b/include/phasar/Utils/Printer.h @@ -27,7 +27,7 @@ class Function; namespace psr { namespace detail { template -PSR_CONCEPT IsSomehowPrintable = +concept IsSomehowPrintable = has_str_v || is_llvm_printable_v || has_adl_to_string_v; template decltype(auto) printSomehow(const T &Val) { @@ -51,8 +51,7 @@ template decltype(auto) printSomehow(const T &Val) { /// /// Default implementation. Provide your own overload to customize this API for /// your types -template >> +template [[nodiscard]] decltype(auto) NToString(const N &Node) { return detail::printSomehow(Node); } @@ -61,8 +60,7 @@ template >> +template [[nodiscard]] decltype(auto) DToString(const D &Fact) { return detail::printSomehow(Fact); } @@ -71,8 +69,7 @@ template >> +template [[nodiscard]] decltype(auto) LToString(const L &Value) { return detail::printSomehow(Value); } @@ -81,8 +78,7 @@ template >> +template [[nodiscard]] std::string FToString(const F &Fun) { return detail::printSomehow(Fun); } diff --git a/include/phasar/Utils/RepeatIterator.h b/include/phasar/Utils/RepeatIterator.h index 94245930a1..f3dd643bb6 100644 --- a/include/phasar/Utils/RepeatIterator.h +++ b/include/phasar/Utils/RepeatIterator.h @@ -55,8 +55,7 @@ template class RepeatIterator { return !(*this == Other); } - template >>> + template TT> explicit RepeatIterator(TT &&Elem) : Elem(std::forward(Elem)) {} explicit RepeatIterator(size_t Index, std::true_type /*AsEndIterator*/) : Index(Index), Elem(std::nullopt) {} diff --git a/include/phasar/Utils/SCCGeneric.h b/include/phasar/Utils/SCCGeneric.h index c0efe5d5fd..9c31d325d0 100644 --- a/include/phasar/Utils/SCCGeneric.h +++ b/include/phasar/Utils/SCCGeneric.h @@ -40,9 +40,10 @@ struct SCCIdBase { explicit constexpr SCCIdBase(uint32_t Val) noexcept : Value(Val) {} explicit constexpr operator uint32_t() const noexcept { return Value; } - template >> - explicit constexpr operator size_t() const noexcept { + template + explicit constexpr operator size_t() const noexcept + requires(!std::is_same_v) + { return Value; } @@ -109,13 +110,8 @@ template struct SCCHolder { /// \param Name The name of the graph /// \param NodeToString If the graph has node-labels, convert a node-label to /// string - template ::vertex_t, GraphNodeId>, - int> = 0> -#if __cplusplus >= 202002L - requires is_const_graph -#endif + template + requires std::is_same_v::vertex_t, GraphNodeId> void print(const G &Graph, llvm::raw_ostream &OS, llvm::StringRef Name = "", NodeTransform NodeToString = {}) const { OS << "digraph \""; diff --git a/include/phasar/Utils/StableVector.h b/include/phasar/Utils/StableVector.h index 8406bea98a..21b1c7f704 100644 --- a/include/phasar/Utils/StableVector.h +++ b/include/phasar/Utils/StableVector.h @@ -105,16 +105,19 @@ class StableVector { } Iterator(const Iterator &) noexcept = default; - template > - Iterator(const Iterator &Other) noexcept + + Iterator(const Iterator &Other) noexcept + requires IsConst : It(Other.It), ItEnd(Other.ItEnd), Outer(Other.Outer), OuterEnd(Other.OuterEnd), Total(Other.Total), Pos(Other.Pos) {} ~Iterator() = default; Iterator &operator=(const Iterator &) noexcept = default; - template > - Iterator &operator=(const Iterator &Other) noexcept { + + Iterator &operator=(const Iterator &Other) noexcept + requires IsConst + { new (this) Iterator(Other); return *this; } diff --git a/include/phasar/Utils/TableWrappers.h b/include/phasar/Utils/TableWrappers.h index 18accb1b17..d836a762f7 100644 --- a/include/phasar/Utils/TableWrappers.h +++ b/include/phasar/Utils/TableWrappers.h @@ -82,27 +82,27 @@ template class UnorderedTable1d { return Map.try_emplace(std::move(Key), std::move(Value)); } - template >> - V getOr(ByConstRef Key, V Or) const { + V getOr(ByConstRef Key, V Or) const + requires CanEfficientlyPassByValue + { if (auto It = Map.find(Key); It != Map.end()) { return It->second; } return Or; } - template >> - const V &getOr(ByConstRef Key, const V &Or) const { + const V &getOr(ByConstRef Key, const V &Or) const + requires(!CanEfficientlyPassByValue) + { if (auto It = Map.find(Key); It != Map.end()) { return It->second; } return Or; } - template >> - const V &getOr(ByConstRef Key, V &&Or) const = delete; + const V &getOr(ByConstRef Key, V &&Or) const + requires(!CanEfficientlyPassByValue) + = delete; const_iterator find(ByConstRef Key) const { return Map.find(Key); } @@ -288,27 +288,27 @@ template class DummyUnorderedTable1d { return Value; } - template >> - V getOr(ByConstRef Key, V Or) const { + V getOr(ByConstRef Key, V Or) const + requires CanEfficientlyPassByValue + { if (Map.count(Key)) { return Value; } return Or; } - template >> - const V &getOr(ByConstRef Key, const V &Or) const { + const V &getOr(ByConstRef Key, const V &Or) const + requires(!CanEfficientlyPassByValue) + { if (Map.count(Key)) { return Value; } return Or; } - template >> - const V &getOr(ByConstRef Key, V &&Or) const = delete; + const V &getOr(ByConstRef Key, V &&Or) const + requires(!CanEfficientlyPassByValue) + = delete; const_iterator find(ByConstRef Key) const { return llvm::map_iterator(Map.find(Key), @@ -480,27 +480,27 @@ template class DenseTable1d { return Map.try_emplace(std::move(Key), std::move(Value)); } - template >> - V getOr(ByConstRef Key, V Or) const { + V getOr(ByConstRef Key, V Or) const + requires CanEfficientlyPassByValue + { if (auto It = Map.find(Key); It != Map.end()) { return It->second; } return Or; } - template >> - const V &getOr(ByConstRef Key, const V &Or) const { + const V &getOr(ByConstRef Key, const V &Or) const + requires(!CanEfficientlyPassByValue) + { if (auto It = Map.find(Key); It != Map.end()) { return It->second; } return Or; } - template >> - const V &getOr(ByConstRef Key, V &&Or) const = delete; + const V &getOr(ByConstRef Key, V &&Or) const + requires(!CanEfficientlyPassByValue) + = delete; const_iterator find(ByConstRef Key) const { return Map.find(Key); } @@ -673,27 +673,27 @@ template class SmallDenseTable1d { return Map.try_emplace(std::move(Key), std::move(Value)); } - template >> - V getOr(ByConstRef Key, V Or) const { + V getOr(ByConstRef Key, V Or) const + requires CanEfficientlyPassByValue + { if (auto It = Map.find(Key); It != Map.end()) { return It->second; } return Or; } - template >> - const V &getOr(ByConstRef Key, const V &Or) const { + const V &getOr(ByConstRef Key, const V &Or) const + requires(!CanEfficientlyPassByValue) + { if (auto It = Map.find(Key); It != Map.end()) { return It->second; } return Or; } - template >> - const V &getOr(ByConstRef Key, V &&Or) const = delete; + const V &getOr(ByConstRef Key, V &&Or) const + requires(!CanEfficientlyPassByValue) + = delete; const_iterator find(ByConstRef Key) const { return Map.find(Key); } @@ -871,27 +871,27 @@ template class DummyDenseTable1d { return Value; } - template >> - V getOr(ByConstRef Key, V Or) const { + V getOr(ByConstRef Key, V Or) const + requires CanEfficientlyPassByValue + { if (Map.contains(Key)) { return Value; } return Or; } - template >> - const V &getOr(ByConstRef Key, const V &Or) const { + const V &getOr(ByConstRef Key, const V &Or) const + requires(!CanEfficientlyPassByValue) + { if (Map.contains(Key)) { return Value; } return Or; } - template >> - const V &getOr(ByConstRef Key, V &&Or) const = delete; + const V &getOr(ByConstRef Key, V &&Or) const + requires(!CanEfficientlyPassByValue) + = delete; const_iterator find(ByConstRef Key) const { return llvm::map_iterator(Map.find(Key), diff --git a/include/phasar/Utils/TypeTraits.h b/include/phasar/Utils/TypeTraits.h index b9aef51b52..97e324c379 100644 --- a/include/phasar/Utils/TypeTraits.h +++ b/include/phasar/Utils/TypeTraits.h @@ -15,6 +15,7 @@ #include "llvm/ADT/STLExtras.h" #include "llvm/Support/raw_ostream.h" +#include #include #include #include @@ -25,13 +26,8 @@ namespace psr { -#if __cplusplus < 202002L -template struct type_identity { - using type = T; -}; -#else -template using type_identity = std::type_identity; -#endif +using std::type_identity; +using std::type_identity_t; /// \file TODO: We should stick to one naming convention here and not mix /// CamelCase with lower_case! @@ -39,23 +35,6 @@ template using type_identity = std::type_identity; // NOLINTBEGIN(readability-identifier-naming) namespace detail { -template -struct is_iterable : std::false_type {}; // NOLINT -template -struct is_iterable())), - decltype(llvm::adl_end(std::declval()))>> - : public std::true_type {}; - -template -struct is_iterable_over : std::false_type {}; // NOLINT -template -struct is_iterable_over< - T, U, - std::enable_if_t::value && - std::is_same_v()))>>>> - : public std::true_type {}; - template struct is_pair : std::false_type {}; // NOLINT template struct is_pair> : std::true_type {}; // NOLINT @@ -64,67 +43,6 @@ template struct is_tuple : std::false_type {}; // NOLINT template struct is_tuple> : std::true_type {}; // NOLINT -template -struct is_printable : std::false_type {}; // NOLINT -template -struct is_printable< // NOLINT - T, OS, decltype(std::declval() << std::declval())> - : std::true_type {}; - -template -using is_llvm_printable = is_printable; // NOLINT - -template -using is_std_printable = is_printable; // NOLINT - -template -struct has_str : std::false_type {}; // NOLINT -template -struct has_str().str())> : std::true_type { -}; // NOLINT - -template struct has_reserve : std::false_type {}; -template -struct has_reserve< - T, std::void_t().reserve(size_t(0)))>> - : std::true_type {}; - -template struct has_adl_to_string { - template ())))> - static std::true_type test(int); - template ()))> - static std::true_type test(long); - template static std::false_type test(...); - - static constexpr bool value = - std::is_same_v; -}; - -template -struct has_erase_iterator : std::false_type {}; // NOLINT -template -struct has_erase_iterator< // NOLINT - T, std::void_t().erase( - std::declval()))>> : std::true_type {}; - -template -struct is_std_hashable : std::false_type {}; // NOLINT -template -struct is_std_hashable>()( // NOLINT - std::declval()))> : std::true_type {}; - -template -struct is_llvm_hashable : std::false_type {}; // NOLINT -template -struct is_llvm_hashable()))> // NOLINT - : std::true_type {}; -template -struct is_llvm_hashable()))> // NOLINT - : std::true_type {}; - template