diff --git a/src/core/hle/result.h b/src/core/hle/result.h
index 82dcf5bba..ad06d00aa 100644
--- a/src/core/hle/result.h
+++ b/src/core/hle/result.h
@@ -9,8 +9,9 @@
 #include <type_traits>
 #include <utility>
 
-#include "common/common_types.h"
 #include "common/bit_field.h"
+#include "common/common_funcs.h"
+#include "common/common_types.h"
 
 // All the constants in this file come from http://3dbrew.org/wiki/Error_codes
 
@@ -364,6 +365,17 @@ public:
         return !empty() ? *GetPointer() : std::move(value);
     }
 
+    /// Asserts that the result succeeded and returns a reference to it.
+    T& Unwrap() {
+        // TODO(yuriks): Should be a release assert
+        _assert_msg_(Common, Succeeded(), "Tried to Unwrap empty ResultVal");
+        return **this;
+    }
+
+    T&& MoveFrom() {
+        return std::move(Unwrap());
+    }
+
 private:
     typedef typename std::aligned_storage<sizeof(T), std::alignment_of<T>::value>::type StorageType;
 
@@ -400,3 +412,15 @@ template <typename T, typename... Args>
 ResultVal<T> MakeResult(Args&&... args) {
     return ResultVal<T>::WithCode(RESULT_SUCCESS, std::forward<Args>(args)...);
 }
+
+/**
+ * Check for the success of `source` (which must evaluate to a ResultVal). If it succeeds, unwraps
+ * the contained value and assigns it to `target`, which can be either an l-value expression or a
+ * variable declaration. If it fails the return code is returned from the current function. Thus it
+ * can be used to cascade errors out, achieving something akin to exception handling.
+ */
+#define CASCADE_RESULT(target, source) \
+        auto CONCAT2(check_result_L, __LINE__) = source; \
+        if (CONCAT2(check_result_L, __LINE__).Failed()) \
+            return CONCAT2(check_result_L, __LINE__).Code(); \
+        target = std::move(*CONCAT2(check_result_L, __LINE__))