Skip to content

Instantly share code, notes, and snippets.

@rileylev
Last active May 3, 2022 05:07
Show Gist options
  • Save rileylev/0b9e5881c5b5c45bfb684bb33dacf71f to your computer and use it in GitHub Desktop.
Save rileylev/0b9e5881c5b5c45bfb684bb33dacf71f to your computer and use it in GitHub Desktop.
Shadow, poison, and frezee
#include "hedley.h"
// https://www.fluentcpp.com/2019/08/30/how-to-disable-a-warning-in-cpp/
#include <initializer_list>
//#pragma GCC diagnostic error "-Wshadow"
#define PRAGMA_IGNORE_SHADOW_GCC \
_Pragma("GCC diagnostic ignored \"-Wshadow\"")
#define MSVC_DISABLE_WARNING(num) __pragma(warning(disable : num))
#define PRAGMA_IGNORE_SHADOW_MSVC \
/* declaration of 'identifier' hides previous local declaration */ \
MSVC_DISABLE_WARNING(4456) \
/* declaration of 'identifier' hides function parameter*/ \
MSVC_DISABLE_WARNING(4457) \
/* declaration of 'identifier' hides class member */ \
MSVC_DISABLE_WARNING(4458) \
/* declaration of 'identifier' hides global declaration */ \
MSVC_DISABLE_WARNING(4459)
#if __GNUC__
# define PRAGMA_IGNORE_SHADOW PRAGMA_IGNORE_SHADOW_GCC
#elif _MSC_VER
# define PRAGMA_IGNORE_SHADOW PRAGMA_IGNORE_SHADOW_MSVC
#else
# define PRAGMA_IGNORE_SHADOW
#endif
#define IGNORE_SHADOW(...) \
HEDLEY_DIAGNOSTIC_PUSH PRAGMA_IGNORE_SHADOW __VA_ARGS__ \
HEDLEY_DIAGNOSTIC_POP
#define GENSYM(sym) HEDLEY_CONCAT3(sym, gensym, __COUNTER__)
/**
* Defines a new variable in the introduced scope
*
* LET1(int x = 3){
* ++x;
* }
*/
#define LET1(...) for(__VA_ARGS__; [[maybe_unused]] auto GENSYM(_) : {0})
/**
* Disable warnings for shadowing for one variable definition introduced in
* a new scope
*
* int const x = 2;
* SHADOW(int x = 0){
* ++x; // ok!
* }
*/
#define SHADOW(...) IGNORE_SHADOW(LET1(__VA_ARGS__))
/**
* Poisons a variable within the introduced scope
*
* int x = 0;
* POISON(x){
* int y = x; // warning/error!
* }
*/
#define POISON(name) \
SHADOW([[deprecated("poisoned"), maybe_unused]] char name)
#define FREEZE_(tmp, name) \
LET1(auto const& tmp = name) SHADOW(auto const& name = tmp)
/**
* Freezes a variable into a const within the new scope:
*
* for(int i =0; i < 10; ++i)
* FREEZE(i){
* ++i; // error! i is const here
* }
*/
#define FREEZE(name) FREEZE_(GENSYM(tmp), name)
#include <type_traits>
template<class T>
using ReadIn = std::conditional_t<
std::is_trivially_copyable_v<T> && sizeof(T) <= 2 * sizeof(void*),
T const,
T const&>;
#define READIN_(tmp, name) \
LET1(auto const& tmp = name) \
SHADOW(ReadIn<std::remove_reference_t<decltype(tmp)>> name = tmp)
/**
* Rebind `name` to a ReadIn within the new scope
*
* To pass by value or const&? How expensive is a copy? How much do
* references befuddle the optimizer? Can we automate this decision without
* interfering with template type deduction?
*
* Using READIN, we can take a variable by * const& and rebind it to a
* ReadIn, copying if that's cheap.
*
* template<class T>
* auto f(T const& x) {
* READIN(x){
* // now x becomes a copy if that's cheap
* // without messing with template type deduction
* }
* }
*
* The template function is inlinable, so the optimizer can (with luck) see
* if we end up taking a copy.
*/
#define READIN(name) READIN_(GENSYM(tmp), name)
int const x = 0;
int test() {
SHADOW(int x = 2) {
++x;
auto y = x;
POISON(x) {
++x;
FREEZE(y) { return ++y; }
}
}
}
@rileylev
Copy link
Author

rileylev commented May 3, 2022

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment