1*89a1d03eSRichard // RUN: %check_clang_tidy %s cppcoreguidelines-interfaces-global-init %t 2*89a1d03eSRichard makesInt()3*89a1d03eSRichardconstexpr int makesInt() { return 3; } takesInt(int i)4*89a1d03eSRichardconstexpr int takesInt(int i) { return i + 1; } takesIntPtr(int * i)5*89a1d03eSRichardconstexpr int takesIntPtr(int *i) { return *i; } 6*89a1d03eSRichard 7*89a1d03eSRichard extern int ExternGlobal; 8*89a1d03eSRichard static int GlobalScopeBadInit1 = ExternGlobal; 9*89a1d03eSRichard // CHECK-MESSAGES: [[@LINE-1]]:12: warning: initializing non-local variable with non-const expression depending on uninitialized non-local variable 'ExternGlobal' 10*89a1d03eSRichard static int GlobalScopeBadInit2 = takesInt(ExternGlobal); 11*89a1d03eSRichard // CHECK-MESSAGES: [[@LINE-1]]:12: warning: initializing non-local variable with non-const expression depending on uninitialized non-local variable 'ExternGlobal' 12*89a1d03eSRichard static int GlobalScopeBadInit3 = takesIntPtr(&ExternGlobal); 13*89a1d03eSRichard // CHECK-MESSAGES: [[@LINE-1]]:12: warning: initializing non-local variable with non-const expression depending on uninitialized non-local variable 'ExternGlobal' 14*89a1d03eSRichard static int GlobalScopeBadInit4 = 3 * (ExternGlobal + 2); 15*89a1d03eSRichard // CHECK-MESSAGES: [[@LINE-1]]:12: warning: initializing non-local variable with non-const expression depending on uninitialized non-local variable 'ExternGlobal' 16*89a1d03eSRichard 17*89a1d03eSRichard namespace ns { 18*89a1d03eSRichard static int NamespaceScope = makesInt(); 19*89a1d03eSRichard static int NamespaceScopeBadInit = takesInt(ExternGlobal); 20*89a1d03eSRichard // CHECK-MESSAGES: [[@LINE-1]]:12: warning: initializing non-local variable with non-const expression depending on uninitialized non-local variable 'ExternGlobal' 21*89a1d03eSRichard 22*89a1d03eSRichard struct A { 23*89a1d03eSRichard static int ClassScope; 24*89a1d03eSRichard static int ClassScopeBadInit; 25*89a1d03eSRichard }; 26*89a1d03eSRichard 27*89a1d03eSRichard int A::ClassScopeBadInit = takesInt(ExternGlobal); 28*89a1d03eSRichard // CHECK-MESSAGES: [[@LINE-1]]:8: warning: initializing non-local variable with non-const expression depending on uninitialized non-local variable 'ExternGlobal' 29*89a1d03eSRichard 30*89a1d03eSRichard static int FromClassBadInit = takesInt(A::ClassScope); 31*89a1d03eSRichard // CHECK-MESSAGES: [[@LINE-1]]:12: warning: initializing non-local variable with non-const expression depending on uninitialized non-local variable 'ClassScope' 32*89a1d03eSRichard } // namespace ns 33*89a1d03eSRichard 34*89a1d03eSRichard // "const int B::I;" is fine, it just ODR-defines B::I. See [9.4.3] Static 35*89a1d03eSRichard // members [class.static]. However the ODR-definitions are not in the right 36*89a1d03eSRichard // order (C::I after C::J, see [3.6.2.3]). 37*89a1d03eSRichard class B1 { 38*89a1d03eSRichard static const int I = 0; 39*89a1d03eSRichard static const int J = I; 40*89a1d03eSRichard }; 41*89a1d03eSRichard const int B1::J; 42*89a1d03eSRichard // CHECK-MESSAGES: [[@LINE-1]]:15: warning: initializing non-local variable with non-const expression depending on uninitialized non-local variable 'I' 43*89a1d03eSRichard const int B1::I; 44*89a1d03eSRichard f()45*89a1d03eSRichardvoid f() { 46*89a1d03eSRichard // This is fine, it's executed after dynamic initialization occurs. 47*89a1d03eSRichard static int G = takesInt(ExternGlobal); 48*89a1d03eSRichard } 49*89a1d03eSRichard 50*89a1d03eSRichard // Declaration then definition then usage is fine. 51*89a1d03eSRichard extern int ExternGlobal2; 52*89a1d03eSRichard extern int ExternGlobal2; 53*89a1d03eSRichard int ExternGlobal2 = 123; 54*89a1d03eSRichard static int GlobalScopeGoodInit1 = ExternGlobal2; 55*89a1d03eSRichard 56*89a1d03eSRichard 57*89a1d03eSRichard // Defined global variables are fine: 58*89a1d03eSRichard static int GlobalScope = makesInt(); 59*89a1d03eSRichard static int GlobalScopeGoodInit2 = takesInt(GlobalScope); 60*89a1d03eSRichard static int GlobalScope2 = takesInt(ns::NamespaceScope); 61*89a1d03eSRichard // Enums are fine. 62*89a1d03eSRichard enum Enum { kEnumValue = 1 }; 63*89a1d03eSRichard static int GlobalScopeFromEnum = takesInt(kEnumValue); 64*89a1d03eSRichard 65*89a1d03eSRichard // Leave constexprs alone. 66*89a1d03eSRichard extern constexpr int GlobalScopeConstexpr = makesInt(); 67*89a1d03eSRichard static constexpr int GlobalScopeConstexprOk = 68*89a1d03eSRichard takesInt(GlobalScopeConstexpr); 69*89a1d03eSRichard 70*89a1d03eSRichard // This is a pretty common instance: People are usually not using constexpr, but 71*89a1d03eSRichard // this is what they should write: 72*89a1d03eSRichard static constexpr const char kValue[] = "value"; Fingerprint(const char * value)73*89a1d03eSRichardconstexpr int Fingerprint(const char *value) { return 0; } 74*89a1d03eSRichard static int kFingerprint = Fingerprint(kValue); 75*89a1d03eSRichard 76*89a1d03eSRichard // This is fine because the ODR-definitions are in the right order (C::J after 77*89a1d03eSRichard // C::I). 78*89a1d03eSRichard class B2 { 79*89a1d03eSRichard static const int I = 0; 80*89a1d03eSRichard static const int J = I; 81*89a1d03eSRichard }; 82*89a1d03eSRichard const int B2::I; 83*89a1d03eSRichard const int B2::J; 84*89a1d03eSRichard 85