aboutsummaryrefslogtreecommitdiff
path: root/test/CodeGenCXX/static-local-in-local-class.cpp
blob: a70afcdc3883e7749c1c907f062211591da0ae3d (plain) (blame)
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
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
// RUN: %clang_cc1 -triple x86_64-linux -fblocks -emit-llvm -o - %s -std=c++1y | FileCheck %s

// CHECK: @"_ZZZNK17pr18020_constexpr3$_1clEvENKUlvE_clEvE2l2" =
// CHECK: internal global i32* @"_ZZNK17pr18020_constexpr3$_1clEvE2l1"
// CHECK: @_ZZL14deduced_returnvE1n = internal global i32 42
// CHECK: @_ZZZL20block_deduced_returnvEUb_E1n = internal global i32 42
// CHECK: @_ZZ18static_local_labelPvE1q = linkonce_odr global i8* blockaddress(@_Z18static_local_labelPv, %{{.*}})
// CHECK: @"_ZZNK3$_2clEvE1x" = internal global i32 42

namespace pr6769 {
struct X {
  static void f();
};

void X::f() {
  static int *i;
  {
    struct Y {
      static void g() {
        i = new int();
	*i = 100;
	(*i) = (*i) +1;
      }
    };
    (void)Y::g();
  }
  (void)i;
}
}

namespace pr7101 {
void foo() {
    static int n = 0;
    struct Helper {
        static void Execute() {
            n++;
        }
    };
    Helper::Execute();
}
}

// These tests all break the assumption that the static var decl has to be
// emitted before use of the var decl.  This happens because we defer emission
// of variables with internal linkage and no initialization side effects, such
// as 'x'.  Then we hit operator()() in 'f', and emit the callee before we emit
// the arguments, so we emit the innermost function first.

namespace pr18020_lambda {
// Referring to l1 before emitting it used to crash.
auto x = []() {
  static int l1 = 0;
  return [] { return l1; };
};
int f() { return x()(); }
}

// CHECK-LABEL: define internal i32 @"_ZZNK14pr18020_lambda3$_0clEvENKUlvE_clEv"
// CHECK: load i32, i32* @"_ZZNK14pr18020_lambda3$_0clEvE2l1"

namespace pr18020_constexpr {
// Taking the address of l1 in a constant expression used to crash.
auto x = []() {
  static int l1 = 0;
  return [] {
    static int *l2 = &l1;
    return *l2;
  };
};
int f() { return x()(); }
}

// CHECK-LABEL: define internal i32 @"_ZZNK17pr18020_constexpr3$_1clEvENKUlvE_clEv"
// CHECK: load i32*, i32** @"_ZZZNK17pr18020_constexpr3$_1clEvENKUlvE_clEvE2l2"

// Lambda-less reduction that references l1 before emitting it.  This didn't
// crash if you put it in a namespace.
struct pr18020_class {
  auto operator()() {
    static int l1 = 0;
    struct U {
      int operator()() { return l1; }
    };
    return U();
  }
};
static pr18020_class x;
int pr18020_f() { return x()(); }

// CHECK-LABEL: define linkonce_odr i32 @_ZZN13pr18020_classclEvEN1UclEv
// CHECK: load i32, i32* @_ZZN13pr18020_classclEvE2l1

// In this test case, the function containing the static local will not be
// emitted because it is unneeded. However, the operator call of the inner class
// is called, and the static local is referenced and must be emitted.
static auto deduced_return() {
  static int n = 42;
  struct S { int *operator()() { return &n; } };
  return S();
}
extern "C" int call_deduced_return_operator() {
  return *decltype(deduced_return())()();
}

// CHECK-LABEL: define i32 @call_deduced_return_operator()
// CHECK: call i32* @_ZZL14deduced_returnvEN1SclEv(
// CHECK: load i32, i32* %
// CHECK: ret i32 %

// CHECK-LABEL: define internal i32* @_ZZL14deduced_returnvEN1SclEv(%struct.S* %this)
// CHECK: ret i32* @_ZZL14deduced_returnvE1n

static auto block_deduced_return() {
  auto (^b)() = ^() {
    static int n = 42;
    struct S { int *operator()() { return &n; } };
    return S();
  };
  return b();
}
extern "C" int call_block_deduced_return() {
  return *decltype(block_deduced_return())()();
}

// CHECK-LABEL: define i32 @call_block_deduced_return()
// CHECK: call i32* @_ZZZL20block_deduced_returnvEUb_EN1SclEv(
// CHECK: load i32, i32* %
// CHECK: ret i32 %

// CHECK-LABEL: define internal i32* @_ZZZL20block_deduced_returnvEUb_EN1SclEv(%struct.S.6* %this) #0 align 2 {
// CHECK: ret i32* @_ZZZL20block_deduced_returnvEUb_E1n

inline auto static_local_label(void *p) {
  if (p)
    goto *p;
  static void *q = &&label;
  struct S { static void *get() { return q; } };
  return S();
label:
  __builtin_abort();
}
void *global_label = decltype(static_local_label(0))::get();

// CHECK-LABEL: define linkonce_odr i8* @_ZZ18static_local_labelPvEN1S3getEv()
// CHECK: %[[lbl:[^ ]*]] = load i8*, i8** @_ZZ18static_local_labelPvE1q
// CHECK: ret i8* %[[lbl]]

auto global_lambda = []() {
  static int x = 42;
  struct S { static int *get() { return &x; } };
  return S();
};
extern "C" int use_global_lambda() {
  return *decltype(global_lambda())::get();
}
// CHECK-LABEL: define i32 @use_global_lambda()
// CHECK: call i32* @"_ZZNK3$_2clEvEN1S3getEv"()

// CHECK-LABEL: define internal i32* @"_ZZNK3$_2clEvEN1S3getEv"()
// CHECK: ret i32* @"_ZZNK3$_2clEvE1x"