1// Copyright 2017 The Abseil Authors.
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// https://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15#ifndef ABSL_BASE_INTERNAL_INLINE_VARIABLE_EMULATION_H_
16#define ABSL_BASE_INTERNAL_INLINE_VARIABLE_EMULATION_H_
17
18#include <type_traits>
19
20#include "absl/base/internal/identity.h"
21
22// File:
23// This file define a macro that allows the creation of or emulation of C++17
24// inline variables based on whether or not the feature is supported.
25
26////////////////////////////////////////////////////////////////////////////////
27// Macro: ABSL_INTERNAL_INLINE_CONSTEXPR(type, name, init)
28//
29// Description:
30// Expands to the equivalent of an inline constexpr instance of the specified
31// `type` and `name`, initialized to the value `init`. If the compiler being
32// used is detected as supporting actual inline variables as a language
33// feature, then the macro expands to an actual inline variable definition.
34//
35// Requires:
36// `type` is a type that is usable in an extern variable declaration.
37//
38// Requires: `name` is a valid identifier
39//
40// Requires:
41// `init` is an expression that can be used in the following definition:
42// constexpr type name = init;
43//
44// Usage:
45//
46// // Equivalent to: `inline constexpr size_t variant_npos = -1;`
47// ABSL_INTERNAL_INLINE_CONSTEXPR(size_t, variant_npos, -1);
48//
49// Differences in implementation:
50// For a direct, language-level inline variable, decltype(name) will be the
51// type that was specified along with const qualification, whereas for
52// emulated inline variables, decltype(name) may be different (in practice
53// it will likely be a reference type).
54////////////////////////////////////////////////////////////////////////////////
55
56#ifdef __cpp_inline_variables
57
58// Clang's -Wmissing-variable-declarations option erroneously warned that
59// inline constexpr objects need to be pre-declared. This has now been fixed,
60// but we will need to support this workaround for people building with older
61// versions of clang.
62//
63// Bug: https://bugs.llvm.org/show_bug.cgi?id=35862
64//
65// Note:
66// identity_t is used here so that the const and name are in the
67// appropriate place for pointer types, reference types, function pointer
68// types, etc..
69#if defined(__clang__)
70#define ABSL_INTERNAL_EXTERN_DECL(type, name) \
71 extern const ::absl::internal::identity_t<type> name;
72#else // Otherwise, just define the macro to do nothing.
73#define ABSL_INTERNAL_EXTERN_DECL(type, name)
74#endif // defined(__clang__)
75
76// See above comment at top of file for details.
77#define ABSL_INTERNAL_INLINE_CONSTEXPR(type, name, init) \
78 ABSL_INTERNAL_EXTERN_DECL(type, name) \
79 inline constexpr ::absl::internal::identity_t<type> name = init
80
81#else
82
83// See above comment at top of file for details.
84//
85// Note:
86// identity_t is used here so that the const and name are in the
87// appropriate place for pointer types, reference types, function pointer
88// types, etc..
89#define ABSL_INTERNAL_INLINE_CONSTEXPR(var_type, name, init) \
90 template <class /*AbslInternalDummy*/ = void> \
91 struct AbslInternalInlineVariableHolder##name { \
92 static constexpr ::absl::internal::identity_t<var_type> kInstance = init; \
93 }; \
94 \
95 template <class AbslInternalDummy> \
96 constexpr ::absl::internal::identity_t<var_type> \
97 AbslInternalInlineVariableHolder##name<AbslInternalDummy>::kInstance; \
98 \
99 static constexpr const ::absl::internal::identity_t<var_type>& \
100 name = /* NOLINT */ \
101 AbslInternalInlineVariableHolder##name<>::kInstance; \
102 static_assert(sizeof(void (*)(decltype(name))) != 0, \
103 "Silence unused variable warnings.")
104
105#endif // __cpp_inline_variables
106
107#endif // ABSL_BASE_INTERNAL_INLINE_VARIABLE_EMULATION_H_
108