summaryrefslogtreecommitdiff
path: root/test/CodeGenCXX/static-data-member.cpp
blob: 5f4d9b6599b8cf5937d4a64e1d5b91c9d8600c08 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
// RUN: %clang_cc1 -triple x86_64-pc-linux -std=c++14 -emit-llvm -o - %s | FileCheck %s
// RUN: %clang_cc1 -triple x86_64-apple-darwin -std=c++14 -emit-llvm -o - %s \
// RUN:     | FileCheck %s --check-prefix=MACHO
// RUN: %clang_cc1 -triple x86_64-pc-windows-msvc -std=c++14 -emit-llvm -o - %s \
// RUN:     | FileCheck %s --check-prefix=MSVC
// RUN: %clang_cc1 -triple x86_64-pc-windows-msvc -std=c++17 -emit-llvm -o - %s \
// RUN:     | FileCheck %s --check-prefix=MSVC

// CHECK: @_ZN5test11A1aE = constant i32 10, align 4
// CHECK: @_ZN5test212_GLOBAL__N_11AIiE1xE = internal global i32 0, align 4
// CHECK: @_ZN5test31AIiE1xE = weak_odr global i32 0, comdat, align 4
// CHECK: @_ZGVN5test31AIiE1xE = weak_odr global i64 0, comdat($_ZN5test31AIiE1xE)
// MACHO: @_ZGVN5test31AIiE1xE = weak_odr global i64 0
// MACHO-NOT: comdat

// MSVC: @"\01?a@A@test1@@2HB" = linkonce_odr constant i32 10, comdat, align 4
// MSVC: @"\01?i@S@test1@@2HA" = external global i32
// MSVC: @"\01?x@?$A@H@?A@test2@@2HA" = internal global i32 0, align 4

// CHECK: _ZN5test51U2k0E = global i32 0
// CHECK: _ZN5test51U2k1E = global i32 0
// CHECK: _ZN5test51U2k2E = constant i32 76
// CHECK-NOT: test51U2k3E
// CHECK-NOT: test51U2k4E

// On Linux in C++14, neither of these are inline.
// CHECK: @_ZN16inline_constexpr1A10just_constE = available_externally constant i32 42
// CHECK: @_ZN16inline_constexpr1A10const_exprE = available_externally constant i32 43
//
// In MSVC, these are both implicitly inline regardless of the C++ standard
// version.
// MSVC: @"\01?just_const@A@inline_constexpr@@2HB" = linkonce_odr constant i32 42, comdat, align 4
// MSVC: @"\01?const_expr@A@inline_constexpr@@2HB" = linkonce_odr constant i32 43, comdat, align 4

// PR5564.
namespace test1 {
  struct A {
    static const int a = 10;
  };

  const int A::a;

  struct S { 
    static int i;
  };

  void f() { 
    int a = *&A::a + S::i;
  }
}

// Test that we don't use guards for initializing template static data
// members with internal linkage.
namespace test2 {
  int foo();

  namespace {
    template <class T> struct A {
      static int x;
    };

    template <class T> int A<T>::x = foo();
    template struct A<int>;
  }

  // CHECK-LABEL: define internal void @__cxx_global_var_init()
  // CHECK:      [[TMP:%.*]] = call i32 @_ZN5test23fooEv()
  // CHECK-NEXT: store i32 [[TMP]], i32* @_ZN5test212_GLOBAL__N_11AIiE1xE, align 4
  // CHECK-NEXT: ret void

  // MSVC-LABEL: define internal void @"\01??__Ex@?$A@H@?A@test2@@2HA@YAXXZ"()
  // MSVC:      [[TMP:%.*]] = call i32 @"\01?foo@test2@@YAHXZ"()
  // MSVC-NEXT: store i32 [[TMP]], i32* @"\01?x@?$A@H@?A@test2@@2HA", align 4
  // MSVC-NEXT: ret void
}

// Test that we don't use threadsafe statics when initializing
// template static data members.
namespace test3 {
  int foo();

  template <class T> struct A {
    static int x;
  };

  template <class T> int A<T>::x = foo();
  template struct A<int>;

  // CHECK-LABEL: define internal void @__cxx_global_var_init.1() {{.*}} comdat($_ZN5test31AIiE1xE)
  // MACHO-LABEL: define internal void @__cxx_global_var_init.1()
  // MACHO-NOT: comdat
  // CHECK:      [[GUARDBYTE:%.*]] = load i8, i8* bitcast (i64* @_ZGVN5test31AIiE1xE to i8*)
  // CHECK-NEXT: [[UNINITIALIZED:%.*]] = icmp eq i8 [[GUARDBYTE]], 0
  // CHECK-NEXT: br i1 [[UNINITIALIZED]]
  // CHECK:      [[TMP:%.*]] = call i32 @_ZN5test33fooEv()
  // CHECK-NEXT: store i32 [[TMP]], i32* @_ZN5test31AIiE1xE, align 4
  // CHECK-NEXT: store i64 1, i64* @_ZGVN5test31AIiE1xE
  // CHECK-NEXT: br label
  // CHECK:      ret void
}

// Test that we can fold member lookup expressions which resolve to static data
// members.
namespace test4 {
  struct A {
    static const int n = 76;
  };

  int f(A *a) {
    // CHECK-LABEL: define i32 @_ZN5test41fEPNS_1AE
    // CHECK: ret i32 76
    return a->n;
  }
}

// Test that static data members in unions behave properly.
namespace test5 {
  union U {
    static int k0;
    static const int k1;
    static const int k2 = 76;
    static const int k3;
    static const int k4 = 81;
  };
  int U::k0;
  const int U::k1 = (k0 = 9, 42);
  const int U::k2;

  // CHECK: store i32 9, i32* @_ZN5test51U2k0E
  // CHECK: store i32 {{.*}}, i32* @_ZN5test51U2k1E
  // CHECK-NOT: store {{.*}} i32* @_ZN5test51U2k2E
}

// Test that MSVC mode static constexpr data members are always inline, even pre
// C++17.
namespace inline_constexpr {
struct A {
  static const int just_const = 42;
  static constexpr int const_expr = 43;
};
int useit() { return *&A::just_const + *&A::const_expr; }
}