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