From 8bbb5fb763547b11bb5a6738c3c3970baf4376ae Mon Sep 17 00:00:00 2001 From: Hans-Kristian Arntzen Date: Thu, 23 Jan 2020 10:49:43 +0100 Subject: [PATCH] Make SmallVector noexcept. Fixes a linting error from cppcheck where reserve() calls can throw, but caller is marked noexcept to allow proper move semantics. Only real place to throw would be if allocations fail, but these allocations tend to be small, and if allocation actually fails here, we're basically OOM anyways, so just terminate. Constructors and assignment could also fail, but the only way that could happen is memory related in SPIRV-Cross' case, so just terminate if that happens as well. Also, for good measure, add missing -fno-exceptions to EXCEPTIONS_TO_ASSERTIONS path in CMake. --- CMakeLists.txt | 7 ++-- spirv_cross_containers.hpp | 70 +++++++++++++++++++++----------------- 2 files changed, 43 insertions(+), 34 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 590ff9fe..a2ebb6ba 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -75,11 +75,14 @@ endif() string(TIMESTAMP spirv-cross-timestamp) configure_file(${CMAKE_CURRENT_SOURCE_DIR}/cmake/gitversion.in.h ${CMAKE_CURRENT_BINARY_DIR}/gitversion.h @ONLY) -if(SPIRV_CROSS_EXCEPTIONS_TO_ASSERTIONS) +if (SPIRV_CROSS_EXCEPTIONS_TO_ASSERTIONS) set(spirv-compiler-defines ${spirv-compiler-defines} SPIRV_CROSS_EXCEPTIONS_TO_ASSERTIONS) + if (NOT MSVC) + set(spirv-compiler-options ${spirv-compiler-options} -fno-exceptions) + endif() endif() -if(SPIRV_CROSS_FORCE_STL_TYPES) +if (SPIRV_CROSS_FORCE_STL_TYPES) set(spirv-compiler-defines ${spirv-compiler-defines} SPIRV_CROSS_FORCE_STL_TYPES) endif() diff --git a/spirv_cross_containers.hpp b/spirv_cross_containers.hpp index a2f6fac6..5b69c120 100644 --- a/spirv_cross_containers.hpp +++ b/spirv_cross_containers.hpp @@ -85,72 +85,72 @@ template class VectorView { public: - T &operator[](size_t i) + T &operator[](size_t i) SPIRV_CROSS_NOEXCEPT { return ptr[i]; } - const T &operator[](size_t i) const + const T &operator[](size_t i) const SPIRV_CROSS_NOEXCEPT { return ptr[i]; } - bool empty() const + bool empty() const SPIRV_CROSS_NOEXCEPT { return buffer_size == 0; } - size_t size() const + size_t size() const SPIRV_CROSS_NOEXCEPT { return buffer_size; } - T *data() + T *data() SPIRV_CROSS_NOEXCEPT { return ptr; } - const T *data() const + const T *data() const SPIRV_CROSS_NOEXCEPT { return ptr; } - T *begin() + T *begin() SPIRV_CROSS_NOEXCEPT { return ptr; } - T *end() + T *end() SPIRV_CROSS_NOEXCEPT { return ptr + buffer_size; } - const T *begin() const + const T *begin() const SPIRV_CROSS_NOEXCEPT { return ptr; } - const T *end() const + const T *end() const SPIRV_CROSS_NOEXCEPT { return ptr + buffer_size; } - T &front() + T &front() SPIRV_CROSS_NOEXCEPT { return ptr[0]; } - const T &front() const + const T &front() const SPIRV_CROSS_NOEXCEPT { return ptr[0]; } - T &back() + T &back() SPIRV_CROSS_NOEXCEPT { return ptr[buffer_size - 1]; } - const T &back() const + const T &back() const SPIRV_CROSS_NOEXCEPT { return ptr[buffer_size - 1]; } @@ -194,13 +194,13 @@ template class SmallVector : public VectorView { public: - SmallVector() + SmallVector() SPIRV_CROSS_NOEXCEPT { this->ptr = stack_storage.data(); buffer_capacity = N; } - SmallVector(const T *arg_list_begin, const T *arg_list_end) + SmallVector(const T *arg_list_begin, const T *arg_list_end) SPIRV_CROSS_NOEXCEPT : SmallVector() { auto count = size_t(arg_list_end - arg_list_begin); @@ -245,14 +245,17 @@ public: return *this; } - SmallVector(const SmallVector &other) + SmallVector(const SmallVector &other) SPIRV_CROSS_NOEXCEPT : SmallVector() { *this = other; } - SmallVector &operator=(const SmallVector &other) + SmallVector &operator=(const SmallVector &other) SPIRV_CROSS_NOEXCEPT { + if (this == &other) + return *this; + clear(); reserve(other.buffer_size); for (size_t i = 0; i < other.buffer_size; i++) @@ -261,7 +264,7 @@ public: return *this; } - explicit SmallVector(size_t count) + explicit SmallVector(size_t count) SPIRV_CROSS_NOEXCEPT : SmallVector() { resize(count); @@ -274,28 +277,28 @@ public: free(this->ptr); } - void clear() + void clear() SPIRV_CROSS_NOEXCEPT { for (size_t i = 0; i < this->buffer_size; i++) this->ptr[i].~T(); this->buffer_size = 0; } - void push_back(const T &t) + void push_back(const T &t) SPIRV_CROSS_NOEXCEPT { reserve(this->buffer_size + 1); new (&this->ptr[this->buffer_size]) T(t); this->buffer_size++; } - void push_back(T &&t) + void push_back(T &&t) SPIRV_CROSS_NOEXCEPT { reserve(this->buffer_size + 1); new (&this->ptr[this->buffer_size]) T(std::move(t)); this->buffer_size++; } - void pop_back() + void pop_back() SPIRV_CROSS_NOEXCEPT { // Work around false positive warning on GCC 8.3. // Calling pop_back on empty vector is undefined. @@ -304,14 +307,14 @@ public: } template - void emplace_back(Ts &&... ts) + void emplace_back(Ts &&... ts) SPIRV_CROSS_NOEXCEPT { reserve(this->buffer_size + 1); new (&this->ptr[this->buffer_size]) T(std::forward(ts)...); this->buffer_size++; } - void reserve(size_t count) + void reserve(size_t count) SPIRV_CROSS_NOEXCEPT { if (count > buffer_capacity) { @@ -327,8 +330,9 @@ public: T *new_buffer = target_capacity > N ? static_cast(malloc(target_capacity * sizeof(T))) : stack_storage.data(); + // If we actually fail this malloc, we are hosed anyways, there is no reason to attempt recovery. if (!new_buffer) - SPIRV_CROSS_THROW("Out of memory."); + std::terminate(); // In case for some reason two allocations both come from same stack. if (new_buffer != this->ptr) @@ -348,7 +352,7 @@ public: } } - void insert(T *itr, const T *insert_begin, const T *insert_end) + void insert(T *itr, const T *insert_begin, const T *insert_end) SPIRV_CROSS_NOEXCEPT { auto count = size_t(insert_end - insert_begin); if (itr == this->end()) @@ -374,8 +378,10 @@ public: // Need to allocate new buffer. Move everything to a new buffer. T *new_buffer = target_capacity > N ? static_cast(malloc(target_capacity * sizeof(T))) : stack_storage.data(); + + // If we actually fail this malloc, we are hosed anyways, there is no reason to attempt recovery. if (!new_buffer) - SPIRV_CROSS_THROW("Out of memory."); + std::terminate(); // First, move elements from source buffer to new buffer. // We don't deal with types which can throw in move constructor. @@ -447,19 +453,19 @@ public: } } - void insert(T *itr, const T &value) + void insert(T *itr, const T &value) SPIRV_CROSS_NOEXCEPT { insert(itr, &value, &value + 1); } - T *erase(T *itr) + T *erase(T *itr) SPIRV_CROSS_NOEXCEPT { std::move(itr + 1, this->end(), itr); this->ptr[--this->buffer_size].~T(); return itr; } - void erase(T *start_erase, T *end_erase) + void erase(T *start_erase, T *end_erase) SPIRV_CROSS_NOEXCEPT { if (end_erase == this->end()) { @@ -473,7 +479,7 @@ public: } } - void resize(size_t new_size) + void resize(size_t new_size) SPIRV_CROSS_NOEXCEPT { if (new_size < this->buffer_size) {