summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorGravatar bunnei2015-03-08 22:25:04 -0400
committerGravatar bunnei2015-03-08 22:25:04 -0400
commitba8ce6c8f59f012cd22dbc76d26ba290d9174d60 (patch)
tree07bdfa055455654f2d1d74998137ea3b285a96a8 /src
parentMerge pull request #639 from archshift/appbundle (diff)
parentAsserts: Use lambdas to keep assertion code away from the main code path (diff)
downloadyuzu-ba8ce6c8f59f012cd22dbc76d26ba290d9174d60.tar.gz
yuzu-ba8ce6c8f59f012cd22dbc76d26ba290d9174d60.tar.xz
yuzu-ba8ce6c8f59f012cd22dbc76d26ba290d9174d60.zip
Merge pull request #584 from yuriks/outline-asserts
Asserts: Use lambdas to keep assertion code away from the main code path
Diffstat (limited to 'src')
-rw-r--r--src/common/assert.h31
1 files changed, 25 insertions, 6 deletions
diff --git a/src/common/assert.h b/src/common/assert.h
index 3b2232a7e..9ca7adb15 100644
--- a/src/common/assert.h
+++ b/src/common/assert.h
@@ -4,24 +4,43 @@
4 4
5#pragma once 5#pragma once
6 6
7#include <cstdlib>
8
7#include "common/common_funcs.h" 9#include "common/common_funcs.h"
8 10
11// For asserts we'd like to keep all the junk executed when an assert happens away from the
12// important code in the function. One way of doing this is to put all the relevant code inside a
13// lambda and force the compiler to not inline it. Unfortunately, MSVC seems to have no syntax to
14// specify __declspec on lambda functions, so what we do instead is define a noinline wrapper
15// template that calls the lambda. This seems to generate an extra instruction at the call-site
16// compared to the ideal implementation (which wouldn't support ASSERT_MSG parameters), but is good
17// enough for our purposes.
18template <typename Fn>
19#if defined(_MSC_VER)
20 __declspec(noinline, noreturn)
21#elif defined(__GNUC__)
22 __attribute__((noinline, noreturn, cold))
23#endif
24static void assert_noinline_call(const Fn& fn) {
25 fn();
26 Crash();
27 exit(1); // Keeps GCC's mouth shut about this actually returning
28}
29
9// TODO (yuriks) allow synchronous logging so we don't need printf 30// TODO (yuriks) allow synchronous logging so we don't need printf
10#define ASSERT(_a_) \ 31#define ASSERT(_a_) \
11 do if (!(_a_)) {\ 32 do if (!(_a_)) { assert_noinline_call([] { \
12 fprintf(stderr, "Assertion Failed!\n\n Line: %d\n File: %s\n Time: %s\n", \ 33 fprintf(stderr, "Assertion Failed!\n\n Line: %d\n File: %s\n Time: %s\n", \
13 __LINE__, __FILE__, __TIME__); \ 34 __LINE__, __FILE__, __TIME__); \
14 Crash(); \ 35 }); } while (0)
15 } while (0)
16 36
17#define ASSERT_MSG(_a_, ...) \ 37#define ASSERT_MSG(_a_, ...) \
18 do if (!(_a_)) {\ 38 do if (!(_a_)) { assert_noinline_call([&] { \
19 fprintf(stderr, "Assertion Failed!\n\n Line: %d\n File: %s\n Time: %s\n", \ 39 fprintf(stderr, "Assertion Failed!\n\n Line: %d\n File: %s\n Time: %s\n", \
20 __LINE__, __FILE__, __TIME__); \ 40 __LINE__, __FILE__, __TIME__); \
21 fprintf(stderr, __VA_ARGS__); \ 41 fprintf(stderr, __VA_ARGS__); \
22 fprintf(stderr, "\n"); \ 42 fprintf(stderr, "\n"); \
23 Crash(); \ 43 }); } while (0)
24 } while (0)
25 44
26#define UNREACHABLE() ASSERT_MSG(false, "Unreachable code!") 45#define UNREACHABLE() ASSERT_MSG(false, "Unreachable code!")
27 46