250 lines · c
1/**2 * This file contains tests for the -Wunique_object_duplication warning.3 * See the warning's documentation for more information.4 */5 6#ifdef WINDOWS_TEST7#define HIDDEN8// dllimport also suffices for visibility, but those can't have definitions9#define VISIBLE __declspec(dllexport)10#else11#define HIDDEN __attribute__((visibility("hidden")))12#define VISIBLE __attribute__((visibility("default")))13#endif14 15// Helper functions16constexpr int init_constexpr(int x) { return x; };17extern double init_dynamic(int);18 19/******************************************************************************20 * Case one: Static local variables in an externally-visible function21 ******************************************************************************/22namespace StaticLocalTest {23 24inline void has_static_locals_external() {25 // Mutable26 static int disallowedStatic1 = 0; // hidden-warning {{'disallowedStatic1' may be duplicated when built into a shared library: it is mutable, with external linkage and hidden visibility}}27 // windows-warning@-1 {{'disallowedStatic1' may be duplicated when built into a shared library: it is mutable, with external linkage and no import/export annotation}}28 // Initialization might run more than once29 static const double disallowedStatic2 = disallowedStatic1++; // hidden-warning {{initialization of 'disallowedStatic2' may run twice when built into a shared library: it has external linkage and hidden visibility}}30 // windows-warning@-1 {{initialization of 'disallowedStatic2' may run twice when built into a shared library: it has external linkage and no import/export annotation}}31 // OK, because immutable and compile-time-initialized32 static constexpr int allowedStatic1 = 0;33 static const float allowedStatic2 = 1;34 static constexpr int allowedStatic3 = init_constexpr(2);35 static const int allowedStatic4 = init_constexpr(3);36}37 38// Don't warn for non-inline functions, since they can't (legally) appear39// in more than one TU in the first place.40void has_static_locals_non_inline() {41 // Mutable42 static int allowedStatic1 = 0;43 // Initialization might run more than once44 static const double allowedStatic2 = allowedStatic1++;45}46 47// Everything in this function is OK because the function is TU-local48static void has_static_locals_internal() {49 static int allowedStatic1 = 0;50 static double allowedStatic2 = init_dynamic(2);51 static char allowedStatic3 = []() { return allowedStatic1++; }();52 static constexpr int allowedStatic4 = 0;53}54 55namespace {56 57// Everything in this function is OK because the function is also TU-local58void has_static_locals_anon() {59 static int allowedStatic1 = 0;60 static double allowedStatic2 = init_dynamic(2);61 static char allowedStatic3 = []() { return allowedStatic1++; }();62 static constexpr int allowedStatic4 = init_constexpr(3);63}64 65} // Anonymous namespace66 67HIDDEN inline void static_local_always_hidden() {68 static int disallowedStatic1 = 3; // hidden-warning {{'disallowedStatic1' may be duplicated when built into a shared library: it is mutable, with external linkage and hidden visibility}}69 // expected-warning@-1 {{'disallowedStatic1' may be duplicated when built into a shared library: it is mutable, with external linkage and hidden visibility}}70 // windows-warning@-2 {{'disallowedStatic1' may be duplicated when built into a shared library: it is mutable, with external linkage and no import/export annotation}}71 {72 static int disallowedStatic2 = 3; // hidden-warning {{'disallowedStatic2' may be duplicated when built into a shared library: it is mutable, with external linkage and hidden visibility}}73 // expected-warning@-1 {{'disallowedStatic2' may be duplicated when built into a shared library: it is mutable, with external linkage and hidden visibility}}74 // windows-warning@-2 {{'disallowedStatic2' may be duplicated when built into a shared library: it is mutable, with external linkage and no import/export annotation}}75 }76 77 auto lmb = []() {78 static int disallowedStatic3 = 3; // hidden-warning {{'disallowedStatic3' may be duplicated when built into a shared library: it is mutable, with external linkage and hidden visibility}}79 // expected-warning@-1 {{'disallowedStatic3' may be duplicated when built into a shared library: it is mutable, with external linkage and hidden visibility}}80 // windows-warning@-2 {{'disallowedStatic3' may be duplicated when built into a shared library: it is mutable, with external linkage and no import/export annotation}}81 };82}83 84// Always visible85VISIBLE void static_local_never_hidden() {86 static int allowedStatic1 = 3;87 88 {89 static int allowedStatic2 = 3;90 }91 92 auto lmb = []() {93 static int allowedStatic3 = 3;94 };95}96 97// Don't warn on this because it's not in a function98const int setByLambda = ([]() { static int x = 3; return x++; })();99 100inline void has_extern_local() {101 extern int allowedAddressExtern; // Not a definition102}103 104inline void has_regular_local() {105 int allowedAddressLocal = 0;106}107 108inline void has_thread_local() {109 // thread_local variables are static by default110 thread_local int disallowedThreadLocal = 0; // hidden-warning {{'disallowedThreadLocal' may be duplicated when built into a shared library: it is mutable, with external linkage and hidden visibility}}111 // windows-warning@-1 {{'disallowedThreadLocal' may be duplicated when built into a shared library: it is mutable, with external linkage and no import/export annotation}}112}113 114// Functions themselves are always immutable, so referencing them is okay115inline auto& allowedFunctionReference = has_static_locals_external;116 117} // namespace StaticLocalTest118 119/******************************************************************************120 * Case two: Globals with external linkage121 ******************************************************************************/122namespace GlobalTest {123 // Mutable124 inline float disallowedGlobal1 = 3.14; // hidden-warning {{'disallowedGlobal1' may be duplicated when built into a shared library: it is mutable, with external linkage and hidden visibility}}125 // windows-warning@-1 {{'disallowedGlobal1' may be duplicated when built into a shared library: it is mutable, with external linkage and no import/export annotation}}126 127 128 // Initialization might run more than once129 inline const double disallowedGlobal5 = disallowedGlobal1++; // hidden-warning {{initialization of 'disallowedGlobal5' may run twice when built into a shared library: it has external linkage and hidden visibility}}130 // windows-warning@-1 {{initialization of 'disallowedGlobal5' may run twice when built into a shared library: it has external linkage and no import/export annotation}}131 // OK because internal linkage, so duplication is intended132 static float allowedGlobal1 = 3.14;133 const double allowedGlobal2 = init_dynamic(2);134 static const char allowedGlobal3 = []() { return disallowedGlobal1++; }();135 static inline double allowedGlobal4 = init_dynamic(2);136 137 // OK, because immutable and compile-time-initialized138 constexpr int allowedGlobal5 = 0;139 const float allowedGlobal6 = 1;140 constexpr int allowedGlobal7 = init_constexpr(2);141 const int allowedGlobal8 = init_constexpr(3);142 143 // We don't warn on this because non-inline variables can't (legally) appear144 // in more than one TU.145 float allowedGlobal9 = 3.14;146 147 // Pointers need to be double-const-qualified148 inline float& nonConstReference = disallowedGlobal1; // hidden-warning {{'nonConstReference' may be duplicated when built into a shared library: it is mutable, with external linkage and hidden visibility}}149 // windows-warning@-1 {{'nonConstReference' may be duplicated when built into a shared library: it is mutable, with external linkage and no import/export annotation}}150 const inline int& constReference = allowedGlobal5;151 152 inline int* nonConstPointerToNonConst = nullptr; // hidden-warning {{'nonConstPointerToNonConst' may be duplicated when built into a shared library: it is mutable, with external linkage and hidden visibility}}153 // windows-warning@-1 {{'nonConstPointerToNonConst' may be duplicated when built into a shared library: it is mutable, with external linkage and no import/export annotation}}154 inline int const* nonConstPointerToConst = nullptr; // hidden-warning {{'nonConstPointerToConst' may be duplicated when built into a shared library: it is mutable, with external linkage and hidden visibility}}155 // windows-warning@-1 {{'nonConstPointerToConst' may be duplicated when built into a shared library: it is mutable, with external linkage and no import/export annotation}}156 inline int* const constPointerToNonConst = nullptr; // hidden-warning {{'constPointerToNonConst' may be duplicated when built into a shared library: it is mutable, with external linkage and hidden visibility}}157 // windows-warning@-1 {{'constPointerToNonConst' may be duplicated when built into a shared library: it is mutable, with external linkage and no import/export annotation}}158 inline int const* const constPointerToConst = nullptr;159 // Don't warn on new because it tends to generate false positives160 inline int const* const constPointerToConstNew = new int(7);161 162 inline int const * const * const * const nestedConstPointer = nullptr;163 inline int const * const ** const * const nestedNonConstPointer = nullptr; // hidden-warning {{'nestedNonConstPointer' may be duplicated when built into a shared library: it is mutable, with external linkage and hidden visibility}}164 // windows-warning@-1 {{'nestedNonConstPointer' may be duplicated when built into a shared library: it is mutable, with external linkage and no import/export annotation}}165 166 struct Test {167 static inline float disallowedStaticMember1; // hidden-warning {{'disallowedStaticMember1' may be duplicated when built into a shared library: it is mutable, with external linkage and hidden visibility}}168 // windows-warning@-1 {{'disallowedStaticMember1' may be duplicated when built into a shared library: it is mutable, with external linkage and no import/export annotation}}169 // Defined below, in the header file170 static float disallowedStaticMember2;171 // Defined in the cpp file, so won't get duplicated172 static float allowedStaticMember1;173 174 // Always visible175 VISIBLE static inline float allowedStaticMember2 = 0.0;176 };177 178 inline float Test::disallowedStaticMember2 = 2.3; // hidden-warning {{'disallowedStaticMember2' may be duplicated when built into a shared library: it is mutable, with external linkage and hidden visibility}}179 // windows-warning@-1 {{'disallowedStaticMember2' may be duplicated when built into a shared library: it is mutable, with external linkage and no import/export annotation}}180 181 // This is always visible, so nothing inside it will get duplicated182 struct VISIBLE NeverHidden {183 static inline float allowedStaticMember3;184 static float allowedStaticMember4;185 };186 187 inline float NeverHidden::allowedStaticMember4 = 3.4;188} // namespace GlobalTest189 190/******************************************************************************191 * Case three: Inside templates192 ******************************************************************************/193 194namespace TemplateTest {195 196// We never warn inside templates because it's usually infeasible to actually197// fix the warning.198 199template <typename T>200int allowedTemplate1 = 0;201 202template int allowedTemplate1<int>;203 204template <typename T>205inline int allowedTemplate2 = 0;206 207template int allowedTemplate2<int>;208 209} // namespace TemplateTest210 211/******************************************************************************212 * Case four: Nested classes213 ******************************************************************************/214 215namespace NestedClassTest {216// Unlike visibility, declexport annotations do not propagate down to nested217// classes. Hence on windows, we only avoid duplication of class members if218// their immediate containing class is annotated. On posix, we get avoid219// duplication if any containing class is annotated.220 221class VISIBLE Outer {222 // Visible because their class is exported223 inline static int allowedOuterMember = 0;224 int* allowedOuterFunction() {225 static int allowed = 0;226 return &allowed;227 }228 229 // No annotation, and visibility is only propagated on posix.230 class HiddenOnWindows {231 inline static int disallowedInnerMember = 0; // windows-warning {{'disallowedInnerMember' may be duplicated when built into a shared library: it is mutable, with external linkage and no import/export annotation}}232 233 234 int* disallowedInnerFunction() {235 static int disallowed = 0; // windows-warning {{'disallowed' may be duplicated when built into a shared library: it is mutable, with external linkage and no import/export annotation}}236 return &disallowed;237 }238 };239 240 class VISIBLE AlwaysVisible {241 inline static int allowedInnerMember = 0;242 243 int* allowedInnerFunction() {244 static int allowed = 0;245 return &allowed;246 }247 };248};249 250}