Make ConsumedError require handling the returned bool.

This change makes it harder to misuse ConsumedError which can cause
device loss. When it is a known error, instead use HandleError to
bypass the "unlikely" if clause.

Bug: dawn:1336
Change-Id: I3052db343fe4080b257f1c2f9535f743a0e78526
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/120384
Reviewed-by: Austin Eng <enga@chromium.org>
Reviewed-by: Corentin Wallez <cwallez@chromium.org>
Commit-Queue: Loko Kung <lokokung@google.com>
Kokoro: Kokoro <noreply+kokoro@google.com>
diff --git a/src/dawn/native/Buffer.cpp b/src/dawn/native/Buffer.cpp
index c7124e5..338d515 100644
--- a/src/dawn/native/Buffer.cpp
+++ b/src/dawn/native/Buffer.cpp
@@ -506,9 +506,7 @@
     if (GetDevice()->ConsumedError(ValidateUnmap(), "calling %s.Unmap().", this)) {
         return;
     }
-    if (GetDevice()->ConsumedError(Unmap(), "calling %s.Unmap().", this)) {
-        return;
-    }
+    DAWN_UNUSED(GetDevice()->ConsumedError(Unmap(), "calling %s.Unmap().", this));
 }
 
 MaybeError BufferBase::Unmap() {
diff --git a/src/dawn/native/ComputePassEncoder.cpp b/src/dawn/native/ComputePassEncoder.cpp
index d3c6a5c..63505c7 100644
--- a/src/dawn/native/ComputePassEncoder.cpp
+++ b/src/dawn/native/ComputePassEncoder.cpp
@@ -151,7 +151,7 @@
 
 void ComputePassEncoder::APIEnd() {
     if (mEnded && IsValidationEnabled()) {
-        GetDevice()->ConsumedError(DAWN_VALIDATION_ERROR("%s was already ended.", this));
+        GetDevice()->HandleError(DAWN_VALIDATION_ERROR("%s was already ended.", this));
         return;
     }
 
diff --git a/src/dawn/native/Device.cpp b/src/dawn/native/Device.cpp
index 28956d0..53356e1 100644
--- a/src/dawn/native/Device.cpp
+++ b/src/dawn/native/Device.cpp
@@ -469,6 +469,7 @@
 void DeviceBase::HandleError(std::unique_ptr<ErrorData> error,
                              InternalErrorType additionalAllowedErrors,
                              WGPUDeviceLostReason lost_reason) {
+    AppendDebugLayerMessages(error.get());
     InternalErrorType allowedErrors =
         InternalErrorType::Validation | InternalErrorType::DeviceLost | additionalAllowedErrors;
     InternalErrorType type = error->GetType();
@@ -545,7 +546,6 @@
 void DeviceBase::ConsumeError(std::unique_ptr<ErrorData> error,
                               InternalErrorType additionalAllowedErrors) {
     ASSERT(error != nullptr);
-    AppendDebugLayerMessages(error.get());
     HandleError(std::move(error), additionalAllowedErrors);
 }
 
@@ -1203,21 +1203,24 @@
     // The validation errors on BufferDescriptor should be prior to any OOM errors when
     // MapppedAtCreation == false.
     MaybeError maybeError = ValidateBufferDescriptor(this, &fakeDescriptor);
-    if (maybeError.IsError()) {
-        ConsumedError(maybeError.AcquireError(), InternalErrorType::OutOfMemory,
-                      "calling %s.CreateBuffer(%s).", this, desc);
-    } else {
-        const DawnBufferDescriptorErrorInfoFromWireClient* clientErrorInfo = nullptr;
-        FindInChain(desc->nextInChain, &clientErrorInfo);
-        if (clientErrorInfo != nullptr && clientErrorInfo->outOfMemory) {
-            ConsumedError(DAWN_OUT_OF_MEMORY_ERROR("Failed to allocate memory for buffer mapping"),
-                          InternalErrorType::OutOfMemory);
-        }
-    }
 
     // Set the size of the error buffer to 0 as this function is called only when an OOM happens at
     // the client side.
     fakeDescriptor.size = 0;
+
+    if (maybeError.IsError()) {
+        std::unique_ptr<ErrorData> error = maybeError.AcquireError();
+        error->AppendContext("calling %s.CreateBuffer(%s).", this, desc);
+        HandleError(std::move(error), InternalErrorType::OutOfMemory);
+    } else {
+        const DawnBufferDescriptorErrorInfoFromWireClient* clientErrorInfo = nullptr;
+        FindInChain(desc->nextInChain, &clientErrorInfo);
+        if (clientErrorInfo != nullptr && clientErrorInfo->outOfMemory) {
+            HandleError(DAWN_OUT_OF_MEMORY_ERROR("Failed to allocate memory for buffer mapping"),
+                        InternalErrorType::OutOfMemory);
+        }
+    }
+
     return BufferBase::MakeError(this, &fakeDescriptor);
 }
 
@@ -1401,7 +1404,7 @@
 }
 
 void DeviceBase::APIValidateTextureDescriptor(const TextureDescriptor* desc) {
-    ConsumedError(ValidateTextureDescriptor(this, desc));
+    DAWN_UNUSED(ConsumedError(ValidateTextureDescriptor(this, desc)));
 }
 
 QueueBase* DeviceBase::GetQueue() const {
diff --git a/src/dawn/native/Device.h b/src/dawn/native/Device.h
index ba3c7c7..0507bc2 100644
--- a/src/dawn/native/Device.h
+++ b/src/dawn/native/Device.h
@@ -76,8 +76,12 @@
                      InternalErrorType additionalAllowedErrors = InternalErrorType::None,
                      WGPUDeviceLostReason lost_reason = WGPUDeviceLostReason_Undefined);
 
-    bool ConsumedError(MaybeError maybeError,
-                       InternalErrorType additionalAllowedErrors = InternalErrorType::None) {
+    // Variants of ConsumedError must use the returned boolean to handle failure cases since an
+    // error may cause a device loss and further execution may be undefined. This is especially
+    // true for the ResultOrError variants.
+    [[nodiscard]] bool ConsumedError(
+        MaybeError maybeError,
+        InternalErrorType additionalAllowedErrors = InternalErrorType::None) {
         if (DAWN_UNLIKELY(maybeError.IsError())) {
             ConsumeError(maybeError.AcquireError(), additionalAllowedErrors);
             return true;
@@ -86,9 +90,10 @@
     }
 
     template <typename T>
-    bool ConsumedError(ResultOrError<T> resultOrError,
-                       T* result,
-                       InternalErrorType additionalAllowedErrors = InternalErrorType::None) {
+    [[nodiscard]] bool ConsumedError(
+        ResultOrError<T> resultOrError,
+        T* result,
+        InternalErrorType additionalAllowedErrors = InternalErrorType::None) {
         if (DAWN_UNLIKELY(resultOrError.IsError())) {
             ConsumeError(resultOrError.AcquireError(), additionalAllowedErrors);
             return true;
@@ -98,10 +103,10 @@
     }
 
     template <typename... Args>
-    bool ConsumedError(MaybeError maybeError,
-                       InternalErrorType additionalAllowedErrors,
-                       const char* formatStr,
-                       const Args&... args) {
+    [[nodiscard]] bool ConsumedError(MaybeError maybeError,
+                                     InternalErrorType additionalAllowedErrors,
+                                     const char* formatStr,
+                                     const Args&... args) {
         if (DAWN_UNLIKELY(maybeError.IsError())) {
             std::unique_ptr<ErrorData> error = maybeError.AcquireError();
             if (error->GetType() == InternalErrorType::Validation) {
@@ -114,17 +119,18 @@
     }
 
     template <typename... Args>
-    bool ConsumedError(MaybeError maybeError, const char* formatStr, Args&&... args) {
-        return ConsumedError(std::move(maybeError), InternalErrorType::None, formatStr,
-                             std::forward<Args>(args)...);
+    [[nodiscard]] bool ConsumedError(MaybeError maybeError,
+                                     const char* formatStr,
+                                     const Args&... args) {
+        return ConsumedError(std::move(maybeError), InternalErrorType::None, formatStr, args...);
     }
 
     template <typename T, typename... Args>
-    bool ConsumedError(ResultOrError<T> resultOrError,
-                       T* result,
-                       InternalErrorType additionalAllowedErrors,
-                       const char* formatStr,
-                       const Args&... args) {
+    [[nodiscard]] bool ConsumedError(ResultOrError<T> resultOrError,
+                                     T* result,
+                                     InternalErrorType additionalAllowedErrors,
+                                     const char* formatStr,
+                                     const Args&... args) {
         if (DAWN_UNLIKELY(resultOrError.IsError())) {
             std::unique_ptr<ErrorData> error = resultOrError.AcquireError();
             if (error->GetType() == InternalErrorType::Validation) {
@@ -138,12 +144,12 @@
     }
 
     template <typename T, typename... Args>
-    bool ConsumedError(ResultOrError<T> resultOrError,
-                       T* result,
-                       const char* formatStr,
-                       Args&&... args) {
+    [[nodiscard]] bool ConsumedError(ResultOrError<T> resultOrError,
+                                     T* result,
+                                     const char* formatStr,
+                                     const Args&... args) {
         return ConsumedError(std::move(resultOrError), result, InternalErrorType::None, formatStr,
-                             std::forward<Args>(args)...);
+                             args...);
     }
 
     MaybeError ValidateObject(const ApiObjectBase* object) const;
diff --git a/src/dawn/native/Queue.cpp b/src/dawn/native/Queue.cpp
index a8d92e3..926e13a 100644
--- a/src/dawn/native/Queue.cpp
+++ b/src/dawn/native/Queue.cpp
@@ -281,7 +281,7 @@
                                uint64_t bufferOffset,
                                const void* data,
                                size_t size) {
-    GetDevice()->ConsumedError(WriteBuffer(buffer, bufferOffset, data, size));
+    DAWN_UNUSED(GetDevice()->ConsumedError(WriteBuffer(buffer, bufferOffset, data, size)));
 }
 
 MaybeError QueueBase::WriteBuffer(BufferBase* buffer,
@@ -322,8 +322,8 @@
                                 size_t dataSize,
                                 const TextureDataLayout* dataLayout,
                                 const Extent3D* writeSize) {
-    GetDevice()->ConsumedError(
-        WriteTextureInternal(destination, data, dataSize, *dataLayout, writeSize));
+    DAWN_UNUSED(GetDevice()->ConsumedError(
+        WriteTextureInternal(destination, data, dataSize, *dataLayout, writeSize)));
 }
 
 MaybeError QueueBase::WriteTextureInternal(const ImageCopyTexture* destination,
@@ -389,16 +389,16 @@
                                          const ImageCopyTexture* destination,
                                          const Extent3D* copySize,
                                          const CopyTextureForBrowserOptions* options) {
-    GetDevice()->ConsumedError(
-        CopyTextureForBrowserInternal(source, destination, copySize, options));
+    DAWN_UNUSED(GetDevice()->ConsumedError(
+        CopyTextureForBrowserInternal(source, destination, copySize, options)));
 }
 
 void QueueBase::APICopyExternalTextureForBrowser(const ImageCopyExternalTexture* source,
                                                  const ImageCopyTexture* destination,
                                                  const Extent3D* copySize,
                                                  const CopyTextureForBrowserOptions* options) {
-    GetDevice()->ConsumedError(
-        CopyExternalTextureForBrowserInternal(source, destination, copySize, options));
+    DAWN_UNUSED(GetDevice()->ConsumedError(
+        CopyExternalTextureForBrowserInternal(source, destination, copySize, options)));
 }
 
 MaybeError QueueBase::CopyTextureForBrowserInternal(const ImageCopyTexture* source,
diff --git a/src/dawn/native/RenderPassEncoder.cpp b/src/dawn/native/RenderPassEncoder.cpp
index 3b5a062..5b3e409 100644
--- a/src/dawn/native/RenderPassEncoder.cpp
+++ b/src/dawn/native/RenderPassEncoder.cpp
@@ -137,7 +137,7 @@
 
 void RenderPassEncoder::APIEnd() {
     if (mEnded && IsValidationEnabled()) {
-        GetDevice()->ConsumedError(DAWN_VALIDATION_ERROR("%s was already ended.", this));
+        GetDevice()->HandleError(DAWN_VALIDATION_ERROR("%s was already ended.", this));
         return;
     }
 
diff --git a/src/dawn/native/SwapChain.cpp b/src/dawn/native/SwapChain.cpp
index 3e1d3de..a43067f 100644
--- a/src/dawn/native/SwapChain.cpp
+++ b/src/dawn/native/SwapChain.cpp
@@ -35,16 +35,16 @@
                       wgpu::TextureUsage allowedUsage,
                       uint32_t width,
                       uint32_t height) override {
-        GetDevice()->ConsumedError(DAWN_VALIDATION_ERROR("%s is an error swapchain.", this));
+        GetDevice()->HandleError(DAWN_VALIDATION_ERROR("%s is an error swapchain.", this));
     }
 
     TextureViewBase* APIGetCurrentTextureView() override {
-        GetDevice()->ConsumedError(DAWN_VALIDATION_ERROR("%s is an error swapchain.", this));
+        GetDevice()->HandleError(DAWN_VALIDATION_ERROR("%s is an error swapchain.", this));
         return TextureViewBase::MakeError(GetDevice());
     }
 
     void APIPresent() override {
-        GetDevice()->ConsumedError(DAWN_VALIDATION_ERROR("%s is an error swapchain.", this));
+        GetDevice()->HandleError(DAWN_VALIDATION_ERROR("%s is an error swapchain.", this));
     }
 };
 
@@ -300,7 +300,7 @@
                                     wgpu::TextureUsage allowedUsage,
                                     uint32_t width,
                                     uint32_t height) {
-    GetDevice()->ConsumedError(
+    GetDevice()->HandleError(
         DAWN_VALIDATION_ERROR("Configure is invalid for surface-based swapchains."));
 }
 
diff --git a/src/dawn/tests/unittests/validation/DeviceValidationTests.cpp b/src/dawn/tests/unittests/validation/DeviceValidationTests.cpp
index e1c9e0b..041ca96 100644
--- a/src/dawn/tests/unittests/validation/DeviceValidationTests.cpp
+++ b/src/dawn/tests/unittests/validation/DeviceValidationTests.cpp
@@ -226,6 +226,6 @@
     ExpectDeviceDestruction();
     device.Destroy();
     dawn::native::DeviceBase* nativeDevice = dawn::native::FromAPI(device.Get());
-    ASSERT_DEVICE_ERROR(nativeDevice->ConsumedError(nativeDevice->Tick()),
+    ASSERT_DEVICE_ERROR(EXPECT_TRUE(nativeDevice->ConsumedError(nativeDevice->Tick())),
                         HasSubstr("[Device] is lost."));
 }