From 6cf31486e1fee6dd4a2807e0f1402445ed15e368 Mon Sep 17 00:00:00 2001 From: Michael Scire Date: Sat, 12 Mar 2022 15:05:43 -0800 Subject: [PATCH] fs: fix clang-build, os: StackGuardManager --- .../fssystem/fssystem_bucket_tree.hpp | 2 +- .../fssystem/fssystem_compressed_storage.hpp | 38 +++++---- .../impl/fssystem_block_cache_manager.hpp | 4 +- .../os/impl/os_address_space_allocator.hpp | 6 ++ .../source/os/impl/os_resource_manager.hpp | 4 +- .../source/os/impl/os_stack_guard_manager.hpp | 26 ++++++ ...os_stack_guard_manager_impl.os.horizon.hpp | 36 +++++++++ .../os_stack_guard_manager_impl.os.linux.hpp | 29 +++++++ .../os_stack_guard_manager_impl.os.macos.hpp | 29 +++++++ ...os_stack_guard_manager_impl.os.windows.hpp | 29 +++++++ .../os/impl/os_stack_guard_manager_types.hpp | 81 +++++++++++++++++++ .../source/os/impl/os_vamm_manager.cpp | 6 -- .../include/vapours/util/util_i_function.hpp | 2 +- 13 files changed, 264 insertions(+), 28 deletions(-) create mode 100644 libraries/libstratosphere/source/os/impl/os_stack_guard_manager.hpp create mode 100644 libraries/libstratosphere/source/os/impl/os_stack_guard_manager_impl.os.horizon.hpp create mode 100644 libraries/libstratosphere/source/os/impl/os_stack_guard_manager_impl.os.linux.hpp create mode 100644 libraries/libstratosphere/source/os/impl/os_stack_guard_manager_impl.os.macos.hpp create mode 100644 libraries/libstratosphere/source/os/impl/os_stack_guard_manager_impl.os.windows.hpp create mode 100644 libraries/libstratosphere/source/os/impl/os_stack_guard_manager_types.hpp diff --git a/libraries/libstratosphere/include/stratosphere/fssystem/fssystem_bucket_tree.hpp b/libraries/libstratosphere/include/stratosphere/fssystem/fssystem_bucket_tree.hpp index f64399242..aebb41c6c 100644 --- a/libraries/libstratosphere/include/stratosphere/fssystem/fssystem_bucket_tree.hpp +++ b/libraries/libstratosphere/include/stratosphere/fssystem/fssystem_bucket_tree.hpp @@ -58,7 +58,7 @@ namespace ams::fssystem { s64 end_offset; constexpr bool IsInclude(s64 offset) const { - return this->start_offset <= offset & offset < this->end_offset; + return this->start_offset <= offset && offset < this->end_offset; } constexpr bool IsInclude(s64 offset, s64 size) const { diff --git a/libraries/libstratosphere/include/stratosphere/fssystem/fssystem_compressed_storage.hpp b/libraries/libstratosphere/include/stratosphere/fssystem/fssystem_compressed_storage.hpp index 8922cd0d6..059c9fd0f 100644 --- a/libraries/libstratosphere/include/stratosphere/fssystem/fssystem_compressed_storage.hpp +++ b/libraries/libstratosphere/include/stratosphere/fssystem/fssystem_compressed_storage.hpp @@ -370,6 +370,8 @@ namespace ams::fssystem { s64 appropriate_virtual_offset = offset; R_TRY(this->OperatePerEntry(offset, table_offsets.end_offset - offset, [&] (bool *out_continuous, const Entry &entry, s64 virtual_data_size, s64 data_offset, s64 read_size) -> Result { + AMS_UNUSED(virtual_data_size); + /* Determine the physical extents. */ s64 physical_offset, physical_size; if (CompressionTypeUtility::IsRandomAccessible(entry.compression_type)) { @@ -528,7 +530,7 @@ namespace ams::fssystem { for (s32 entry_idx = 0; entry_idx < entry_count; ++entry_idx) { /* Determine the current read size. */ bool will_use_pooled_buffer = false; - const size_t cur_read_size = [&] ALWAYS_INLINE_LAMBDA () -> size_t { + const size_t cur_read_size = [&] () ALWAYS_INLINE_LAMBDA -> size_t { if (const size_t target_entry_size = static_cast(entries[entry_idx].physical_size) + static_cast(entries[entry_idx].gap_from_prev); target_entry_size <= pooled_buffer.GetSize()) { /* We'll be using the pooled buffer. */ will_use_pooled_buffer = true; @@ -687,11 +689,11 @@ namespace ams::fssystem { const s64 required_access_physical_end = required_access_physical_offset + required_access_physical_size; if (required_access_physical_size > 0) { const bool required_by_gap = !(required_access_physical_end <= physical_offset && physical_offset <= util::AlignUp(required_access_physical_end, CompressionBlockAlignment)); - const bool required_by_continuous_size = ((physical_size + physical_offset) - required_access_physical_end) + required_access_physical_size > m_continuous_reading_size_max; + const bool required_by_continuous_size = ((physical_size + physical_offset) - required_access_physical_end) + required_access_physical_size > static_cast(m_continuous_reading_size_max); const bool required_by_entry_count = entry_count == EntriesCountMax; if (required_by_gap || required_by_continuous_size || required_by_entry_count) { /* Check that our planned access is sane. */ - AMS_ASSERT(!will_allocate_pooled_buffer || required_access_physical_size <= m_continuous_reading_size_max); + AMS_ASSERT(!will_allocate_pooled_buffer || required_access_physical_size <= static_cast(m_continuous_reading_size_max)); /* Perform the required read. */ R_TRY(PerformRequiredRead()); @@ -716,9 +718,9 @@ namespace ams::fssystem { if (CompressionTypeUtility::IsDataStorageAccessRequired(entry.compression_type)) { /* If the data is compressed, ensure the access is sane. */ if (entry.compression_type != CompressionType_None) { - R_UNLESS(data_offset == 0, fs::ResultInvalidOffset()); - R_UNLESS(virtual_data_size == read_size, fs::ResultInvalidSize()); - R_UNLESS(entry.GetPhysicalSize() <= m_block_size_max, fs::ResultUnexpectedInCompressedStorageD()); + R_UNLESS(data_offset == 0, fs::ResultInvalidOffset()); + R_UNLESS(virtual_data_size == read_size, fs::ResultInvalidSize()); + R_UNLESS(entry.GetPhysicalSize() <= static_cast(m_block_size_max), fs::ResultUnexpectedInCompressedStorageD()); } /* Update the required access parameters. */ @@ -926,16 +928,16 @@ namespace ams::fssystem { head_range = { .virtual_offset = entry.virt_offset, .virtual_size = virtual_data_size, - .physical_size = entry.phys_size, + .physical_size = static_cast(entry.phys_size), .is_block_alignment_required = CompressionTypeUtility::IsBlockAlignmentRequired(entry.compression_type), }; /* If required, set the tail range. */ - if ((offset + read_size) <= entry.virt_offset + virtual_data_size) { + if (static_cast(offset + read_size) <= entry.virt_offset + virtual_data_size) { tail_range = { .virtual_offset = entry.virt_offset, .virtual_size = virtual_data_size, - .physical_size = entry.phys_size, + .physical_size = static_cast(entry.phys_size), .is_block_alignment_required = CompressionTypeUtility::IsBlockAlignmentRequired(entry.compression_type), }; is_tail_set = true; @@ -955,7 +957,7 @@ namespace ams::fssystem { tail_range = { .virtual_offset = entry.virt_offset, .virtual_size = virtual_data_size, - .physical_size = entry.phys_size, + .physical_size = static_cast(entry.phys_size), .is_block_alignment_required = CompressionTypeUtility::IsBlockAlignmentRequired(entry.compression_type), }; @@ -986,15 +988,15 @@ namespace ams::fssystem { } /* Determine our alignment. */ - const bool head_unaligned = head_range.is_block_alignment_required && (cur_offset != head_range.virtual_offset || cur_size < head_range.virtual_size); - const bool tail_unaligned = [&] ALWAYS_INLINE_LAMBDA () -> bool { + const bool head_unaligned = head_range.is_block_alignment_required && (cur_offset != head_range.virtual_offset || static_cast(cur_size) < head_range.virtual_size); + const bool tail_unaligned = [&] () ALWAYS_INLINE_LAMBDA -> bool { if (tail_range.is_block_alignment_required) { - if (cur_size + cur_offset == tail_range.GetEndVirtualOffset()) { + if (static_cast(cur_size + cur_offset) == tail_range.GetEndVirtualOffset()) { return false; } else if (!head_unaligned) { return true; } else { - return cur_size + cur_offset < head_range.GetEndVirtualOffset(); + return static_cast(cur_size + cur_offset) < head_range.GetEndVirtualOffset(); } } else { return false; @@ -1188,7 +1190,7 @@ namespace ams::fssystem { /* Determine the current access extents. */ s64 cur_offset = head_range.virtual_offset + util::AlignDown(access_offset - head_range.virtual_offset, m_cache_size_unk_0); - while (cur_offset < head_range.GetEndVirtualOffset() && cur_offset < offset + size) { + while (cur_offset < head_range.GetEndVirtualOffset() && cur_offset < static_cast(offset + size)) { /* Find the relevant entry. */ fs::IBufferManager::MemoryRange memory_range = {}; CacheEntry entry = {}; @@ -1240,7 +1242,7 @@ namespace ams::fssystem { new_head_range = { .virtual_offset = entry.virt_offset, .virtual_size = virtual_data_size, - .physical_size = entry.phys_size, + .physical_size = static_cast(entry.phys_size), .is_block_alignment_required = CompressionTypeUtility::IsBlockAlignmentRequired(entry.compression_type), }; } @@ -1306,7 +1308,7 @@ namespace ams::fssystem { tail_range = { .virtual_offset = entry.virt_offset, .virtual_size = virtual_data_size, - .physical_size = entry.phys_size, + .physical_size = static_cast(entry.phys_size), .is_block_alignment_required = CompressionTypeUtility::IsBlockAlignmentRequired(entry.compression_type), }; @@ -1406,6 +1408,8 @@ namespace ams::fssystem { } virtual Result OperateRange(void *dst, size_t dst_size, fs::OperationId op_id, s64 offset, s64 size, const void *src, size_t src_size) override { + AMS_UNUSED(src, src_size); + /* Check pre-conditions. */ AMS_ASSERT(offset >= 0); AMS_ASSERT(size >= 0); diff --git a/libraries/libstratosphere/include/stratosphere/fssystem/impl/fssystem_block_cache_manager.hpp b/libraries/libstratosphere/include/stratosphere/fssystem/impl/fssystem_block_cache_manager.hpp index 1fcdc5970..cbd4f5cb2 100644 --- a/libraries/libstratosphere/include/stratosphere/fssystem/impl/fssystem_block_cache_manager.hpp +++ b/libraries/libstratosphere/include/stratosphere/fssystem/impl/fssystem_block_cache_manager.hpp @@ -24,10 +24,10 @@ namespace ams::fssystem::impl { NON_COPYABLE(BlockCacheManager); NON_MOVEABLE(BlockCacheManager); public: - using MemoryRange = AllocatorType::MemoryRange; + using MemoryRange = typename AllocatorType::MemoryRange; using CacheIndex = s32; - using BufferAttribute = AllocatorType::BufferAttribute; + using BufferAttribute = typename AllocatorType::BufferAttribute; static constexpr CacheIndex InvalidCacheIndex = -1; diff --git a/libraries/libstratosphere/source/os/impl/os_address_space_allocator.hpp b/libraries/libstratosphere/source/os/impl/os_address_space_allocator.hpp index c8197a858..f76031bf8 100644 --- a/libraries/libstratosphere/source/os/impl/os_address_space_allocator.hpp +++ b/libraries/libstratosphere/source/os/impl/os_address_space_allocator.hpp @@ -19,6 +19,12 @@ namespace ams::os::impl { + enum AddressAllocationResult { + AddressAllocationResult_Success, + AddressAllocationResult_OutOfMemory, + AddressAllocationResult_OutOfSpace, + }; + template class AddressSpaceAllocatorBase { NON_COPYABLE(AddressSpaceAllocatorBase); diff --git a/libraries/libstratosphere/source/os/impl/os_resource_manager.hpp b/libraries/libstratosphere/source/os/impl/os_resource_manager.hpp index ea6f0e575..a4fcc645b 100644 --- a/libraries/libstratosphere/source/os/impl/os_resource_manager.hpp +++ b/libraries/libstratosphere/source/os/impl/os_resource_manager.hpp @@ -17,6 +17,7 @@ #include #include "os_rng_manager_impl.hpp" #include "os_thread_manager_types.hpp" +#include "os_stack_guard_manager_types.hpp" #include "os_tick_manager_impl.hpp" #include "os_aslr_space_manager_types.hpp" #include "os_tls_manager_types.hpp" @@ -29,7 +30,7 @@ namespace ams::os::impl { private: RngManager m_rng_manager{}; AslrSpaceManager m_aslr_space_manager{}; - /* TODO */ + StackGuardManager m_stack_guard_manager; ThreadManager m_thread_manager{}; //TlsManager m_tls_manager{}; TickManager m_tick_manager{}; @@ -42,6 +43,7 @@ namespace ams::os::impl { constexpr ALWAYS_INLINE RngManager &GetRngManager() { return m_rng_manager; } constexpr ALWAYS_INLINE AslrSpaceManager &GetAslrSpaceManager() { return m_aslr_space_manager; } constexpr ALWAYS_INLINE ThreadManager &GetThreadManager() { return m_thread_manager; } + constexpr ALWAYS_INLINE StackGuardManager &GetStackGuardManager() { return m_stack_guard_manager; } //constexpr ALWAYS_INLINE TlsManager &GetTlsManager() { return m_tls_manager; } constexpr ALWAYS_INLINE TickManager &GetTickManager() { return m_tick_manager; } constexpr ALWAYS_INLINE VammManager &GetVammManager() { return m_vamm_manager; } diff --git a/libraries/libstratosphere/source/os/impl/os_stack_guard_manager.hpp b/libraries/libstratosphere/source/os/impl/os_stack_guard_manager.hpp new file mode 100644 index 000000000..5a6b0dc90 --- /dev/null +++ b/libraries/libstratosphere/source/os/impl/os_stack_guard_manager.hpp @@ -0,0 +1,26 @@ +/* + * Copyright (c) Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#pragma once +#include +#include "os_resource_manager.hpp" + +namespace ams::os::impl { + + ALWAYS_INLINE StackGuardManager &GetStackGuardManager() { + return GetResourceManager().GetStackGuardManager(); + } + +} diff --git a/libraries/libstratosphere/source/os/impl/os_stack_guard_manager_impl.os.horizon.hpp b/libraries/libstratosphere/source/os/impl/os_stack_guard_manager_impl.os.horizon.hpp new file mode 100644 index 000000000..12d5f8514 --- /dev/null +++ b/libraries/libstratosphere/source/os/impl/os_stack_guard_manager_impl.os.horizon.hpp @@ -0,0 +1,36 @@ +/* + * Copyright (c) Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#pragma once +#include + +namespace ams::os::impl { + + class StackGuardManagerHorizonImpl { + private: + static u64 GetStackInfo(svc::InfoType type) { + u64 value; + R_ABORT_UNLESS(svc::GetInfo(std::addressof(value), type, svc::PseudoHandle::CurrentProcess, 0)); + AMS_ASSERT(value <= std::numeric_limits::max()); + return static_cast(static_cast(value)); + } + public: + static u64 GetStackGuardBeginAddress() { return GetStackInfo(svc::InfoType_StackRegionAddress); } + static u64 GetStackGuardEndAddress() { return GetStackInfo(svc::InfoType_StackRegionSize); } + }; + + using StackGuardManagerImpl = StackGuardManagerHorizonImpl; + +} diff --git a/libraries/libstratosphere/source/os/impl/os_stack_guard_manager_impl.os.linux.hpp b/libraries/libstratosphere/source/os/impl/os_stack_guard_manager_impl.os.linux.hpp new file mode 100644 index 000000000..47136ef26 --- /dev/null +++ b/libraries/libstratosphere/source/os/impl/os_stack_guard_manager_impl.os.linux.hpp @@ -0,0 +1,29 @@ +/* + * Copyright (c) Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#pragma once +#include + +namespace ams::os::impl { + + class StackGuardManagerLinuxImpl { + public: + static u64 GetStackGuardBeginAddress() { return 256_MB; } + static u64 GetStackGuardEndAddress() { return 256_MB + 1_GB; } + }; + + using StackGuardManagerImpl = StackGuardManagerLinuxImpl; + +} diff --git a/libraries/libstratosphere/source/os/impl/os_stack_guard_manager_impl.os.macos.hpp b/libraries/libstratosphere/source/os/impl/os_stack_guard_manager_impl.os.macos.hpp new file mode 100644 index 000000000..6e16610b5 --- /dev/null +++ b/libraries/libstratosphere/source/os/impl/os_stack_guard_manager_impl.os.macos.hpp @@ -0,0 +1,29 @@ +/* + * Copyright (c) Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#pragma once +#include + +namespace ams::os::impl { + + class StackGuardManagerMacosImpl { + public: + static u64 GetStackGuardBeginAddress() { return 256_MB; } + static u64 GetStackGuardEndAddress() { return 256_MB + 1_GB; } + }; + + using StackGuardManagerImpl = StackGuardManagerMacosImpl; + +} diff --git a/libraries/libstratosphere/source/os/impl/os_stack_guard_manager_impl.os.windows.hpp b/libraries/libstratosphere/source/os/impl/os_stack_guard_manager_impl.os.windows.hpp new file mode 100644 index 000000000..45773bd44 --- /dev/null +++ b/libraries/libstratosphere/source/os/impl/os_stack_guard_manager_impl.os.windows.hpp @@ -0,0 +1,29 @@ +/* + * Copyright (c) Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#pragma once +#include + +namespace ams::os::impl { + + class StackGuardManagerWindowsImpl { + public: + static u64 GetStackGuardBeginAddress() { return 256_MB; } + static u64 GetStackGuardEndAddress() { return 256_MB + 1_GB; } + }; + + using StackGuardManagerImpl = StackGuardManagerWindowsImpl; + +} diff --git a/libraries/libstratosphere/source/os/impl/os_stack_guard_manager_types.hpp b/libraries/libstratosphere/source/os/impl/os_stack_guard_manager_types.hpp new file mode 100644 index 000000000..b49c4dd63 --- /dev/null +++ b/libraries/libstratosphere/source/os/impl/os_stack_guard_manager_types.hpp @@ -0,0 +1,81 @@ +/* + * Copyright (c) Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#pragma once +#include +#include "os_address_space_allocator.hpp" + +#if defined(ATMOSPHERE_OS_HORIZON) + #include "os_stack_guard_manager_impl.os.horizon.hpp" +#elif defined(ATMOSPHERE_OS_WINDOWS) + #include "os_stack_guard_manager_impl.os.windows.hpp" +#elif defined(ATMOSPHERE_OS_LINUX) + #include "os_stack_guard_manager_impl.os.linux.hpp" +#elif defined(ATMOSPHERE_OS_MACOS) + #include "os_stack_guard_manager_impl.os.macos.hpp" +#else + #error "Unknown OS for StackGuardManagerImpl" +#endif + +namespace ams::os::impl { + + constexpr inline size_t StackGuardSize = 4 * os::MemoryPageSize; + + class StackGuardManager { + private: + StackGuardManagerImpl m_impl; + AddressSpaceAllocator m_allocator; + public: + StackGuardManager() : m_impl(), m_allocator(m_impl.GetStackGuardBeginAddress(), m_impl.GetStackGuardEndAddress(), StackGuardSize, nullptr, 0) { + /* ... */ + } + + void *AllocateStackGuardSpace(size_t size) { + return reinterpret_cast(m_allocator.AllocateSpace(size, os::MemoryPageSize, 0)); + } + + bool CheckGuardSpace(uintptr_t address, size_t size) { + return m_allocator.CheckGuardSpace(address, size, StackGuardSize); + } + + AddressAllocationResult MapAtRandomAddress(void **out, bool (*map)(const void *, const void *, size_t), void (*unmap)(const void *, const void *, size_t), const void *address, size_t size) { + /* Try to map up to 0x40 times. */ + constexpr int TryCountMax = 0x40; + for (auto i = 0; i < TryCountMax; ++i) { + /* Get stack guard space. */ + void * const space = this->AllocateStackGuardSpace(size); + if (space == nullptr) { + return AddressAllocationResult_OutOfMemory; + } + + /* Try to map. */ + if (map(space, address, size)) { + /* Check that the guard space is still there. */ + if (this->CheckGuardSpace(reinterpret_cast(space), size)) { + *out = space; + return AddressAllocationResult_Success; + } else { + /* We need to retry. */ + unmap(space, address, size); + } + } + } + + /* We failed. */ + return AddressAllocationResult_OutOfSpace; + } + }; + +} \ No newline at end of file diff --git a/libraries/libstratosphere/source/os/impl/os_vamm_manager.cpp b/libraries/libstratosphere/source/os/impl/os_vamm_manager.cpp index 3414b2a77..7bdfbb2da 100644 --- a/libraries/libstratosphere/source/os/impl/os_vamm_manager.cpp +++ b/libraries/libstratosphere/source/os/impl/os_vamm_manager.cpp @@ -33,12 +33,6 @@ namespace ams::os::impl { namespace { - enum AddressAllocationResult { - AddressAllocationResult_Success, - AddressAllocationResult_OutOfMemory, - AddressAllocationResult_OutOfSpace, - }; - class AddressRegion : public util::IntrusiveRedBlackTreeBaseNode { private: uintptr_t m_address; diff --git a/libraries/libvapours/include/vapours/util/util_i_function.hpp b/libraries/libvapours/include/vapours/util/util_i_function.hpp index 813da435a..e49f4350c 100644 --- a/libraries/libvapours/include/vapours/util/util_i_function.hpp +++ b/libraries/libvapours/include/vapours/util/util_i_function.hpp @@ -100,7 +100,7 @@ namespace ams::util { } }; - template::value>::type> + template::value>::type> constexpr ALWAYS_INLINE auto MakeIFunction(F f) { static_assert(!std::is_member_pointer::value);