From 5e4ad75362b3c36a2a3a550d4cc46c91bffef84a Mon Sep 17 00:00:00 2001 From: Fabian Schiebel Date: Sat, 11 Oct 2025 18:17:44 +0200 Subject: [PATCH 1/8] Requiring C++20 --- BreakingChanges.md | 2 +- README.md | 13 +- cmake/phasar_macros.cmake | 2 +- .../phasar/DataFlow/IfdsIde/EdgeFunction.h | 40 +-- include/phasar/Domain/LatticeDomain.h | 46 ---- .../PhasarLLVM/TaintConfig/TaintConfigData.h | 8 - include/phasar/Utils/AdjacencyList.h | 2 - include/phasar/Utils/DFAMinimizer.h | 16 +- include/phasar/Utils/GraphTraits.h | 105 ++------ include/phasar/Utils/Macros.h | 10 - include/phasar/Utils/MaybeUniquePtr.h | 5 +- include/phasar/Utils/TypeTraits.h | 248 ++++++------------ utils/conan/clang/test_package/CMakeLists.txt | 2 +- 13 files changed, 123 insertions(+), 376 deletions(-) diff --git a/BreakingChanges.md b/BreakingChanges.md index 8c17daa8ae..e8b7b1ed2b 100644 --- a/BreakingChanges.md +++ b/BreakingChanges.md @@ -2,7 +2,7 @@ ## development HEAD -*None* +- Requiring C++20 instead of C++17 ## v2503 diff --git a/README.md b/README.md index a6342ea32e..5577f0fd72 100644 --- a/README.md +++ b/README.md @@ -2,10 +2,10 @@ # 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) +[![Latest Release](https://img.shields.io/github/v/release/secure-software-engineering/phasar?sort=date&style=flat)](https://github.com/secure-software-engineering/phasar/releases) -Version 2503 ## What is PhASAR? @@ -25,7 +25,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 @@ -43,12 +43,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 2bd952852c..a0a6b64e38 100644 --- a/cmake/phasar_macros.cmake +++ b/cmake/phasar_macros.cmake @@ -275,7 +275,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/DataFlow/IfdsIde/EdgeFunction.h b/include/phasar/DataFlow/IfdsIde/EdgeFunction.h index 0559e17afe..af2468f8ea 100644 --- a/include/phasar/DataFlow/IfdsIde/EdgeFunction.h +++ b/include/phasar/DataFlow/IfdsIde/EdgeFunction.h @@ -35,39 +35,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, diff --git a/include/phasar/Domain/LatticeDomain.h b/include/phasar/Domain/LatticeDomain.h index 560409f370..72226cc8a8 100644 --- a/include/phasar/Domain/LatticeDomain.h +++ b/include/phasar/Domain/LatticeDomain.h @@ -177,52 +177,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) { 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/Utils/AdjacencyList.h b/include/phasar/Utils/AdjacencyList.h index b69abe74cf..107ec9b3a8 100644 --- a/include/phasar/Utils/AdjacencyList.h +++ b/include/phasar/Utils/AdjacencyList.h @@ -290,9 +290,7 @@ struct GraphTraits> { return It; } -#if __cplusplus >= 202002L static_assert(is_graph>); -#endif static_assert(is_reservable_graph_trait_v>>); }; 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/GraphTraits.h b/include/phasar/Utils/GraphTraits.h index de96b9cc20..c3ca55a577 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 { /// Once moving to C++20, we have nice type-checking using concepts template struct GraphTraits; -#if __cplusplus >= 202002L - template concept is_graph_edge = requires(const Edge e1, Edge e2) { { e1 == e2 } -> std::convertible_to; @@ -55,36 +51,36 @@ concept is_graph_trait = requires(typename GraphTrait::graph_type &graph, { GraphTrait::Invalid } -> std::convertible_to; { GraphTrait::addNode(graph, val) - } -> std::convertible_to; - {GraphTrait::addEdge(graph, vtx, edge)}; + } -> std::convertible_to; + { GraphTrait::addEdge(graph, vtx, edge) }; { GraphTrait::outEdges(cgraph, vtx) - } -> psr::is_iterable_over_v; + } -> psr::is_iterable_over_v; { GraphTrait::outDegree(cgraph, vtx) } -> std::convertible_to; - {GraphTrait::dedupOutEdges(graph, vtx)}; + { GraphTrait::dedupOutEdges(graph, vtx) }; { GraphTrait::nodes(cgraph) - } -> psr::is_iterable_over_v; + } -> psr::is_iterable_over_v; { GraphTrait::vertices(cgraph) - } -> psr::is_iterable_over_v; + } -> psr::is_iterable_over_v; { GraphTrait::node(cgraph, vtx) - } -> std::convertible_to; + } -> std::convertible_to; { GraphTrait::size(cgraph) } -> std::convertible_to; - {GraphTrait::addRoot(graph, vtx)}; + { GraphTrait::addRoot(graph, vtx) }; { GraphTrait::roots(cgraph) - } -> psr::is_iterable_over_v; + } -> psr::is_iterable_over_v; { GraphTrait::pop(graph, vtx) } -> std::same_as; { GraphTrait::roots_size(cgraph) } -> std::convertible_to; { GraphTrait::target(edge) - } -> std::convertible_to; + } -> std::convertible_to; { GraphTrait::withEdgeTarget(edge, vtx) - } -> std::convertible_to; - {GraphTrait::weight(edge)}; + } -> std::convertible_to; + { GraphTrait::weight(edge) }; }; template @@ -94,70 +90,25 @@ concept is_graph = requires(Graph g) { }; template -concept is_reservable_graph_trait_v = is_graph_trait && - requires(typename GraphTrait::graph_type &g) { - {GraphTrait::reserve(g, size_t(0))}; -}; +concept is_reservable_graph_trait_v = + is_graph_trait && requires(typename GraphTrait::graph_type &g) { + { GraphTrait::reserve(g, size_t(0)) }; + }; template -concept is_removable_graph_trait_v = is_graph_trait && +concept is_removable_graph_trait_v = + is_graph_trait && requires(typename GraphTrait::graph_type &g, typename GraphTrait::vertex_t vtx, typename GraphTrait::edge_iterator edge_it, typename GraphTrait::roots_iterator root_it) { - typename GraphTrait::edge_iterator; - typename GraphTrait::roots_iterator; - {GraphTrait::removeEdge(g, vtx, edge_it)}; - {GraphTrait::removeRoot(g, root_it)}; -}; + typename GraphTrait::edge_iterator; + typename GraphTrait::roots_iterator; + { GraphTrait::removeEdge(g, vtx, edge_it) }; + { GraphTrait::removeRoot(g, root_it) }; + }; -#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) { @@ -189,13 +140,9 @@ struct DefaultNodeTransform { } }; -template +template void printGraph(const GraphTy &G, llvm::raw_ostream &OS, - llvm::StringRef Name = "", NodeTransform NodeToString = {}) -#if __cplusplus >= 202002L - requires is_graph -#endif -{ + llvm::StringRef Name = "", NodeTransform NodeToString = {}) { using traits_t = GraphTraits; OS << "digraph " << Name << " {\n"; 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/MaybeUniquePtr.h b/include/phasar/Utils/MaybeUniquePtr.h index 4e50f2304f..9f3e7e234c 100644 --- a/include/phasar/Utils/MaybeUniquePtr.h +++ b/include/phasar/Utils/MaybeUniquePtr.h @@ -122,10 +122,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/TypeTraits.h b/include/phasar/Utils/TypeTraits.h index 1e2f2524cc..a435f4c1ab 100644 --- a/include/phasar/Utils/TypeTraits.h +++ b/include/phasar/Utils/TypeTraits.h @@ -17,6 +17,7 @@ #include "nlohmann/json.hpp" +#include #include #include #include @@ -27,34 +28,12 @@ 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; // 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 @@ -63,67 +42,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