Asserts: Use lambdas to keep assertion code away from the main code path
This commit is contained in:
		
							parent
							
								
									a78b8b1bc4
								
							
						
					
					
						commit
						714d507938
					
				@ -4,24 +4,43 @@
 | 
			
		||||
 | 
			
		||||
#pragma once
 | 
			
		||||
 | 
			
		||||
#include <cstdlib>
 | 
			
		||||
 | 
			
		||||
#include "common/common_funcs.h"
 | 
			
		||||
 | 
			
		||||
// For asserts we'd like to keep all the junk executed when an assert happens away from the
 | 
			
		||||
// important code in the function. One way of doing this is to put all the relevant code inside a
 | 
			
		||||
// lambda and force the compiler to not inline it. Unfortunately, MSVC seems to have no syntax to
 | 
			
		||||
// specify __declspec on lambda functions, so what we do instead is define a noinline wrapper
 | 
			
		||||
// template that calls the lambda. This seems to generate an extra instruction at the call-site
 | 
			
		||||
// compared to the ideal implementation (which wouldn't support ASSERT_MSG parameters), but is good
 | 
			
		||||
// enough for our purposes.
 | 
			
		||||
template <typename Fn>
 | 
			
		||||
#if defined(_MSC_VER)
 | 
			
		||||
    __declspec(noinline, noreturn)
 | 
			
		||||
#elif defined(__GNUC__)
 | 
			
		||||
    __attribute__((noinline, noreturn, cold))
 | 
			
		||||
#endif
 | 
			
		||||
static void assert_noinline_call(const Fn& fn) {
 | 
			
		||||
    fn();
 | 
			
		||||
    Crash();
 | 
			
		||||
    exit(1); // Keeps GCC's mouth shut about this actually returning
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// TODO (yuriks) allow synchronous logging so we don't need printf
 | 
			
		||||
#define ASSERT(_a_) \
 | 
			
		||||
    do if (!(_a_)) {\
 | 
			
		||||
    do if (!(_a_)) { assert_noinline_call([] { \
 | 
			
		||||
        fprintf(stderr, "Assertion Failed!\n\n  Line: %d\n  File: %s\n  Time: %s\n", \
 | 
			
		||||
                     __LINE__, __FILE__, __TIME__); \
 | 
			
		||||
        Crash(); \
 | 
			
		||||
    } while (0)
 | 
			
		||||
    }); } while (0)
 | 
			
		||||
 | 
			
		||||
#define ASSERT_MSG(_a_, ...) \
 | 
			
		||||
    do if (!(_a_)) {\
 | 
			
		||||
    do if (!(_a_)) { assert_noinline_call([&] { \
 | 
			
		||||
        fprintf(stderr, "Assertion Failed!\n\n  Line: %d\n  File: %s\n  Time: %s\n", \
 | 
			
		||||
                     __LINE__, __FILE__, __TIME__); \
 | 
			
		||||
        fprintf(stderr, __VA_ARGS__); \
 | 
			
		||||
        fprintf(stderr, "\n"); \
 | 
			
		||||
        Crash(); \
 | 
			
		||||
    } while (0)
 | 
			
		||||
    }); } while (0)
 | 
			
		||||
 | 
			
		||||
#define UNREACHABLE() ASSERT_MSG(false, "Unreachable code!")
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
		Loading…
	
		Reference in New Issue
	
	Block a user