From 60c53afe6ea71bfe71ee3f9bfe6a1371cb8a851a Mon Sep 17 00:00:00 2001 From: Dmitry Polukhin Date: Mon, 7 Oct 2024 11:02:14 -0700 Subject: [PATCH] Make `SCOPE_EXIT` ODR safe Summary: `SCOPE_EXIT` macro is actively used in headers but it uses `__COUNTER__` that gives different value in different TU depending on number of previous `__COUNTER__` usages in translation unit. Therefore it violates ODR because function bodies for the same function become different. Clang detects this ODR violations in modularized builds when it merges AST from different modules or between global fragment and module. This diff create ODR safe version of `FB_ANONYMOUS_VARIABLE` that gives stable value but has limitation that it cannot be used more than once on the same line. Reviewed By: Gownta Differential Revision: D63825595 fbshipit-source-id: 7994094df5430a7e58bc51ef6576eae20b5cea0e --- folly/Preprocessor.h | 4 ++++ folly/ScopeGuard.h | 12 ++++++------ 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/folly/Preprocessor.h b/folly/Preprocessor.h index 77ae8e2670f..4b5dde6d5ef 100644 --- a/folly/Preprocessor.h +++ b/folly/Preprocessor.h @@ -100,6 +100,10 @@ #else #define FB_ANONYMOUS_VARIABLE(str) FB_CONCATENATE(str, __LINE__) #endif +// FB_ANONYMOUS_VARIABLE_ODR_SAFE doesn't rely on __COUNTER__ and is safe to use +// in headers that should not violate the one-definition rule (ODR). It is +// especially useful for C++ modules that check for ODR violations. +#define FB_ANONYMOUS_VARIABLE_ODR_SAFE(str) FB_CONCATENATE(str, __LINE__) #endif /** diff --git a/folly/ScopeGuard.h b/folly/ScopeGuard.h index aebbc5f2cbd..698ece1e43d 100644 --- a/folly/ScopeGuard.h +++ b/folly/ScopeGuard.h @@ -356,8 +356,8 @@ ScopeGuardImpl::type, true> operator+( * * @def SCOPE_EXIT */ -#define SCOPE_EXIT \ - auto FB_ANONYMOUS_VARIABLE(SCOPE_EXIT_STATE) = \ +#define SCOPE_EXIT \ + auto FB_ANONYMOUS_VARIABLE_ODR_SAFE(SCOPE_EXIT_STATE) = \ ::folly::detail::ScopeGuardOnExit() + [&]() noexcept // SCOPE_FAIL @@ -386,8 +386,8 @@ ScopeGuardImpl::type, true> operator+( * * @def SCOPE_FAIL */ -#define SCOPE_FAIL \ - auto FB_ANONYMOUS_VARIABLE(SCOPE_FAIL_STATE) = \ +#define SCOPE_FAIL \ + auto FB_ANONYMOUS_VARIABLE_ODR_SAFE(SCOPE_FAIL_STATE) = \ ::folly::detail::ScopeGuardOnFail() + [&]() noexcept // SCOPE_SUCCESS @@ -415,6 +415,6 @@ ScopeGuardImpl::type, true> operator+( * * @def SCOPE_SUCCESS */ -#define SCOPE_SUCCESS \ - auto FB_ANONYMOUS_VARIABLE(SCOPE_SUCCESS_STATE) = \ +#define SCOPE_SUCCESS \ + auto FB_ANONYMOUS_VARIABLE_ODR_SAFE(SCOPE_SUCCESS_STATE) = \ ::folly::detail::ScopeGuardOnSuccess() + [&]()