#ifndef DECOMP_FORCE_H #define DECOMP_FORCE_H #include "macros.h" /******************************************************************************* * Configuration */ /* NOTE: This repo's defines "typeof" as a macro. If you aren't using * it, Metrowerks compilers since 2.4.2 have exposed this feature through the * keyword "__typeof__". Metrowerks compilers before this version are not * currently supported. */ #ifndef typeof #define typeof __typeof__ #endif #define DF_TYPEOF typeof /* NOTE: This repo's defines "static_assert" as a macro. If you * aren't using it, Metrowerks compilers since 4.1 have exposed this feature * through the keyword "__static_assert". Alternatively, a typedef-based version * also works as a substitute for any compiler. */ #define DF_SWALLOW_SEMICOLON() static_assert(1, "") /******************************************************************************* * Macro helpers */ #define DF_CONCAT3_(a, b, c) a##b##c #define DF_CONCAT3(a, b, c) DF_CONCAT3_(a, b, c) #define DF_UNIQUE_IDENT(ident_) DF_CONCAT3(ident_, _, __LINE__) #if defined(__clang__) #define DF_SUPPRESS_WARNINGS() \ _Pragma("clang diagnostic push") _Pragma("clang diagnostic ignored \"-Wnull-dereference\"") #define DF_UNSUPPRESS_WARNINGS() _Pragma("clang diagnostic pop") #elif defined(__MWERKS__) #pragma section RX ".decomp" #define DF_SUPPRESS_WARNINGS() __attribute__((section(".decomp"))) #define DF_UNSUPPRESS_WARNINGS() #else #define DF_SUPPRESS_WARNINGS() #define DF_UNSUPPRESS_WARNINGS() #endif /******************************************************************************* * DECOMP_FORCE macro internals */ #define DF_FUNCTION_DECLARATOR_WITH_PROTO(ident_) \ extern void(ident_)(void); \ extern void(ident_)(void) // this is done to prevent default promotion of arguments to variadic functions #define DF_FUNCTION_CALL(ident_, arg_) \ extern void(ident_)(DF_TYPEOF(arg_)); \ (ident_)(arg_) /******************************************************************************* * DECOMP_FORCE macros */ /* Forcefully generate orphaned data, early references, or other shenanigans. * Only works at file or namespace scope. * * Examples: * DECOMP_FORCE(1.0f); * DECOMP_FORCE("I am a string"); * DECOMP_FORCE(UI2D_CONSTANT); */ #define DECOMP_FORCE(arg_) \ DF_SUPPRESS_WARNINGS() \ DF_FUNCTION_DECLARATOR_WITH_PROTO(DF_UNIQUE_IDENT(DECOMP_FORCE)) { \ DF_FUNCTION_CALL(DF_UNIQUE_IDENT(DECOMP_FORCE_CALL), arg_); \ } \ DF_UNSUPPRESS_WARNINGS() \ DF_SWALLOW_SEMICOLON() /* Forcefully instantiate a class's method. For method_, write it as you would * an actual function call. * Only works at file or namespace scope. * * If class_ uses commas outside of nested parentheses, you must enclose the * entire argument in DF_TYPEOF(). If method_ uses commas outside of nested * parentheses, they are handled via __VA_ARGS__. * * Examples: * DECOMP_FORCE_CLASS_METHOD(Class1, ~Class1()); * DECOMP_FORCE_CLASS_METHOD(DF_TYPEOF(Class2), func(2, 3)); * DECOMP_FORCE_CLASS_METHOD(Class3, operator ,(4)); */ #if defined(__cplusplus) #define DECOMP_FORCE_CLASS_METHOD(class_, ...) \ DECOMP_FORCE(((void)(static_cast(0)->__VA_ARGS__), 0)) #endif /******************************************************************************* * DECOMP_FORCE helpers */ // Conversion constants from integer to floating-point extern signed int DECOMP_SI; extern unsigned int DECOMP_UI; #define SI2D_CONSTANT ((float)(DECOMP_SI)) #define UI2D_CONSTANT ((float)(DECOMP_UI)) // clang-format on #endif // DECOMP_FORCE_H