|  | // RUN: %clang_cc1 %s -triple=x86_64-pc-linuxs -emit-llvm -std=c++98 -o - | FileCheck -check-prefix=CHECK -check-prefix=CHECK98 %s | 
|  | // RUN: %clang_cc1 %s -triple=x86_64-pc-linuxs -emit-llvm -std=c++11 -o - | FileCheck -check-prefix=CHECK -check-prefix=CHECK11 %s | 
|  | // RUN: %clang_cc1 %s -triple=x86_64-pc-linuxs -emit-llvm -std=c++20 -o - | FileCheck -check-prefix=CHECK -check-prefix=CHECK20 %s | 
|  |  | 
|  | // CHECK: @_ZZ1hvE1i = internal global i32 0, align 4 | 
|  | // CHECK: @base_req ={{.*}} global [4 x i8] c"foo\00", align 1 | 
|  | // CHECK: @base_req_uchar ={{.*}} global [4 x i8] c"bar\00", align 1 | 
|  |  | 
|  | // CHECK: @_ZZN5test31BC1EvE1u = internal global { i8, [3 x i8] } { i8 97, [3 x i8] undef }, align 4 | 
|  |  | 
|  | // CHECK20: @_ZZN5test51fEvE1a = internal constant %"struct.test5::A" { i32 42 } | 
|  |  | 
|  | // CHECK: @_ZZ2h2vE1i = linkonce_odr global i32 0, comdat, align 4 | 
|  | // CHECK: @_ZGVZ2h2vE1i = linkonce_odr global i64 0, comdat, align 8{{$}} | 
|  | // CHECK: @_ZZN5test1L6getvarEiE3var = internal constant [4 x i32] [i32 1, i32 0, i32 2, i32 4], align 16 | 
|  | // CHECK98: @_ZZN5test414useStaticLocalEvE3obj = linkonce_odr global %"struct.test4::HasVTable" zeroinitializer, comdat, align 8 | 
|  | // CHECK11: @_ZZN5test414useStaticLocalEvE3obj = linkonce_odr global %"struct.test4::HasVTable" { ptr getelementptr inbounds inrange(-16, 8) ({ [3 x ptr] }, ptr @_ZTVN5test49HasVTableE, i32 0, i32 0, i32 2) }, comdat, align 8 | 
|  |  | 
|  | struct A { | 
|  | A(); | 
|  | ~A(); | 
|  | }; | 
|  |  | 
|  | void f() { | 
|  | // CHECK: load atomic i8, ptr @_ZGVZ1fvE1a acquire, align 8 | 
|  | // CHECK: call i32 @__cxa_guard_acquire | 
|  | // CHECK: call void @_ZN1AC1Ev | 
|  | // CHECK: call i32 @__cxa_atexit(ptr @_ZN1AD1Ev, ptr @_ZZ1fvE1a, ptr @__dso_handle) | 
|  | // CHECK: call void @__cxa_guard_release | 
|  | static A a; | 
|  | } | 
|  |  | 
|  | void g() { | 
|  | // CHECK: call noalias noundef nonnull ptr @_Znwm(i64 noundef 1) | 
|  | // CHECK: call void @_ZN1AC1Ev( | 
|  | static A& a = *new A; | 
|  | } | 
|  |  | 
|  | int a(); | 
|  | void h() { | 
|  | static const int i = a(); | 
|  | } | 
|  |  | 
|  | // CHECK: define linkonce_odr void @_Z2h2v() {{.*}} comdat { | 
|  | inline void h2() { | 
|  | static int i = a(); | 
|  | } | 
|  |  | 
|  | void h3() { | 
|  | h2(); | 
|  | } | 
|  |  | 
|  | // PR6980: this shouldn't crash | 
|  | namespace test0 { | 
|  | struct A { A(); }; | 
|  | __attribute__((noreturn)) int throw_exception(); | 
|  |  | 
|  | void test() { | 
|  | throw_exception(); | 
|  | static A r; | 
|  | } | 
|  | } | 
|  |  | 
|  | namespace test1 { | 
|  | // CHECK-LABEL: define internal noundef i32 @_ZN5test1L6getvarEi( | 
|  | static inline int getvar(int index) { | 
|  | static const int var[] = { 1, 0, 2, 4 }; | 
|  | return var[index]; | 
|  | } | 
|  |  | 
|  | void test() { (void) getvar(2); } | 
|  | } | 
|  |  | 
|  | // Make sure we emit the initializer correctly for the following: | 
|  | char base_req[] = { "foo" }; | 
|  | unsigned char base_req_uchar[] = { "bar" }; | 
|  |  | 
|  | namespace union_static_local { | 
|  | // CHECK-LABEL: define internal void @_ZZN18union_static_local4testEvEN1c4mainEv | 
|  | // CHECK: call void @_ZN18union_static_local1fEPNS_1xE(ptr noundef @_ZZN18union_static_local4testEvE3foo) | 
|  | union x { long double y; const char *x[2]; }; | 
|  | void f(union x*); | 
|  | void test() { | 
|  | static union x foo = { .x = { "a", "b" } }; | 
|  | struct c { | 
|  | static void main() { | 
|  | f(&foo); | 
|  | } | 
|  | }; | 
|  | c::main(); | 
|  | } | 
|  | } | 
|  |  | 
|  | //   Static variables should be consistent across constructor | 
|  | //   or destructor variants. | 
|  | namespace test2 { | 
|  | struct A { | 
|  | A(); | 
|  | ~A(); | 
|  | }; | 
|  |  | 
|  | struct B : virtual A { | 
|  | B(); | 
|  | ~B(); | 
|  | }; | 
|  |  | 
|  | // If we ever implement this as a delegate ctor call, just change | 
|  | // this to take variadic arguments or something. | 
|  | extern int foo(); | 
|  | B::B() { | 
|  | static int x = foo(); | 
|  | } | 
|  | // CHECK-LABEL: define{{.*}} void @_ZN5test21BC2Ev | 
|  | // CHECK:   load atomic i8, ptr @_ZGVZN5test21BC1EvE1x acquire, align 8 | 
|  | // CHECK:   call i32 @__cxa_guard_acquire(ptr @_ZGVZN5test21BC1EvE1x) | 
|  | // CHECK:   [[T0:%.*]] = call noundef i32 @_ZN5test23fooEv() | 
|  | // CHECK:   store i32 [[T0]], ptr @_ZZN5test21BC1EvE1x, | 
|  | // CHECK:   call void @__cxa_guard_release(ptr @_ZGVZN5test21BC1EvE1x) | 
|  |  | 
|  | // CHECK-LABEL: define{{.*}} void @_ZN5test21BC1Ev | 
|  | // CHECK:   load atomic i8, ptr @_ZGVZN5test21BC1EvE1x acquire, align 8 | 
|  | // CHECK:   call i32 @__cxa_guard_acquire(ptr @_ZGVZN5test21BC1EvE1x) | 
|  | // CHECK:   [[T0:%.*]] = call noundef i32 @_ZN5test23fooEv() | 
|  | // CHECK:   store i32 [[T0]], ptr @_ZZN5test21BC1EvE1x, | 
|  | // CHECK:   call void @__cxa_guard_release(ptr @_ZGVZN5test21BC1EvE1x) | 
|  |  | 
|  | // This is just for completeness, because we actually emit this | 
|  | // using a delegate dtor call. | 
|  | B::~B() { | 
|  | static int y = foo(); | 
|  | } | 
|  | // CHECK-LABEL: define{{.*}} void @_ZN5test21BD2Ev( | 
|  | // CHECK:   load atomic i8, ptr @_ZGVZN5test21BD1EvE1y acquire, align 8 | 
|  | // CHECK:   call i32 @__cxa_guard_acquire(ptr @_ZGVZN5test21BD1EvE1y) | 
|  | // CHECK:   [[T0:%.*]] = call noundef i32 @_ZN5test23fooEv() | 
|  | // CHECK:   store i32 [[T0]], ptr @_ZZN5test21BD1EvE1y, | 
|  | // CHECK:   call void @__cxa_guard_release(ptr @_ZGVZN5test21BD1EvE1y) | 
|  |  | 
|  | // CHECK-LABEL: define{{.*}} void @_ZN5test21BD1Ev( | 
|  | // CHECK:   call void @_ZN5test21BD2Ev( | 
|  | } | 
|  |  | 
|  | // This shouldn't error out. | 
|  | namespace test3 { | 
|  | struct A { | 
|  | A(); | 
|  | ~A(); | 
|  | }; | 
|  |  | 
|  | struct B : virtual A { | 
|  | B(); | 
|  | ~B(); | 
|  | }; | 
|  |  | 
|  | B::B() { | 
|  | union U { char x; int i; }; | 
|  | static U u = { 'a' }; | 
|  | } | 
|  | // CHECK-LABEL: define{{.*}} void @_ZN5test31BC2Ev( | 
|  | // CHECK-LABEL: define{{.*}} void @_ZN5test31BC1Ev( | 
|  | } | 
|  |  | 
|  | // We forgot to set the comdat when replacing the global with a different type. | 
|  | namespace test4 { | 
|  | struct HasVTable { | 
|  | virtual void f(); | 
|  | }; | 
|  | inline HasVTable &useStaticLocal() { | 
|  | static HasVTable obj; | 
|  | return obj; | 
|  | } | 
|  | void useit() { | 
|  | useStaticLocal(); | 
|  | } | 
|  | // CHECK: define linkonce_odr noundef nonnull align 8 dereferenceable(8) ptr @_ZN5test414useStaticLocalEv() | 
|  | // CHECK: ret ptr{{.*}} @_ZZN5test414useStaticLocalEvE3obj | 
|  | } | 
|  |  | 
|  | #if __cplusplus >= 202002L | 
|  | // A const object with constexpr destructor can be emitted as a constant. | 
|  | namespace test5 { | 
|  | struct A { | 
|  | constexpr A(int x) : x_(x) {} | 
|  | constexpr ~A() {} | 
|  | int x_; | 
|  | }; | 
|  | const int *f() { | 
|  | static const A a{42}; | 
|  | return &a.x_; | 
|  | } | 
|  | } | 
|  | #endif |